Merge "Handle trimming of vlan interface namings" into stable/2023.2

This commit is contained in:
Zuul
2025-02-24 21:16:24 +00:00
committed by Gerrit Code Review
5 changed files with 74 additions and 18 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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(

View File

@@ -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)

View File

@@ -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)