Add support at NB BGP Driver for exposing tenant IPs

Change-Id: Id4df869fdeb7a6b23aee74f4952466851cbc3b4b
This commit is contained in:
Luis Tomas Bolivar 2023-10-26 16:23:36 +02:00
parent c63be7c85c
commit aaa0ae0c1a
8 changed files with 615 additions and 28 deletions

View File

@ -151,7 +151,9 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
events.update(["ChassisRedirectCreateEvent",
"ChassisRedirectDeleteEvent",
"LogicalSwitchPortSubnetAttachEvent",
"LogicalSwitchPortSubnetDetachEvent"])
"LogicalSwitchPortSubnetDetachEvent",
"LogicalSwitchPortTenantCreateEvent",
"LogicalSwitchPortTenantDeleteEvent"])
return events
@lockutils.synchronized('nbbgp')
@ -187,6 +189,8 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
subnet_info = {
'associated_router': port.external_ids.get(
constants.OVN_DEVICE_ID_EXT_ID_KEY),
'network': port.external_ids.get(
constants.OVN_LS_NAME_EXT_ID_KEY),
'address_scopes': driver_utils.get_addr_scopes(port)}
self._expose_subnet(ips, subnet_info)
@ -385,6 +389,8 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
subnet_info = {
'associated_router': port.external_ids.get(
constants.OVN_DEVICE_ID_EXT_ID_KEY),
'network': port.external_ids.get(
constants.OVN_LS_NAME_EXT_ID_KEY),
'address_scopes': driver_utils.get_addr_scopes(port)}
self._expose_subnet(ips, subnet_info)
else:
@ -442,6 +448,8 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
subnet_info = {
'associated_router': port.external_ids.get(
constants.OVN_DEVICE_ID_EXT_ID_KEY),
'network': port.external_ids.get(
constants.OVN_LS_NAME_EXT_ID_KEY),
'address_scopes': driver_utils.get_addr_scopes(port)}
self._withdraw_subnet(ips, subnet_info)
try:
@ -545,12 +553,50 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
LOG.debug("Deleted BGP route for FIP with ip %s", ip)
@lockutils.synchronized('nbbgp')
def expose_remote_ip(self, ips, row):
pass
def expose_remote_ip(self, ips, ips_info):
self._expose_remote_ip(ips, ips_info)
def _expose_remote_ip(self, ips, ips_info):
ips_to_expose = ips
if not CONF.expose_tenant_networks:
# This means CONF.expose_ipv6_gua_tenant_networks is enabled
gua_ips = [ip for ip in ips if driver_utils.is_ipv6_gua(ip)]
if not gua_ips:
return
ips_to_expose = gua_ips
LOG.debug("Adding BGP route for tenant IP(s) %s on chassis %s",
ips_to_expose, self.chassis)
bgp_utils.announce_ips(ips_to_expose)
for ip in ips_to_expose:
self._exposed_ips.setdefault(
ips_info['logical_switch'], {}).update({ip: {}})
LOG.debug("Added BGP route for tenant IP(s) %s on chassis %s",
ips_to_expose, self.chassis)
@lockutils.synchronized('nbbgp')
def withdraw_remote_ip(self, ips, row, chassis=None):
pass
def withdraw_remote_ip(self, ips, ips_info):
self._withdraw_remote_ip(ips, ips_info)
def _withdraw_remote_ip(self, ips, ips_info):
ips_to_withdraw = ips
if not CONF.expose_tenant_networks:
# This means CONF.expose_ipv6_gua_tenant_networks is enabled
gua_ips = [ip for ip in ips if driver_utils.is_ipv6_gua(ip)]
if not gua_ips:
return
ips_to_withdraw = gua_ips
LOG.debug("Deleting BGP route for tenant IP(s) %s on chassis %s",
ips_to_withdraw, self.chassis)
bgp_utils.withdraw_ips(ips_to_withdraw)
for ip in ips_to_withdraw:
if self._exposed_ips.get(
ips_info['logical_switch'], {}).get(ip):
self._exposed_ips[
ips_info['logical_switch']].pop(ip)
LOG.debug("Deleted BGP route for tenant IP(s) %s on chassis %s",
ips_to_withdraw, self.chassis)
@lockutils.synchronized('nbbgp')
def expose_subnet(self, ips, subnet_info):
@ -577,6 +623,20 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
"and they have not been properly exposed", ips)
return
ports = self.nb_idl.get_active_lsp(subnet_info['network'])
for port in ports:
ips = port.addresses[0].split(' ')[1:]
mac = port.addresses[0].strip().split(' ')[0]
ips_info = {
'mac': mac,
'cidrs': port.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
"").split(),
'type': port.type,
'logical_switch': port.external_ids.get(
constants.OVN_LS_NAME_EXT_ID_KEY)
}
self._expose_remote_ip(ips, ips_info)
def _withdraw_subnet(self, ips, subnet_info):
gateway_router = subnet_info['associated_router']
if not gateway_router:
@ -593,6 +653,19 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
return
self._withdraw_router_lsp(ips, subnet_info, cr_lrp_info)
ports = self.nb_idl.get_active_lsp(subnet_info['network'])
for port in ports:
ips = port.addresses[0].split(' ')[1:]
mac = port.addresses[0].strip().split(' ')[0]
ips_info = {
'mac': mac,
'cidrs': port.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
"").split(),
'type': port.type,
'logical_switch': port.external_ids.get(
constants.OVN_LS_NAME_EXT_ID_KEY)
}
self._withdraw_remote_ip(ips, ips_info)
def _expose_router_lsp(self, ips, subnet_info, cr_lrp_info):
if not self._expose_tenant_networks:
@ -617,6 +690,10 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
{ip: {
'bridge_device': cr_lrp_info.get('bridge_device'),
'bridge_vlan': cr_lrp_info.get('bridge_vlan')}})
if self.ovn_local_lrps.get(subnet_info['network']):
self.ovn_local_lrps[subnet_info['network']].append(ip)
else:
self.ovn_local_lrps[subnet_info['network']] = [ip]
else:
success = False
@ -653,6 +730,11 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
LOG.exception("Unexpected exception while unwiring subnet "
"CIDRs %s: %s", ip, e)
return False
try:
del self.ovn_local_lrps[subnet_info['network']]
except KeyError:
# Router port for subnet already cleanup
pass
return True
def _address_scope_allowed(self, ip, address_scopes):

