From: Thomas Goirand Date: Thu, 16 Jul 2015 13:08:09 +0000 (+0200) Subject: Merge tag '7.0.0_b1' into debian/liberty X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=950370f067bdd02413a90280ea5259d655513a1c;p=openstack-build%2Fneutron-build.git Merge tag '7.0.0_b1' into debian/liberty Neutron liberty-1 milestone (7.0.0.0b1) --- 950370f067bdd02413a90280ea5259d655513a1c diff --cc neutron/agent/l3/ha.py index 9a55d25c2,95f3fd763..5dad68757 --- a/neutron/agent/l3/ha.py +++ b/neutron/agent/l3/ha.py @@@ -135,16 -134,16 +134,24 @@@ class AgentMixin(object) else: LOG.debug('Closing metadata proxy for router %s', router_id) self.metadata_driver.destroy_monitored_metadata_proxy( - self.process_monitor, ri.router_id, ri.ns_name, self.conf) + self.process_monitor, ri.router_id, self.conf) + + def _update_radvd_daemon(self, ri, state): + # Radvd has to be spawned only on the Master HA Router. If there are + # any state transitions, we enable/disable radvd accordingly. + if state == 'master': + ri.enable_radvd() + else: + ri.disable_radvd() + def _update_radvd_daemon(self, ri, state): + # Radvd has to be spawned only on the Master HA Router. If there are + # any state transitions, we enable/disable radvd accordingly. + if state == 'master': + ri.enable_radvd() + else: + ri.disable_radvd() + def notify_server(self, batched_events): translation_map = {'master': 'active', 'backup': 'standby', diff --cc neutron/agent/l3/ha_router.py index a44f92ea1,b430f44e5..a9190bef8 --- a/neutron/agent/l3/ha_router.py +++ b/neutron/agent/l3/ha_router.py @@@ -200,16 -195,13 +195,16 @@@ class HaRouter(router.RouterInfo) netaddr.IPAddress(gw_ip).version == 4 else n_consts.IPv6_ANY) instance = self._get_keepalived_instance() - instance.virtual_routes = ( - [route for route in instance.virtual_routes - if route.destination != default_gw]) - instance.virtual_routes.append( - keepalived.KeepalivedVirtualRoute( - default_gw, gw_ip, interface_name)) + default_gw_rts.append(keepalived.KeepalivedVirtualRoute( + default_gw, gw_ip, interface_name)) + instance.virtual_routes.gateway_routes = default_gw_rts + + if enable_ra_on_gw: + self.driver.configure_ipv6_ra(self.ns_name, interface_name) + if enable_ra_on_gw: + self.driver.configure_ipv6_ra(self.ns_name, interface_name) + def _should_delete_ipv6_lladdr(self, ipv6_lladdr): """Only the master should have any IP addresses configured. Let keepalived manage IPv6 link local addresses, the same way we let diff --cc neutron/tests/functional/agent/test_l3_agent.py index 5b503abc6,f2674d82a..2c4b781bd mode 100755,100644..100644 --- a/neutron/tests/functional/agent/test_l3_agent.py +++ b/neutron/tests/functional/agent/test_l3_agent.py @@@ -780,29 -753,27 +753,100 @@@ class L3HATestFramework(L3AgentTestFram utils.wait_until_true(lambda: router1.ha_state == 'master') utils.wait_until_true(lambda: router2.ha_state == 'backup') + self.fail_ha_router(router1) + + utils.wait_until_true(lambda: router2.ha_state == 'master') + utils.wait_until_true(lambda: router1.ha_state == 'backup') + + def test_ha_router_ipv6_radvd_status(self): + router_info = self.generate_router_info(ip_version=6, enable_ha=True) + router1 = self.manage_router(self.agent, router_info) + utils.wait_until_true(lambda: router1.ha_state == 'master') + utils.wait_until_true(lambda: router1.radvd.enabled) + + def _check_lla_status(router, expected): + internal_devices = router.router[l3_constants.INTERFACE_KEY] + for device in internal_devices: + lladdr = ip_lib.get_ipv6_lladdr(device['mac_address']) + exists = ip_lib.device_exists_with_ips_and_mac( + router.get_internal_device_name(device['id']), [lladdr], + device['mac_address'], router.ns_name) + self.assertEqual(expected, exists) + + _check_lla_status(router1, True) ++ + device_name = router1.get_ha_device_name() + ha_device = ip_lib.IPDevice(device_name, namespace=router1.ns_name) + ha_device.link.set_down() + - utils.wait_until_true(lambda: router2.ha_state == 'master') + utils.wait_until_true(lambda: router1.ha_state == 'backup') ++ 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) + + def test_ha_router_ipv6_radvd_status(self): + router_info = self.generate_router_info(ip_version=6, enable_ha=True) + router1 = self.manage_router(self.agent, router_info) + utils.wait_until_true(lambda: router1.ha_state == 'master') + utils.wait_until_true(lambda: router1.radvd.enabled) + + def _check_lla_status(router, expected): + internal_devices = router.router[l3_constants.INTERFACE_KEY] + for device in internal_devices: + lladdr = ip_lib.get_ipv6_lladdr(device['mac_address']) + exists = ip_lib.device_exists_with_ips_and_mac( + router.get_internal_device_name(device['id']), [lladdr], + device['mac_address'], router.ns_name) + self.assertEqual(expected, exists) + + _check_lla_status(router1, True) device_name = router1.get_ha_device_name() ha_device = ip_lib.IPDevice(device_name, namespace=router1.ns_name) diff --cc neutron/tests/functional/agent/test_ovs_flows.py index da359e2ae,0108577bb..d73e4ae48 --- a/neutron/tests/functional/agent/test_ovs_flows.py +++ b/neutron/tests/functional/agent/test_ovs_flows.py @@@ -49,42 -114,41 +114,67 @@@ class _ARPSpoofTestCase(object) self._setup_arp_spoof_for_port(self.dst_p.name, [self.dst_addr]) self.src_p.addr.add('%s/24' % self.src_addr) self.dst_p.addr.add('%s/24' % self.dst_addr) - pinger = helpers.Pinger(self.src_ns) - pinger.assert_ping(self.dst_addr) + net_helpers.assert_ping(self.src_namespace, self.dst_addr, count=2) + + def test_arp_spoof_doesnt_block_ipv6(self): + self.src_addr = '2000::1' + self.dst_addr = '2000::2' + self._setup_arp_spoof_for_port(self.src_p.name, [self.src_addr]) + self._setup_arp_spoof_for_port(self.dst_p.name, [self.dst_addr]) + self.src_p.addr.add('%s/64' % self.src_addr) + self.dst_p.addr.add('%s/64' % self.dst_addr) + # make sure the IPv6 addresses are ready before pinging + self.src_p.addr.wait_until_address_ready(self.src_addr) + self.dst_p.addr.wait_until_address_ready(self.dst_addr) + net_helpers.assert_ping(self.src_namespace, self.dst_addr, count=2) + def test_arp_spoof_doesnt_block_ipv6(self): + self.src_addr = '2000::1' + self.dst_addr = '2000::2' + self._setup_arp_spoof_for_port(self.src_p.name, [self.src_addr]) + self._setup_arp_spoof_for_port(self.dst_p.name, [self.dst_addr]) + self.src_p.addr.add('%s/64' % self.src_addr) + self.dst_p.addr.add('%s/64' % self.dst_addr) + # IPv6 addresses seem to take longer to initialize + pinger = helpers.Pinger(self.src_ns, max_attempts=4) + pinger.assert_ping(self.dst_addr) + def test_arp_spoof_blocks_response(self): # this will prevent the destination from responding to the ARP # request for it's own address self._setup_arp_spoof_for_port(self.dst_p.name, ['192.168.0.3']) self.src_p.addr.add('%s/24' % self.src_addr) self.dst_p.addr.add('%s/24' % self.dst_addr) - pinger = helpers.Pinger(self.src_ns) - pinger.assert_no_ping(self.dst_addr) + net_helpers.assert_no_ping(self.src_namespace, self.dst_addr, count=2) + + def test_arp_spoof_blocks_request(self): + # this will prevent the source from sending an ARP + # request with its own address + self._setup_arp_spoof_for_port(self.src_p.name, ['192.168.0.3']) + self.src_p.addr.add('%s/24' % self.src_addr) + self.dst_p.addr.add('%s/24' % self.dst_addr) + ns_ip_wrapper = ip_lib.IPWrapper(self.src_namespace) + try: + ns_ip_wrapper.netns.execute(['arping', '-I', self.src_p.name, + '-c1', self.dst_addr]) + tools.fail("arping should have failed. The arp request should " + "have been blocked.") + except RuntimeError: ++ pass + + def test_arp_spoof_blocks_request(self): + # this will prevent the source from sending an ARP + # request with its own address + self._setup_arp_spoof_for_port(self.src_p.name, ['192.168.0.3']) + self.src_p.addr.add('%s/24' % self.src_addr) + self.dst_p.addr.add('%s/24' % self.dst_addr) + ns_ip_wrapper = ip_lib.IPWrapper(self.src_ns) + try: + ns_ip_wrapper.netns.execute(['arping', '-I', self.src_p.name, + '-c1', self.dst_addr]) + tools.fail("arping should have failed. The arp request should " + "have been blocked.") + except RuntimeError: pass def test_arp_spoof_allowed_address_pairs(self): diff --cc neutron/tests/unit/agent/l3/test_agent.py index 727ac6f43,5042ce287..b4082b782 --- a/neutron/tests/unit/agent/l3/test_agent.py +++ b/neutron/tests/unit/agent/l3/test_agent.py @@@ -1233,13 -895,15 +895,16 @@@ class TestBasicRouterOperations(BasicRo self.assertTrue(fips.called) self.assertEqual(ri.fip_ns.agent_gateway_port, agent_gateway_port[0]) + self.assertTrue(ri.rtr_fip_subnet) - def test_process_router_cent_floating_ip_add(self): + @mock.patch.object(lla.LinkLocalAllocator, '_write') + def test_create_dvr_fip_interfaces_for_restart_l3agent_case(self, + lla_write): fake_floatingips = {'floatingips': [ {'id': _uuid(), - 'floating_ip_address': '15.1.2.3', + 'floating_ip_address': '20.0.0.3', 'fixed_ip_address': '192.168.0.1', + 'status': 'DOWN', 'floating_network_id': _uuid(), 'port_id': _uuid(), 'host': HOSTNAME}]} diff --cc neutron/tests/unit/plugins/openvswitch/agent/test_ovs_neutron_agent.py index e1ff55f98,fec863aa5..e9e37dd85 --- a/neutron/tests/unit/plugins/openvswitch/agent/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/plugins/openvswitch/agent/test_ovs_neutron_agent.py @@@ -1084,28 -1002,28 +1002,36 @@@ class TestOvsNeutronAgent(object) except Exception: pass - scan_ports.assert_has_calls([ - mock.call(set(), set()), - mock.call(set(), set()) - ]) - process_network_ports.assert_has_calls([ - mock.call(reply2, False), - mock.call(reply3, True) - ]) - self.assertTrue(update_stale.called) - # Verify the OVS restart we triggered in the loop - # re-setup the bridges - setup_int_br.assert_has_calls([mock.call()]) - setup_phys_br.assert_has_calls([mock.call({})]) + scan_ports.assert_has_calls([ + mock.call(set(), set()), + mock.call(set(), set()) + ]) + process_network_ports.assert_has_calls([ + mock.call(reply2, False), + mock.call(reply3, True) + ]) + self.assertTrue(update_stale.called) + # Verify the OVS restart we triggered in the loop + # re-setup the bridges + setup_int_br.assert_has_calls([mock.call()]) + setup_phys_br.assert_has_calls([mock.call({})]) + + def test_ovs_status(self): + self._test_ovs_status(constants.OVS_NORMAL, + constants.OVS_DEAD, + constants.OVS_RESTARTED) + # OVS will not DEAD in some exception, like DBConnectionError. + self._test_ovs_status(constants.OVS_NORMAL, + constants.OVS_RESTARTED) + def test_ovs_status(self): + self._test_ovs_status(constants.OVS_NORMAL, + constants.OVS_DEAD, + constants.OVS_RESTARTED) + # OVS will not DEAD in some exception, like DBConnectionError. + self._test_ovs_status(constants.OVS_NORMAL, + constants.OVS_RESTARTED) + def test_set_rpc_timeout(self): self.agent._handle_sigterm(None, None) for rpc_client in (self.agent.plugin_rpc.client,