Merge "Ensure netlink commands are privsep executed"
This commit is contained in:
commit
ab1e00f14f
|
@ -14,15 +14,142 @@
|
|||
|
||||
import ipaddress
|
||||
import os
|
||||
import pyroute2
|
||||
|
||||
from pyroute2.netlink.rtnl import ndmsg
|
||||
from socket import AF_INET6
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
|
||||
from ovn_bgp_agent import constants
|
||||
from ovn_bgp_agent.utils import linux_net as l_net
|
||||
|
||||
import ovn_bgp_agent.privileged.linux_net
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def set_device_status(device, status, ndb=None):
|
||||
_ndb = ndb
|
||||
if ndb is None:
|
||||
_ndb = pyroute2.NDB()
|
||||
try:
|
||||
with _ndb.interfaces[device] as dev:
|
||||
if dev['state'] != status:
|
||||
dev['state'] = status
|
||||
finally:
|
||||
if ndb is None:
|
||||
_ndb.close()
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def ensure_vrf(vrf_name, vrf_table):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(vrf_name, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
ndb.interfaces.create(
|
||||
kind="vrf", ifname=vrf_name, vrf_table=int(vrf_table)).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def ensure_bridge(bridge_name):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(bridge_name, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
ndb.interfaces.create(
|
||||
kind="bridge", ifname=bridge_name, br_stp_state=0).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def ensure_vxlan(vxlan_name, vni, local_ip, dstport):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(vxlan_name, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
# FIXME: Perhaps we need to set neigh_suppress on
|
||||
ndb.interfaces.create(
|
||||
kind="vxlan", ifname=vxlan_name, vxlan_id=int(vni),
|
||||
vxlan_port=dstport, vxlan_local=local_ip,
|
||||
vxlan_learning=False).set('state', constants.LINK_UP).commit()
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def ensure_veth(veth_name, veth_peer):
|
||||
try:
|
||||
set_device_status(veth_name, constants.LINK_UP)
|
||||
except KeyError:
|
||||
with pyroute2.NDB() as ndb:
|
||||
ndb.interfaces.create(
|
||||
kind="veth", ifname=veth_name, peer=veth_peer).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
set_device_status(veth_peer, constants.LINK_UP)
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def set_master_for_device(device, master):
|
||||
with pyroute2.NDB() as ndb:
|
||||
# Check if already associated to the master, and associate it if not
|
||||
if (ndb.interfaces[device].get('master') !=
|
||||
ndb.interfaces[master]['index']):
|
||||
with ndb.interfaces[device] as iface:
|
||||
iface.set('master', ndb.interfaces[master]['index'])
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def ensure_dummy_device(device):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(device, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
ndb.interfaces.create(kind="dummy", ifname=device).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def delete_device(device):
|
||||
try:
|
||||
with pyroute2.NDB() as ndb:
|
||||
ndb.interfaces[device].remove().commit()
|
||||
except KeyError:
|
||||
LOG.debug("Interfaces %s already deleted.", device)
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def route_create(route):
|
||||
with pyroute2.NDB() as ndb:
|
||||
ndb.routes.create(route).commit()
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def route_delete(route):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
with ndb.routes[route] as r:
|
||||
r.remove()
|
||||
except (KeyError, ValueError):
|
||||
LOG.debug("Route already deleted: {}".format(route))
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def ensure_vlan_device_for_network(bridge, vlan_tag):
|
||||
vlan_device_name = '{}.{}'.format(bridge, vlan_tag)
|
||||
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(vlan_device_name, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
ndb.interfaces.create(
|
||||
kind="vlan", ifname=vlan_device_name, vlan_id=vlan_tag,
|
||||
link=ndb.interfaces[bridge]['index']).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def set_kernel_flag(flag, value):
|
||||
command = ["sysctl", "-w", "{}={}".format(flag, value)]
|
||||
|
@ -33,6 +160,60 @@ def set_kernel_flag(flag, value):
|
|||
raise
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def delete_exposed_ips(ips, nic):
|
||||
with pyroute2.NDB() as ndb:
|
||||
for ip in ips:
|
||||
address = '{}/32'.format(ip)
|
||||
if l_net.get_ip_version(ip) == constants.IP_VERSION_6:
|
||||
address = '{}/128'.format(ip)
|
||||
try:
|
||||
ndb.interfaces[nic].ipaddr[address].remove().commit()
|
||||
except KeyError:
|
||||
LOG.debug("IP address {} already removed from nic {}.".format(
|
||||
ip, nic))
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def rule_create(rule):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
ndb.rules[rule]
|
||||
except KeyError:
|
||||
LOG.debug("Creating ip rule with: %s", rule)
|
||||
ndb.rules.create(rule).commit()
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def rule_delete(rule):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
ndb.rules[rule].remove().commit()
|
||||
LOG.debug("Deleting ip rule with: %s", rule)
|
||||
except KeyError:
|
||||
LOG.debug("Rule already deleted: %s", rule)
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def delete_ip_rules(ip_rules):
|
||||
with pyroute2.NDB() as ndb:
|
||||
for rule_ip, rule_info in ip_rules.items():
|
||||
rule = {'dst': rule_ip.split("/")[0],
|
||||
'dst_len': rule_ip.split("/")[1],
|
||||
'table': rule_info['table'],
|
||||
'family': rule_info['family']}
|
||||
try:
|
||||
with ndb.rules[rule] as r:
|
||||
r.remove()
|
||||
except KeyError:
|
||||
LOG.debug("Rule {} already deleted".format(rule))
|
||||
except pyroute2.netlink.exceptions.NetlinkError:
|
||||
# FIXME: There is a issue with NDB and ip rules deletion:
|
||||
# https://github.com/svinota/pyroute2/issues/771
|
||||
LOG.debug("This should not happen, skipping: NetlinkError "
|
||||
"deleting rule %s", rule)
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def add_ndp_proxy(ip, dev, vlan=None):
|
||||
# FIXME(ltomasbo): This should use pyroute instead but I didn't find
|
||||
|
@ -70,6 +251,79 @@ def del_ndp_proxy(ip, dev, vlan=None):
|
|||
raise
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def add_ip_to_dev(ip, nic):
|
||||
with pyroute2.NDB() as ndb:
|
||||
with ndb.interfaces[nic] as iface:
|
||||
address = '{}/32'.format(ip)
|
||||
if l_net.get_ip_version(ip) == constants.IP_VERSION_6:
|
||||
address = '{}/128'.format(ip)
|
||||
iface.add_ip(address)
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def del_ip_from_dev(ip, nic):
|
||||
with pyroute2.NDB() as ndb:
|
||||
with ndb.interfaces[nic] as iface:
|
||||
address = '{}/32'.format(ip)
|
||||
if l_net.get_ip_version(ip) == constants.IP_VERSION_6:
|
||||
address = '{}/128'.format(ip)
|
||||
iface.del_ip(address)
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def add_ip_nei(ip, lladdr, dev):
|
||||
ip_version = l_net.get_ip_version(ip)
|
||||
with pyroute2.IPRoute() as iproute:
|
||||
# This is doing something like:
|
||||
# sudo ip nei replace 172.24.4.69
|
||||
# lladdr fa:16:3e:d3:5d:7b dev br-ex nud permanent
|
||||
network_bridge_if = iproute.link_lookup(ifname=dev)[0]
|
||||
if ip_version == constants.IP_VERSION_6:
|
||||
iproute.neigh('set',
|
||||
dst=ip,
|
||||
lladdr=lladdr,
|
||||
family=AF_INET6,
|
||||
ifindex=network_bridge_if,
|
||||
state=ndmsg.states['permanent'])
|
||||
else:
|
||||
iproute.neigh('set',
|
||||
dst=ip,
|
||||
lladdr=lladdr,
|
||||
ifindex=network_bridge_if,
|
||||
state=ndmsg.states['permanent'])
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def del_ip_nei(ip, lladdr, dev):
|
||||
ip_version = l_net.get_ip_version(ip)
|
||||
with pyroute2.IPRoute() as iproute:
|
||||
# This is doing something like:
|
||||
# sudo ip nei del 172.24.4.69
|
||||
# lladdr fa:16:3e:d3:5d:7b dev br-ex nud permanent
|
||||
try:
|
||||
network_bridge_if = iproute.link_lookup(
|
||||
ifname=dev)[0]
|
||||
except IndexError:
|
||||
# Neigbhbor device does not exists, continuing
|
||||
LOG.debug("No need to remove nei for dev %s as it does not "
|
||||
"exists", dev)
|
||||
return
|
||||
if ip_version == constants.IP_VERSION_6:
|
||||
iproute.neigh('del',
|
||||
dst=ip.split("/")[0],
|
||||
lladdr=lladdr,
|
||||
family=AF_INET6,
|
||||
ifindex=network_bridge_if,
|
||||
state=ndmsg.states['permanent'])
|
||||
else:
|
||||
iproute.neigh('del',
|
||||
dst=ip.split("/")[0],
|
||||
lladdr=lladdr,
|
||||
ifindex=network_bridge_if,
|
||||
state=ndmsg.states['permanent'])
|
||||
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def add_unreachable_route(vrf_name):
|
||||
# FIXME: This should use pyroute instead but I didn't find
|
||||
|
|
|
@ -14,12 +14,16 @@
|
|||
# under the License.
|
||||
|
||||
import imp
|
||||
import pyroute2
|
||||
from socket import AF_INET6
|
||||
from unittest import mock
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
from ovn_bgp_agent import constants
|
||||
from ovn_bgp_agent.privileged import linux_net as priv_linux_net
|
||||
from ovn_bgp_agent.tests import base as test_base
|
||||
from ovn_bgp_agent.utils import linux_net
|
||||
|
||||
# Mock the privsep decorator and reload the module
|
||||
mock.patch('ovn_bgp_agent.privileged.default.entrypoint', lambda x: x).start()
|
||||
|
@ -35,11 +39,201 @@ class TestPrivilegedLinuxNet(test_base.TestCase):
|
|||
def setUp(self):
|
||||
super(TestPrivilegedLinuxNet, self).setUp()
|
||||
# Mock pyroute2.NDB context manager object
|
||||
self.mock_ndb = mock.patch.object(linux_net.pyroute2, 'NDB').start()
|
||||
self.fake_ndb = self.mock_ndb().__enter__()
|
||||
# Mock pyroute2.IPRoute context manager object
|
||||
self.mock_iproute = mock.patch.object(
|
||||
linux_net.pyroute2, 'IPRoute').start()
|
||||
self.fake_iproute = self.mock_iproute().__enter__()
|
||||
|
||||
self.mock_exc = mock.patch.object(processutils, 'execute').start()
|
||||
|
||||
# Helper variables used accross many tests
|
||||
self.ip = '10.10.1.16'
|
||||
self.ipv6 = '2002::1234:abcd:ffff:c0a8:101'
|
||||
self.dev = 'ethfake'
|
||||
self.mac = 'aa:bb:cc:dd:ee:ff'
|
||||
|
||||
def test_set_device_status(self):
|
||||
state_dict = {'state': constants.LINK_DOWN}
|
||||
dev = mock.MagicMock()
|
||||
dev.__enter__.return_value = state_dict
|
||||
self.mock_ndb().interfaces = {'fake-dev': dev}
|
||||
|
||||
priv_linux_net.set_device_status('fake-dev', constants.LINK_UP)
|
||||
|
||||
# Assert the method updates the state to "up"
|
||||
self.assertEqual(constants.LINK_UP, state_dict['state'])
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_vrf(self, mock_dev_status):
|
||||
priv_linux_net.ensure_vrf('fake-vrf', 10)
|
||||
mock_dev_status.assert_called_once_with(
|
||||
'fake-vrf', constants.LINK_UP, ndb=self.fake_ndb)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_vrf_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = KeyError('Typhoons')
|
||||
priv_linux_net.ensure_vrf('fake-vrf', 10)
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='vrf', ifname='fake-vrf', vrf_table=10)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_bridge(self, mock_dev_status):
|
||||
priv_linux_net.ensure_bridge('fake-bridge')
|
||||
mock_dev_status.assert_called_once_with(
|
||||
'fake-bridge', constants.LINK_UP, ndb=self.fake_ndb)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_bridge_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = KeyError('Oblivion')
|
||||
priv_linux_net.ensure_bridge('fake-bridge')
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='bridge', ifname='fake-bridge', br_stp_state=0)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_vxlan(self, mock_dev_status):
|
||||
priv_linux_net.ensure_vxlan('fake-vxlan', 11, self.ip, 7)
|
||||
mock_dev_status.assert_called_once_with(
|
||||
'fake-vxlan', constants.LINK_UP, ndb=self.fake_ndb)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_vxlan_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = KeyError('Who Needs Friends')
|
||||
priv_linux_net.ensure_vxlan('fake-vxlan', 11, self.ip, 7)
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='vxlan', ifname='fake-vxlan', vxlan_id=11, vxlan_port=7,
|
||||
vxlan_local=self.ip, vxlan_learning=False)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_veth(self, mock_dev_status):
|
||||
priv_linux_net.ensure_veth('fake-veth', 'fake-veth-peer')
|
||||
calls = [mock.call('fake-veth', constants.LINK_UP),
|
||||
mock.call('fake-veth-peer', constants.LINK_UP)]
|
||||
mock_dev_status.assert_has_calls(calls)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_veth_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = (KeyError('Million and One'), None)
|
||||
priv_linux_net.ensure_veth('fake-veth', 'fake-veth-peer')
|
||||
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='veth', ifname='fake-veth', peer='fake-veth-peer')
|
||||
calls = [mock.call('fake-veth', constants.LINK_UP),
|
||||
mock.call('fake-veth-peer', constants.LINK_UP)]
|
||||
mock_dev_status.assert_has_calls(calls)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_dummy_device(self, mock_dev_status):
|
||||
priv_linux_net.ensure_dummy_device('fake-dev')
|
||||
mock_dev_status.assert_called_once_with(
|
||||
'fake-dev', constants.LINK_UP, ndb=self.fake_ndb)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_dummy_device_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = KeyError('All We Have Is Now')
|
||||
priv_linux_net.ensure_dummy_device('fake-dev')
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='dummy', ifname='fake-dev')
|
||||
|
||||
def test_delete_device(self):
|
||||
dev = mock.Mock()
|
||||
iface_dict = {'fake-dev': dev}
|
||||
self.fake_ndb.interfaces = iface_dict
|
||||
|
||||
priv_linux_net.delete_device('fake-dev')
|
||||
dev.remove.assert_called_once_with()
|
||||
|
||||
def test_delete_device_keyerror(self):
|
||||
dev = mock.Mock()
|
||||
iface_dict = {'fake-dev': dev}
|
||||
self.fake_ndb.interfaces = iface_dict
|
||||
|
||||
priv_linux_net.delete_device('fake-dev')
|
||||
dev.remove.assert_called_once_with()
|
||||
|
||||
def test_route_create(self):
|
||||
fake_route = {'dst': 'default',
|
||||
'oif': 1,
|
||||
'table': 10,
|
||||
'scope': 253,
|
||||
'proto': 3}
|
||||
priv_linux_net.route_create(fake_route)
|
||||
self.fake_ndb.routes.create.assert_called_once_with(fake_route)
|
||||
|
||||
def test_route_delete(self):
|
||||
fake_route = mock.MagicMock()
|
||||
self.fake_ndb.routes.__getitem__.return_value = fake_route
|
||||
priv_linux_net.route_delete(fake_route)
|
||||
fake_route.__enter__().remove.assert_called_once_with()
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_vlan_device_for_network(self, mock_dev_status):
|
||||
priv_linux_net.ensure_vlan_device_for_network('fake-br', 10)
|
||||
vlan_name = 'fake-br.10'
|
||||
mock_dev_status.assert_called_once_with(
|
||||
vlan_name, constants.LINK_UP, ndb=self.fake_ndb)
|
||||
|
||||
@mock.patch.object(priv_linux_net, 'set_device_status')
|
||||
def test_ensure_vlan_device_for_network_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = KeyError('Boilermaker')
|
||||
priv_linux_net.ensure_vlan_device_for_network('fake-br', 10)
|
||||
|
||||
vlan_name = 'fake-br.10'
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='vlan', ifname=vlan_name, vlan_id=10, link=mock.ANY)
|
||||
|
||||
def test_delete_exposed_ips(self):
|
||||
ip0 = mock.Mock(address='10.10.1.16')
|
||||
ip1 = mock.Mock(address='2002::1234:abcd:ffff:c0a8:101')
|
||||
iface = mock.Mock()
|
||||
iface.ipaddr = {'10.10.1.16/32': ip0,
|
||||
'2002::1234:abcd:ffff:c0a8:101/128': ip1}
|
||||
self.fake_ndb.interfaces = {self.dev: iface}
|
||||
|
||||
ips = ['10.10.1.16', '2002::1234:abcd:ffff:c0a8:101', '10.10.1.17']
|
||||
priv_linux_net.delete_exposed_ips(ips, self.dev)
|
||||
|
||||
ip0.remove.assert_called_once_with()
|
||||
ip1.remove.assert_called_once_with()
|
||||
|
||||
def test_rule_create(self):
|
||||
fake_rule = mock.MagicMock()
|
||||
self.fake_ndb.rules.__getitem__.side_effect = KeyError
|
||||
priv_linux_net.rule_create(fake_rule)
|
||||
self.fake_ndb.rules.create.assert_called_once_with(fake_rule)
|
||||
|
||||
def test_rule_create_existing(self):
|
||||
fake_rule = mock.MagicMock()
|
||||
self.fake_ndb.rules.__getitem__.return_value = fake_rule
|
||||
priv_linux_net.rule_create(fake_rule)
|
||||
self.fake_ndb.rules.create.assert_not_called()
|
||||
|
||||
def test_delete_ip_rules(self):
|
||||
rule0 = mock.MagicMock()
|
||||
rule1 = mock.MagicMock()
|
||||
self.fake_ndb.rules.__getitem__.side_effect = (rule0, rule1)
|
||||
|
||||
ip_rules = {'10/128': {'table': 7, 'family': 'fake'},
|
||||
'6/128': {'table': 10, 'family': 'fake'}}
|
||||
priv_linux_net.delete_ip_rules(ip_rules)
|
||||
|
||||
# Assert remove() was called on rules
|
||||
rule0.__enter__().remove.assert_called_once_with()
|
||||
rule1.__enter__().remove.assert_called_once_with()
|
||||
|
||||
def test_delete_ip_rules_exceptions(self):
|
||||
rule0 = mock.MagicMock()
|
||||
self.fake_ndb.rules.__getitem__.side_effect = (
|
||||
KeyError('Limbo'),
|
||||
pyroute2.netlink.exceptions.NetlinkError(123))
|
||||
|
||||
ip_rules = {'10/128': {'table': 7, 'family': 'fake'},
|
||||
'6/128': {'table': 10, 'family': 'fake'}}
|
||||
priv_linux_net.delete_ip_rules(ip_rules)
|
||||
|
||||
# Assert remove() was not called due to the exceptions
|
||||
self.assertFalse(rule0.__enter__().remove.called)
|
||||
|
||||
def test_set_kernel_flag(self):
|
||||
priv_linux_net.set_kernel_flag('net.ipv6.conf.fake', 1)
|
||||
|
@ -93,6 +287,61 @@ class TestPrivilegedLinuxNet(test_base.TestCase):
|
|||
self.mock_exc.side_effect = exp
|
||||
self.assertIsNone(priv_linux_net.del_ndp_proxy(self.ipv6, self.dev))
|
||||
|
||||
def test_add_ips_to_dev(self):
|
||||
iface = mock.MagicMock(index=7)
|
||||
self.fake_ndb.interfaces = {self.dev: iface}
|
||||
|
||||
priv_linux_net.add_ip_to_dev(self.ip, self.dev)
|
||||
priv_linux_net.add_ip_to_dev(self.ipv6, self.dev)
|
||||
|
||||
# Assert add_ip() was called for each ip
|
||||
calls = [mock.call('%s/32' % self.ip),
|
||||
mock.call('%s/128' % self.ipv6)]
|
||||
iface.__enter__().add_ip.assert_has_calls(calls)
|
||||
|
||||
def test_del_ips_from_dev(self):
|
||||
iface = mock.MagicMock()
|
||||
self.fake_ndb.interfaces = {self.dev: iface}
|
||||
|
||||
priv_linux_net.del_ip_from_dev(self.ip, self.dev)
|
||||
priv_linux_net.del_ip_from_dev(self.ipv6, self.dev)
|
||||
|
||||
calls = [mock.call('%s/32' % self.ip),
|
||||
mock.call('%s/128' % self.ipv6)]
|
||||
iface.__enter__().del_ip.assert_has_calls(calls)
|
||||
|
||||
def test_add_ip_nei(self):
|
||||
priv_linux_net.add_ip_nei(self.ip, self.mac, self.dev)
|
||||
|
||||
self.fake_iproute.link_lookup.assert_called_once_with(ifname=self.dev)
|
||||
self.fake_iproute.neigh.assert_called_once_with(
|
||||
'set', dst=self.ip, lladdr=self.mac,
|
||||
ifindex=mock.ANY, state=mock.ANY)
|
||||
|
||||
def test_add_ip_nei_ipv6(self):
|
||||
priv_linux_net.add_ip_nei(self.ipv6, self.mac, self.dev)
|
||||
|
||||
self.fake_iproute.link_lookup.assert_called_once_with(ifname=self.dev)
|
||||
self.fake_iproute.neigh.assert_called_once_with(
|
||||
'set', dst=self.ipv6, family=AF_INET6,
|
||||
lladdr=self.mac, ifindex=mock.ANY, state=mock.ANY)
|
||||
|
||||
def test_del_ip_nei(self):
|
||||
priv_linux_net.del_ip_nei(self.ip, self.mac, self.dev)
|
||||
|
||||
self.fake_iproute.link_lookup.assert_called_once_with(ifname=self.dev)
|
||||
self.fake_iproute.neigh.assert_called_once_with(
|
||||
'del', dst=self.ip, lladdr=self.mac,
|
||||
ifindex=mock.ANY, state=mock.ANY)
|
||||
|
||||
def test_del_ip_nei_ipv6(self):
|
||||
priv_linux_net.del_ip_nei(self.ipv6, self.mac, self.dev)
|
||||
|
||||
self.fake_iproute.link_lookup.assert_called_once_with(ifname=self.dev)
|
||||
self.fake_iproute.neigh.assert_called_once_with(
|
||||
'del', dst=self.ipv6, family=AF_INET6,
|
||||
lladdr=self.mac, ifindex=mock.ANY, state=mock.ANY)
|
||||
|
||||
def test_add_unreachable_route(self):
|
||||
priv_linux_net.add_unreachable_route('fake-vrf')
|
||||
calls = [mock.call('ip', -4, 'route', 'add', 'vrf', 'fake-vrf',
|
||||
|
|
|
@ -18,10 +18,8 @@ import ipaddress
|
|||
from socket import AF_INET
|
||||
from socket import AF_INET6
|
||||
|
||||
import pyroute2
|
||||
from unittest import mock
|
||||
|
||||
from ovn_bgp_agent import constants
|
||||
from ovn_bgp_agent import exceptions as agent_exc
|
||||
from ovn_bgp_agent.tests import base as test_base
|
||||
from ovn_bgp_agent.utils import linux_net
|
||||
|
@ -34,10 +32,6 @@ class TestLinuxNet(test_base.TestCase):
|
|||
# Mock pyroute2.NDB context manager object
|
||||
self.mock_ndb = mock.patch.object(linux_net.pyroute2, 'NDB').start()
|
||||
self.fake_ndb = self.mock_ndb().__enter__()
|
||||
# Mock pyroute2.IPRoute context manager object
|
||||
self.mock_iproute = mock.patch.object(
|
||||
linux_net.pyroute2, 'IPRoute').start()
|
||||
self.fake_iproute = self.mock_iproute().__enter__()
|
||||
|
||||
# Helper variables used accross many tests
|
||||
self.ip = '10.10.1.16'
|
||||
|
@ -68,63 +62,25 @@ class TestLinuxNet(test_base.TestCase):
|
|||
ret = linux_net.get_interface_index('fake-nic')
|
||||
self.assertEqual(7, ret)
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_vrf(self, mock_dev_status):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.ensure_vrf')
|
||||
def test_ensure_vrf(self, mock_ensure_vrf):
|
||||
linux_net.ensure_vrf('fake-vrf', 10)
|
||||
mock_dev_status.assert_called_once_with(
|
||||
'fake-vrf', constants.LINK_UP, ndb=self.fake_ndb)
|
||||
mock_ensure_vrf.assert_called_once_with('fake-vrf', 10)
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_vrf_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = KeyError('Typhoons')
|
||||
linux_net.ensure_vrf('fake-vrf', 10)
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='vrf', ifname='fake-vrf', vrf_table=10)
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_bridge(self, mock_dev_status):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.ensure_bridge')
|
||||
def test_ensure_bridge(self, mock_ensure_bridge):
|
||||
linux_net.ensure_bridge('fake-bridge')
|
||||
mock_dev_status.assert_called_once_with(
|
||||
'fake-bridge', constants.LINK_UP, ndb=self.fake_ndb)
|
||||
mock_ensure_bridge.assert_called_once_with('fake-bridge')
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_bridge_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = KeyError('Oblivion')
|
||||
linux_net.ensure_bridge('fake-bridge')
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='bridge', ifname='fake-bridge', br_stp_state=0)
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_vxlan(self, mock_dev_status):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.ensure_vxlan')
|
||||
def test_ensure_vxlan(self, mock_ensure_vxlan):
|
||||
linux_net.ensure_vxlan('fake-vxlan', 11, self.ip, 7)
|
||||
mock_dev_status.assert_called_once_with(
|
||||
'fake-vxlan', constants.LINK_UP, ndb=self.fake_ndb)
|
||||
mock_ensure_vxlan.assert_called_once_with('fake-vxlan', 11, self.ip, 7)
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_vxlan_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = KeyError('Who Needs Friends')
|
||||
linux_net.ensure_vxlan('fake-vxlan', 11, self.ip, 7)
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='vxlan', ifname='fake-vxlan', vxlan_id=11, vxlan_port=7,
|
||||
vxlan_local=self.ip, vxlan_learning=False)
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_veth(self, mock_dev_status):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.ensure_veth')
|
||||
def test_ensure_veth(self, mock_ensure_veth):
|
||||
linux_net.ensure_veth('fake-veth', 'fake-veth-peer')
|
||||
calls = [mock.call('fake-veth', constants.LINK_UP),
|
||||
mock.call('fake-veth-peer', constants.LINK_UP)]
|
||||
mock_dev_status.assert_has_calls(calls)
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_veth_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = (KeyError('Million and One'), None)
|
||||
linux_net.ensure_veth('fake-veth', 'fake-veth-peer')
|
||||
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='veth', ifname='fake-veth', peer='fake-veth-peer')
|
||||
calls = [mock.call('fake-veth', constants.LINK_UP),
|
||||
mock.call('fake-veth-peer', constants.LINK_UP)]
|
||||
mock_dev_status.assert_has_calls(calls)
|
||||
mock_ensure_veth.assert_called_once_with('fake-veth', 'fake-veth-peer')
|
||||
|
||||
def test_set_master_for_device(self):
|
||||
dev = mock.MagicMock()
|
||||
|
@ -144,29 +100,10 @@ class TestLinuxNet(test_base.TestCase):
|
|||
# Both values were the same, assert set() is not called
|
||||
self.assertFalse(dev.__enter__().set.called)
|
||||
|
||||
def test_set_device_status(self):
|
||||
state_dict = {'state': constants.LINK_DOWN}
|
||||
dev = mock.MagicMock()
|
||||
dev.__enter__.return_value = state_dict
|
||||
self.mock_ndb().interfaces = {'fake-dev': dev}
|
||||
|
||||
linux_net.set_device_status('fake-dev', constants.LINK_UP)
|
||||
|
||||
# Assert the method updates the state to "up"
|
||||
self.assertEqual(constants.LINK_UP, state_dict['state'])
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_dummy_device(self, mock_dev_status):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.ensure_dummy_device')
|
||||
def test_ensure_dummy_device(self, mock_ensure_dummy_device):
|
||||
linux_net.ensure_dummy_device('fake-dev')
|
||||
mock_dev_status.assert_called_once_with(
|
||||
'fake-dev', constants.LINK_UP, ndb=self.fake_ndb)
|
||||
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_dummy_device_keyerror(self, mock_dev_status):
|
||||
mock_dev_status.side_effect = KeyError('All We Have Is Now')
|
||||
linux_net.ensure_dummy_device('fake-dev')
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='dummy', ifname='fake-dev')
|
||||
mock_ensure_dummy_device.assert_called_once_with('fake-dev')
|
||||
|
||||
@mock.patch.object(linux_net, 'ensure_dummy_device')
|
||||
@mock.patch.object(linux_net, 'set_master_for_device')
|
||||
|
@ -175,13 +112,10 @@ class TestLinuxNet(test_base.TestCase):
|
|||
mock_dummy.assert_called_once_with('ifname')
|
||||
mock_master.assert_called_once_with('ifname', 'fake-vrf')
|
||||
|
||||
def test_delete_device(self):
|
||||
dev = mock.Mock()
|
||||
iface_dict = {'fake-dev': dev}
|
||||
self.fake_ndb.interfaces = iface_dict
|
||||
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.delete_device')
|
||||
def test_delete_device(self, mock_delete_device):
|
||||
linux_net.delete_device('fake-dev')
|
||||
dev.remove.assert_called_once_with()
|
||||
mock_delete_device.assert_called_once_with('fake-dev')
|
||||
|
||||
def test_ensure_routing_table_for_bridge(self):
|
||||
# TODO(lucasagomes): This method is massive and complex, perhaps
|
||||
|
@ -191,29 +125,14 @@ class TestLinuxNet(test_base.TestCase):
|
|||
|
||||
@mock.patch.object(linux_net, 'enable_proxy_arp')
|
||||
@mock.patch.object(linux_net, 'enable_proxy_ndp')
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
@mock.patch(
|
||||
'ovn_bgp_agent.privileged.linux_net.ensure_vlan_device_for_network')
|
||||
def test_ensure_vlan_device_for_network(
|
||||
self, mock_dev_status, mock_ndp, mock_arp):
|
||||
self, mock_ensure_vlan_device_for_network, mock_ndp, mock_arp):
|
||||
linux_net.ensure_vlan_device_for_network('fake-br', 10)
|
||||
vlan_name = 'fake-br.10'
|
||||
expected_dev = 'fake-br/10'
|
||||
mock_dev_status.assert_called_once_with(
|
||||
vlan_name, constants.LINK_UP, ndb=self.fake_ndb)
|
||||
mock_ndp.assert_called_once_with(expected_dev)
|
||||
mock_arp.assert_called_once_with(expected_dev)
|
||||
|
||||
@mock.patch.object(linux_net, 'enable_proxy_arp')
|
||||
@mock.patch.object(linux_net, 'enable_proxy_ndp')
|
||||
@mock.patch.object(linux_net, 'set_device_status')
|
||||
def test_ensure_vlan_device_for_network_keyerror(
|
||||
self, mock_dev_status, mock_ndp, mock_arp):
|
||||
mock_dev_status.side_effect = KeyError('Boilermaker')
|
||||
linux_net.ensure_vlan_device_for_network('fake-br', 10)
|
||||
|
||||
vlan_name = 'fake-br.10'
|
||||
expected_dev = 'fake-br/10'
|
||||
self.fake_ndb.interfaces.create.assert_called_once_with(
|
||||
kind='vlan', ifname=vlan_name, vlan_id=10, link=mock.ANY)
|
||||
mock_ensure_vlan_device_for_network.assert_called_once_with(
|
||||
'fake-br', 10)
|
||||
mock_ndp.assert_called_once_with(expected_dev)
|
||||
mock_arp.assert_called_once_with(expected_dev)
|
||||
|
||||
|
@ -300,47 +219,20 @@ class TestLinuxNet(test_base.TestCase):
|
|||
'6/128': {'table': 10, 'family': 'fake'}}
|
||||
self.assertEqual(expected_ret, ret)
|
||||
|
||||
def test_delete_exposed_ips(self):
|
||||
ip0 = mock.Mock(address='10.10.1.16')
|
||||
ip1 = mock.Mock(address='2002::1234:abcd:ffff:c0a8:101')
|
||||
iface = mock.Mock()
|
||||
iface.ipaddr = {'10.10.1.16/32': ip0,
|
||||
'2002::1234:abcd:ffff:c0a8:101/128': ip1}
|
||||
self.fake_ndb.interfaces = {self.dev: iface}
|
||||
|
||||
ips = ['10.10.1.16', '2002::1234:abcd:ffff:c0a8:101', '10.10.1.17']
|
||||
linux_net.delete_exposed_ips(ips, self.dev)
|
||||
|
||||
ip0.remove.assert_called_once_with()
|
||||
ip1.remove.assert_called_once_with()
|
||||
|
||||
def test_delete_ip_rules(self):
|
||||
rule0 = mock.MagicMock()
|
||||
rule1 = mock.MagicMock()
|
||||
self.fake_ndb.rules.__getitem__.side_effect = (rule0, rule1)
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.delete_exposed_ips')
|
||||
def test_delete_exposed_ips(self, mock_delete_exposed_ips):
|
||||
linux_net.delete_exposed_ips([self.ip], self.dev)
|
||||
mock_delete_exposed_ips.assert_called_once_with([self.ip], self.dev)
|
||||
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.delete_ip_rules')
|
||||
def test_delete_ip_rules(self, mock_delete_ip_rules):
|
||||
ip_rules = {'10/128': {'table': 7, 'family': 'fake'},
|
||||
'6/128': {'table': 10, 'family': 'fake'}}
|
||||
linux_net.delete_ip_rules(ip_rules)
|
||||
mock_delete_ip_rules.assert_called_once_with(ip_rules)
|
||||
|
||||
# Assert remove() was called on rules
|
||||
rule0.__enter__().remove.assert_called_once_with()
|
||||
rule1.__enter__().remove.assert_called_once_with()
|
||||
|
||||
def test_delete_ip_rules_exceptions(self):
|
||||
rule0 = mock.MagicMock()
|
||||
self.fake_ndb.rules.__getitem__.side_effect = (
|
||||
KeyError('Limbo'),
|
||||
pyroute2.netlink.exceptions.NetlinkError(123))
|
||||
|
||||
ip_rules = {'10/128': {'table': 7, 'family': 'fake'},
|
||||
'6/128': {'table': 10, 'family': 'fake'}}
|
||||
linux_net.delete_ip_rules(ip_rules)
|
||||
|
||||
# Assert remove() was not called due to the exceptions
|
||||
self.assertFalse(rule0.__enter__().remove.called)
|
||||
|
||||
def _test_delete_bridge_ip_routes(self, is_vlan=False, has_gateway=False):
|
||||
def _test_delete_bridge_ip_routes(self, mock_route_delete, is_vlan=False,
|
||||
has_gateway=False):
|
||||
gateway = '1.1.1.1'
|
||||
oif = 11
|
||||
vlan = 30 if is_vlan else None
|
||||
|
@ -371,20 +263,22 @@ class TestLinuxNet(test_base.TestCase):
|
|||
routing_tables, routing_tables_routes, extra_routes)
|
||||
|
||||
# Assert extra_route1 has been removed
|
||||
self.fake_ndb.routes.__getitem__.assert_called_once_with(extra_route1)
|
||||
self.fake_ndb.routes.__getitem__().__enter__().\
|
||||
remove.assert_called_once_with()
|
||||
mock_route_delete.assert_called_once_with(extra_route1)
|
||||
|
||||
def test_delete_bridge_ip_routes(self):
|
||||
self._test_delete_bridge_ip_routes()
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_delete_bridge_ip_routes(self, mock_route_delete):
|
||||
self._test_delete_bridge_ip_routes(mock_route_delete)
|
||||
|
||||
def test_delete_bridge_ip_routes_vlan(self):
|
||||
self._test_delete_bridge_ip_routes(is_vlan=True)
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_delete_bridge_ip_routes_vlan(self, mock_route_delete):
|
||||
self._test_delete_bridge_ip_routes(mock_route_delete, is_vlan=True)
|
||||
|
||||
def test_delete_bridge_ip_routes_gateway(self):
|
||||
self._test_delete_bridge_ip_routes(has_gateway=True)
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_delete_bridge_ip_routes_gateway(self, mock_route_delete):
|
||||
self._test_delete_bridge_ip_routes(mock_route_delete, has_gateway=True)
|
||||
|
||||
def test_delete_routes_from_table(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_delete_routes_from_table(self, mock_route_delete):
|
||||
route0 = mock.MagicMock(scope=1, proto=11)
|
||||
route1 = mock.MagicMock(scope=2, proto=22)
|
||||
route2 = mock.MagicMock(scope=254, proto=186)
|
||||
|
@ -392,14 +286,13 @@ class TestLinuxNet(test_base.TestCase):
|
|||
route0, route1, route2]
|
||||
|
||||
self.fake_ndb.routes.__getitem__.side_effect = (
|
||||
route0, route1, KeyError('Mad Visions'))
|
||||
route0, route1)
|
||||
|
||||
linux_net.delete_routes_from_table('fake-table')
|
||||
|
||||
# Assert remove() was called on rules
|
||||
route0.__enter__().remove.assert_called_once_with()
|
||||
route1.__enter__().remove.assert_called_once_with()
|
||||
self.assertFalse(route2.__enter__().remove.called)
|
||||
calls = [mock.call(route0),
|
||||
mock.call(route1)]
|
||||
mock_route_delete.assert_has_calls(calls)
|
||||
|
||||
def test_get_routes_on_tables(self):
|
||||
route0 = mock.MagicMock(table=10, dst='10.10.10.10', proto=10)
|
||||
|
@ -417,7 +310,8 @@ class TestLinuxNet(test_base.TestCase):
|
|||
|
||||
self.assertEqual([route0, route2], ret)
|
||||
|
||||
def test_delete_ip_routes(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_delete_ip_routes(self, mock_route_delete):
|
||||
route0 = mock.MagicMock(
|
||||
table=10, dst='10.10.10.10', proto=10, dst_len=128,
|
||||
oif='ethout', family='fake', gateway='1.1.1.1')
|
||||
|
@ -429,25 +323,7 @@ class TestLinuxNet(test_base.TestCase):
|
|||
|
||||
linux_net.delete_ip_routes(routes)
|
||||
|
||||
route0.__enter__().remove.assert_called_once_with()
|
||||
route1.__enter__().remove.assert_called_once_with()
|
||||
|
||||
def test_delete_ip_routes_keyerror(self):
|
||||
route0 = mock.MagicMock(
|
||||
table=10, dst='10.10.10.10', proto=10, dst_len=128,
|
||||
oif='ethout', family='fake', gateway='1.1.1.1')
|
||||
route1 = mock.MagicMock(
|
||||
table=11, dst='11.11.11.11', proto=11, dst_len=64,
|
||||
oif='ethout', family='fake', gateway='2.2.2.2')
|
||||
routes = [route0, route1]
|
||||
self.fake_ndb.routes.__getitem__.side_effect = (
|
||||
KeyError('Either You Want It'))
|
||||
|
||||
linux_net.delete_ip_routes(routes)
|
||||
|
||||
# Assert remove() wasn't called due to KeyError
|
||||
self.assertFalse(route0.__enter__().remove.called)
|
||||
self.assertFalse(route1.__enter__().remove.called)
|
||||
mock_route_delete.has_calls([mock.call(route0), mock.call(route1)])
|
||||
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.add_ndp_proxy')
|
||||
def test_add_ndp_proxy(self, mock_ndp_proxy):
|
||||
|
@ -459,101 +335,86 @@ class TestLinuxNet(test_base.TestCase):
|
|||
linux_net.del_ndp_proxy(self.ip, self.dev, vlan=10)
|
||||
mock_ndp_proxy.assert_called_once_with(self.ip, self.dev, 10)
|
||||
|
||||
def test_add_ips_to_dev(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.add_ip_to_dev')
|
||||
def test_add_ips_to_dev(self, mock_add_ip_to_dev, mock_route_delete):
|
||||
iface = mock.MagicMock(index=7)
|
||||
self.fake_ndb.interfaces = {self.dev: iface}
|
||||
# clear_local_route_at_table bits below
|
||||
route0 = mock.MagicMock()
|
||||
route1 = mock.MagicMock()
|
||||
self.fake_ndb.routes.__getitem__.side_effect = (route0, route1)
|
||||
|
||||
ips = [self.ip, self.ipv6]
|
||||
linux_net.add_ips_to_dev(
|
||||
self.dev, ips, clear_local_route_at_table=123)
|
||||
|
||||
# Assert add_ip() was called for each ip
|
||||
calls = [mock.call('%s/32' % self.ip),
|
||||
mock.call('%s/128' % self.ipv6)]
|
||||
iface.__enter__().add_ip.assert_has_calls(calls)
|
||||
# Assert called for each ip
|
||||
calls = [mock.call(self.ip, self.dev),
|
||||
mock.call(self.ipv6, self.dev)]
|
||||
mock_add_ip_to_dev.has_calls(calls)
|
||||
|
||||
# Assert clear_local_route_at_table were invoked
|
||||
route0.__enter__().remove.assert_called_once_with()
|
||||
route1.__enter__().remove.assert_called_once_with()
|
||||
r1 = {'table': 123, 'proto': 2, 'scope': 254, 'dst': self.ip, 'oif': 7}
|
||||
r2 = {'table': 123, 'proto': 2, 'scope': 254, 'dst': self.ipv6,
|
||||
'oif': 7}
|
||||
calls = [mock.call(r1),
|
||||
mock.call(r2)]
|
||||
mock_route_delete.has_calls(calls)
|
||||
|
||||
def test_del_ips_from_dev(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.del_ip_from_dev')
|
||||
def test_del_ips_from_dev(self, mock_del_ip_from_dev):
|
||||
iface = mock.MagicMock()
|
||||
self.fake_ndb.interfaces = {self.dev: iface}
|
||||
|
||||
ips = [self.ip, self.ipv6]
|
||||
linux_net.del_ips_from_dev(self.dev, ips)
|
||||
|
||||
calls = [mock.call('%s/32' % self.ip),
|
||||
mock.call('%s/128' % self.ipv6)]
|
||||
iface.__enter__().del_ip.assert_has_calls(calls)
|
||||
calls = [mock.call(self.ip, self.dev),
|
||||
mock.call(self.ipv6, self.dev)]
|
||||
mock_del_ip_from_dev.has_calls(calls)
|
||||
|
||||
@mock.patch.object(linux_net, 'add_ip_nei')
|
||||
def test_add_ip_rule(self, mock_add_ip_nei):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.rule_create')
|
||||
def test_add_ip_rule(self, mock_rule_create, mock_add_ip_nei):
|
||||
linux_net.add_ip_rule(
|
||||
self.ip, 7, dev=self.dev, lladdr=self.mac)
|
||||
|
||||
expected_args = {'dst': self.ip, 'table': 7, 'dst_len': 32}
|
||||
self.fake_ndb.rules.__getitem__.assert_called_once_with(expected_args)
|
||||
|
||||
mock_rule_create.assert_called_once_with(expected_args)
|
||||
mock_add_ip_nei.assert_called_once_with(self.ip, self.mac, self.dev)
|
||||
|
||||
@mock.patch.object(linux_net, 'add_ip_nei')
|
||||
def test_add_ip_rule_ipv6(self, mock_add_ip_nei):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.rule_create')
|
||||
def test_add_ip_rule_ipv6(self, mock_rule_create, mock_add_ip_nei):
|
||||
linux_net.add_ip_rule(self.ipv6, 7, dev=self.dev, lladdr=self.mac)
|
||||
|
||||
expected_args = {'dst': self.ipv6,
|
||||
'table': 7, 'dst_len': 128, 'family': AF_INET6}
|
||||
self.fake_ndb.rules.__getitem__.assert_called_once_with(expected_args)
|
||||
|
||||
mock_rule_create.assert_called_once_with(expected_args)
|
||||
mock_add_ip_nei.assert_called_once_with(self.ipv6, self.mac, self.dev)
|
||||
|
||||
def test_add_ip_rule_create(self):
|
||||
self.fake_ndb.rules.__getitem__.side_effect = KeyError('Hold On')
|
||||
|
||||
linux_net.add_ip_rule(self.ip, 7)
|
||||
|
||||
expected_args = {'dst': self.ip, 'table': 7, 'dst_len': 32}
|
||||
self.fake_ndb.rules.create.assert_called_once_with(expected_args)
|
||||
|
||||
def test_add_ip_rule_invalid_ip(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.rule_create')
|
||||
def test_add_ip_rule_invalid_ip(self, mock_rule_create):
|
||||
self.assertRaises(agent_exc.InvalidPortIP,
|
||||
linux_net.add_ip_rule, '10.10.1.6/30/128', 7)
|
||||
self.assertFalse(self.fake_ndb.rules.create.called)
|
||||
mock_rule_create.assert_not_called()
|
||||
|
||||
def test_add_ip_nei(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.add_ip_nei')
|
||||
def test_add_ip_nei(self, mock_add_ip_nei):
|
||||
linux_net.add_ip_nei(self.ip, self.mac, self.dev)
|
||||
|
||||
self.fake_iproute.link_lookup.assert_called_once_with(ifname=self.dev)
|
||||
self.fake_iproute.neigh.assert_called_once_with(
|
||||
'set', dst=self.ip, lladdr=self.mac,
|
||||
ifindex=mock.ANY, state=mock.ANY)
|
||||
|
||||
def test_add_ip_nei_ipv6(self):
|
||||
linux_net.add_ip_nei(self.ipv6, self.mac, self.dev)
|
||||
|
||||
self.fake_iproute.link_lookup.assert_called_once_with(ifname=self.dev)
|
||||
self.fake_iproute.neigh.assert_called_once_with(
|
||||
'set', dst=self.ipv6, family=AF_INET6,
|
||||
lladdr=self.mac, ifindex=mock.ANY, state=mock.ANY)
|
||||
mock_add_ip_nei.assert_called_once_with(self.ip, self.mac, self.dev)
|
||||
|
||||
@mock.patch.object(linux_net, 'del_ip_nei')
|
||||
def test_del_ip_rule(self, mock_del_ip_nei):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.rule_delete')
|
||||
def test_del_ip_rule(self, mock_rule_delete, mock_del_ip_nei):
|
||||
rule = mock.MagicMock()
|
||||
self.fake_ndb.rules.__getitem__.return_value = rule
|
||||
|
||||
linux_net.del_ip_rule(self.ip, 7, dev=self.dev, lladdr=self.mac)
|
||||
|
||||
expected_args = {'dst': self.ip, 'table': 7, 'dst_len': 32}
|
||||
self.fake_ndb.rules.__getitem__.assert_called_once_with(expected_args)
|
||||
rule.remove.assert_called_once_with()
|
||||
mock_rule_delete.assert_called_once_with(expected_args)
|
||||
mock_del_ip_nei.assert_called_once_with(self.ip, self.mac, self.dev)
|
||||
|
||||
@mock.patch.object(linux_net, 'del_ip_nei')
|
||||
def test_del_ip_rule_ipv6(self, mock_del_ip_nei):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.rule_delete')
|
||||
def test_del_ip_rule_ipv6(self, mock_rule_delete, mock_del_ip_nei):
|
||||
rule = mock.MagicMock()
|
||||
self.fake_ndb.rules.__getitem__.return_value = rule
|
||||
|
||||
|
@ -561,41 +422,32 @@ class TestLinuxNet(test_base.TestCase):
|
|||
|
||||
expected_args = {'dst': self.ipv6, 'table': 7,
|
||||
'dst_len': 128, 'family': AF_INET6}
|
||||
self.fake_ndb.rules.__getitem__.assert_called_once_with(expected_args)
|
||||
rule.remove.assert_called_once_with()
|
||||
mock_rule_delete.assert_called_once_with(expected_args)
|
||||
mock_del_ip_nei.assert_called_once_with(self.ipv6, self.mac, self.dev)
|
||||
|
||||
@mock.patch.object(linux_net, 'del_ip_nei')
|
||||
def test_del_ip_rule_invalid_ip(self, mock_del_ip_nei):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.rule_delete')
|
||||
def test_del_ip_rule_invalid_ip(self, mock_rule_delete, mock_del_ip_nei):
|
||||
rule = mock.MagicMock()
|
||||
self.fake_ndb.rules.__getitem__.return_value = rule
|
||||
|
||||
self.assertIsNone(linux_net.del_ip_rule('10.10.1.6/30/128', 7))
|
||||
self.assertFalse(self.fake_ndb.rules.remove.called)
|
||||
self.assertFalse(rule.remove.called)
|
||||
|
||||
def test_del_ip_nei(self):
|
||||
mock_rule_delete.assert_not_called()
|
||||
mock_del_ip_nei.assert_not_called()
|
||||
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.del_ip_nei')
|
||||
def test_del_ip_nei(self, mock_del_ip_nei):
|
||||
linux_net.del_ip_nei(self.ip, self.mac, self.dev)
|
||||
|
||||
self.fake_iproute.link_lookup.assert_called_once_with(ifname=self.dev)
|
||||
self.fake_iproute.neigh.assert_called_once_with(
|
||||
'del', dst=self.ip, lladdr=self.mac,
|
||||
ifindex=mock.ANY, state=mock.ANY)
|
||||
|
||||
def test_del_ip_nei_ipv6(self):
|
||||
linux_net.del_ip_nei(self.ipv6, self.mac, self.dev)
|
||||
|
||||
self.fake_iproute.link_lookup.assert_called_once_with(ifname=self.dev)
|
||||
self.fake_iproute.neigh.assert_called_once_with(
|
||||
'del', dst=self.ipv6, family=AF_INET6,
|
||||
lladdr=self.mac, ifindex=mock.ANY, state=mock.ANY)
|
||||
mock_del_ip_nei.assert_called_once_with(self.ip, self.mac, self.dev)
|
||||
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.add_unreachable_route')
|
||||
def test_add_unreachable_route(self, mock_add_route):
|
||||
linux_net.add_unreachable_route('fake-vrf')
|
||||
mock_add_route.assert_called_once_with('fake-vrf')
|
||||
|
||||
def test_add_ip_route(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_create')
|
||||
def test_add_ip_route(self, mock_route_create):
|
||||
routes = {}
|
||||
linux_net.add_ip_route(routes, self.ip, 7, self.dev)
|
||||
expected_routes = {
|
||||
|
@ -608,8 +460,10 @@ class TestLinuxNet(test_base.TestCase):
|
|||
'vlan': None}]}
|
||||
self.assertEqual(expected_routes, routes)
|
||||
self.assertFalse(self.fake_ndb.routes.create.called)
|
||||
mock_route_create.assert_not_called()
|
||||
|
||||
def test_add_ip_route_ipv6(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_create')
|
||||
def test_add_ip_route_ipv6(self, mock_route_create):
|
||||
routes = {}
|
||||
linux_net.add_ip_route(routes, self.ipv6, 7, self.dev)
|
||||
expected_routes = {
|
||||
|
@ -621,9 +475,10 @@ class TestLinuxNet(test_base.TestCase):
|
|||
'table': 7},
|
||||
'vlan': None}]}
|
||||
self.assertEqual(expected_routes, routes)
|
||||
self.assertFalse(self.fake_ndb.routes.create.called)
|
||||
mock_route_create.assert_not_called()
|
||||
|
||||
def test_add_ip_route_via(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_create')
|
||||
def test_add_ip_route_via(self, mock_route_create):
|
||||
routes = {}
|
||||
linux_net.add_ip_route(routes, self.ip, 7, self.dev, via='1.1.1.1')
|
||||
expected_routes = {
|
||||
|
@ -636,9 +491,10 @@ class TestLinuxNet(test_base.TestCase):
|
|||
'table': 7},
|
||||
'vlan': None}]}
|
||||
self.assertEqual(expected_routes, routes)
|
||||
self.assertFalse(self.fake_ndb.routes.create.called)
|
||||
mock_route_create.assert_not_called()
|
||||
|
||||
def test_add_ip_route_vlan(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_create')
|
||||
def test_add_ip_route_vlan(self, mock_route_create):
|
||||
routes = {}
|
||||
linux_net.add_ip_route(routes, self.ip, 7, self.dev, vlan=10)
|
||||
expected_routes = {
|
||||
|
@ -650,9 +506,10 @@ class TestLinuxNet(test_base.TestCase):
|
|||
'table': 7},
|
||||
'vlan': 10}]}
|
||||
self.assertEqual(expected_routes, routes)
|
||||
self.assertFalse(self.fake_ndb.routes.create.called)
|
||||
mock_route_create.assert_not_called()
|
||||
|
||||
def test_add_ip_route_mask(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_create')
|
||||
def test_add_ip_route_mask(self, mock_route_create):
|
||||
routes = {}
|
||||
linux_net.add_ip_route(routes, self.ip, 7, self.dev, mask=30)
|
||||
expected_routes = {
|
||||
|
@ -664,9 +521,10 @@ class TestLinuxNet(test_base.TestCase):
|
|||
'table': 7},
|
||||
'vlan': None}]}
|
||||
self.assertEqual(expected_routes, routes)
|
||||
self.assertFalse(self.fake_ndb.routes.create.called)
|
||||
mock_route_create.assert_not_called()
|
||||
|
||||
def test_add_ip_route_keyerror(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_create')
|
||||
def test_add_ip_route_keyerror(self, mock_route_create):
|
||||
self.fake_ndb.routes.__getitem__.side_effect = KeyError('Nite Expo')
|
||||
routes = {}
|
||||
linux_net.add_ip_route(routes, self.ip, 7, self.dev)
|
||||
|
@ -679,10 +537,11 @@ class TestLinuxNet(test_base.TestCase):
|
|||
'table': 7},
|
||||
'vlan': None}]}
|
||||
self.assertEqual(expected_routes, routes)
|
||||
self.fake_ndb.routes.create.assert_called_once_with(
|
||||
mock_route_create.assert_called_once_with(
|
||||
expected_routes[self.dev][0]['route'])
|
||||
|
||||
def test_del_ip_route(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_del_ip_route(self, mock_route_delete):
|
||||
routes = {
|
||||
self.dev: [{'route': {'dst': self.ip,
|
||||
'dst_len': 32,
|
||||
|
@ -695,12 +554,11 @@ class TestLinuxNet(test_base.TestCase):
|
|||
|
||||
linux_net.del_ip_route(routes, self.ip, 7, self.dev)
|
||||
|
||||
self.fake_ndb.routes.__getitem__.assert_called_once_with(route)
|
||||
self.fake_ndb.routes.__getitem__().__enter__().\
|
||||
remove.assert_called_once_with()
|
||||
self.assertEqual({self.dev: []}, routes)
|
||||
mock_route_delete.assert_called_once_with(route)
|
||||
|
||||
def test_del_ip_route_ipv6(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_del_ip_route_ipv6(self, mock_route_delete):
|
||||
routes = {
|
||||
self.dev: [{'route': {'dst': self.ipv6,
|
||||
'dst_len': 128,
|
||||
|
@ -714,12 +572,11 @@ class TestLinuxNet(test_base.TestCase):
|
|||
|
||||
linux_net.del_ip_route(routes, self.ipv6, 7, self.dev)
|
||||
|
||||
self.fake_ndb.routes.__getitem__.assert_called_once_with(route)
|
||||
self.fake_ndb.routes.__getitem__().__enter__().\
|
||||
remove.assert_called_once_with()
|
||||
self.assertEqual({self.dev: []}, routes)
|
||||
mock_route_delete.assert_called_once_with(route)
|
||||
|
||||
def test_del_ip_route_via(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_del_ip_route_via(self, mock_route_delete):
|
||||
routes = {
|
||||
self.dev: [{'route': {'dst': self.ip,
|
||||
'dst_len': 32,
|
||||
|
@ -733,12 +590,11 @@ class TestLinuxNet(test_base.TestCase):
|
|||
|
||||
linux_net.del_ip_route(routes, self.ip, 7, self.dev, via='1.1.1.1')
|
||||
|
||||
self.fake_ndb.routes.__getitem__.assert_called_once_with(route)
|
||||
self.fake_ndb.routes.__getitem__().__enter__().\
|
||||
remove.assert_called_once_with()
|
||||
self.assertEqual({self.dev: []}, routes)
|
||||
mock_route_delete.assert_called_once_with(route)
|
||||
|
||||
def test_del_ip_route_vlan(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_del_ip_route_vlan(self, mock_route_delete):
|
||||
routes = {
|
||||
self.dev: [{'route': {'dst': self.ip,
|
||||
'dst_len': 32,
|
||||
|
@ -751,12 +607,11 @@ class TestLinuxNet(test_base.TestCase):
|
|||
|
||||
linux_net.del_ip_route(routes, self.ip, 7, self.dev, vlan=10)
|
||||
|
||||
self.fake_ndb.routes.__getitem__.assert_called_once_with(route)
|
||||
self.fake_ndb.routes.__getitem__().__enter__().\
|
||||
remove.assert_called_once_with()
|
||||
self.assertEqual({self.dev: []}, routes)
|
||||
mock_route_delete.assert_called_once_with(route)
|
||||
|
||||
def test_del_ip_route_mask(self):
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_del_ip_route_mask(self, mock_route_delete):
|
||||
routes = {
|
||||
self.dev: [{'route': {'dst': self.ip,
|
||||
'dst_len': 30,
|
||||
|
@ -769,7 +624,5 @@ class TestLinuxNet(test_base.TestCase):
|
|||
|
||||
linux_net.del_ip_route(routes, self.ip, 7, self.dev, mask=30)
|
||||
|
||||
self.fake_ndb.routes.__getitem__.assert_called_once_with(route)
|
||||
self.fake_ndb.routes.__getitem__().__enter__().\
|
||||
remove.assert_called_once_with()
|
||||
self.assertEqual({self.dev: []}, routes)
|
||||
mock_route_delete.assert_called_once_with(route)
|
||||
|
|
|
@ -18,7 +18,6 @@ import random
|
|||
import re
|
||||
import sys
|
||||
|
||||
from pyroute2.netlink.rtnl import ndmsg
|
||||
from socket import AF_INET
|
||||
from socket import AF_INET6
|
||||
|
||||
|
@ -47,77 +46,28 @@ def get_interface_index(nic):
|
|||
|
||||
|
||||
def ensure_vrf(vrf_name, vrf_table):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(vrf_name, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
ndb.interfaces.create(
|
||||
kind="vrf", ifname=vrf_name, vrf_table=int(vrf_table)).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
ovn_bgp_agent.privileged.linux_net.ensure_vrf(vrf_name, vrf_table)
|
||||
|
||||
|
||||
def ensure_bridge(bridge_name):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(bridge_name, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
ndb.interfaces.create(
|
||||
kind="bridge", ifname=bridge_name, br_stp_state=0).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
ovn_bgp_agent.privileged.linux_net.ensure_bridge(bridge_name)
|
||||
|
||||
|
||||
def ensure_vxlan(vxlan_name, vni, local_ip, dstport):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(vxlan_name, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
# FIXME: Perhaps we need to set neigh_suppress on
|
||||
ndb.interfaces.create(
|
||||
kind="vxlan", ifname=vxlan_name, vxlan_id=int(vni),
|
||||
vxlan_port=dstport, vxlan_local=local_ip,
|
||||
vxlan_learning=False).set('state', constants.LINK_UP).commit()
|
||||
ovn_bgp_agent.privileged.linux_net.ensure_vxlan(vxlan_name, vni, local_ip,
|
||||
dstport)
|
||||
|
||||
|
||||
def ensure_veth(veth_name, veth_peer):
|
||||
try:
|
||||
set_device_status(veth_name, constants.LINK_UP)
|
||||
except KeyError:
|
||||
with pyroute2.NDB() as ndb:
|
||||
ndb.interfaces.create(
|
||||
kind="veth", ifname=veth_name, peer=veth_peer).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
set_device_status(veth_peer, constants.LINK_UP)
|
||||
ovn_bgp_agent.privileged.linux_net.ensure_veth(veth_name, veth_peer)
|
||||
|
||||
|
||||
def set_master_for_device(device, master):
|
||||
with pyroute2.NDB() as ndb:
|
||||
# Check if already associated to the master, and associate it if not
|
||||
if (ndb.interfaces[device].get('master') !=
|
||||
ndb.interfaces[master]['index']):
|
||||
with ndb.interfaces[device] as iface:
|
||||
iface.set('master', ndb.interfaces[master]['index'])
|
||||
|
||||
|
||||
def set_device_status(device, status, ndb=None):
|
||||
_ndb = ndb
|
||||
if ndb is None:
|
||||
_ndb = pyroute2.NDB()
|
||||
try:
|
||||
with _ndb.interfaces[device] as dev:
|
||||
if dev['state'] != status:
|
||||
dev['state'] = status
|
||||
finally:
|
||||
if ndb is None:
|
||||
_ndb.close()
|
||||
ovn_bgp_agent.privileged.linux_net.set_master_for_device(device, master)
|
||||
|
||||
|
||||
def ensure_dummy_device(device):
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(device, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
ndb.interfaces.create(kind="dummy", ifname=device).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
ovn_bgp_agent.privileged.linux_net.ensure_dummy_device(device)
|
||||
|
||||
|
||||
def ensure_ovn_device(ovn_ifname, vrf_name):
|
||||
|
@ -126,11 +76,12 @@ def ensure_ovn_device(ovn_ifname, vrf_name):
|
|||
|
||||
|
||||
def delete_device(device):
|
||||
try:
|
||||
with pyroute2.NDB() as ndb:
|
||||
ndb.interfaces[device].remove().commit()
|
||||
except KeyError:
|
||||
LOG.debug("Interfaces %s already deleted.", device)
|
||||
ovn_bgp_agent.privileged.linux_net.delete_device(device)
|
||||
|
||||
|
||||
def create_routing_table_for_bridge(table_number, bridge):
|
||||
with open('/etc/iproute2/rt_tables', 'a') as rt_tables:
|
||||
rt_tables.write('{} {}\n'.format(table_number, bridge))
|
||||
|
||||
|
||||
def ensure_routing_table_for_bridge(ovn_routing_tables, bridge):
|
||||
|
@ -163,9 +114,7 @@ def ensure_routing_table_for_bridge(ovn_routing_tables, bridge):
|
|||
"at /etc/iproute2/rt_tables", bridge)
|
||||
sys.exit()
|
||||
|
||||
with open('/etc/iproute2/rt_tables', 'a') as rt_tables:
|
||||
rt_tables.write('{} {}\n'.format(table_number, bridge))
|
||||
|
||||
create_routing_table_for_bridge(table_number, bridge)
|
||||
ovn_routing_tables[bridge] = int(table_number)
|
||||
LOG.debug("Added routing table for %s with number: %s", bridge,
|
||||
table_number)
|
||||
|
@ -177,16 +126,15 @@ def ensure_routing_table_for_bridge(ovn_routing_tables, bridge):
|
|||
table_route_dsts = set([r.dst for r in ndb.routes.summary().filter(
|
||||
table=ovn_routing_tables[bridge])])
|
||||
if not table_route_dsts:
|
||||
ndb.routes.create(dst='default',
|
||||
oif=ndb.interfaces[bridge]['index'],
|
||||
table=ovn_routing_tables[bridge],
|
||||
scope=253,
|
||||
proto=3).commit()
|
||||
ndb.routes.create(dst='default',
|
||||
oif=ndb.interfaces[bridge]['index'],
|
||||
table=ovn_routing_tables[bridge],
|
||||
family=AF_INET6,
|
||||
proto=3).commit()
|
||||
r1 = {'dst': 'default', 'oif': ndb.interfaces[bridge]['index'],
|
||||
'table': ovn_routing_tables[bridge], 'scope': 253,
|
||||
'proto': 3}
|
||||
ovn_bgp_agent.privileged.linux_net.route_create(r1)
|
||||
|
||||
r2 = {'dst': 'default', 'oif': ndb.interfaces[bridge]['index'],
|
||||
'table': ovn_routing_tables[bridge], 'family': AF_INET6,
|
||||
'proto': 3}
|
||||
ovn_bgp_agent.privileged.linux_net.route_create(r2)
|
||||
else:
|
||||
route_missing = True
|
||||
route6_missing = True
|
||||
|
@ -225,32 +173,21 @@ def ensure_routing_table_for_bridge(ovn_routing_tables, bridge):
|
|||
)
|
||||
|
||||
if route_missing:
|
||||
ndb.routes.create(dst='default',
|
||||
oif=ndb.interfaces[bridge]['index'],
|
||||
table=ovn_routing_tables[bridge],
|
||||
scope=253,
|
||||
proto=3).commit()
|
||||
r = {'dst': 'default', 'oif': ndb.interfaces[bridge]['index'],
|
||||
'table': ovn_routing_tables[bridge], 'scope': 253,
|
||||
'proto': 3}
|
||||
ovn_bgp_agent.privileged.linux_net.route_create(r)
|
||||
if route6_missing:
|
||||
ndb.routes.create(dst='default',
|
||||
oif=ndb.interfaces[bridge]['index'],
|
||||
table=ovn_routing_tables[bridge],
|
||||
family=AF_INET6,
|
||||
proto=3).commit()
|
||||
r = {'dst': 'default', 'oif': ndb.interfaces[bridge]['index'],
|
||||
'table': ovn_routing_tables[bridge], 'family': AF_INET6,
|
||||
'proto': 3}
|
||||
ovn_bgp_agent.privileged.linux_net.route_create(r)
|
||||
return extra_routes
|
||||
|
||||
|
||||
def ensure_vlan_device_for_network(bridge, vlan_tag):
|
||||
vlan_device_name = '{}.{}'.format(bridge, vlan_tag)
|
||||
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
set_device_status(vlan_device_name, constants.LINK_UP, ndb=ndb)
|
||||
except KeyError:
|
||||
ndb.interfaces.create(
|
||||
kind="vlan", ifname=vlan_device_name, vlan_id=vlan_tag,
|
||||
link=ndb.interfaces[bridge]['index']).set(
|
||||
'state', constants.LINK_UP).commit()
|
||||
|
||||
ovn_bgp_agent.privileged.linux_net.ensure_vlan_device_for_network(bridge,
|
||||
vlan_tag)
|
||||
device = "{}/{}".format(bridge, vlan_tag)
|
||||
enable_proxy_arp(device)
|
||||
enable_proxy_ndp(device)
|
||||
|
@ -323,35 +260,11 @@ def get_ovn_ip_rules(routing_table):
|
|||
|
||||
|
||||
def delete_exposed_ips(ips, nic):
|
||||
with pyroute2.NDB() as ndb:
|
||||
for ip in ips:
|
||||
address = '{}/32'.format(ip)
|
||||
if get_ip_version(ip) == constants.IP_VERSION_6:
|
||||
address = '{}/128'.format(ip)
|
||||
try:
|
||||
ndb.interfaces[nic].ipaddr[address].remove().commit()
|
||||
except KeyError:
|
||||
LOG.debug("IP address {} already removed from nic {}.".format(
|
||||
ip, nic))
|
||||
ovn_bgp_agent.privileged.linux_net.delete_exposed_ips(ips, nic)
|
||||
|
||||
|
||||
def delete_ip_rules(ip_rules):
|
||||
with pyroute2.NDB() as ndb:
|
||||
for rule_ip, rule_info in ip_rules.items():
|
||||
rule = {'dst': rule_ip.split("/")[0],
|
||||
'dst_len': rule_ip.split("/")[1],
|
||||
'table': rule_info['table'],
|
||||
'family': rule_info['family']}
|
||||
try:
|
||||
with ndb.rules[rule] as r:
|
||||
r.remove()
|
||||
except KeyError:
|
||||
LOG.debug("Rule {} already deleted".format(rule))
|
||||
except pyroute2.netlink.exceptions.NetlinkError:
|
||||
# FIXME: There is a issue with NDB and ip rules deletion:
|
||||
# https://github.com/svinota/pyroute2/issues/771
|
||||
LOG.debug("This should not happen, skipping: NetlinkError "
|
||||
"deleting rule %s", rule)
|
||||
ovn_bgp_agent.privileged.linux_net.delete_ip_rules(ip_rules)
|
||||
|
||||
|
||||
def delete_bridge_ip_routes(routing_tables, routing_tables_routes,
|
||||
|
@ -381,19 +294,15 @@ def delete_bridge_ip_routes(routing_tables, routing_tables_routes,
|
|||
for r in possible_matchings:
|
||||
extra_routes[bridge].remove(r)
|
||||
|
||||
for bridge, routes in extra_routes.items():
|
||||
for route in routes:
|
||||
r_info = {'dst': route['dst'],
|
||||
'dst_len': route['dst_len'],
|
||||
'family': route['family'],
|
||||
'oif': route['oif'],
|
||||
'gateway': route['gateway'],
|
||||
'table': routing_tables[bridge]}
|
||||
try:
|
||||
with ndb.routes[r_info] as r:
|
||||
r.remove()
|
||||
except KeyError:
|
||||
LOG.debug("Route already deleted: {}".format(route))
|
||||
for bridge, routes in extra_routes.items():
|
||||
for route in routes:
|
||||
r_info = {'dst': route['dst'],
|
||||
'dst_len': route['dst_len'],
|
||||
'family': route['family'],
|
||||
'oif': route['oif'],
|
||||
'gateway': route['gateway'],
|
||||
'table': routing_tables[bridge]}
|
||||
ovn_bgp_agent.privileged.linux_net.route_delete(r_info)
|
||||
|
||||
|
||||
def delete_routes_from_table(table):
|
||||
|
@ -401,12 +310,8 @@ def delete_routes_from_table(table):
|
|||
# FIXME: problem in pyroute2 removing routes with local (254) scope
|
||||
table_routes = [r for r in ndb.routes.dump().filter(table=table)
|
||||
if r.scope != 254 and r.proto != 186]
|
||||
for route in table_routes:
|
||||
try:
|
||||
with ndb.routes[route] as r:
|
||||
r.remove()
|
||||
except KeyError:
|
||||
LOG.debug("Route already deleted: %s", route)
|
||||
for route in table_routes:
|
||||
ovn_bgp_agent.privileged.linux_net.route_delete(route)
|
||||
|
||||
|
||||
def get_routes_on_tables(table_ids):
|
||||
|
@ -417,19 +322,14 @@ def get_routes_on_tables(table_ids):
|
|||
|
||||
|
||||
def delete_ip_routes(routes):
|
||||
with pyroute2.NDB() as ndb:
|
||||
for route in routes:
|
||||
r_info = {'dst': route['dst'],
|
||||
'dst_len': route['dst_len'],
|
||||
'family': route['family'],
|
||||
'oif': route['oif'],
|
||||
'gateway': route['gateway'],
|
||||
'table': route['table']}
|
||||
try:
|
||||
with ndb.routes[r_info] as r:
|
||||
r.remove()
|
||||
except KeyError:
|
||||
LOG.debug("Route already deleted: %s", route)
|
||||
for route in routes:
|
||||
r_info = {'dst': route['dst'],
|
||||
'dst_len': route['dst_len'],
|
||||
'family': route['family'],
|
||||
'oif': route['oif'],
|
||||
'gateway': route['gateway'],
|
||||
'table': route['table']}
|
||||
ovn_bgp_agent.privileged.linux_net.route_delete(r_info)
|
||||
|
||||
|
||||
def add_ndp_proxy(ip, dev, vlan=None):
|
||||
|
@ -444,12 +344,7 @@ def add_ips_to_dev(nic, ips, clear_local_route_at_table=False):
|
|||
already_added_ips = []
|
||||
for ip in ips:
|
||||
try:
|
||||
with pyroute2.NDB() as ndb:
|
||||
with ndb.interfaces[nic] as iface:
|
||||
address = '{}/32'.format(ip)
|
||||
if get_ip_version(ip) == constants.IP_VERSION_6:
|
||||
address = '{}/128'.format(ip)
|
||||
iface.add_ip(address)
|
||||
ovn_bgp_agent.privileged.linux_net.add_ip_to_dev(ip, nic)
|
||||
except KeyError:
|
||||
# NDB raises KeyError: 'object exists'
|
||||
# if the ip is already added
|
||||
|
@ -466,22 +361,12 @@ def add_ips_to_dev(nic, ips, clear_local_route_at_table=False):
|
|||
'scope': 254,
|
||||
'dst': ip,
|
||||
'oif': oif}
|
||||
try:
|
||||
LOG.debug("Deleting local route: %s", route)
|
||||
with ndb.routes[route] as r:
|
||||
r.remove()
|
||||
except (KeyError, ValueError):
|
||||
LOG.debug("Local route already deleted: %s", route)
|
||||
ovn_bgp_agent.privileged.linux_net.route_delete(route)
|
||||
|
||||
|
||||
def del_ips_from_dev(nic, ips):
|
||||
with pyroute2.NDB() as ndb:
|
||||
with ndb.interfaces[nic] as iface:
|
||||
for ip in ips:
|
||||
address = '{}/32'.format(ip)
|
||||
if get_ip_version(ip) == constants.IP_VERSION_6:
|
||||
address = '{}/128'.format(ip)
|
||||
iface.del_ip(address)
|
||||
for ip in ips:
|
||||
ovn_bgp_agent.privileged.linux_net.del_ip_from_dev(ip, nic)
|
||||
|
||||
|
||||
def add_ip_rule(ip, table, dev=None, lladdr=None):
|
||||
|
@ -500,12 +385,7 @@ def add_ip_rule(ip, table, dev=None, lladdr=None):
|
|||
else:
|
||||
raise agent_exc.InvalidPortIP(ip=ip)
|
||||
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
ndb.rules[rule]
|
||||
except KeyError:
|
||||
LOG.debug("Creating ip rule with: %s", rule)
|
||||
ndb.rules.create(rule).commit()
|
||||
ovn_bgp_agent.privileged.linux_net.rule_create(rule)
|
||||
|
||||
if lladdr:
|
||||
add_ip_nei(ip, lladdr, dev)
|
||||
|
@ -520,25 +400,7 @@ def add_ip_nei(ip, lladdr, dev):
|
|||
"""
|
||||
# FIXME: There is no support for creating neighbours in NDB
|
||||
# So we are using iproute here
|
||||
ip_version = get_ip_version(ip)
|
||||
with pyroute2.IPRoute() as iproute:
|
||||
# This is doing something like:
|
||||
# sudo ip nei replace 172.24.4.69
|
||||
# lladdr fa:16:3e:d3:5d:7b dev br-ex nud permanent
|
||||
network_bridge_if = iproute.link_lookup(ifname=dev)[0]
|
||||
if ip_version == constants.IP_VERSION_6:
|
||||
iproute.neigh('set',
|
||||
dst=ip,
|
||||
lladdr=lladdr,
|
||||
family=AF_INET6,
|
||||
ifindex=network_bridge_if,
|
||||
state=ndmsg.states['permanent'])
|
||||
else:
|
||||
iproute.neigh('set',
|
||||
dst=ip,
|
||||
lladdr=lladdr,
|
||||
ifindex=network_bridge_if,
|
||||
state=ndmsg.states['permanent'])
|
||||
ovn_bgp_agent.privileged.linux_net.add_ip_nei(ip, lladdr, dev)
|
||||
|
||||
|
||||
def del_ip_rule(ip, table, dev=None, lladdr=None):
|
||||
|
@ -557,12 +419,8 @@ def del_ip_rule(ip, table, dev=None, lladdr=None):
|
|||
else:
|
||||
LOG.error("Invalid ip: {}".format(ip))
|
||||
return
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
ndb.rules[rule].remove().commit()
|
||||
LOG.debug("Deleting ip rule with: %s", rule)
|
||||
except KeyError:
|
||||
LOG.debug("Rule already deleted: %s", rule)
|
||||
|
||||
ovn_bgp_agent.privileged.linux_net.rule_delete(rule)
|
||||
|
||||
if lladdr:
|
||||
del_ip_nei(ip, lladdr, dev)
|
||||
|
@ -577,32 +435,7 @@ def del_ip_nei(ip, lladdr, dev):
|
|||
"""
|
||||
# FIXME: There is no support for deleting neighbours in NDB
|
||||
# So we are using iproute here
|
||||
ip_version = get_ip_version(ip)
|
||||
with pyroute2.IPRoute() as iproute:
|
||||
# This is doing something like:
|
||||
# sudo ip nei del 172.24.4.69
|
||||
# lladdr fa:16:3e:d3:5d:7b dev br-ex nud permanent
|
||||
try:
|
||||
network_bridge_if = iproute.link_lookup(
|
||||
ifname=dev)[0]
|
||||
except IndexError:
|
||||
# Neigbhbor device does not exists, continuing
|
||||
LOG.debug("No need to remove nei for dev %s as it does not "
|
||||
"exists", dev)
|
||||
return
|
||||
if ip_version == constants.IP_VERSION_6:
|
||||
iproute.neigh('del',
|
||||
dst=ip.split("/")[0],
|
||||
lladdr=lladdr,
|
||||
family=AF_INET6,
|
||||
ifindex=network_bridge_if,
|
||||
state=ndmsg.states['permanent'])
|
||||
else:
|
||||
iproute.neigh('del',
|
||||
dst=ip.split("/")[0],
|
||||
lladdr=lladdr,
|
||||
ifindex=network_bridge_if,
|
||||
state=ndmsg.states['permanent'])
|
||||
ovn_bgp_agent.privileged.linux_net.del_ip_nei(ip, lladdr, dev)
|
||||
|
||||
|
||||
def add_unreachable_route(vrf_name):
|
||||
|
@ -650,7 +483,7 @@ def add_ip_route(ovn_routing_tables_routes, ip_address, route_table, dev,
|
|||
LOG.debug("Route already existing: %s", r)
|
||||
except KeyError:
|
||||
LOG.debug("Creating route at table %s: %s", route_table, route)
|
||||
ndb.routes.create(route).commit()
|
||||
ovn_bgp_agent.privileged.linux_net.route_create(route)
|
||||
LOG.debug("Route created at table %s: %s", route_table, route)
|
||||
route_info = {'vlan': vlan, 'route': route}
|
||||
ovn_routing_tables_routes.setdefault(dev, []).append(route_info)
|
||||
|
@ -696,13 +529,8 @@ def del_ip_route(ovn_routing_tables_routes, ip_address, route_table, dev,
|
|||
if get_ip_version(net_ip) == constants.IP_VERSION_6:
|
||||
route['family'] = AF_INET6
|
||||
|
||||
with pyroute2.NDB() as ndb:
|
||||
try:
|
||||
LOG.debug("Deleting route at table %s: %s", route_table, route)
|
||||
with ndb.routes[route] as r:
|
||||
r.remove()
|
||||
LOG.debug("Route deleted at table %s: %s", route_table, route)
|
||||
route_info = {'vlan': vlan, 'route': route}
|
||||
ovn_routing_tables_routes[dev].remove(route_info)
|
||||
except (KeyError, ValueError):
|
||||
LOG.debug("Route already deleted: %s", route)
|
||||
LOG.debug("Deleting route at table %s: %s", route_table, route)
|
||||
ovn_bgp_agent.privileged.linux_net.route_delete(route)
|
||||
LOG.debug("Route deleted at table %s: %s", route_table, route)
|
||||
route_info = {'vlan': vlan, 'route': route}
|
||||
ovn_routing_tables_routes[dev].remove(route_info)
|
||||
|
|
Loading…
Reference in New Issue