View File

@ -440,16 +440,33 @@ class OvsdbNbOvnIdl(nb_impl_idl.OvnNbApiIdlImpl, Backend):
def get_active_local_lrps(self, local_gateway_ports):
ports = []
cmd = self.db_find_rows('Logical_Switch_Port', ('up', '=', True),
('type', '=', constants.OVN_ROUTER_PORT_TYPE))
cmd = self.db_find_rows(
'Logical_Switch_Port', ('up', '=', True),
('type', '=', constants.OVN_ROUTER_PORT_TYPE),
('external_ids', '=', {constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
constants.OVN_ROUTER_INTERFACE}))
for row in cmd.execute(check_error=True):
if ((row.external_ids.get(constants.OVN_DEVICE_OWNER_EXT_ID_KEY) ==
constants.OVN_ROUTER_INTERFACE) and
(row.external_ids.get(constants.OVN_DEVICE_ID_EXT_ID_KEY)
in local_gateway_ports)):
if (row.external_ids.get(constants.OVN_DEVICE_ID_EXT_ID_KEY)
in local_gateway_ports):
ports.append(row)
return ports
def get_active_lsp(self, network):
ports = []
# port type ""
cmd = self.db_find_rows(
'Logical_Switch_Port', ('up', '=', True),
('type', '=', constants.OVN_VM_VIF_PORT_TYPE),
('external_ids', '=', {constants.OVN_LS_NAME_EXT_ID_KEY: network}))
ports.extend(cmd.execute(check_error=True))
# port type "virtual"
cmd = self.db_find_rows(
'Logical_Switch_Port', ('up', '=', True),
('type', '=', constants.OVN_VIRTUAL_VIF_PORT_TYPE),
('external_ids', '=', {constants.OVN_LS_NAME_EXT_ID_KEY: network}))
ports.extend(cmd.execute(check_error=True))
return ports
# FIXME(ltomasbo): This can be removed once ovsdbapp version is >=2.3.0
def ls_get_localnet_ports(self, logical_switch, if_exists=True):
return LSGetLocalnetPortsCommand(self, logical_switch,

View File

@ -73,6 +73,12 @@ class LSPChassisEvent(Event):
constants.OVN_CHASSIS_AT_OPTIONS)
return None, None
def _get_network(self, row):
if (hasattr(row, 'external_ids') and
row.external_ids.get(constants.OVN_LS_NAME_EXT_ID_KEY)):
return row.external_ids[constants.OVN_LS_NAME_EXT_ID_KEY]
return None
class LRPChassisEvent(Event):
def __init__(self, bgp_agent, events):
@ -81,3 +87,9 @@ class LRPChassisEvent(Event):
super(LRPChassisEvent, self).__init__(
events, table, None)
self.event_name = self.__class__.__name__
def _get_network(self, row):
if (hasattr(row, 'external_ids') and
row.external_ids.get(constants.OVN_LS_NAME_EXT_ID_KEY)):
return row.external_ids[constants.OVN_LS_NAME_EXT_ID_KEY]
return None

