]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Support multiple IPv6 prefixes on internal router ports for an HA Router
authorsridhargaddam <sridhar.gaddam@enovance.com>
Mon, 20 Apr 2015 10:29:54 +0000 (10:29 +0000)
committerIhar Hrachyshka <ihrachys@redhat.com>
Mon, 1 Jun 2015 12:50:58 +0000 (12:50 +0000)
As part of BP multiple IPv6 prefixes, we can have multiple IPv6 prefixes on
router internal ports. Patch, I7d4e8194815e626f1cfa267f77a3f2475fdfa3d1, adds
the necessary support for a legacy router.

For an HA router, instead of configuring the addresses on the router internal
ports we should be updating the keepalived config file and let keepalived
configure the addresses depending on the state of the router.

Following are the observations with the current code for an HA router.
1. IPv6 addresses are configured on the router internal ports (i.e., qr-xxx)
   irrespective of the state of the router. As the same IP is configured on multiple
   ports you will notice dadfailed status on the ports.
2. Keepalived configuration is not updated with the new IPv6 addresses.

This patch addresses the above issues for an HA Router.

Closes-Bug: #1446161
Partially-implements: blueprint multiple-ipv6-prefixes
Change-Id: Icb9a0e4e6e5deafbdc0135ce7e6b100b1725df66
(cherry picked from commit 99de7cdf700218a54fa6fc2e194cca3ccb35abd4)

neutron/agent/l3/ha_router.py
neutron/agent/l3/router_info.py
neutron/tests/functional/agent/test_l3_agent.py

index 35685b5b51ff750527f9d3e90d82cfff92d7e2ed..0b5e169303a180ad01c08ba949c669f1ebf31bff 100644 (file)
@@ -255,6 +255,12 @@ class HaRouter(router.RouterInfo):
     def remove_floating_ip(self, device, ip_cidr):
         self._remove_vip(ip_cidr)
 
+    def internal_network_updated(self, interface_name, ip_cidrs):
+        self._clear_vips(interface_name)
+        self._disable_ipv6_addressing_on_interface(interface_name)
+        for ip_cidr in ip_cidrs:
+            self._add_vip(ip_cidr, interface_name)
+
     def internal_network_added(self, port):
         port_id = port['id']
         interface_name = self.get_internal_device_name(port_id)
index 3f0d801a660600fd7b433755f51bce31f29d06a8..b9b54b6107dd692f085207711ce665bd0181bb9b 100644 (file)
@@ -353,6 +353,10 @@ class RouterInfo(object):
                   self.router_id)
         self.radvd.disable()
 
+    def internal_network_updated(self, interface_name, ip_cidrs):
+        self.driver.init_l3(interface_name, ip_cidrs=ip_cidrs,
+            namespace=self.ns_name)
+
     def _process_internal_ports(self):
         existing_port_ids = set(p['id'] for p in self.internal_ports)
 
@@ -385,8 +389,7 @@ class RouterInfo(object):
                 self.internal_ports[index] = updated_ports[p['id']]
                 interface_name = self.get_internal_device_name(p['id'])
                 ip_cidrs = common_utils.fixed_ip_cidrs(p['fixed_ips'])
-                self.driver.init_l3(interface_name, ip_cidrs=ip_cidrs,
-                        namespace=self.ns_name)
+                self.internal_network_updated(interface_name, ip_cidrs)
                 enable_ra = enable_ra or self._port_has_ipv6_subnet(p)
 
         # Enable RA
index 0d8b31c12c58d8615fe0b9beaa9bfb20ed3faf29..0683422e21756fe631304d6c1dce87f88e41419e 100755 (executable)
@@ -789,6 +789,54 @@ class L3HATestFramework(L3AgentTestFramework):
         utils.wait_until_true(lambda: not router1.radvd.enabled, timeout=10)
         _check_lla_status(router1, False)
 
+    def test_ha_router_process_ipv6_subnets_to_existing_port(self):
+        router_info = self.generate_router_info(enable_ha=True, ip_version=6)
+        router = self.manage_router(self.agent, router_info)
+
+        def verify_ip_in_keepalived_config(router, iface):
+            config = router.keepalived_manager.config.get_config_str()
+            ip_cidrs = common_utils.fixed_ip_cidrs(iface['fixed_ips'])
+            for ip_addr in ip_cidrs:
+                self.assertIn(ip_addr, config)
+
+        interface_id = router.router[l3_constants.INTERFACE_KEY][0]['id']
+        slaac = l3_constants.IPV6_SLAAC
+        slaac_mode = {'ra_mode': slaac, 'address_mode': slaac}
+
+        # Add a second IPv6 subnet to the router internal interface.
+        self._add_internal_interface_by_subnet(router.router, count=1,
+                ip_version=6, ipv6_subnet_modes=[slaac_mode],
+                interface_id=interface_id)
+        router.process(self.agent)
+        utils.wait_until_true(lambda: router.ha_state == 'master')
+
+        # Verify that router internal interface is present and is configured
+        # with IP address from both the subnets.
+        internal_iface = router.router[l3_constants.INTERFACE_KEY][0]
+        self.assertEqual(2, len(internal_iface['fixed_ips']))
+        self._assert_internal_devices(router)
+
+        # Verify that keepalived config is properly updated.
+        verify_ip_in_keepalived_config(router, internal_iface)
+
+        # Remove one subnet from the router internal iface
+        interfaces = copy.deepcopy(router.router.get(
+            l3_constants.INTERFACE_KEY, []))
+        fixed_ips, subnets = [], []
+        fixed_ips.append(interfaces[0]['fixed_ips'][0])
+        subnets.append(interfaces[0]['subnets'][0])
+        interfaces[0].update({'fixed_ips': fixed_ips, 'subnets': subnets})
+        router.router[l3_constants.INTERFACE_KEY] = interfaces
+        router.process(self.agent)
+
+        # Verify that router internal interface has a single ipaddress
+        internal_iface = router.router[l3_constants.INTERFACE_KEY][0]
+        self.assertEqual(1, len(internal_iface['fixed_ips']))
+        self._assert_internal_devices(router)
+
+        # Verify that keepalived config is properly updated.
+        verify_ip_in_keepalived_config(router, internal_iface)
+
 
 class MetadataFakeProxyHandler(object):