Do not respond to ARP on IPv6-only interfaces

When using dual stack, the IPv6 router interface responds
to ARP requests that only the IPv4 interface should.
This results in ARP flux and can cause a guest to address
packets to the wrong layer-2 address when sending traffic
to the IPv4 gateway.

Change arp_ignore and arp_announce sysctl options on interfaces
in the router namespace to be more strict in how we respond.

Closes-bug: 1692007
Change-Id: Ic3c2370995abb027a3412b473ce6bc63790c1105
This commit is contained in:
Sean Redmond 2017-05-29 10:50:27 +01:00 committed by Brian Haley
parent e4557a7793
commit 0f076cfc2d
3 changed files with 30 additions and 3 deletions

View File

@ -90,9 +90,19 @@ class Namespace(object):
self.use_ipv6 = use_ipv6
def create(self):
# See networking (netdev) tree, file
# Documentation/networking/ip-sysctl.txt for an explanation of
# these sysctl values.
ip_wrapper = self.ip_wrapper_root.ensure_namespace(self.name)
cmd = ['sysctl', '-w', 'net.ipv4.ip_forward=1']
ip_wrapper.netns.execute(cmd)
# 1. Reply only if the target IP address is local address configured
# on the incoming interface; and
# 2. Always use the best local address
cmd = ['sysctl', '-w', 'net.ipv4.conf.all.arp_ignore=1']
ip_wrapper.netns.execute(cmd)
cmd = ['sysctl', '-w', 'net.ipv4.conf.all.arp_announce=2']
ip_wrapper.netns.execute(cmd)
if self.use_ipv6:
cmd = ['sysctl', '-w', 'net.ipv6.conf.all.forwarding=1']
ip_wrapper.netns.execute(cmd)

View File

@ -2105,6 +2105,23 @@ class TestBasicRouterOperations(BasicRouterOperationsFramework):
agent.router_added_to_agent(None, [FAKE_ID])
self.assertEqual(1, agent._queue.add.call_count)
def test_create_router_namespace(self):
self.mock_ip.ensure_namespace.return_value = self.mock_ip
agent = l3_agent.L3NATAgent(HOSTNAME, self.conf)
ns = namespaces.Namespace(
'qrouter-bar', self.conf, agent.driver, agent.use_ipv6)
ns.create()
calls = [mock.call(['sysctl', '-w', 'net.ipv4.ip_forward=1']),
mock.call(['sysctl', '-w', 'net.ipv4.conf.all.arp_ignore=1']),
mock.call(
['sysctl', '-w', 'net.ipv4.conf.all.arp_announce=2'])]
if agent.use_ipv6:
calls.append(mock.call(
['sysctl', '-w', 'net.ipv6.conf.all.forwarding=1']))
self.mock_ip.netns.execute.assert_has_calls(calls)
def test_destroy_namespace(self):
namespace = 'qrouter-bar'

View File

@ -191,9 +191,9 @@ class TestDvrFipNs(base.BaseTestCase):
@mock.patch.object(ip_lib.IpNetnsCommand, 'exists')
def _test_create(self, old_kernel, exists, execute, IPTables):
exists.return_value = True
# There are up to four sysctl calls - two to enable forwarding,
# and two for ip_nonlocal_bind
execute.side_effect = [None, None,
# There are up to six sysctl calls - two to enable forwarding,
# two for arp_ignore and arp_announce, and two for ip_nonlocal_bind
execute.side_effect = [None, None, None, None,
RuntimeError if old_kernel else None, None]
self.fip_ns._iptables_manager = IPTables()