From: sridhargaddam Date: Mon, 20 Apr 2015 10:29:54 +0000 (+0000) Subject: Support multiple IPv6 prefixes on internal router ports for an HA Router X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=99de7cdf700218a54fa6fc2e194cca3ccb35abd4;p=openstack-build%2Fneutron-build.git 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 --- diff --git a/neutron/agent/l3/ha_router.py b/neutron/agent/l3/ha_router.py index 473ba412f..ebccf32b4 100644 --- a/neutron/agent/l3/ha_router.py +++ b/neutron/agent/l3/ha_router.py @@ -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) 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 d21ee536f..b864c0f3e 100755 --- a/neutron/tests/functional/agent/test_l3_agent.py +++ b/neutron/tests/functional/agent/test_l3_agent.py @@ -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):