Merge "Handle trimming of vlan interface namings" into stable/2023.2
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
|
||||
import socket
|
||||
|
||||
from neutron_lib import constants as n_const
|
||||
|
||||
|
||||
OVN_VIF_PORT_TYPES = ("", "chassisredirect", "virtual")
|
||||
|
||||
@@ -92,6 +94,8 @@ OVN_EVPN_VETH_OVS_PREFIX = "veth-ovs-"
|
||||
OVN_INTEGRATION_BRIDGE = 'br-int'
|
||||
OVN_LRP_PORT_NAME_PREFIX = 'lrp-'
|
||||
OVN_CRLRP_PORT_NAME_PREFIX = 'cr-lrp-'
|
||||
OVN_VLAN_DEVICE_MAX_LENGTH = n_const.DEVICE_NAME_MAX_LEN - len(
|
||||
f".{n_const.MAX_VLAN_TAG}")
|
||||
|
||||
# the new prefix will get the first 11 chars of the localnet port prefixed,
|
||||
# neutron-tap style
|
||||
|
||||
@@ -105,7 +105,9 @@ def ensure_dummy_device(device):
|
||||
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def ensure_vlan_device_for_network(bridge, vlan_tag):
|
||||
vlan_device_name = '{}.{}'.format(bridge, vlan_tag)
|
||||
vlan_device_name = '{}.{}'.format(
|
||||
bridge[:constants.OVN_VLAN_DEVICE_MAX_LENGTH],
|
||||
vlan_tag)
|
||||
try:
|
||||
set_device_state(vlan_device_name, constants.LINK_UP)
|
||||
except agent_exc.NetworkInterfaceNotFound:
|
||||
@@ -124,9 +126,9 @@ def ensure_vlan_device_for_network(bridge, vlan_tag):
|
||||
@ovn_bgp_agent.privileged.default.entrypoint
|
||||
def set_master_for_device(device, master):
|
||||
try:
|
||||
dev_index = _get_link_id(ifname=device)
|
||||
master_index = _get_link_id(ifname=master)
|
||||
with pyroute2.IPRoute() as ipr:
|
||||
dev_index = ipr.link_lookup(ifname=device)[0]
|
||||
master_index = ipr.link_lookup(ifname=master)[0]
|
||||
# Check if already associated to the master,
|
||||
# and associate it if not
|
||||
iface = ipr.link('get', index=dev_index)[0]
|
||||
@@ -203,7 +205,7 @@ def add_ndp_proxy(ip, dev, vlan=None):
|
||||
net_ip = str(ipaddress.IPv6Network(ip, strict=False).network_address)
|
||||
dev_name = dev
|
||||
if vlan:
|
||||
dev_name = "{}.{}".format(dev, vlan)
|
||||
dev_name = f"{dev[:constants.OVN_VLAN_DEVICE_MAX_LENGTH]}.{vlan}"
|
||||
command = ["ip", "-6", "nei", "add", "proxy", net_ip, "dev", dev_name]
|
||||
try:
|
||||
return processutils.execute(*command)
|
||||
@@ -219,7 +221,7 @@ def del_ndp_proxy(ip, dev, vlan=None):
|
||||
net_ip = str(ipaddress.IPv6Network(ip, strict=False).network_address)
|
||||
dev_name = dev
|
||||
if vlan:
|
||||
dev_name = "{}.{}".format(dev, vlan)
|
||||
dev_name = f"{dev[:constants.OVN_VLAN_DEVICE_MAX_LENGTH]}.{vlan}"
|
||||
command = ["ip", "-6", "nei", "del", "proxy", net_ip, "dev", dev_name]
|
||||
env = dict(os.environ)
|
||||
env['LC_ALL'] = 'C'
|
||||
@@ -410,6 +412,7 @@ def make_serializable(value):
|
||||
|
||||
|
||||
def _get_link_id(ifname, raise_exception=True):
|
||||
ifname = ifname[:15]
|
||||
with iproute.IPRoute() as ip:
|
||||
link_id = ip.link_lookup(ifname=ifname)
|
||||
if not link_id or len(link_id) < 1:
|
||||
@@ -431,6 +434,7 @@ def get_link_state(device_name):
|
||||
|
||||
|
||||
def get_link_device(device_name):
|
||||
device_name = device_name[:15]
|
||||
for device in get_link_devices():
|
||||
if get_attr(device, 'IFLA_IFNAME') == device_name:
|
||||
return device
|
||||
|
||||
@@ -17,6 +17,7 @@ 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
|
||||
@@ -44,6 +45,7 @@ class TestPrivilegedLinuxNet(test_base.TestCase):
|
||||
self.ip = '10.10.1.16'
|
||||
self.ipv6 = '2002::1234:abcd:ffff:c0a8:101'
|
||||
self.dev = 'ethfake'
|
||||
self.dev_br = 'fake-provider'
|
||||
self.mac = 'aa:bb:cc:dd:ee:ff'
|
||||
|
||||
def test_set_kernel_flag(self):
|
||||
@@ -68,6 +70,13 @@ class TestPrivilegedLinuxNet(test_base.TestCase):
|
||||
'ip', '-6', 'nei', 'add', 'proxy', self.ipv6,
|
||||
'dev', '%s.10' % self.dev)
|
||||
|
||||
def test_add_trimmed_ndp_proxy_vlan(self):
|
||||
priv_linux_net.add_ndp_proxy(self.ipv6, self.dev_br, vlan=1024)
|
||||
self.mock_exc.assert_called_once_with(
|
||||
'ip', '-6', 'nei', 'add', 'proxy', self.ipv6,
|
||||
'dev', '%s.1024' %
|
||||
self.dev_br[:constants.OVN_VLAN_DEVICE_MAX_LENGTH])
|
||||
|
||||
def test_add_ndp_proxy_exception(self):
|
||||
self.mock_exc.side_effect = FakeException()
|
||||
self.assertRaises(
|
||||
@@ -86,6 +95,13 @@ class TestPrivilegedLinuxNet(test_base.TestCase):
|
||||
'ip', '-6', 'nei', 'del', 'proxy', self.ipv6, 'dev',
|
||||
'%s.10' % self.dev, env_variables=mock.ANY)
|
||||
|
||||
def test_del_trimeed_ndp_proxy_vlan(self):
|
||||
priv_linux_net.del_ndp_proxy(self.ipv6, self.dev_br, vlan=1024)
|
||||
self.mock_exc.assert_called_once_with(
|
||||
'ip', '-6', 'nei', 'del', 'proxy', self.ipv6, 'dev',
|
||||
'%s.1024' % self.dev_br[:constants.OVN_VLAN_DEVICE_MAX_LENGTH],
|
||||
env_variables=mock.ANY)
|
||||
|
||||
def test_del_ndp_proxy_exception(self):
|
||||
self.mock_exc.side_effect = FakeException()
|
||||
self.assertRaises(
|
||||
|
||||
@@ -197,12 +197,31 @@ class TestLinuxNet(test_base.TestCase):
|
||||
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(
|
||||
'ovn_bgp_agent.privileged.linux_net.ensure_vlan_device_for_network')
|
||||
def test_ensure_vlan_trimmed_device_for_network(
|
||||
self, mock_ensure_vlan_device_for_network, mock_ndp, mock_arp):
|
||||
linux_net.ensure_vlan_device_for_network('fake-provider', 1020)
|
||||
mock_ensure_vlan_device_for_network.assert_called_once_with(
|
||||
'fake-provider', 1020)
|
||||
expected_dev = 'fake-provi/1020'
|
||||
mock_ndp.assert_called_once_with(expected_dev)
|
||||
mock_arp.assert_called_once_with(expected_dev)
|
||||
|
||||
@mock.patch.object(linux_net, 'delete_device')
|
||||
def test_delete_vlan_device_for_network(self, mock_del):
|
||||
linux_net.delete_vlan_device_for_network('fake-br', 10)
|
||||
vlan_name = 'fake-br.10'
|
||||
mock_del.assert_called_once_with(vlan_name)
|
||||
|
||||
@mock.patch.object(linux_net, 'delete_device')
|
||||
def test_delete_vlan_trimmed_device_for_network(self, mock_del):
|
||||
linux_net.delete_vlan_device_for_network('fake-provider', 1020)
|
||||
vlan_name = 'fake-provi.1020'
|
||||
mock_del.assert_called_once_with(vlan_name)
|
||||
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.set_kernel_flag')
|
||||
def test_enable_proxy_ndp(self, mock_flag):
|
||||
linux_net.enable_proxy_ndp(self.dev)
|
||||
@@ -357,10 +376,12 @@ class TestLinuxNet(test_base.TestCase):
|
||||
|
||||
@mock.patch.object(linux_net, 'get_interface_index')
|
||||
def _test_delete_bridge_ip_routes(self, mock_route_delete, mock_get_index,
|
||||
is_vlan=False, has_gateway=False):
|
||||
is_vlan=False, has_gateway=False,
|
||||
trimmed_bridge=False):
|
||||
gateway = '1.1.1.1'
|
||||
oif = 11
|
||||
vlan = 30 if is_vlan else None
|
||||
bridge = 'br-provider' if trimmed_bridge else self.bridge
|
||||
vlan = 2030 if is_vlan else None
|
||||
mock_get_index.return_value = oif
|
||||
|
||||
route = {'route': {'dst': self.ip,
|
||||
@@ -370,8 +391,8 @@ class TestLinuxNet(test_base.TestCase):
|
||||
if has_gateway:
|
||||
route['route']['gateway'] = gateway
|
||||
|
||||
routing_tables = {self.bridge: 20}
|
||||
routing_tables_routes = {self.bridge: [route]}
|
||||
routing_tables = {bridge: 20}
|
||||
routing_tables_routes = {bridge: [route]}
|
||||
# extra_route0 matches with the route
|
||||
extra_route0 = IPRouteDict({
|
||||
'dst_len': 32, 'family': constants.AF_INET, 'table': 20,
|
||||
@@ -384,7 +405,7 @@ class TestLinuxNet(test_base.TestCase):
|
||||
'attrs': [('RTA_DST', '10.10.1.17'),
|
||||
('RTA_OIF', oif),
|
||||
('RTA_GATEWAY', gateway)]})
|
||||
extra_routes = {self.bridge: [extra_route0, extra_route1]}
|
||||
extra_routes = {bridge: [extra_route0, extra_route1]}
|
||||
|
||||
linux_net.delete_bridge_ip_routes(
|
||||
routing_tables, routing_tables_routes, extra_routes)
|
||||
@@ -404,6 +425,12 @@ class TestLinuxNet(test_base.TestCase):
|
||||
def test_delete_bridge_ip_routes_vlan(self, mock_route_delete):
|
||||
self._test_delete_bridge_ip_routes(mock_route_delete, is_vlan=True)
|
||||
|
||||
@mock.patch('ovn_bgp_agent.privileged.linux_net.route_delete')
|
||||
def test_delete_trimmed_bridge_ip_routes_vlan(self, mock_route_delete):
|
||||
self._test_delete_bridge_ip_routes(mock_route_delete,
|
||||
is_vlan=True,
|
||||
trimmed_bridge=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)
|
||||
|
||||
@@ -403,13 +403,15 @@ def get_extra_routing_table_for_bridge(ovn_routing_tables, bridge):
|
||||
def ensure_vlan_device_for_network(bridge, vlan_tag):
|
||||
ovn_bgp_agent.privileged.linux_net.ensure_vlan_device_for_network(bridge,
|
||||
vlan_tag)
|
||||
device = "{}/{}".format(bridge, vlan_tag)
|
||||
device = "{}/{}".format(
|
||||
bridge[:constants.OVN_VLAN_DEVICE_MAX_LENGTH], vlan_tag)
|
||||
enable_proxy_arp(device)
|
||||
enable_proxy_ndp(device)
|
||||
|
||||
|
||||
def delete_vlan_device_for_network(bridge, vlan_tag):
|
||||
vlan_device_name = '{}.{}'.format(bridge, vlan_tag)
|
||||
vlan_device_name = '{}.{}'.format(
|
||||
bridge[:constants.OVN_VLAN_DEVICE_MAX_LENGTH], vlan_tag)
|
||||
delete_device(vlan_device_name)
|
||||
|
||||
|
||||
@@ -418,12 +420,12 @@ def get_bridge_vlans(bridge):
|
||||
|
||||
|
||||
def enable_proxy_ndp(device):
|
||||
flag = "net.ipv6.conf.{}.proxy_ndp".format(device)
|
||||
flag = "net.ipv6.conf.{}.proxy_ndp".format(device[:15])
|
||||
ovn_bgp_agent.privileged.linux_net.set_kernel_flag(flag, 1)
|
||||
|
||||
|
||||
def enable_proxy_arp(device):
|
||||
flag = "net.ipv4.conf.{}.proxy_arp".format(device)
|
||||
flag = "net.ipv4.conf.{}.proxy_arp".format(device[:15])
|
||||
ovn_bgp_agent.privileged.linux_net.set_kernel_flag(flag, 1)
|
||||
|
||||
|
||||
@@ -550,8 +552,9 @@ def delete_bridge_ip_routes(routing_tables, routing_tables_routes,
|
||||
for route_info in routes_info:
|
||||
oif = get_interface_index(device)
|
||||
if route_info['vlan']:
|
||||
vlan_device_name = '{}.{}'.format(device,
|
||||
route_info['vlan'])
|
||||
vlan_device_name = '{}.{}'.format(
|
||||
device[:constants.OVN_VLAN_DEVICE_MAX_LENGTH],
|
||||
route_info['vlan'])
|
||||
oif = get_interface_index(vlan_device_name)
|
||||
if 'gateway' in route_info['route'].keys(): # subnet route
|
||||
possible_matchings = [
|
||||
@@ -745,7 +748,8 @@ def add_ip_route(ovn_routing_tables_routes, ip_address, route_table, dev,
|
||||
ip, strict=False).network_address)
|
||||
|
||||
if vlan:
|
||||
oif_name = '{}.{}'.format(dev, vlan)
|
||||
oif_name = '{}.{}'.format(
|
||||
dev[:constants.OVN_VLAN_DEVICE_MAX_LENGTH], vlan)
|
||||
try:
|
||||
oif = get_interface_index(oif_name)
|
||||
except agent_exc.NetworkInterfaceNotFound:
|
||||
@@ -799,7 +803,8 @@ def del_ip_route(ovn_routing_tables_routes, ip_address, route_table, dev,
|
||||
|
||||
try:
|
||||
if vlan:
|
||||
oif_name = '{}.{}'.format(dev, vlan)
|
||||
oif_name = '{}.{}'.format(
|
||||
dev[:constants.OVN_VLAN_DEVICE_MAX_LENGTH], vlan)
|
||||
oif = get_interface_index(oif_name)
|
||||
else:
|
||||
oif = get_interface_index(dev)
|
||||
|
||||
Reference in New Issue
Block a user