clean_connections=True)
for fixed_ip in ex_gw_port['fixed_ips']:
- ip_lib.send_gratuitous_arp(ns_name,
- interface_name,
- fixed_ip['ip_address'],
- self.agent_conf.send_arp_for_ha)
+ ip_lib.send_ip_addr_adv_notif(ns_name,
+ interface_name,
+ fixed_ip['ip_address'],
+ self.agent_conf)
for subnet in ex_gw_port['subnets']:
gw_ip = subnet.get('gateway_ip')
interface_name = (
self.fip_ns.get_ext_device_name(
self.fip_ns.agent_gateway_port['id']))
- ip_lib.send_gratuitous_arp(fip_ns_name,
- interface_name,
- floating_ip,
- self.agent_conf.send_arp_for_ha)
+ ip_lib.send_ip_addr_adv_notif(fip_ns_name,
+ interface_name,
+ floating_ip,
+ self.agent_conf)
# update internal structures
self.dist_fip_count = self.dist_fip_count + 1
# As GARP is processed in a distinct thread the call below
# won't raise an exception to be handled.
- ip_lib.send_gratuitous_arp(self.ns_name,
- interface_name,
- fip['floating_ip_address'],
- self.agent_conf.send_arp_for_ha)
+ ip_lib.send_ip_addr_adv_notif(self.ns_name,
+ interface_name,
+ fip['floating_ip_address'],
+ self.agent_conf)
return l3_constants.FLOATINGIP_STATUS_ACTIVE
ip_cidrs = common_utils.fixed_ip_cidrs(fixed_ips)
self.driver.init_l3(interface_name, ip_cidrs, namespace=ns_name)
for fixed_ip in fixed_ips:
- ip_lib.send_gratuitous_arp(ns_name,
- interface_name,
- fixed_ip['ip_address'],
- self.agent_conf.send_arp_for_ha)
+ ip_lib.send_ip_addr_adv_notif(ns_name,
+ interface_name,
+ fixed_ip['ip_address'],
+ self.agent_conf)
def internal_network_added(self, port):
network_id = port['network_id']
enable_ra_on_gw=enable_ra_on_gw,
clean_connections=True)
for fixed_ip in ex_gw_port['fixed_ips']:
- ip_lib.send_gratuitous_arp(ns_name,
- interface_name,
- fixed_ip['ip_address'],
- self.agent_conf.send_arp_for_ha)
+ ip_lib.send_ip_addr_adv_notif(ns_name,
+ interface_name,
+ fixed_ip['ip_address'],
+ self.agent_conf)
def is_v6_gateway_set(self, gateway_ips):
"""Check to see if list of gateway_ips has an IPv6 gateway.
'ns': ns_name})
-def send_gratuitous_arp(ns_name, iface_name, address, count):
- """Send a gratuitous arp using given namespace, interface, and address."""
+def send_ip_addr_adv_notif(ns_name, iface_name, address, config):
+ """Send advance notification of an IP address assignment.
+
+ If the address is in the IPv4 family, send gratuitous ARP.
+
+ If the address is in the IPv6 family, no advance notification is
+ necessary, since the Neighbor Discovery Protocol (NDP), Duplicate
+ Address Discovery (DAD), and (for stateless addresses) router
+ advertisements (RAs) are sufficient for address resolution and
+ duplicate address detection.
+ """
+ count = config.send_arp_for_ha
def arping():
_arping(ns_name, iface_name, address, count)
- if count > 0:
+ if count > 0 and netaddr.IPAddress(address).version == 4:
eventlet.spawn_n(arping)
self.process_monitor = mock.patch(
'neutron.agent.linux.external_process.ProcessMonitor').start()
- self.send_arp_p = mock.patch(
- 'neutron.agent.linux.ip_lib.send_gratuitous_arp')
- self.send_arp = self.send_arp_p.start()
+ self.send_adv_notif_p = mock.patch(
+ 'neutron.agent.linux.ip_lib.send_ip_addr_adv_notif')
+ self.send_adv_notif = self.send_adv_notif_p.start()
self.dvr_cls_p = mock.patch('neutron.agent.linux.interface.NullDriver')
driver_cls = self.dvr_cls_p.start()
ri.internal_network_added(port)
self.assertEqual(self.mock_driver.plug.call_count, 1)
self.assertEqual(self.mock_driver.init_l3.call_count, 1)
- self.send_arp.assert_called_once_with(ri.ns_name, interface_name,
- '99.0.1.9', mock.ANY)
+ self.send_adv_notif.assert_called_once_with(ri.ns_name,
+ interface_name,
+ '99.0.1.9', mock.ANY)
elif action == 'remove':
self.device_exists.return_value = True
ri.internal_network_removed(port)
self.assertEqual(self.mock_driver.plug.call_count, 1)
self.assertEqual(self.mock_driver.init_l3.call_count, 1)
if no_subnet and not dual_stack:
- self.assertEqual(self.send_arp.call_count, 0)
+ self.assertEqual(self.send_adv_notif.call_count, 0)
ip_cidrs = []
gateway_ips = []
if no_sub_gw:
exp_arp_calls += [mock.call(ri.ns_name, interface_name,
'2001:192:168:100::2',
mock.ANY)]
- self.send_arp.assert_has_calls(exp_arp_calls)
+ self.send_adv_notif.assert_has_calls(exp_arp_calls)
ip_cidrs = ['20.0.0.30/24']
gateway_ips = ['20.0.0.1']
if dual_stack:
ri.use_ipv6 = True
exp_arp_calls += [mock.call(ri.ns_name, interface_name,
'2001:192:168:100::2', mock.ANY)]
- self.send_arp.assert_has_calls(exp_arp_calls)
+ self.send_adv_notif.assert_has_calls(exp_arp_calls)
ip_cidrs = ['20.0.0.30/24']
gateway_ips = ['20.0.0.1']
if dual_stack:
del router[l3_constants.INTERFACE_KEY]
del router['gw_port']
ri.process(agent)
- self.assertEqual(self.send_arp.call_count, 1)
+ self.assertEqual(self.send_adv_notif.call_count, 1)
distributed = ri.router.get('distributed', False)
self.assertEqual(ri.process_floating_ip_addresses.called,
distributed)
self.assertEqual(len(mangle_rules_delta), 1)
self._verify_snat_mangle_rules(nat_rules_delta, mangle_rules_delta,
router)
- self.assertEqual(self.send_arp.call_count, 1)
+ self.assertEqual(self.send_adv_notif.call_count, 1)
def test_process_router_snat_enabled(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
self.assertEqual(len(mangle_rules_delta), 1)
self._verify_snat_mangle_rules(nat_rules_delta, mangle_rules_delta,
router)
- self.assertEqual(self.send_arp.call_count, 1)
+ self.assertEqual(self.send_adv_notif.call_count, 1)
def test_process_router_interface_added(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
# Reassign the router object to RouterInfo
ri.router = router
ri.process(agent)
- # send_arp is called both times process is called
- self.assertEqual(self.send_arp.call_count, 2)
+ # send_ip_addr_adv_notif is called both times process is called
+ self.assertEqual(self.send_adv_notif.call_count, 2)
def _test_process_ipv6_only_or_dual_stack_gw(self, dual_stack=False):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
# Reassign the router object to RouterInfo
ri.router = router
ri.process(agent)
- # send_arp is called both times process is called
- self.assertEqual(self.send_arp.call_count, 2)
+ # send_ip_addr_adv_notif is called both times process is called
+ self.assertEqual(self.send_adv_notif.call_count, 2)
def test_process_router_ipv6_interface_removed(self):
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
@mock.patch.object(ip_lib, 'IPWrapper')
@mock.patch.object(ip_lib, 'IPDevice')
- @mock.patch.object(ip_lib, 'send_gratuitous_arp')
+ @mock.patch.object(ip_lib, 'send_ip_addr_adv_notif')
@mock.patch.object(ip_lib, 'device_exists')
- def test_gateway_added(self, device_exists, send_arp, IPDevice, IPWrapper):
+ def test_gateway_added(self, device_exists, send_adv_notif,
+ IPDevice, IPWrapper):
subnet_id = _uuid()
agent_gw_port = {'fixed_ips': [{'ip_address': '20.0.0.30',
'prefixlen': 24,
mock.sentinel.interface_name)
self.assertEqual(self.driver.plug.call_count, 1)
self.assertEqual(self.driver.init_l3.call_count, 1)
- send_arp.assert_called_once_with(self.fip_ns.get_name(),
- mock.sentinel.interface_name,
- '20.0.0.30',
- mock.ANY)
+ send_adv_notif.assert_called_once_with(self.fip_ns.get_name(),
+ mock.sentinel.interface_name,
+ '20.0.0.30',
+ mock.ANY)
@mock.patch.object(ip_lib, 'IPWrapper')
def test_destroy(self, IPWrapper):
self.assertEqual([{'host': mock.sentinel.myhost}], fips)
- @mock.patch.object(ip_lib, 'send_gratuitous_arp')
+ @mock.patch.object(ip_lib, 'send_ip_addr_adv_notif')
@mock.patch.object(ip_lib, 'IPDevice')
@mock.patch.object(ip_lib, 'IPRule')
- def test_floating_ip_added_dist(self, mIPRule, mIPDevice, mock_arp):
+ def test_floating_ip_added_dist(self, mIPRule, mIPDevice, mock_adv_notif):
router = mock.MagicMock()
ri = self._create_router(router)
ext_net_id = _uuid()
device.delete_addr_and_conntrack_state.assert_called_once_with(cidr)
-@mock.patch.object(ip_lib, 'send_gratuitous_arp')
+@mock.patch.object(ip_lib, 'send_ip_addr_adv_notif')
class TestAddFloatingIpWithMockGarp(BasicRouterTestCaseFramework):
- def test_add_floating_ip(self, send_gratuitous_arp):
+ def test_add_floating_ip(self, send_ip_addr_adv_notif):
ri = self._create_router()
ri._add_fip_addr_to_device = mock.Mock(return_value=True)
- self.agent_conf.send_arp_for_ha = mock.sentinel.arp_count
ip = '15.1.2.3'
result = ri.add_floating_ip({'floating_ip_address': ip},
mock.sentinel.interface_name,
mock.sentinel.device)
- ip_lib.send_gratuitous_arp.assert_called_once_with(
+ ip_lib.send_ip_addr_adv_notif.assert_called_once_with(
ri.ns_name,
mock.sentinel.interface_name,
ip,
- mock.sentinel.arp_count)
+ self.agent_conf)
self.assertEqual(l3_constants.FLOATINGIP_STATUS_ACTIVE, result)
- def test_add_floating_ip_error(self, send_gratuitous_arp):
+ def test_add_floating_ip_error(self, send_ip_addr_adv_notif):
ri = self._create_router()
ri._add_fip_addr_to_device = mock.Mock(return_value=False)
result = ri.add_floating_ip({'floating_ip_address': '15.1.2.3'},
mock.sentinel.interface_name,
mock.sentinel.device)
- self.assertFalse(ip_lib.send_gratuitous_arp.called)
+ self.assertFalse(ip_lib.send_ip_addr_adv_notif.called)
self.assertEqual(l3_constants.FLOATINGIP_STATUS_ERROR, result)
class TestArpPing(TestIPCmdBase):
- def _test_arping(self, function, address, spawn_n, mIPWrapper):
+ @mock.patch.object(ip_lib, 'IPWrapper')
+ @mock.patch('eventlet.spawn_n')
+ def test_send_ipv4_addr_adv_notif(self, spawn_n, mIPWrapper):
spawn_n.side_effect = lambda f: f()
ARPING_COUNT = 3
- function(mock.sentinel.ns_name,
- mock.sentinel.iface_name,
- address,
- ARPING_COUNT)
+ address = '20.0.0.1'
+ config = mock.Mock()
+ config.send_arp_for_ha = ARPING_COUNT
+ ip_lib.send_ip_addr_adv_notif(mock.sentinel.ns_name,
+ mock.sentinel.iface_name,
+ address,
+ config)
self.assertTrue(spawn_n.called)
mIPWrapper.assert_called_once_with(namespace=mock.sentinel.ns_name)
ip_wrapper.netns.execute.assert_any_call(arping_cmd,
check_exit_code=True)
- @mock.patch.object(ip_lib, 'IPWrapper')
@mock.patch('eventlet.spawn_n')
- def test_send_gratuitous_arp(self, spawn_n, mIPWrapper):
- self._test_arping(
- ip_lib.send_gratuitous_arp, '20.0.0.1', spawn_n, mIPWrapper)
+ def test_no_ipv6_addr_notif(self, spawn_n):
+ ipv6_addr = 'fd00::1'
+ config = mock.Mock()
+ config.send_arp_for_ha = 3
+ ip_lib.send_ip_addr_adv_notif(mock.sentinel.ns_name,
+ mock.sentinel.iface_name,
+ ipv6_addr,
+ config)
+ self.assertFalse(spawn_n.called)
class TestAddNamespaceToCmd(base.BaseTestCase):