View File

@ -60,6 +60,7 @@ class LogicalSwitchPortProviderCreateEvent(base_watcher.LSPChassisEvent):
return True
except (IndexError, AttributeError):
return False
return False
def _run(self, event, row, old):
if row.type not in [constants.OVN_VM_VIF_PORT_TYPE,
@ -73,8 +74,7 @@ class LogicalSwitchPortProviderCreateEvent(base_watcher.LSPChassisEvent):
'cidrs': row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
"").split(),
'type': row.type,
'logical_switch': row.external_ids.get(
constants.OVN_LS_NAME_EXT_ID_KEY)
'logical_switch': self._get_network(row)
}
self.agent.expose_ip(ips, ips_info)
@ -93,7 +93,8 @@ class LogicalSwitchPortProviderDeleteEvent(base_watcher.LSPChassisEvent):
current_chassis, chassis_location = self._get_chassis(row)
if event == self.ROW_DELETE:
return current_chassis == self.agent.chassis and row.up
return (current_chassis == self.agent.chassis and
bool(row.up[0]))
# ROW_UPDATE EVENT
if hasattr(old, 'up'):
@ -127,6 +128,7 @@ class LogicalSwitchPortProviderDeleteEvent(base_watcher.LSPChassisEvent):
return True
except (IndexError, AttributeError):
return False
return False
def _run(self, event, row, old):
if row.type not in [constants.OVN_VM_VIF_PORT_TYPE,
@ -339,8 +341,7 @@ class ChassisRedirectCreateEvent(base_watcher.LRPChassisEvent):
'mac': row.mac,
'cidrs': row.networks,
'type': constants.OVN_CR_LRP_PORT_TYPE,
'logical_switch': row.external_ids.get(
constants.OVN_LS_NAME_EXT_ID_KEY),
'logical_switch': self._get_network(row),
'router': row.external_ids.get(
constants.OVN_LR_NAME_EXT_ID_KEY)
}
@ -379,8 +380,7 @@ class ChassisRedirectDeleteEvent(base_watcher.LRPChassisEvent):
'mac': row.mac,
'cidrs': row.networks,
'type': constants.OVN_CR_LRP_PORT_TYPE,
'logical_switch': row.external_ids.get(
constants.OVN_LS_NAME_EXT_ID_KEY),
'logical_switch': self._get_network(row),
'router': row.external_ids.get(
constants.OVN_LR_NAME_EXT_ID_KEY)
}
@ -434,6 +434,7 @@ class LogicalSwitchPortSubnetAttachEvent(base_watcher.LSPChassisEvent):
subnet_info = {
'associated_router': row.external_ids.get(
constants.OVN_DEVICE_ID_EXT_ID_KEY),
'network': self._get_network(row),
'address_scopes': driver_utils.get_addr_scopes(row)}
self.agent.expose_subnet(ips, subnet_info)
@ -508,6 +509,7 @@ class LogicalSwitchPortSubnetDetachEvent(base_watcher.LSPChassisEvent):
subnet_info = {
'associated_router': row.external_ids.get(
constants.OVN_DEVICE_ID_EXT_ID_KEY),
'network': self._get_network(row),
'address_scopes': driver_utils.get_addr_scopes(row)}
else:
associated_router = row.external_ids.get(
@ -519,6 +521,98 @@ class LogicalSwitchPortSubnetDetachEvent(base_watcher.LSPChassisEvent):
associated_router = previous_associated_router
subnet_info = {
'associated_router': associated_router,
'network': self._get_network(row),
'address_scopes': driver_utils.get_addr_scopes(row)}
self.agent.withdraw_subnet(ips, subnet_info)
class LogicalSwitchPortTenantCreateEvent(base_watcher.LSPChassisEvent):
def __init__(self, bgp_agent):
events = (self.ROW_UPDATE,)
super(LogicalSwitchPortTenantCreateEvent, self).__init__(
bgp_agent, events)
def match_fn(self, event, row, old):
try:
# single and dual-stack format
if not self._check_ip_associated(row.addresses[0]):
return False
if not bool(row.up[0]):
return False
current_network = self._get_network(row)
if current_network not in self.agent.ovn_local_lrps:
return False
if hasattr(old, 'up'):
if not bool(old.up[0]):
return True
if hasattr(old, 'external_ids'):
old_network = self._get_network(old)
if old_network != current_network:
return True
except (IndexError, AttributeError):
return False
return False
def _run(self, event, row, old):
if row.type not in [constants.OVN_VM_VIF_PORT_TYPE,
constants.OVN_VIRTUAL_VIF_PORT_TYPE]:
return
with _SYNC_STATE_LOCK.read_lock():
ips = row.addresses[0].split(' ')[1:]
mac = row.addresses[0].strip().split(' ')[0]
ips_info = {
'mac': mac,
'cidrs': row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
"").split(),
'type': row.type,
'logical_switch': self._get_network(row)
}
self.agent.expose_remote_ip(ips, ips_info)
class LogicalSwitchPortTenantDeleteEvent(base_watcher.LSPChassisEvent):
def __init__(self, bgp_agent):
events = (self.ROW_UPDATE, self.ROW_DELETE,)
super(LogicalSwitchPortTenantDeleteEvent, self).__init__(
bgp_agent, events)
def match_fn(self, event, row, old):
try:
# single and dual-stack format
if not self._check_ip_associated(row.addresses[0]):
return False
current_network = self._get_network(row)
# Assuming the current_network cannot be changed at once
if current_network not in self.agent.ovn_local_lrps:
return False
if event == self.ROW_DELETE:
return bool(row.up[0])
# ROW UPDATE EVENT
if hasattr(old, 'up'):
return bool(old.up[0])
except (IndexError, AttributeError):
return False
return False
def _run(self, event, row, old):
if row.type not in [constants.OVN_VM_VIF_PORT_TYPE,
constants.OVN_VIRTUAL_VIF_PORT_TYPE]:
return
with _SYNC_STATE_LOCK.read_lock():
ips = row.addresses[0].split(' ')[1:]
mac = row.addresses[0].strip().split(' ')[0]
ips_info = {
'mac': mac,
'cidrs': row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
"").split(),
'type': row.type,
'logical_switch': self._get_network(row)
}
self.agent.withdraw_remote_ip(ips, ips_info)

