]> 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)
committersridhargaddam <sridhar.gaddam@enovance.com>
Mon, 27 Apr 2015 13:20:38 +0000 (13:20 +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

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

index 473ba412fccb88239476c388553e254ce4961111..ebccf32b4ab37c4504c678a5a1fa0f791b9851c1 100644 (file)
@@ -247,6 +247,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 d21ee536fa31311ae3b3c5a97d0765ed968d60e1..b864c0f3e64e556b682482b57ca86dce769bc429 100755 (executable)
@@ -765,6 +765,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):