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',
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
utils.wait_until_true(lambda: router1.ha_state == 'master')
utils.wait_until_true(lambda: router2.ha_state == 'backup')
- utils.wait_until_true(lambda: router2.ha_state == 'master')
+ 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: 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)
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):
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}]}
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,