View File

@ -27,8 +27,10 @@ from ovn_bgp_agent.drivers.openstack.utils import ovs
from ovn_bgp_agent.drivers.openstack.utils import wire as wire_utils
from ovn_bgp_agent.tests import base as test_base
from ovn_bgp_agent.tests.unit import fakes
from ovn_bgp_agent.tests import utils
from ovn_bgp_agent.utils import linux_net
CONF = cfg.CONF
@ -155,6 +157,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
'name': 'lrp_port',
'external_ids': {
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'fake-router'}})
port0 = fakes.create_object({
'name': 'port-0',
@ -205,6 +208,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
mock_expose_subnet.assert_called_once_with(
["10.0.0.1/24"],
{'associated_router': 'fake-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}})
mock_ensure_lsp_exposed.assert_called_once_with(port0)
mock_del_exposed_ips.assert_called_once_with(
@ -443,6 +447,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
'name': 'lrp_port',
'external_ids': {
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'}})
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
@ -473,6 +478,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips_info['type'] == constants.OVN_CR_LRP_PORT_TYPE):
mock_expose_subnet.assert_called_once_with(
["10.0.0.1/24"], {'associated_router': 'router1',
'network': 'network1',
'address_scopes': {4: None, 6: None}})
def test_expose_ip(self):
@ -540,6 +546,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
'name': 'lrp_port',
'external_ids': {
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'}})
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
@ -569,6 +576,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
if ips_info.get('router'):
mock_withdraw_subnet.assert_called_once_with(
["10.0.0.1/24"], {'associated_router': 'router1',
'network': 'network1',
'address_scopes': {4: None, 6: None}})
def test_withdraw_ip(self):
@ -759,22 +767,117 @@ class TestNBOVNBGPDriver(test_base.TestCase):
self.nb_bgp_driver.withdraw_fip(ip, row)
mock_withdraw_provider_port.assert_not_called()
@mock.patch.object(bgp_utils, 'announce_ips')
def test_expose_remote_ip(self, m_announce_ips):
ips = [self.ipv4, self.ipv6]
ips_info = {
'mac': 'fake-mac',
'cidrs': [],
'type': constants.OVN_VM_VIF_PORT_TYPE,
'logical_switch': 'test-ls'
}
self.nb_bgp_driver.expose_remote_ip(ips, ips_info)
m_announce_ips.assert_called_once_with(ips)
@mock.patch.object(driver_utils, 'is_ipv6_gua')
@mock.patch.object(bgp_utils, 'announce_ips')
def test_expose_remote_ip_gua(self, m_announce_ips, m_gua):
CONF.set_override('expose_tenant_networks', False)
self.addCleanup(CONF.clear_override, 'expose_tenant_networks')
CONF.set_override('expose_ipv6_gua_tenant_networks', True)
self.addCleanup(CONF.clear_override, 'expose_ipv6_gua_tenant_networks')
ips = [self.ipv4, self.ipv6]
ips_info = {
'mac': 'fake-mac',
'cidrs': [],
'type': constants.OVN_VM_VIF_PORT_TYPE,
'logical_switch': 'test-ls'
}
m_gua.side_effect = [False, True]
self.nb_bgp_driver.expose_remote_ip(ips, ips_info)
m_announce_ips.assert_called_once_with([self.ipv6])
@mock.patch.object(bgp_utils, 'withdraw_ips')
def test_withdraw_remote_ip(self, m_withdraw_ips):
ips = [self.ipv4, self.ipv6]
ips_info = {
'mac': 'fake-mac',
'cidrs': [],
'type': constants.OVN_VM_VIF_PORT_TYPE,
'logical_switch': 'test-ls'
}
self.nb_bgp_driver.withdraw_remote_ip(ips, ips_info)
m_withdraw_ips.assert_called_once_with(ips)
@mock.patch.object(driver_utils, 'is_ipv6_gua')
@mock.patch.object(bgp_utils, 'withdraw_ips')
def test_withdraw_remote_ip_gua(self, m_withdraw_ips, m_gua):
CONF.set_override('expose_tenant_networks', False)
self.addCleanup(CONF.clear_override, 'expose_tenant_networks')
CONF.set_override('expose_ipv6_gua_tenant_networks', True)
self.addCleanup(CONF.clear_override, 'expose_ipv6_gua_tenant_networks')
ips = [self.ipv4, self.ipv6]
ips_info = {
'mac': 'fake-mac',
'cidrs': [],
'type': constants.OVN_VM_VIF_PORT_TYPE,
'logical_switch': 'test-ls'
}
m_gua.side_effect = [False, True]
self.nb_bgp_driver.withdraw_remote_ip(ips, ips_info)
m_withdraw_ips.assert_called_once_with([self.ipv6])
def test_expose_subnet(self):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'router1',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_expose_router_lsp = mock.patch.object(
self.nb_bgp_driver, '_expose_router_lsp').start()
mock_expose_remote_ip = mock.patch.object(
self.nb_bgp_driver, '_expose_remote_ip').start()
port0 = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 192.168.0.5'],
external_ids={
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.0.5/24",
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1'
})
port1 = utils.create_row(
type=constants.OVN_VIRTUAL_VIF_PORT_TYPE,
addresses=['mac 192.168.0.6'],
external_ids={
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.0.6/24",
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1'
})
self.nb_idl.get_active_lsp.return_value = [port0, port1]
self.nb_bgp_driver.expose_subnet(ips, subnet_info)
mock_expose_router_lsp.assert_called_once_with(
ips, subnet_info, self.router1_info)
ips_info0 = {'mac': 'mac',
'cidrs': ['192.168.0.5/24'],
'type': constants.OVN_VM_VIF_PORT_TYPE,
'logical_switch': 'network1'}
ips_info1 = {'mac': 'mac',
'cidrs': ['192.168.0.6/24'],
'type': constants.OVN_VIRTUAL_VIF_PORT_TYPE,
'logical_switch': 'network1'}
expected_calls = [mock.call(['192.168.0.5'], ips_info0),
mock.call(['192.168.0.6'], ips_info1)]
mock_expose_remote_ip.assert_has_calls(expected_calls)
def test_expose_subnet_no_router(self):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': None,
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_expose_router_lsp = mock.patch.object(
self.nb_bgp_driver, '_expose_router_lsp').start()
@ -786,6 +889,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_expose_router_lsp = mock.patch.object(
self.nb_bgp_driver, '_expose_router_lsp').start()
@ -797,18 +901,49 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'router1',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_withdraw_router_lsp = mock.patch.object(
self.nb_bgp_driver, '_withdraw_router_lsp').start()
mock_withdraw_remote_ip = mock.patch.object(
self.nb_bgp_driver, '_withdraw_remote_ip').start()
port0 = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 192.168.0.5'],
external_ids={
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.0.5/24",
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1'
})
port1 = utils.create_row(
type=constants.OVN_VIRTUAL_VIF_PORT_TYPE,
addresses=['mac 192.168.0.6'],
external_ids={
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.0.6/24",
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1'
})
self.nb_idl.get_active_lsp.return_value = [port0, port1]
self.nb_bgp_driver.withdraw_subnet(ips, subnet_info)
mock_withdraw_router_lsp.assert_called_once_with(
ips, subnet_info, self.router1_info)
ips_info0 = {'mac': 'mac',
'cidrs': ['192.168.0.5/24'],
'type': constants.OVN_VM_VIF_PORT_TYPE,
'logical_switch': 'network1'}
ips_info1 = {'mac': 'mac',
'cidrs': ['192.168.0.6/24'],
'type': constants.OVN_VIRTUAL_VIF_PORT_TYPE,
'logical_switch': 'network1'}
expected_calls = [mock.call(['192.168.0.5'], ips_info0),
mock.call(['192.168.0.6'], ips_info1)]
mock_withdraw_remote_ip.assert_has_calls(expected_calls)
def test_withdraw_subnet_no_router(self):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': None,
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_withdraw_router_lsp = mock.patch.object(
self.nb_bgp_driver, '_withdraw_router_lsp').start()
@ -820,6 +955,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_withdraw_router_lsp = mock.patch.object(
self.nb_bgp_driver, '_withdraw_router_lsp').start()
@ -832,6 +968,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
ret = self.nb_bgp_driver._expose_router_lsp(ips, subnet_info,
@ -848,6 +985,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_wire.side_effect = Exception
@ -867,6 +1005,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
ret = self.nb_bgp_driver._expose_router_lsp(ips, subnet_info,
@ -886,6 +1025,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24', '2002::1/64']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_gua.side_effect = [False, True]
@ -903,6 +1043,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
ret = self.nb_bgp_driver._withdraw_router_lsp(ips, subnet_info,
@ -919,6 +1060,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_unwire.side_effect = Exception
@ -938,6 +1080,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
ret = self.nb_bgp_driver._withdraw_router_lsp(ips, subnet_info,
@ -958,6 +1101,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
ips = ['10.0.0.1/24', '2002::1/64']
subnet_info = {
'associated_router': 'other-router',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
mock_gua.side_effect = [False, True]

View File

@ -159,11 +159,6 @@ class TestOvsdbNbOvnIdl(test_base.TestCase):
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'
}})
row2 = fakes.create_object({
'external_ids': {
constants.OVN_DEVICE_OWNER_EXT_ID_KEY: 'other_device_owner',
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'
}})
row3 = fakes.create_object({
'external_ids': {
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
constants.OVN_ROUTER_INTERFACE,
@ -171,13 +166,42 @@ class TestOvsdbNbOvnIdl(test_base.TestCase):
}})
self.nb_idl.db_find_rows.return_value.execute.return_value = [
row1, row2, row3]
row1, row2]
ret = self.nb_idl.get_active_local_lrps(local_gateway_ports)
self.assertEqual([row1], ret)
self.nb_idl.db_find_rows.assert_called_once_with(
'Logical_Switch_Port',
('up', '=', True), ('type', '=', constants.OVN_ROUTER_PORT_TYPE))
('up', '=', True), ('type', '=', constants.OVN_ROUTER_PORT_TYPE),
('external_ids', '=', {constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
constants.OVN_ROUTER_INTERFACE}))
def test_get_active_lsp(self):
row1 = fakes.create_object({
'type': constants.OVN_VM_VIF_PORT_TYPE,
'external_ids': {constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'}})
row2 = fakes.create_object({
'type': constants.OVN_VIRTUAL_VIF_PORT_TYPE,
'external_ids': {constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'}})
self.nb_idl.db_find_rows.return_value.execute.side_effect = [
[row1], [row2]]
ret = self.nb_idl.get_active_lsp('net1')
self.assertEqual([row1, row2], ret)
expected_calls = [
mock.call('Logical_Switch_Port', ('up', '=', True),
('type', '=', constants.OVN_VM_VIF_PORT_TYPE),
('external_ids', '=',
{constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'})),
mock.call().execute(check_error=True),
mock.call('Logical_Switch_Port', ('up', '=', True),
('type', '=', constants.OVN_VIRTUAL_VIF_PORT_TYPE),
('external_ids', '=',
{constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'})),
mock.call().execute(check_error=True)]
self.nb_idl.db_find_rows.assert_has_calls(expected_calls)
class TestOvsdbSbOvnIdl(test_base.TestCase):

View File

@ -15,8 +15,10 @@
from unittest import mock
from ovn_bgp_agent import constants
from ovn_bgp_agent.drivers.openstack.watchers import base_watcher
from ovn_bgp_agent.tests import base as test_base
from ovn_bgp_agent.tests import utils
class FakePortBindingChassisEvent(base_watcher.PortBindingChassisEvent):
@ -63,3 +65,30 @@ class TestLSPChassisEvent(test_base.TestCase):
'aa:bb:cc:dd:ee:ff'))
self.assertTrue(self.lsp_event._check_ip_associated(
'aa:bb:cc:dd:ee:ff 10.10.1.16 10.10.1.17 10.10.1.18'))
def test__get_network(self):
row = utils.create_row(
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'test-net'})
self.assertEqual('test-net', self.lsp_event._get_network(row))
row = utils.create_row(external_ids={})
self.assertEqual(None, self.lsp_event._get_network(row))
class FakeLRPChassisEvent(base_watcher.LRPChassisEvent):
def run(self):
pass
class TestLRPChassisEvent(test_base.TestCase):
def setUp(self):
super(TestLRPChassisEvent, self).setUp()
self.lrp_event = FakeLRPChassisEvent(
mock.Mock(), [mock.Mock()])
def test__get_network(self):
row = utils.create_row(
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'test-net'})
self.assertEqual('test-net', self.lrp_event._get_network(row))
row = utils.create_row(external_ids={})
self.assertEqual(None, self.lrp_event._get_network(row))

View File

@ -734,19 +734,21 @@ class TestLogicalSwitchPortSubnetAttachEvent(test_base.TestCase):
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
'network:router_interface',
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
up=[True])
subnet_info = {
'associated_router': 'router1',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
self.event.run(None, row, None)
self.agent.expose_subnet.assert_called_once_with(["192.168.24.1/24"],
subnet_info)
class TestLogicalSwitchPortSubnetDetachEventt(test_base.TestCase):
class TestLogicalSwitchPortSubnetDetachEvent(test_base.TestCase):
def setUp(self):
super(TestLogicalSwitchPortSubnetDetachEventt, self).setUp()
super(TestLogicalSwitchPortSubnetDetachEvent, self).setUp()
self.chassis = 'fake-chassis'
self.chassis_id = 'fake-chassis-id'
self.agent = mock.Mock(chassis=self.chassis,
@ -864,6 +866,7 @@ class TestLogicalSwitchPortSubnetDetachEventt(test_base.TestCase):
type=constants.OVN_ROUTER_PORT_TYPE,
external_ids={
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
'network:router_interface'},
up=[True])
@ -872,9 +875,11 @@ class TestLogicalSwitchPortSubnetDetachEventt(test_base.TestCase):
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
'network:router_interface',
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'})
subnet_info = {
'associated_router': 'router1',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
self.event.run(None, row, old)
self.agent.withdraw_subnet.assert_called_once_with(
@ -887,11 +892,13 @@ class TestLogicalSwitchPortSubnetDetachEventt(test_base.TestCase):
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
'network:router_interface',
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
up=[True])
old = utils.create_row()
subnet_info = {
'associated_router': 'router1',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
self.event.run(None, row, old)
self.agent.withdraw_subnet.assert_called_once_with(
@ -905,11 +912,189 @@ class TestLogicalSwitchPortSubnetDetachEventt(test_base.TestCase):
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
'network:router_interface',
constants.OVN_LS_NAME_EXT_ID_KEY: 'network1',
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
up=[True])
subnet_info = {
'associated_router': 'router1',
'network': 'network1',
'address_scopes': {4: None, 6: None}}
self.event.run(event, row, mock.Mock())
self.agent.withdraw_subnet.assert_called_once_with(
["192.168.24.1/24"], subnet_info)
class TestLogicalSwitchPortTenantCreateEvent(test_base.TestCase):
def setUp(self):
super(TestLogicalSwitchPortTenantCreateEvent, self).setUp()
self.chassis = 'fake-chassis'
self.chassis_id = 'fake-chassis-id'
self.agent = mock.Mock(chassis=self.chassis,
chassis_id=self.chassis_id)
self.agent.ovn_local_lrps = {
'net1': ['10.0.0.5']}
self.event = nb_bgp_watcher.LogicalSwitchPortTenantCreateEvent(
self.agent)
def test_match_fn(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
up=[True])
old = utils.create_row(up=[False])
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
def test_match_fn_network_set(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
up=[True])
old = utils.create_row(external_ids={})
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
def test_match_fn_wong_ip(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
up=[True])
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
def test_match_fn_not_up(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
up=[False])
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
def test_match_fn_not_local_lrp(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net2'},
up=[True])
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
def test_match_fn_exception(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'})
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
def test_run(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1',
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.6/24"},
up=[True])
ips_info = {
'mac': 'mac',
'cidrs': ["10.0.0.6/24"],
'type': constants.OVN_VM_VIF_PORT_TYPE,
'logical_switch': 'net1'}
self.event.run(None, row, mock.Mock())
self.agent.expose_remote_ip.assert_called_once_with(
["10.0.0.6"], ips_info)
def test_run_wrong_type(self):
row = utils.create_row(
type=constants.OVN_PATCH_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1',
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.6/24"},
up=[True])
self.event.run(None, row, mock.Mock())
self.agent.expose_remote_ip.assert_not_called()
class TestLogicalSwitchPortTenantDeleteEvent(test_base.TestCase):
def setUp(self):
super(TestLogicalSwitchPortTenantDeleteEvent, self).setUp()
self.chassis = 'fake-chassis'
self.chassis_id = 'fake-chassis-id'
self.agent = mock.Mock(chassis=self.chassis,
chassis_id=self.chassis_id)
self.agent.ovn_local_lrps = {
'net1': ['10.0.0.5']}
self.event = nb_bgp_watcher.LogicalSwitchPortTenantDeleteEvent(
self.agent)
def test_match_fn(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
up=[False])
old = utils.create_row(up=[True])
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
def test_match_fn_delete(self):
event = self.event.ROW_DELETE
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
up=[True])
self.assertTrue(self.event.match_fn(event, row, mock.Mock()))
def test_match_fn_wong_ip(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
up=[True])
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
def test_match_fn_not_up(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'},
up=[True])
old = utils.create_row(up=[False])
self.assertFalse(self.event.match_fn(mock.Mock(), row, old))
def test_match_fn_not_local_lrp(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net2'},
up=[True])
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
def test_match_fn_exception(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1'})
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
def test_run(self):
row = utils.create_row(
type=constants.OVN_VM_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1',
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.6/24"},
up=[True])
ips_info = {
'mac': 'mac',
'cidrs': ["10.0.0.6/24"],
'type': constants.OVN_VM_VIF_PORT_TYPE,
'logical_switch': 'net1'}
self.event.run(None, row, mock.Mock())
self.agent.withdraw_remote_ip.assert_called_once_with(
["10.0.0.6"], ips_info)
def test_run_wrong_type(self):
row = utils.create_row(
type=constants.OVN_PATCH_VIF_PORT_TYPE,
addresses=['mac 10.0.0.6'],
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'net1',
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.6/24"},
up=[True])
self.event.run(None, row, mock.Mock())
self.agent.withdraw_remote_ip.assert_not_called()