LBaaS VIP doesn't work after delete and re-add
When delete and re-add the same vip, we need to send gratuitous ARP to flush the ARP cache in the Router. Change-Id: Id97088abb95f4433a100abdae8c8726b3be42ed2 Closes-Bug: 1301165
This commit is contained in:
parent
70214434ca
commit
e7d7414548
@ -36,3 +36,7 @@
|
||||
|
||||
# The user group
|
||||
# user_group = nogroup
|
||||
|
||||
# When delete and re-add the same vip, send this many gratuitous ARPs to flush
|
||||
# the ARP cache in the Router. Set it below or equal to 0 to disable this feature.
|
||||
# send_gratuitous_arp = 3
|
||||
|
@ -20,3 +20,6 @@ mm-ctl: CommandFilter, mm-ctl, root
|
||||
# ip_lib
|
||||
ip: IpFilter, ip, root
|
||||
ip_exec: IpNetnsExecFilter, ip, root
|
||||
|
||||
# arping
|
||||
arping: CommandFilter, arping, root
|
||||
|
@ -53,6 +53,13 @@ OPTS = [
|
||||
default=USER_GROUP_DEFAULT,
|
||||
help=_('The user group'),
|
||||
deprecated_opts=[cfg.DeprecatedOpt('user_group')],
|
||||
),
|
||||
cfg.IntOpt(
|
||||
'send_gratuitous_arp',
|
||||
default=3,
|
||||
help=_('When delete and re-add the same vip, send this many '
|
||||
'gratuitous ARPs to flush the ARP cache in the Router. '
|
||||
'Set it below or equal to 0 to disable this feature.'),
|
||||
)
|
||||
]
|
||||
cfg.CONF.register_opts(OPTS, 'haproxy')
|
||||
@ -270,6 +277,16 @@ class HaproxyNSDriver(agent_device_driver.AgentDeviceDriver):
|
||||
ip_wrapper = ip_lib.IPWrapper(self.root_helper,
|
||||
namespace=namespace)
|
||||
ip_wrapper.netns.execute(cmd, check_exit_code=False)
|
||||
# When delete and re-add the same vip, we need to
|
||||
# send gratuitous ARP to flush the ARP cache in the Router.
|
||||
gratuitous_arp = self.conf.haproxy.send_gratuitous_arp
|
||||
if gratuitous_arp > 0:
|
||||
for ip in port['fixed_ips']:
|
||||
cmd_arping = ['arping', '-U',
|
||||
'-I', interface_name,
|
||||
'-c', gratuitous_arp,
|
||||
ip['ip_address']]
|
||||
ip_wrapper.netns.execute(cmd_arping, check_exit_code=False)
|
||||
|
||||
def _unplug(self, namespace, port_id):
|
||||
port_stub = {'id': port_id}
|
||||
|
@ -33,7 +33,9 @@ class TestHaproxyNSDriver(base.BaseTestCase):
|
||||
conf.haproxy.loadbalancer_state_path = '/the/path'
|
||||
conf.interface_driver = 'intdriver'
|
||||
conf.haproxy.user_group = 'test_group'
|
||||
conf.haproxy.send_gratuitous_arp = 3
|
||||
conf.AGENT.root_helper = 'sudo_test'
|
||||
self.conf = conf
|
||||
self.mock_importer = mock.patch.object(namespace_driver,
|
||||
'importutils').start()
|
||||
|
||||
@ -278,15 +280,44 @@ class TestHaproxyNSDriver(base.BaseTestCase):
|
||||
namespace=
|
||||
'test_ns')
|
||||
cmd = ['route', 'add', 'default', 'gw', '10.0.0.1']
|
||||
cmd_arping = ['arping', '-U', '-I',
|
||||
'test_interface', '-c',
|
||||
self.conf.haproxy.send_gratuitous_arp, '10.0.0.2']
|
||||
ip_wrap.assert_has_calls([
|
||||
mock.call('sudo_test', namespace='test_ns'),
|
||||
mock.call().netns.execute(cmd, check_exit_code=False),
|
||||
mock.call().netns.execute(cmd_arping, check_exit_code=False),
|
||||
])
|
||||
|
||||
dev_exists.return_value = True
|
||||
self.assertRaises(exceptions.PreexistingDeviceFailure,
|
||||
self.driver._plug, 'test_ns', test_port, False)
|
||||
|
||||
def test_plug_not_send_gratuitous_arp(self):
|
||||
self.conf.haproxy.send_gratuitous_arp = 0
|
||||
test_port = {'id': 'port_id',
|
||||
'network_id': 'net_id',
|
||||
'mac_address': 'mac_addr',
|
||||
'fixed_ips': [{'ip_address': '10.0.0.2',
|
||||
'subnet': {'cidr': '10.0.0.0/24',
|
||||
'gateway_ip': '10.0.0.1'}}]}
|
||||
with contextlib.nested(
|
||||
mock.patch('neutron.agent.linux.ip_lib.device_exists'),
|
||||
mock.patch('netaddr.IPNetwork'),
|
||||
mock.patch('neutron.agent.linux.ip_lib.IPWrapper'),
|
||||
) as (dev_exists, ip_net, ip_wrap):
|
||||
self.vif_driver.get_device_name.return_value = 'test_interface'
|
||||
dev_exists.return_value = False
|
||||
ip_net.return_value = ip_net
|
||||
ip_net.prefixlen = 24
|
||||
|
||||
self.driver._plug('test_ns', test_port)
|
||||
cmd = ['route', 'add', 'default', 'gw', '10.0.0.1']
|
||||
expected = [
|
||||
mock.call('sudo_test', namespace='test_ns'),
|
||||
mock.call().netns.execute(cmd, check_exit_code=False)]
|
||||
self.assertEqual(expected, ip_wrap.mock_calls)
|
||||
|
||||
def test_plug_no_gw(self):
|
||||
test_port = {'id': 'port_id',
|
||||
'network_id': 'net_id',
|
||||
|
Loading…
Reference in New Issue
Block a user