From b04ca9e2fbaffb4b553127bd08bf80fab5605954 Mon Sep 17 00:00:00 2001 From: sridhargaddam Date: Mon, 20 Apr 2015 10:29:54 +0000 Subject: [PATCH] Support multiple IPv6 prefixes on internal router ports for an HA Router 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 | 6 +++ neutron/agent/l3/router_info.py | 7 ++- .../tests/functional/agent/test_l3_agent.py | 48 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/neutron/agent/l3/ha_router.py b/neutron/agent/l3/ha_router.py index 35685b5b5..0b5e16930 100644 --- a/neutron/agent/l3/ha_router.py +++ b/neutron/agent/l3/ha_router.py @@ -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) diff --git a/neutron/agent/l3/router_info.py b/neutron/agent/l3/router_info.py index 3f0d801a6..b9b54b610 100644 --- a/neutron/agent/l3/router_info.py +++ b/neutron/agent/l3/router_info.py @@ -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 diff --git a/neutron/tests/functional/agent/test_l3_agent.py b/neutron/tests/functional/agent/test_l3_agent.py index 0d8b31c12..0683422e2 100755 --- a/neutron/tests/functional/agent/test_l3_agent.py +++ b/neutron/tests/functional/agent/test_l3_agent.py @@ -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): -- 2.45.2