Merge "support 'send_arp_for_ha' option in l3_agent"
This commit is contained in:
commit
1be1394c20
@ -54,3 +54,7 @@ root_helper = sudo
|
|||||||
|
|
||||||
# The time in seconds between state poll requests
|
# The time in seconds between state poll requests
|
||||||
# polling_interval = 3
|
# polling_interval = 3
|
||||||
|
|
||||||
|
# Send this many gratuitous ARPs for HA setup. Set it below or equal to 0
|
||||||
|
# to disable this feature.
|
||||||
|
# send_arp_for_ha = 3
|
||||||
|
@ -8,6 +8,10 @@
|
|||||||
|
|
||||||
[Filters]
|
[Filters]
|
||||||
|
|
||||||
|
# arping
|
||||||
|
arping: CommandFilter, /usr/bin/arping, root
|
||||||
|
arping_sbin: CommandFilter, /sbin/arping, root
|
||||||
|
|
||||||
# l3_agent
|
# l3_agent
|
||||||
sysctl: CommandFilter, /sbin/sysctl, root
|
sysctl: CommandFilter, /sbin/sysctl, root
|
||||||
route: CommandFilter, /sbin/route, root
|
route: CommandFilter, /sbin/route, root
|
||||||
|
@ -83,10 +83,10 @@ class L3NATAgent(object):
|
|||||||
cfg.IntOpt('metadata_port',
|
cfg.IntOpt('metadata_port',
|
||||||
default=8775,
|
default=8775,
|
||||||
help="TCP Port used by Nova metadata server."),
|
help="TCP Port used by Nova metadata server."),
|
||||||
#FIXME(danwent): not currently used
|
cfg.IntOpt('send_arp_for_ha',
|
||||||
cfg.BoolOpt('send_arp_for_ha',
|
default=3,
|
||||||
default=True,
|
help="Send this many gratuitous ARPs for HA setup, "
|
||||||
help="Send gratuitious ARP when router IP is configured"),
|
"set it below or equal to 0 to disable this feature."),
|
||||||
cfg.BoolOpt('use_namespaces', default=True,
|
cfg.BoolOpt('use_namespaces', default=True,
|
||||||
help="Allow overlapping IP."),
|
help="Allow overlapping IP."),
|
||||||
cfg.StrOpt('router_id', default='',
|
cfg.StrOpt('router_id', default='',
|
||||||
@ -359,6 +359,23 @@ class L3NATAgent(object):
|
|||||||
LOG.error("Ignoring multiple gateway ports for router %s"
|
LOG.error("Ignoring multiple gateway ports for router %s"
|
||||||
% ri.router_id)
|
% ri.router_id)
|
||||||
|
|
||||||
|
def _send_gratuitous_arp_packet(self, ri, interface_name, ip_address):
|
||||||
|
if self.conf.send_arp_for_ha > 0:
|
||||||
|
arping_cmd = ['arping', '-A', '-U',
|
||||||
|
'-I', interface_name,
|
||||||
|
'-c', self.conf.send_arp_for_ha,
|
||||||
|
ip_address]
|
||||||
|
try:
|
||||||
|
if self.conf.use_namespaces:
|
||||||
|
ip_wrapper = ip_lib.IPWrapper(self.conf.root_helper,
|
||||||
|
namespace=ri.ns_name())
|
||||||
|
ip_wrapper.netns.execute(arping_cmd, check_exit_code=True)
|
||||||
|
else:
|
||||||
|
utils.execute(arping_cmd, check_exit_code=True,
|
||||||
|
root_helper=self.conf.root_helper)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_("Failed sending gratuitous ARP: %s") % str(e))
|
||||||
|
|
||||||
def get_internal_device_name(self, port_id):
|
def get_internal_device_name(self, port_id):
|
||||||
return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
|
return (INTERNAL_DEV_PREFIX + port_id)[:self.driver.DEV_NAME_LEN]
|
||||||
|
|
||||||
@ -380,6 +397,8 @@ class L3NATAgent(object):
|
|||||||
prefix=EXTERNAL_DEV_PREFIX)
|
prefix=EXTERNAL_DEV_PREFIX)
|
||||||
self.driver.init_l3(interface_name, [ex_gw_port['ip_cidr']],
|
self.driver.init_l3(interface_name, [ex_gw_port['ip_cidr']],
|
||||||
namespace=ri.ns_name())
|
namespace=ri.ns_name())
|
||||||
|
ip_address = ex_gw_port['ip_cidr'].split('/')[0]
|
||||||
|
self._send_gratuitous_arp_packet(ri, interface_name, ip_address)
|
||||||
|
|
||||||
gw_ip = ex_gw_port['subnet']['gateway_ip']
|
gw_ip = ex_gw_port['subnet']['gateway_ip']
|
||||||
if ex_gw_port['subnet']['gateway_ip']:
|
if ex_gw_port['subnet']['gateway_ip']:
|
||||||
@ -454,6 +473,8 @@ class L3NATAgent(object):
|
|||||||
|
|
||||||
self.driver.init_l3(interface_name, [internal_cidr],
|
self.driver.init_l3(interface_name, [internal_cidr],
|
||||||
namespace=ri.ns_name())
|
namespace=ri.ns_name())
|
||||||
|
ip_address = internal_cidr.split('/')[0]
|
||||||
|
self._send_gratuitous_arp_packet(ri, interface_name, ip_address)
|
||||||
|
|
||||||
if ex_gw_port:
|
if ex_gw_port:
|
||||||
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
|
ex_gw_ip = ex_gw_port['fixed_ips'][0]['ip_address']
|
||||||
@ -494,6 +515,7 @@ class L3NATAgent(object):
|
|||||||
if not ip_cidr in [addr['cidr'] for addr in device.addr.list()]:
|
if not ip_cidr in [addr['cidr'] for addr in device.addr.list()]:
|
||||||
net = netaddr.IPNetwork(ip_cidr)
|
net = netaddr.IPNetwork(ip_cidr)
|
||||||
device.addr.add(net.version, ip_cidr, str(net.broadcast))
|
device.addr.add(net.version, ip_cidr, str(net.broadcast))
|
||||||
|
self._send_gratuitous_arp_packet(ri, interface_name, floating_ip)
|
||||||
|
|
||||||
for chain, rule in self.floating_forward_rules(floating_ip, fixed_ip):
|
for chain, rule in self.floating_forward_rules(floating_ip, fixed_ip):
|
||||||
ri.iptables_manager.ipv4['nat'].add_rule(chain, rule)
|
ri.iptables_manager.ipv4['nat'].add_rule(chain, rule)
|
||||||
|
@ -125,13 +125,23 @@ class TestBasicRouterOperations(unittest.TestCase):
|
|||||||
'network_id': _uuid(),
|
'network_id': _uuid(),
|
||||||
'mac_address': 'ca:fe:de:ad:be:ef',
|
'mac_address': 'ca:fe:de:ad:be:ef',
|
||||||
'ip_cidr': '20.0.0.30/24'}
|
'ip_cidr': '20.0.0.30/24'}
|
||||||
|
interface_name = agent.get_external_device_name(ex_gw_port['id'])
|
||||||
|
|
||||||
if action == 'add':
|
if action == 'add':
|
||||||
self.device_exists.return_value = False
|
self.device_exists.return_value = False
|
||||||
agent.external_gateway_added(ri, ex_gw_port, internal_cidrs)
|
agent.external_gateway_added(ri, ex_gw_port, internal_cidrs)
|
||||||
self.assertEquals(self.mock_driver.plug.call_count, 1)
|
self.assertEquals(self.mock_driver.plug.call_count, 1)
|
||||||
self.assertEquals(self.mock_driver.init_l3.call_count, 1)
|
self.assertEquals(self.mock_driver.init_l3.call_count, 1)
|
||||||
self.assertEquals(self.mock_ip.netns.execute.call_count, 1)
|
arping_cmd = ['arping', '-A', '-U',
|
||||||
|
'-I', interface_name,
|
||||||
|
'-c', self.conf.send_arp_for_ha,
|
||||||
|
'20.0.0.30']
|
||||||
|
if self.conf.use_namespaces:
|
||||||
|
self.mock_ip.netns.execute.assert_any_call(
|
||||||
|
arping_cmd, check_exit_code=True)
|
||||||
|
else:
|
||||||
|
self.utils_exec.assert_any_call(
|
||||||
|
check_exit_code=True, root_helper=self.conf.root_helper)
|
||||||
|
|
||||||
elif action == 'remove':
|
elif action == 'remove':
|
||||||
self.device_exists.return_value = True
|
self.device_exists.return_value = True
|
||||||
@ -159,10 +169,21 @@ class TestBasicRouterOperations(unittest.TestCase):
|
|||||||
'id': _uuid(),
|
'id': _uuid(),
|
||||||
'mac_address': 'ca:fe:de:ad:be:ef',
|
'mac_address': 'ca:fe:de:ad:be:ef',
|
||||||
'ip_cidr': '20.0.0.30/24'}
|
'ip_cidr': '20.0.0.30/24'}
|
||||||
|
interface_name = agent.get_external_device_name(ex_gw_port['id'])
|
||||||
|
|
||||||
if action == 'add':
|
if action == 'add':
|
||||||
self.device_exists.return_value = False
|
self.device_exists.return_value = False
|
||||||
agent.floating_ip_added(ri, ex_gw_port, floating_ip, fixed_ip)
|
agent.floating_ip_added(ri, ex_gw_port, floating_ip, fixed_ip)
|
||||||
|
arping_cmd = ['arping', '-A', '-U',
|
||||||
|
'-I', interface_name,
|
||||||
|
'-c', self.conf.send_arp_for_ha,
|
||||||
|
floating_ip]
|
||||||
|
if self.conf.use_namespaces:
|
||||||
|
self.mock_ip.netns.execute.assert_any_call(
|
||||||
|
arping_cmd, check_exit_code=True)
|
||||||
|
else:
|
||||||
|
self.utils_exec.assert_any_call(
|
||||||
|
check_exit_code=True, root_helper=self.conf.root_helper)
|
||||||
|
|
||||||
elif action == 'remove':
|
elif action == 'remove':
|
||||||
self.device_exists.return_value = True
|
self.device_exists.return_value = True
|
||||||
|
Loading…
Reference in New Issue
Block a user