Skip to content

Conversation

@ProjectMoon
Copy link

This pull request fixes a concurrency issue when disabling static NAT on a bunch of IPs simultaneously. Under the old behavior, executing multiple disable requests would result in invalid IP associations being sent to the virtual router. This commit changes the behavior to apply an IP association for only the IP being added/released, which means that it is impossible for the virtual router to receive invalid data.

This was tested against a virtual router running on KVM and VMware. It would be nice to have some input how this change could affect redundant routers and other static NAT providers.

@ProjectMoon ProjectMoon changed the title Enable/disable static NAT associates only relevant IPs. CLOUDSTACK-9317: Enable/disable static NAT associates only relevant IPs. Mar 22, 2016
List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
// get the list of public ip's that need to be applied for the static NAT. manipulating only these
// ips prevents concurrency issues when disabling static nat at the same time.
List<IPAddressVO> userIps = new ArrayList<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ProjectMoon, what about creating a method that returns the userIps list. This new method would contain lines 1719-1722. Then, you would be able to write a unit test and add lines 1717-1718 as its java documentation.

@ProjectMoon
Copy link
Author

I added a basic test now and moved the method out @rafaelweingartner. Maybe there are more scenarios that can be tested?

List<IPAddressVO> ips = _ipManager.getStaticNatSourceIps(Collections.singletonList(snat));
Assert.assertNotNull(ips);
Assert.assertEquals(1, ips.size());

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also add a check here to confirm that the ipAddrDao.findById was called only once.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is it possible to do that with JUnit?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do not use JUnit for that.
You use your mock API such as easy mock or mockito that we use here.

you can do something like this:
Mockito.verify(mock, Mockito.times(1)).method(parameter);

@rafaelweingartner
Copy link
Member

It is always great to see parts of a bigger method being extracted to smaller ones, and then test cases and java docs being used.

I believe the tests like you did are ok, I would only add another assert there as I pointed out at line 67 of the test class.

if (firstIP) {
sourceNat = true;
/* enable sourceNAT for the first ip of the public interface as long as it's source nat. */
if (firstIP && !sourceNat) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For additional public subnet case, sourceNat should be set to 'true' to add a source nat rule on VR for the first ip in that subnet. This changes will break that.

If there is no source nat rule for the additional public subnet the traffic to this subnet from he VMs always go through the default source nat interface.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I trigger this case using the CS API? Is it by adding multiple NICs to the virtual router?

@cristofolini
Copy link
Contributor

@ProjectMoon According to that comment on line 781 in CommandSetupHelper the conditional that follows is there to enable sourceNAT, yet you removed the command setting the sourceNat variable to true. Is that being done somewhere else? You might want to change that comment to clarify your change and avoid confusion in the future. :)

@ProjectMoon
Copy link
Author

@cristofolini The idea was that the source NAT IP is always the first IP. Not sure if the logic is correct. But apparently I need to correct the logic for the case @jayapalu mentioned.

@swill
Copy link
Contributor

swill commented May 12, 2016

CI RESULTS

Tests Run: 85
  Skipped: 0
   Failed: 0
   Errors: 0
 Duration: 8h 34m 12s

Associated Uploads

/tmp/MarvinLogs/DeployDataCenter__May_12_2016_05_59_28_PU8AAL:

/tmp/MarvinLogs/test_network_N9BTSG:

/tmp/MarvinLogs/test_vpc_routers_5Y7V1C:

Uploads will be available until 2016-07-12 02:00:00 +0200 CEST

Comment created by upr comment.

@swill
Copy link
Contributor

swill commented May 12, 2016

Can I get some code review on this one? Thx...

@DaanHoogland
Copy link
Contributor

tag:needsreview

@ProjectMoon
Copy link
Author

It would be useful for someone knowledgeable in the network internals to elaborate on @jayapalu's comment. We currently do not use the feature he's talking about, so it would be helpful if someone could direct me where to find setup instructions for that case.

@swill
Copy link
Contributor

swill commented May 26, 2016

CI is clean and everything is green. I need some code review on this one. Thanks...

@ProjectMoon
Copy link
Author

Rebased against latest 4.7.

@bvbharatk
Copy link
Contributor

ACS CI BVT Run

Sumarry:
Build Number 154
Hypervisor xenserver
NetworkType Advanced
Passed=73
Failed=0
Skipped=3

Link to logs Folder (search by build_no): https://www.dropbox.com/sh/yj3wnzbceo9uef2/AAB6u-Iap-xztdm6jHX9SjPja?dl=0

Failed tests:

Skipped tests:
test_vm_nic_adapter_vmxnet3
test_static_role_account_acls
test_deploy_vgpu_enabled_vm

Passed test suits:
test_deploy_vm_with_userdata.py
test_affinity_groups_projects.py
test_portable_publicip.py
test_vpc_vpn.py
test_over_provisioning.py
test_global_settings.py
test_scale_vm.py
test_service_offerings.py
test_routers_iptables_default_policy.py
test_routers.py
test_reset_vm_on_reboot.py
test_snapshots.py
test_deploy_vms_with_varied_deploymentplanners.py
test_login.py
test_list_ids_parameter.py
test_public_ip_range.py
test_multipleips_per_nic.py
test_regions.py
test_affinity_groups.py
test_network_acl.py
test_pvlan.py
test_volumes.py
test_nic.py
test_deploy_vm_root_resize.py
test_resource_detail.py
test_secondary_storage.py
test_vm_life_cycle.py
test_disk_offerings.py

@ProjectMoon
Copy link
Author

Updated to latest 4.7.

@ProjectMoon
Copy link
Author

Closing to reopen against 4.8.

@jayapalu
Copy link
Contributor

I tested this patch with below steps. It is not removing the ip addresses on the VR interface. Some times observed that even there is one ip with static nat but the interface got removed.

Steps to test this:

  1. Configure additional public subnet and acquire 4 ip addresses
  2. Enabled static nat on the 4 public ip addresses.
  3. Go to VR console and see the new public interface created and ips are configured on the interface.
  4. Disable static on all 4 public addresses (disable from UI one by one quickly)
    expected: inteface should get removed from the VR. But the interface is there in VR

In another case in step4 disable static nat on only 3 public ip addresses.
expected: interface with one ip supposed to be there. But the interface is deleted

@ProjectMoon
Copy link
Author

@jayapalu Can you post this in the new version of the fix? (And possibly re-test, if you were using an older version)

@jayapalu
Copy link
Contributor

jayapalu commented Jan 13, 2017

@ProjectMoon
I am working on it. I am working fix, will be updating the fix soon.

@jayapalu
Copy link
Contributor

@ProjectMoon
Added the new PR #1908 for addressing missing issues in this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants