Add support at NB BGP Driver for exposing subnets
Change-Id: I45e7269306e5c61cda8b6c429dd06c26828ee07b
This commit is contained in:
parent
0c6a71314b
commit
c63be7c85c
@ -17,14 +17,19 @@ OVN_VIF_PORT_TYPES = ("", "chassisredirect", "virtual")
|
||||
OVN_VIRTUAL_VIF_PORT_TYPE = "virtual"
|
||||
OVN_VM_VIF_PORT_TYPE = ""
|
||||
OVN_PATCH_VIF_PORT_TYPE = "patch"
|
||||
OVN_ROUTER_PORT_TYPE = "router"
|
||||
OVN_CHASSISREDIRECT_VIF_PORT_TYPE = "chassisredirect"
|
||||
OVN_LOCALNET_VIF_PORT_TYPE = "localnet"
|
||||
OVN_DNAT_AND_SNAT = "dnat_and_snat"
|
||||
OVN_CR_LRP_PORT_TYPE = 'crlrp'
|
||||
OVN_ROUTER_INTERFACE = 'network:router_interface'
|
||||
|
||||
OVN_CIDRS_EXT_ID_KEY = 'neutron:cidrs'
|
||||
OVN_PORT_NAME_EXT_ID_KEY = 'neutron:port_name'
|
||||
OVN_LS_NAME_EXT_ID_KEY = 'neutron:network_name'
|
||||
OVN_LR_NAME_EXT_ID_KEY = 'neutron:router_name'
|
||||
OVN_DEVICE_ID_EXT_ID_KEY = 'neutron:device_id'
|
||||
OVN_DEVICE_OWNER_EXT_ID_KEY = 'neutron:device_owner'
|
||||
OVN_FIP_EXT_ID_KEY = 'neutron:port_fip'
|
||||
OVN_FIP_NET_EXT_ID_KEY = 'neutron:fip_network_id'
|
||||
LB_VIP_PORT_PREFIX = "ovn-lb-vip-"
|
||||
|
@ -22,6 +22,7 @@ from oslo_log import log as logging
|
||||
from ovn_bgp_agent import constants
|
||||
from ovn_bgp_agent.drivers import driver_api
|
||||
from ovn_bgp_agent.drivers.openstack.utils import bgp as bgp_utils
|
||||
from ovn_bgp_agent.drivers.openstack.utils import driver_utils
|
||||
from ovn_bgp_agent.drivers.openstack.utils import ovn
|
||||
from ovn_bgp_agent.drivers.openstack.utils import ovs
|
||||
from ovn_bgp_agent.drivers.openstack.utils import wire as wire_utils
|
||||
@ -148,7 +149,9 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
"LocalnetCreateDeleteEvent"])
|
||||
if self._expose_tenant_networks:
|
||||
events.update(["ChassisRedirectCreateEvent",
|
||||
"ChassisRedirectDeleteEvent"])
|
||||
"ChassisRedirectDeleteEvent",
|
||||
"LogicalSwitchPortSubnetAttachEvent",
|
||||
"LogicalSwitchPortSubnetDetachEvent"])
|
||||
return events
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
@ -171,10 +174,22 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
routing_tables=self.ovn_routing_tables))
|
||||
|
||||
LOG.debug("Syncing current routes.")
|
||||
# add missing reoutes/ips for OVN router gateway ports
|
||||
# add missing routes/ips for OVN router gateway ports
|
||||
ports = self.nb_idl.get_active_cr_lrp_on_chassis(self.chassis_id)
|
||||
for port in ports:
|
||||
self._ensure_crlrp_exposed(port)
|
||||
# add missing routes/ips for subnets connected to local gateway ports
|
||||
ports = self.nb_idl.get_active_local_lrps(
|
||||
self.ovn_local_cr_lrps.keys())
|
||||
for port in ports:
|
||||
ips = port.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"").split()
|
||||
subnet_info = {
|
||||
'associated_router': port.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY),
|
||||
'address_scopes': driver_utils.get_addr_scopes(port)}
|
||||
self._expose_subnet(ips, subnet_info)
|
||||
|
||||
# add missing routes/ips for IPs on provider network
|
||||
ports = self.nb_idl.get_active_lsp_on_chassis(self.chassis)
|
||||
for port in ports:
|
||||
@ -227,8 +242,8 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
ips = port.addresses[0].strip().split(' ')[1:]
|
||||
mac = port.addresses[0].strip().split(' ')[0]
|
||||
self._expose_ip(ips, mac, logical_switch, bridge_device, bridge_vlan,
|
||||
port.type, [port.external_ids.get(
|
||||
constants.OVN_CIDRS_EXT_ID_KEY)])
|
||||
port.type, port.external_ids.get(
|
||||
constants.OVN_CIDRS_EXT_ID_KEY, "").split())
|
||||
|
||||
def _ensure_crlrp_exposed(self, port):
|
||||
if not port.networks:
|
||||
@ -249,9 +264,10 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
'bridge_vlan': bridge_vlan,
|
||||
'localnet': localnet}
|
||||
ips = [net.split("/")[0] for net in port.networks]
|
||||
router = port.external_ids.get(constants.OVN_LR_NAME_EXT_ID_KEY)
|
||||
self._expose_ip(ips, port.mac, logical_switch, bridge_device,
|
||||
bridge_vlan, constants.OVN_CR_LRP_PORT_TYPE,
|
||||
port.networks)
|
||||
port.networks, router=router)
|
||||
|
||||
def _expose_provider_port(self, port_ips, mac, logical_switch,
|
||||
bridge_device, bridge_vlan, localnet,
|
||||
@ -273,6 +289,7 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
LOG.exception("Unexpected exception while wiring provider port: "
|
||||
"%s", e)
|
||||
return False
|
||||
return True
|
||||
|
||||
def _withdraw_provider_port(self, port_ips, logical_switch, bridge_device,
|
||||
bridge_vlan, proxy_cidrs=None):
|
||||
@ -335,10 +352,11 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
mac = ips_info.get('mac')
|
||||
return self._expose_ip(ips, mac, logical_switch, bridge_device,
|
||||
bridge_vlan, port_type=ips_info['type'],
|
||||
cidrs=ips_info['cidrs'])
|
||||
cidrs=ips_info['cidrs'],
|
||||
router=ips_info.get('router'))
|
||||
|
||||
def _expose_ip(self, ips, mac, logical_switch, bridge_device, bridge_vlan,
|
||||
port_type, cidrs):
|
||||
port_type, cidrs, router=None):
|
||||
LOG.debug("Adding BGP route for logical port with ip %s", ips)
|
||||
localnet = self.ovn_provider_ls[logical_switch]['localnet']
|
||||
|
||||
@ -351,7 +369,24 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
bridge_device, bridge_vlan,
|
||||
localnet, cidrs):
|
||||
return []
|
||||
|
||||
if router and port_type == constants.OVN_CR_LRP_PORT_TYPE:
|
||||
# Store information about local CR-LRPs that will later be used
|
||||
# to expose networks
|
||||
self.ovn_local_cr_lrps[router] = {
|
||||
'bridge_device': bridge_device,
|
||||
'bridge_vlan': bridge_vlan,
|
||||
'ips': ips,
|
||||
}
|
||||
# Expose associated subnets
|
||||
ports = self.nb_idl.get_active_local_lrps([router])
|
||||
for port in ports:
|
||||
ips = port.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"").split()
|
||||
subnet_info = {
|
||||
'associated_router': port.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY),
|
||||
'address_scopes': driver_utils.get_addr_scopes(port)}
|
||||
self._expose_subnet(ips, subnet_info)
|
||||
else:
|
||||
if not self._expose_provider_port(ips, mac, logical_switch,
|
||||
bridge_device, bridge_vlan,
|
||||
@ -397,6 +432,23 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
else:
|
||||
self._withdraw_provider_port(ips, logical_switch, bridge_device,
|
||||
bridge_vlan)
|
||||
if ips_info.get('router'):
|
||||
# It is a Logical Router Port (CR-LRP)
|
||||
# Withdraw associated subnets
|
||||
ports = self.nb_idl.get_active_local_lrps([ips_info['router']])
|
||||
for port in ports:
|
||||
ips = port.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"").split()
|
||||
subnet_info = {
|
||||
'associated_router': port.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY),
|
||||
'address_scopes': driver_utils.get_addr_scopes(port)}
|
||||
self._withdraw_subnet(ips, subnet_info)
|
||||
try:
|
||||
del self.ovn_local_cr_lrps[ips_info['router']]
|
||||
except KeyError:
|
||||
LOG.debug("Gateway port for router %s already cleanup.",
|
||||
ips_info['router'])
|
||||
LOG.debug("Deleted BGP route for logical port with ip %s", ips)
|
||||
|
||||
def _get_ls_localnet_info(self, logical_switch):
|
||||
@ -501,9 +553,118 @@ class NBOVNBGPDriver(driver_api.AgentDriverBase):
|
||||
pass
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
def expose_subnet(self, ip, row):
|
||||
pass
|
||||
def expose_subnet(self, ips, subnet_info):
|
||||
return self._expose_subnet(ips, subnet_info)
|
||||
|
||||
@lockutils.synchronized('nbbgp')
|
||||
def withdraw_subnet(self, ip, row):
|
||||
pass
|
||||
def withdraw_subnet(self, ips, subnet_info):
|
||||
return self._withdraw_subnet(ips, subnet_info)
|
||||
|
||||
def _expose_subnet(self, ips, subnet_info):
|
||||
gateway_router = subnet_info['associated_router']
|
||||
if not gateway_router:
|
||||
LOG.debug("Subnet CIDRs %s not exposed as there is no associated "
|
||||
"router", ips)
|
||||
return
|
||||
cr_lrp_info = self.ovn_local_cr_lrps.get(gateway_router)
|
||||
if not cr_lrp_info:
|
||||
LOG.debug("Subnet CIDRs %s not exposed as there is no local "
|
||||
"cr-lrp matching %s", ips, gateway_router)
|
||||
return
|
||||
|
||||
if not self._expose_router_lsp(ips, subnet_info, cr_lrp_info):
|
||||
LOG.debug("Something happen while exposing the Subnet CIRDs %s "
|
||||
"and they have not been properly exposed", ips)
|
||||
return
|
||||
|
||||
def _withdraw_subnet(self, ips, subnet_info):
|
||||
gateway_router = subnet_info['associated_router']
|
||||
if not gateway_router:
|
||||
LOG.debug("Subnet CIDRs %s not withdrawn as there is no associated"
|
||||
" router", ips)
|
||||
return
|
||||
cr_lrp_info = self.ovn_local_cr_lrps.get(gateway_router)
|
||||
if not cr_lrp_info:
|
||||
# NOTE(ltomasbo) there is a chance the cr-lrp just got moved
|
||||
# to this node but was not yet processed. In that case there
|
||||
# is no need to withdraw the network as it was not exposed here
|
||||
LOG.debug("Subnet CIDRs %s not withdrawn as there is no local "
|
||||
"cr-lrp matching %s", ips, gateway_router)
|
||||
return
|
||||
|
||||
self._withdraw_router_lsp(ips, subnet_info, cr_lrp_info)
|
||||
|
||||
def _expose_router_lsp(self, ips, subnet_info, cr_lrp_info):
|
||||
if not self._expose_tenant_networks:
|
||||
return True
|
||||
success = True
|
||||
for ip in ips:
|
||||
if not CONF.expose_tenant_networks:
|
||||
# This means CONF.expose_ipv6_gua_tenant_networks is enabled
|
||||
if not driver_utils.is_ipv6_gua(ip):
|
||||
continue
|
||||
if not self._address_scope_allowed(ip,
|
||||
subnet_info['address_scopes']):
|
||||
continue
|
||||
try:
|
||||
if wire_utils.wire_lrp_port(
|
||||
self.ovn_routing_tables_routes, ip,
|
||||
cr_lrp_info.get('bridge_device'),
|
||||
cr_lrp_info.get('bridge_vlan'),
|
||||
self.ovn_routing_tables, cr_lrp_info.get('ips')):
|
||||
self._exposed_ips.setdefault(
|
||||
subnet_info['associated_router'], {}).update(
|
||||
{ip: {
|
||||
'bridge_device': cr_lrp_info.get('bridge_device'),
|
||||
'bridge_vlan': cr_lrp_info.get('bridge_vlan')}})
|
||||
else:
|
||||
success = False
|
||||
|
||||
except Exception as e:
|
||||
LOG.exception("Unexpected exception while wiring subnet CIDRs"
|
||||
" %s: %s", ip, e)
|
||||
success = False
|
||||
return success
|
||||
|
||||
def _withdraw_router_lsp(self, ips, subnet_info, cr_lrp_info):
|
||||
if not self._expose_tenant_networks:
|
||||
return
|
||||
for ip in ips:
|
||||
if (not CONF.expose_tenant_networks and
|
||||
not driver_utils.is_ipv6_gua(ip)):
|
||||
# This means CONF.expose_ipv6_gua_tenant_networks is enabled
|
||||
continue
|
||||
if not self._address_scope_allowed(ip,
|
||||
subnet_info['address_scopes']):
|
||||
continue
|
||||
try:
|
||||
if wire_utils.unwire_lrp_port(
|
||||
self.ovn_routing_tables_routes, ip,
|
||||
cr_lrp_info.get('bridge_device'),
|
||||
cr_lrp_info.get('bridge_vlan'),
|
||||
self.ovn_routing_tables, cr_lrp_info.get('ips')):
|
||||
if self._exposed_ips.get(
|
||||
subnet_info['associated_router'], {}).get(ip):
|
||||
self._exposed_ips[
|
||||
subnet_info['associated_router']].pop(ip)
|
||||
else:
|
||||
return False
|
||||
except Exception as e:
|
||||
LOG.exception("Unexpected exception while unwiring subnet "
|
||||
"CIDRs %s: %s", ip, e)
|
||||
return False
|
||||
return True
|
||||
|
||||
def _address_scope_allowed(self, ip, address_scopes):
|
||||
if not self.allowed_address_scopes:
|
||||
# No address scopes to filter on => announce everything
|
||||
return True
|
||||
|
||||
# if we should filter on address scopes and this port has no
|
||||
# address scopes set we do not need to expose it
|
||||
if not any(address_scopes.values()):
|
||||
return False
|
||||
# if address scope does not match, no need to expose it
|
||||
ip_version = linux_net.get_ip_version(ip)
|
||||
|
||||
return address_scopes[ip_version] in self.allowed_address_scopes
|
||||
|
@ -369,7 +369,7 @@ class OVNBGPDriver(driver_api.AgentDriverBase):
|
||||
# specific case for ovn-lb vips on tenant networks
|
||||
if not port.mac and not port.chassis and not port.up[0]:
|
||||
ext_n_cidr = port.external_ids.get(
|
||||
constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
constants.OVN_CIDRS_EXT_ID_KEY, "")
|
||||
if ext_n_cidr:
|
||||
ovn_lb_ip = ext_n_cidr.split(" ")[0].split("/")[0]
|
||||
bgp_utils.announce_ips([ovn_lb_ip])
|
||||
@ -390,7 +390,8 @@ class OVNBGPDriver(driver_api.AgentDriverBase):
|
||||
if port.mac == ['unknown']:
|
||||
# Handling the case for unknown MACs when configdrive is used
|
||||
# instead of dhcp
|
||||
n_cidrs = port.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
n_cidrs = port.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"")
|
||||
port_ips = [ip.split("/")[0] for ip in n_cidrs.split(" ")]
|
||||
else:
|
||||
port_ips = port.mac[0].strip().split(' ')[1:]
|
||||
@ -581,10 +582,10 @@ class OVNBGPDriver(driver_api.AgentDriverBase):
|
||||
# NOTE: This is neutron specific as we need the provider
|
||||
# prefix to add the ndp proxy
|
||||
n_cidr = row.external_ids.get(
|
||||
constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
constants.OVN_CIDRS_EXT_ID_KEY, "").split()
|
||||
exposed_port = self._expose_provider_port(
|
||||
ips, row.datapath, bridge_device, bridge_vlan, None,
|
||||
[n_cidr])
|
||||
n_cidr)
|
||||
else:
|
||||
exposed_port = self._expose_provider_port(ips,
|
||||
row.datapath)
|
||||
@ -721,11 +722,11 @@ class OVNBGPDriver(driver_api.AgentDriverBase):
|
||||
# NOTE: This is neutron specific as we need the
|
||||
# provider prefix to add the ndp proxy
|
||||
n_cidr = row.external_ids.get(
|
||||
constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
constants.OVN_CIDRS_EXT_ID_KEY, "").split()
|
||||
if n_cidr:
|
||||
withdrawn_port = self._withdraw_provider_port(
|
||||
ips, row.datapath, bridge_device, bridge_vlan, None,
|
||||
[n_cidr])
|
||||
n_cidr)
|
||||
else:
|
||||
withdrawn_port = self._withdraw_provider_port(ips,
|
||||
row.datapath)
|
||||
|
@ -438,6 +438,18 @@ class OvsdbNbOvnIdl(nb_impl_idl.OvnNbApiIdlImpl, Backend):
|
||||
ports.append(row)
|
||||
return ports
|
||||
|
||||
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))
|
||||
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)):
|
||||
ports.append(row)
|
||||
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,
|
||||
@ -714,7 +726,7 @@ class OvsdbSbOvnIdl(sb_impl_idl.OvnSbApiIdlImpl, Backend):
|
||||
# This is depending on the external-id information added by
|
||||
# neutron, regarding the neutron:cidrs
|
||||
ip_info = row.external_ids.get(
|
||||
constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
constants.OVN_CIDRS_EXT_ID_KEY, "")
|
||||
if not ip_info:
|
||||
continue
|
||||
port_name = row.external_ids.get(
|
||||
|
@ -403,11 +403,14 @@ def _cleanup_wiring_underlay(idl, bridge_mappings, ovs_flows, exposed_ips,
|
||||
ovn_ip_rules = linux_net.get_ovn_ip_rules(routing_tables.values())
|
||||
if ovn_ip_rules:
|
||||
for ip in expected_ips:
|
||||
ip_version = linux_net.get_ip_version(ip)
|
||||
if ip_version == constants.IP_VERSION_6:
|
||||
ip_dst = "{}/128".format(ip)
|
||||
if len(ip.split("/")) == 1:
|
||||
ip_version = linux_net.get_ip_version(ip)
|
||||
if ip_version == constants.IP_VERSION_6:
|
||||
ip_dst = "{}/128".format(ip)
|
||||
else:
|
||||
ip_dst = "{}/32".format(ip)
|
||||
else:
|
||||
ip_dst = "{}/32".format(ip)
|
||||
ip_dst = ip
|
||||
ovn_ip_rules.pop(ip_dst, None)
|
||||
linux_net.delete_ip_rules(ovn_ip_rules)
|
||||
|
||||
@ -573,12 +576,29 @@ def _unwire_provider_port_ovn(ovn_idl, port_ips):
|
||||
|
||||
|
||||
def wire_lrp_port(routing_tables_routes, ip, bridge_device, bridge_vlan,
|
||||
routing_table, cr_lrp_ips):
|
||||
routing_tables, cr_lrp_ips):
|
||||
if CONF.exposing_method == constants.EXPOSE_METHOD_UNDERLAY:
|
||||
return _wire_lrp_port_underlay(routing_tables_routes, ip,
|
||||
bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
elif CONF.exposing_method == constants.EXPOSE_METHOD_OVN:
|
||||
# TODO(ltomasbo): Add flow on br-ex(-X)
|
||||
# ovs-ofctl add-flow br-ex
|
||||
# "cookie=0xbadcaf2,ip,nw_dst=20.0.0.0/24,in_port=enp2s0,priority=100,
|
||||
# actions=mod_dl_dst:$ENP2S0_MAC,output=$patch"
|
||||
# Add router route to go through cr-lrp ip:
|
||||
# ovn-nbctl lr-route-add bgp-router 20.0.0.0/24 172.16.100.143
|
||||
# bgp-router-public
|
||||
return
|
||||
|
||||
|
||||
def _wire_lrp_port_underlay(routing_tables_routes, ip, bridge_device,
|
||||
bridge_vlan, routing_tables, cr_lrp_ips):
|
||||
if not bridge_device:
|
||||
return False
|
||||
LOG.debug("Adding IP Rules for network %s", ip)
|
||||
try:
|
||||
linux_net.add_ip_rule(ip, routing_table[bridge_device])
|
||||
linux_net.add_ip_rule(ip, routing_tables[bridge_device])
|
||||
except agent_exc.InvalidPortIP:
|
||||
LOG.exception("Invalid IP to create a rule for the lrp (network "
|
||||
"router interface) port: %s", ip)
|
||||
@ -594,7 +614,7 @@ def wire_lrp_port(routing_tables_routes, ip, bridge_device, bridge_vlan,
|
||||
linux_net.add_ip_route(
|
||||
routing_tables_routes,
|
||||
ip.split("/")[0],
|
||||
routing_table[bridge_device],
|
||||
routing_tables[bridge_device],
|
||||
bridge_device,
|
||||
vlan=bridge_vlan,
|
||||
mask=ip.split("/")[1],
|
||||
@ -605,12 +625,23 @@ def wire_lrp_port(routing_tables_routes, ip, bridge_device, bridge_vlan,
|
||||
|
||||
|
||||
def unwire_lrp_port(routing_tables_routes, ip, bridge_device, bridge_vlan,
|
||||
routing_table, cr_lrp_ips):
|
||||
routing_tables, cr_lrp_ips):
|
||||
if CONF.exposing_method == constants.EXPOSE_METHOD_UNDERLAY:
|
||||
return _unwire_lrp_port_underlay(routing_tables_routes, ip,
|
||||
bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
elif CONF.exposing_method == constants.EXPOSE_METHOD_OVN:
|
||||
# TODO(ltomasbo): Remove flow(s) and router route
|
||||
return
|
||||
|
||||
|
||||
def _unwire_lrp_port_underlay(routing_tables_routes, ip, bridge_device,
|
||||
bridge_vlan, routing_tables, cr_lrp_ips):
|
||||
if not bridge_device:
|
||||
return False
|
||||
LOG.debug("Deleting IP Rules for network %s", ip)
|
||||
try:
|
||||
linux_net.del_ip_rule(ip, routing_table[bridge_device])
|
||||
linux_net.del_ip_rule(ip, routing_tables[bridge_device])
|
||||
except agent_exc.InvalidPortIP:
|
||||
LOG.exception("Invalid IP to delete a rule for the "
|
||||
"lrp (network router interface) port: %s", ip)
|
||||
@ -624,7 +655,7 @@ def unwire_lrp_port(routing_tables_routes, ip, bridge_device, bridge_vlan,
|
||||
linux_net.del_ip_route(
|
||||
routing_tables_routes,
|
||||
ip.split("/")[0],
|
||||
routing_table[bridge_device],
|
||||
routing_tables[bridge_device],
|
||||
bridge_device,
|
||||
vlan=bridge_vlan,
|
||||
mask=ip.split("/")[1],
|
||||
|
@ -261,7 +261,8 @@ class TenantPortCreatedEvent(base_watcher.PortBindingChassisEvent):
|
||||
# Handling the case for unknown MACs when configdrive is used
|
||||
# instead of dhcp
|
||||
if row.mac == ['unknown']:
|
||||
n_cidrs = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
n_cidrs = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"").split()
|
||||
if not n_cidrs:
|
||||
return False
|
||||
# single and dual-stack format
|
||||
@ -280,7 +281,8 @@ class TenantPortCreatedEvent(base_watcher.PortBindingChassisEvent):
|
||||
if row.mac == ['unknown']:
|
||||
# Handling the case for unknown MACs when configdrive is used
|
||||
# instead of dhcp
|
||||
n_cidrs = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
n_cidrs = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"")
|
||||
ips = [ip.split("/")[0] for ip in n_cidrs.split(" ")]
|
||||
else:
|
||||
ips = row.mac[0].split(' ')[1:]
|
||||
@ -298,7 +300,8 @@ class TenantPortDeletedEvent(base_watcher.PortBindingChassisEvent):
|
||||
if row.mac == ['unknown']:
|
||||
# Handling the case for unknown MACs when configdrive is used
|
||||
# instead of dhcp
|
||||
n_cidrs = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
n_cidrs = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"").split()
|
||||
if not n_cidrs:
|
||||
return False
|
||||
# single and dual-stack format
|
||||
@ -324,7 +327,8 @@ class TenantPortDeletedEvent(base_watcher.PortBindingChassisEvent):
|
||||
if row.mac == ['unknown']:
|
||||
# Handling the case for unknown MACs when configdrive is used
|
||||
# instead of dhcp
|
||||
n_cidrs = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
n_cidrs = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"")
|
||||
ips = [ip.split("/")[0] for ip in n_cidrs.split(" ")]
|
||||
else:
|
||||
ips = row.mac[0].split(' ')[1:]
|
||||
@ -356,7 +360,8 @@ class OVNLBVIPPortEvent(base_watcher.PortBindingChassisEvent):
|
||||
with _SYNC_STATE_LOCK.read_lock():
|
||||
# This is depending on the external-id information added by
|
||||
# neutron, regarding the neutron:cidrs
|
||||
ext_n_cidr = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
ext_n_cidr = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"")
|
||||
if not ext_n_cidr:
|
||||
return
|
||||
|
||||
@ -402,7 +407,7 @@ class OVNLBMemberCreateEvent(base_watcher.OVNLBMemberEvent):
|
||||
vip_port = self.agent.sb_idl.get_ovn_vip_port(row.name)
|
||||
if not vip_port:
|
||||
return
|
||||
vip_ip = vip_port.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY)
|
||||
vip_ip = vip_port.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY, "")
|
||||
if not vip_ip:
|
||||
return
|
||||
vip_ip = vip_ip.strip().split(" ")[0].split("/")[0]
|
||||
|
@ -16,6 +16,7 @@ from oslo_concurrency import lockutils
|
||||
from oslo_log import log as logging
|
||||
|
||||
from ovn_bgp_agent import constants
|
||||
from ovn_bgp_agent.drivers.openstack.utils import driver_utils
|
||||
from ovn_bgp_agent.drivers.openstack.watchers import base_watcher
|
||||
|
||||
|
||||
@ -69,8 +70,8 @@ class LogicalSwitchPortProviderCreateEvent(base_watcher.LSPChassisEvent):
|
||||
mac = row.addresses[0].strip().split(' ')[0]
|
||||
ips_info = {
|
||||
'mac': mac,
|
||||
'cidrs': [
|
||||
row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY)],
|
||||
'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)
|
||||
@ -136,8 +137,8 @@ class LogicalSwitchPortProviderDeleteEvent(base_watcher.LSPChassisEvent):
|
||||
mac = row.addresses[0].strip().split(' ')[0]
|
||||
ips_info = {
|
||||
'mac': mac,
|
||||
'cidrs': [
|
||||
row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY)],
|
||||
'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)
|
||||
@ -327,9 +328,9 @@ class ChassisRedirectCreateEvent(base_watcher.LRPChassisEvent):
|
||||
constants.OVN_STATUS_CHASSIS)
|
||||
if old_hosting_chassis != hosting_chassis:
|
||||
return True
|
||||
return False
|
||||
except (IndexError, AttributeError):
|
||||
return False
|
||||
return False
|
||||
|
||||
def _run(self, event, row, old):
|
||||
with _SYNC_STATE_LOCK.read_lock():
|
||||
@ -339,7 +340,9 @@ class ChassisRedirectCreateEvent(base_watcher.LRPChassisEvent):
|
||||
'cidrs': row.networks,
|
||||
'type': constants.OVN_CR_LRP_PORT_TYPE,
|
||||
'logical_switch': row.external_ids.get(
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY)
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY),
|
||||
'router': row.external_ids.get(
|
||||
constants.OVN_LR_NAME_EXT_ID_KEY)
|
||||
}
|
||||
ips = [net.split("/")[0] for net in row.networks]
|
||||
self.agent.expose_ip(ips, ips_info)
|
||||
@ -365,9 +368,9 @@ class ChassisRedirectDeleteEvent(base_watcher.LRPChassisEvent):
|
||||
if (hosting_chassis != old_hosting_chassis and
|
||||
old_hosting_chassis == self.agent.chassis_id):
|
||||
return True
|
||||
return False
|
||||
except (IndexError, AttributeError):
|
||||
return False
|
||||
return False
|
||||
|
||||
def _run(self, event, row, old):
|
||||
with _SYNC_STATE_LOCK.read_lock():
|
||||
@ -377,7 +380,145 @@ class ChassisRedirectDeleteEvent(base_watcher.LRPChassisEvent):
|
||||
'cidrs': row.networks,
|
||||
'type': constants.OVN_CR_LRP_PORT_TYPE,
|
||||
'logical_switch': row.external_ids.get(
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY)
|
||||
constants.OVN_LS_NAME_EXT_ID_KEY),
|
||||
'router': row.external_ids.get(
|
||||
constants.OVN_LR_NAME_EXT_ID_KEY)
|
||||
}
|
||||
ips = [net.split("/")[0] for net in row.networks]
|
||||
self.agent.withdraw_ip(ips, ips_info)
|
||||
|
||||
|
||||
class LogicalSwitchPortSubnetAttachEvent(base_watcher.LSPChassisEvent):
|
||||
def __init__(self, bgp_agent):
|
||||
events = (self.ROW_UPDATE,)
|
||||
super(LogicalSwitchPortSubnetAttachEvent, self).__init__(
|
||||
bgp_agent, events)
|
||||
|
||||
def match_fn(self, event, row, old):
|
||||
try:
|
||||
if row.type != constants.OVN_ROUTER_PORT_TYPE:
|
||||
return False
|
||||
# skip route_gateway port events
|
||||
row_device_owner = row.external_ids.get(
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY)
|
||||
if row_device_owner != constants.OVN_ROUTER_INTERFACE:
|
||||
return False
|
||||
|
||||
if not bool(row.up[0]):
|
||||
return False
|
||||
|
||||
associated_router = row.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY)
|
||||
|
||||
if associated_router not in self.agent.ovn_local_cr_lrps:
|
||||
return False
|
||||
|
||||
if hasattr(old, 'up') and not bool(old.up[0]):
|
||||
return True
|
||||
|
||||
if hasattr(old, 'external_ids'):
|
||||
previous_associated_router = old.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY)
|
||||
if (associated_router != previous_associated_router and
|
||||
previous_associated_router not in
|
||||
self.agent.ovn_local_cr_lrps):
|
||||
return True
|
||||
except (IndexError, AttributeError):
|
||||
return False
|
||||
return False
|
||||
|
||||
def _run(self, event, row, old):
|
||||
with _SYNC_STATE_LOCK.read_lock():
|
||||
ips = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"").split()
|
||||
subnet_info = {
|
||||
'associated_router': row.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY),
|
||||
'address_scopes': driver_utils.get_addr_scopes(row)}
|
||||
self.agent.expose_subnet(ips, subnet_info)
|
||||
|
||||
|
||||
class LogicalSwitchPortSubnetDetachEvent(base_watcher.LSPChassisEvent):
|
||||
def __init__(self, bgp_agent):
|
||||
events = (self.ROW_UPDATE, self.ROW_DELETE,)
|
||||
super(LogicalSwitchPortSubnetDetachEvent, self).__init__(
|
||||
bgp_agent, events)
|
||||
|
||||
def match_fn(self, event, row, old):
|
||||
try:
|
||||
if row.type != constants.OVN_ROUTER_PORT_TYPE:
|
||||
return False
|
||||
# skip route_gateway port events
|
||||
row_device_owner = row.external_ids.get(
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY)
|
||||
if row_device_owner != constants.OVN_ROUTER_INTERFACE:
|
||||
return False
|
||||
|
||||
associated_router = row.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY)
|
||||
|
||||
if event == self.ROW_DELETE:
|
||||
if not bool(row.up[0]):
|
||||
return False
|
||||
if associated_router in self.agent.ovn_local_cr_lrps:
|
||||
return True
|
||||
return False
|
||||
|
||||
# ROW UPDATE
|
||||
# We need to withdraw the subnet in the next cases:
|
||||
# 1. same/local associated router and status moves from up to down
|
||||
# 2. status changes to down and also associated router changes to a
|
||||
# non local one
|
||||
# 3. status is up (same) but associated router changes to a non
|
||||
# local one
|
||||
if hasattr(old, 'up'):
|
||||
if not bool(old.up[0]):
|
||||
return False
|
||||
if hasattr(old, 'external_ids'):
|
||||
previous_associated_router = old.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY)
|
||||
if previous_associated_router in (
|
||||
self.agent.ovn_local_cr_lrps):
|
||||
return True
|
||||
else:
|
||||
if associated_router in self.agent.ovn_local_cr_lrps:
|
||||
return True
|
||||
else:
|
||||
# no change in status
|
||||
if not bool(row.up[0]):
|
||||
# it was not exposed
|
||||
return False
|
||||
if hasattr(old, 'external_ids'):
|
||||
previous_associated_router = old.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY)
|
||||
if (previous_associated_router and
|
||||
associated_router != previous_associated_router and
|
||||
previous_associated_router in
|
||||
self.agent.ovn_local_cr_lrps):
|
||||
return True
|
||||
except (IndexError, AttributeError):
|
||||
return False
|
||||
return False
|
||||
|
||||
def _run(self, event, row, old):
|
||||
with _SYNC_STATE_LOCK.read_lock():
|
||||
ips = row.external_ids.get(constants.OVN_CIDRS_EXT_ID_KEY,
|
||||
"").split()
|
||||
if event == self.ROW_DELETE:
|
||||
subnet_info = {
|
||||
'associated_router': row.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY),
|
||||
'address_scopes': driver_utils.get_addr_scopes(row)}
|
||||
else:
|
||||
associated_router = row.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY)
|
||||
if hasattr(old, 'external_ids'):
|
||||
previous_associated_router = old.external_ids.get(
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY)
|
||||
if previous_associated_router != associated_router:
|
||||
associated_router = previous_associated_router
|
||||
subnet_info = {
|
||||
'associated_router': associated_router,
|
||||
'address_scopes': driver_utils.get_addr_scopes(row)}
|
||||
|
||||
self.agent.withdraw_subnet(ips, subnet_info)
|
||||
|
@ -20,6 +20,7 @@ from oslo_config import cfg
|
||||
from ovn_bgp_agent import constants
|
||||
from ovn_bgp_agent.drivers.openstack import nb_ovn_bgp_driver
|
||||
from ovn_bgp_agent.drivers.openstack.utils import bgp as bgp_utils
|
||||
from ovn_bgp_agent.drivers.openstack.utils import driver_utils
|
||||
from ovn_bgp_agent.drivers.openstack.utils import frr
|
||||
from ovn_bgp_agent.drivers.openstack.utils import ovn
|
||||
from ovn_bgp_agent.drivers.openstack.utils import ovs
|
||||
@ -35,6 +36,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestNBOVNBGPDriver, self).setUp()
|
||||
CONF.set_override('expose_tenant_networks', True)
|
||||
self.bridge = 'fake-bridge'
|
||||
self.nb_bgp_driver = nb_ovn_bgp_driver.NBOVNBGPDriver()
|
||||
self.nb_bgp_driver._post_start_event = mock.Mock()
|
||||
@ -53,6 +55,11 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
self.fip = '172.24.4.33'
|
||||
self.mac = 'aa:bb:cc:dd:ee:ff'
|
||||
|
||||
self.router1_info = {'bridge_device': self.bridge,
|
||||
'bridge_vlan': 100,
|
||||
'ips': ['172.24.4.11']}
|
||||
self.nb_bgp_driver.ovn_local_cr_lrps = {
|
||||
'router1': self.router1_info}
|
||||
self.ovn_routing_tables = {
|
||||
self.bridge: 100,
|
||||
'br-vlan': 200}
|
||||
@ -144,6 +151,11 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
|
||||
crlrp_port = fakes.create_object({
|
||||
'name': 'crlrp_port'})
|
||||
lrp0 = fakes.create_object({
|
||||
'name': 'lrp_port',
|
||||
'external_ids': {
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'fake-router'}})
|
||||
port0 = fakes.create_object({
|
||||
'name': 'port-0',
|
||||
'type': constants.OVN_VM_VIF_PORT_TYPE})
|
||||
@ -151,10 +163,13 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
'name': 'port-1',
|
||||
'type': constants.OVN_CHASSISREDIRECT_VIF_PORT_TYPE})
|
||||
self.nb_idl.get_active_cr_lrp_on_chassis.return_value = [crlrp_port]
|
||||
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
|
||||
self.nb_idl.get_active_lsp_on_chassis.return_value = [
|
||||
port0, port1]
|
||||
mock_ensure_crlrp_exposed = mock.patch.object(
|
||||
self.nb_bgp_driver, '_ensure_crlrp_exposed').start()
|
||||
mock_expose_subnet = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_subnet').start()
|
||||
mock_ensure_lsp_exposed = mock.patch.object(
|
||||
self.nb_bgp_driver, '_ensure_lsp_exposed').start()
|
||||
mock_routing_bridge.return_value = ['fake-route']
|
||||
@ -187,12 +202,15 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
mock_remove_flows.assert_has_calls(expected_calls)
|
||||
mock_get_ip_rules.assert_called_once()
|
||||
mock_ensure_crlrp_exposed.assert_called_once_with(crlrp_port)
|
||||
mock_expose_subnet.assert_called_once_with(
|
||||
["10.0.0.1/24"],
|
||||
{'associated_router': 'fake-router',
|
||||
'address_scopes': {4: None, 6: None}})
|
||||
mock_ensure_lsp_exposed.assert_called_once_with(port0)
|
||||
mock_del_exposed_ips.assert_called_once_with(
|
||||
ips, CONF.bgp_nic)
|
||||
mock_del_ip_rules.assert_called_once_with(fake_ip_rules)
|
||||
mock_del_ip_routes.assert_called_once()
|
||||
|
||||
bridge = set(self.nb_bgp_driver.ovn_bridge_mappings.values()).pop()
|
||||
mock_delete_vlan_dev.assert_called_once_with(bridge, 12)
|
||||
|
||||
@ -267,7 +285,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
mock_expose_fip.assert_not_called()
|
||||
mock_expose_ip.assert_called_once_with(
|
||||
['192.168.0.10'], 'fake_mac', 'test-ls', 'br-ex', 10,
|
||||
constants.OVN_VM_VIF_PORT_TYPE, [None])
|
||||
constants.OVN_VM_VIF_PORT_TYPE, [])
|
||||
|
||||
def test__ensure_crlrp_exposed(self):
|
||||
port = fakes.create_object({
|
||||
@ -286,7 +304,7 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
|
||||
mock_expose_ip.assert_called_once_with(
|
||||
['172.24.16.2'], 'fake_mac', 'test-ls', 'br-ex', 10,
|
||||
constants.OVN_CR_LRP_PORT_TYPE, ['172.24.16.2/24'])
|
||||
constants.OVN_CR_LRP_PORT_TYPE, ['172.24.16.2/24'], router=None)
|
||||
|
||||
def test__ensure_crlrp_exposed_no_networks(self):
|
||||
port = fakes.create_object({
|
||||
@ -419,6 +437,14 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
self.nb_bgp_driver, '_get_ls_localnet_info').start()
|
||||
mock_get_ls_localnet_info.return_value = ('fake-localnet', 'br-ex', 10)
|
||||
self.nb_bgp_driver.ovn_bridge_mappings = {'fake-localnet': 'br-ex'}
|
||||
mock_expose_subnet = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_subnet').start()
|
||||
lrp0 = fakes.create_object({
|
||||
'name': 'lrp_port',
|
||||
'external_ids': {
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'}})
|
||||
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
|
||||
|
||||
self.nb_bgp_driver.expose_ip(ips, ips_info)
|
||||
|
||||
@ -433,7 +459,8 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
self.nb_bgp_driver.ovn_provider_ls[ips_info['logical_switch']],
|
||||
{'bridge_device': 'br-ex', 'bridge_vlan': 10,
|
||||
'localnet': 'fake-localnet'})
|
||||
if (ips_info['type'] == constants.OVN_VIRTUAL_VIF_PORT_TYPE and
|
||||
if (ips_info['type'] in [constants.OVN_VIRTUAL_VIF_PORT_TYPE,
|
||||
constants.OVN_CR_LRP_PORT_TYPE] and
|
||||
ips_info['cidrs']):
|
||||
mock_expose_provider_port.assert_called_once_with(
|
||||
ips, 'fake-mac', 'test-ls', 'br-ex', 10, 'fake-localnet',
|
||||
@ -442,6 +469,12 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
mock_expose_provider_port.assert_called_once_with(
|
||||
ips, 'fake-mac', 'test-ls', 'br-ex', 10, 'fake-localnet')
|
||||
|
||||
if (ips_info.get('router') and
|
||||
ips_info['type'] == constants.OVN_CR_LRP_PORT_TYPE):
|
||||
mock_expose_subnet.assert_called_once_with(
|
||||
["10.0.0.1/24"], {'associated_router': 'router1',
|
||||
'address_scopes': {4: None, 6: None}})
|
||||
|
||||
def test_expose_ip(self):
|
||||
ips = [self.ipv4, self.ipv6]
|
||||
ips_info = {
|
||||
@ -475,6 +508,18 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
|
||||
self._test_expose_ip(ips, ips_info)
|
||||
|
||||
def test_expose_ip_router(self):
|
||||
ips = [self.ipv4, self.ipv6]
|
||||
ips_info = {
|
||||
'mac': 'fake-mac',
|
||||
'cidrs': ['test-cidr'],
|
||||
'type': constants.OVN_CR_LRP_PORT_TYPE,
|
||||
'logical_switch': 'test-ls',
|
||||
'router': 'router1'
|
||||
}
|
||||
|
||||
self._test_expose_ip(ips, ips_info)
|
||||
|
||||
@mock.patch.object(linux_net, 'get_ip_version')
|
||||
def _test_withdraw_ip(self, ips, ips_info, provider, mock_ip_version):
|
||||
mock_withdraw_provider_port = mock.patch.object(
|
||||
@ -489,6 +534,15 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
else:
|
||||
mock_get_ls_localnet_info.return_value = (None, None, None)
|
||||
|
||||
mock_withdraw_subnet = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_subnet').start()
|
||||
lrp0 = fakes.create_object({
|
||||
'name': 'lrp_port',
|
||||
'external_ids': {
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "10.0.0.1/24",
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'}})
|
||||
self.nb_idl.get_active_local_lrps.return_value = [lrp0]
|
||||
|
||||
self.nb_bgp_driver.withdraw_ip(ips, ips_info)
|
||||
|
||||
if not ips_info['logical_switch']:
|
||||
@ -503,7 +557,8 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
|
||||
mock_get_ls_localnet_info.assert_called_once_with(
|
||||
ips_info['logical_switch'])
|
||||
if (ips_info['type'] == constants.OVN_VIRTUAL_VIF_PORT_TYPE and
|
||||
if (ips_info['type'] in [constants.OVN_VIRTUAL_VIF_PORT_TYPE,
|
||||
constants.OVN_CR_LRP_PORT_TYPE] and
|
||||
ips_info['cidrs']):
|
||||
mock_withdraw_provider_port.assert_called_once_with(
|
||||
ips, 'test-ls', 'br-ex', 10, ips_info['cidrs'])
|
||||
@ -511,6 +566,11 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
mock_withdraw_provider_port.assert_called_once_with(
|
||||
ips, 'test-ls', 'br-ex', 10)
|
||||
|
||||
if ips_info.get('router'):
|
||||
mock_withdraw_subnet.assert_called_once_with(
|
||||
["10.0.0.1/24"], {'associated_router': 'router1',
|
||||
'address_scopes': {4: None, 6: None}})
|
||||
|
||||
def test_withdraw_ip(self):
|
||||
ips = [self.ipv4, self.ipv6]
|
||||
ips_info = {
|
||||
@ -555,6 +615,18 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
|
||||
self._test_withdraw_ip(ips, ips_info, True)
|
||||
|
||||
def test_withdraw_ip_router(self):
|
||||
ips = [self.ipv4, self.ipv6]
|
||||
ips_info = {
|
||||
'mac': 'fake-mac',
|
||||
'cidrs': ['test-cidr'],
|
||||
'type': constants.OVN_CR_LRP_PORT_TYPE,
|
||||
'logical_switch': 'test-ls',
|
||||
'router': 'router1'
|
||||
}
|
||||
|
||||
self._test_withdraw_ip(ips, ips_info, True)
|
||||
|
||||
def test__get_ls_localnet_info(self):
|
||||
logical_switch = 'lswitch1'
|
||||
fake_localnet_port = fakes.create_object({
|
||||
@ -686,3 +758,214 @@ class TestNBOVNBGPDriver(test_base.TestCase):
|
||||
|
||||
self.nb_bgp_driver.withdraw_fip(ip, row)
|
||||
mock_withdraw_provider_port.assert_not_called()
|
||||
|
||||
def test_expose_subnet(self):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'router1',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_expose_router_lsp = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_router_lsp').start()
|
||||
|
||||
self.nb_bgp_driver.expose_subnet(ips, subnet_info)
|
||||
mock_expose_router_lsp.assert_called_once_with(
|
||||
ips, subnet_info, self.router1_info)
|
||||
|
||||
def test_expose_subnet_no_router(self):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': None,
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_expose_router_lsp = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_router_lsp').start()
|
||||
|
||||
self.nb_bgp_driver.expose_subnet(ips, subnet_info)
|
||||
mock_expose_router_lsp.assert_not_called()
|
||||
|
||||
def test_expose_subnet_no_cr_lrp(self):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_expose_router_lsp = mock.patch.object(
|
||||
self.nb_bgp_driver, '_expose_router_lsp').start()
|
||||
|
||||
self.nb_bgp_driver.expose_subnet(ips, subnet_info)
|
||||
mock_expose_router_lsp.assert_not_called()
|
||||
|
||||
def test_withdraw_subnet(self):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'router1',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_withdraw_router_lsp = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_router_lsp').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_subnet(ips, subnet_info)
|
||||
mock_withdraw_router_lsp.assert_called_once_with(
|
||||
ips, subnet_info, self.router1_info)
|
||||
|
||||
def test_withdraw_subnet_no_router(self):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': None,
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_withdraw_router_lsp = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_router_lsp').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_subnet(ips, subnet_info)
|
||||
mock_withdraw_router_lsp.assert_not_called()
|
||||
|
||||
def test_withdraw_subnet_no_cr_lrp(self):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_withdraw_router_lsp = mock.patch.object(
|
||||
self.nb_bgp_driver, '_withdraw_router_lsp').start()
|
||||
|
||||
self.nb_bgp_driver.withdraw_subnet(ips, subnet_info)
|
||||
mock_withdraw_router_lsp.assert_not_called()
|
||||
|
||||
@mock.patch.object(wire_utils, 'wire_lrp_port')
|
||||
def test__expose_router_lsp(self, mock_wire):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
|
||||
ret = self.nb_bgp_driver._expose_router_lsp(ips, subnet_info,
|
||||
self.router1_info)
|
||||
|
||||
self.assertTrue(ret)
|
||||
mock_wire.assert_called_once_with(
|
||||
mock.ANY, ips[0], self.router1_info['bridge_device'],
|
||||
self.router1_info['bridge_vlan'], mock.ANY,
|
||||
self.router1_info['ips'])
|
||||
|
||||
@mock.patch.object(wire_utils, 'wire_lrp_port')
|
||||
def test__expose_router_lsp_exception(self, mock_wire):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_wire.side_effect = Exception
|
||||
|
||||
ret = self.nb_bgp_driver._expose_router_lsp(ips, subnet_info,
|
||||
self.router1_info)
|
||||
|
||||
self.assertFalse(ret)
|
||||
mock_wire.assert_called_once_with(
|
||||
mock.ANY, ips[0], self.router1_info['bridge_device'],
|
||||
self.router1_info['bridge_vlan'], mock.ANY,
|
||||
self.router1_info['ips'])
|
||||
|
||||
@mock.patch.object(wire_utils, 'wire_lrp_port')
|
||||
def test__expose_router_lsp_no_tenants(self, mock_wire):
|
||||
CONF.set_override('expose_tenant_networks', False)
|
||||
self.addCleanup(CONF.clear_override, 'expose_tenant_networks')
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
|
||||
ret = self.nb_bgp_driver._expose_router_lsp(ips, subnet_info,
|
||||
self.router1_info)
|
||||
|
||||
self.assertTrue(ret)
|
||||
mock_wire.assert_not_called()
|
||||
|
||||
@mock.patch.object(driver_utils, 'is_ipv6_gua')
|
||||
@mock.patch.object(wire_utils, 'wire_lrp_port')
|
||||
def test__expose_router_lsp_no_tenants_but_gua(self, mock_wire, mock_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 = ['10.0.0.1/24', '2002::1/64']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_gua.side_effect = [False, True]
|
||||
|
||||
ret = self.nb_bgp_driver._expose_router_lsp(ips, subnet_info,
|
||||
self.router1_info)
|
||||
|
||||
self.assertTrue(ret)
|
||||
mock_wire.assert_called_once_with(
|
||||
mock.ANY, ips[1], self.router1_info['bridge_device'],
|
||||
self.router1_info['bridge_vlan'], mock.ANY,
|
||||
self.router1_info['ips'])
|
||||
|
||||
@mock.patch.object(wire_utils, 'unwire_lrp_port')
|
||||
def test__withdraw_router_lsp(self, mock_unwire):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
|
||||
ret = self.nb_bgp_driver._withdraw_router_lsp(ips, subnet_info,
|
||||
self.router1_info)
|
||||
|
||||
self.assertTrue(ret)
|
||||
mock_unwire.assert_called_once_with(
|
||||
mock.ANY, ips[0], self.router1_info['bridge_device'],
|
||||
self.router1_info['bridge_vlan'], mock.ANY,
|
||||
self.router1_info['ips'])
|
||||
|
||||
@mock.patch.object(wire_utils, 'unwire_lrp_port')
|
||||
def test__withdraw_router_lsp_exception(self, mock_unwire):
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_unwire.side_effect = Exception
|
||||
|
||||
ret = self.nb_bgp_driver._withdraw_router_lsp(ips, subnet_info,
|
||||
self.router1_info)
|
||||
|
||||
self.assertFalse(ret)
|
||||
mock_unwire.assert_called_once_with(
|
||||
mock.ANY, ips[0], self.router1_info['bridge_device'],
|
||||
self.router1_info['bridge_vlan'], mock.ANY,
|
||||
self.router1_info['ips'])
|
||||
|
||||
@mock.patch.object(wire_utils, 'unwire_lrp_port')
|
||||
def test__withdraw_router_lsp_no_tenants(self, mock_unwire):
|
||||
CONF.set_override('expose_tenant_networks', False)
|
||||
self.addCleanup(CONF.clear_override, 'expose_tenant_networks')
|
||||
ips = ['10.0.0.1/24']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
|
||||
ret = self.nb_bgp_driver._withdraw_router_lsp(ips, subnet_info,
|
||||
self.router1_info)
|
||||
|
||||
self.assertTrue(ret)
|
||||
mock_unwire.assert_not_called()
|
||||
|
||||
@mock.patch.object(driver_utils, 'is_ipv6_gua')
|
||||
@mock.patch.object(wire_utils, 'unwire_lrp_port')
|
||||
def test__withdraw_router_lsp_no_tenants_but_gua(self, mock_unwire,
|
||||
mock_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 = ['10.0.0.1/24', '2002::1/64']
|
||||
subnet_info = {
|
||||
'associated_router': 'other-router',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
mock_gua.side_effect = [False, True]
|
||||
|
||||
ret = self.nb_bgp_driver._withdraw_router_lsp(ips, subnet_info,
|
||||
self.router1_info)
|
||||
|
||||
self.assertTrue(ret)
|
||||
mock_unwire.assert_called_once_with(
|
||||
mock.ANY, ips[1], self.router1_info['bridge_device'],
|
||||
self.router1_info['bridge_vlan'], mock.ANY,
|
||||
self.router1_info['ips'])
|
||||
|
@ -150,6 +150,35 @@ class TestOvsdbNbOvnIdl(test_base.TestCase):
|
||||
self.nb_idl.db_list_rows.assert_called_once_with(
|
||||
'Logical_Router_Port')
|
||||
|
||||
def test_get_active_local_lrps(self):
|
||||
local_gateway_ports = ['router1']
|
||||
row1 = fakes.create_object({
|
||||
'external_ids': {
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
constants.OVN_ROUTER_INTERFACE,
|
||||
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,
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'other_router'
|
||||
}})
|
||||
|
||||
self.nb_idl.db_find_rows.return_value.execute.return_value = [
|
||||
row1, row2, row3]
|
||||
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))
|
||||
|
||||
|
||||
class TestOvsdbSbOvnIdl(test_base.TestCase):
|
||||
|
||||
|
@ -21,6 +21,7 @@ from ovn_bgp_agent import constants
|
||||
from ovn_bgp_agent.drivers.openstack.utils import ovn as ovn_utils
|
||||
from ovn_bgp_agent.drivers.openstack.utils import ovs as ovs_utils
|
||||
from ovn_bgp_agent.drivers.openstack.utils import wire
|
||||
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
|
||||
|
||||
@ -453,3 +454,146 @@ class TestWire(test_base.TestCase):
|
||||
port_ips = []
|
||||
wire._unwire_provider_port_ovn(self.nb_idl, port_ips)
|
||||
m_cmds.assert_not_called()
|
||||
|
||||
@mock.patch.object(wire, '_wire_lrp_port_underlay')
|
||||
def test_wire_lrp_port_underlay(self, mock_underlay):
|
||||
routing_tables_routes = {}
|
||||
ip = 'fake-ip'
|
||||
bridge_device = 'fake-bridge'
|
||||
bridge_vlan = '101'
|
||||
routing_tables = {'fake-bridge': 5}
|
||||
cr_lrp_ips = ['fake-crlrp-ip']
|
||||
|
||||
wire.wire_lrp_port(routing_tables_routes, ip, bridge_device,
|
||||
bridge_vlan, routing_tables, cr_lrp_ips)
|
||||
mock_underlay.assert_called_once_with(
|
||||
routing_tables_routes, ip, bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
|
||||
@mock.patch.object(wire, '_unwire_lrp_port_underlay')
|
||||
def test_unwire_lrp_port_underlay(self, mock_underlay):
|
||||
routing_tables_routes = {}
|
||||
ip = 'fake-ip'
|
||||
bridge_device = 'fake-bridge'
|
||||
bridge_vlan = '101'
|
||||
routing_tables = {'fake-bridge': 5}
|
||||
cr_lrp_ips = ['fake-crlrp-ip']
|
||||
|
||||
wire.unwire_lrp_port(routing_tables_routes, ip, bridge_device,
|
||||
bridge_vlan, routing_tables, cr_lrp_ips)
|
||||
mock_underlay.assert_called_once_with(
|
||||
routing_tables_routes, ip, bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
|
||||
@mock.patch.object(linux_net, 'add_ip_route')
|
||||
@mock.patch.object(linux_net, 'get_ip_version')
|
||||
@mock.patch.object(linux_net, 'add_ip_rule')
|
||||
def test__wire_lrp_port_underlay(self, m_ip_rule, m_ip_version,
|
||||
m_ip_route):
|
||||
routing_tables_routes = {}
|
||||
ip = '10.0.0.1/24'
|
||||
bridge_device = 'fake-bridge'
|
||||
bridge_vlan = '101'
|
||||
routing_tables = {'fake-bridge': 5}
|
||||
cr_lrp_ips = ['fake-crlrp-ip']
|
||||
|
||||
ret = wire._wire_lrp_port_underlay(routing_tables_routes, ip,
|
||||
bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
self.assertTrue(ret)
|
||||
m_ip_rule.assert_called_once_with(ip, 5)
|
||||
m_ip_route.assert_called_once_with(
|
||||
routing_tables_routes, '10.0.0.1', 5, 'fake-bridge',
|
||||
vlan='101', mask='24', via='fake-crlrp-ip')
|
||||
|
||||
@mock.patch.object(linux_net, 'add_ip_rule')
|
||||
def test__wire_lrp_port_underlay_no_bridge(self, m_ip_rule):
|
||||
routing_tables_routes = {}
|
||||
ip = 'fake-ip'
|
||||
bridge_device = None
|
||||
bridge_vlan = None
|
||||
routing_tables = {'fake-bridge': 5}
|
||||
cr_lrp_ips = ['fake-crlrp-ip']
|
||||
|
||||
ret = wire._wire_lrp_port_underlay(routing_tables_routes, ip,
|
||||
bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
|
||||
self.assertFalse(ret)
|
||||
m_ip_rule.assert_not_called()
|
||||
|
||||
@mock.patch.object(linux_net, 'get_ip_version')
|
||||
@mock.patch.object(linux_net, 'add_ip_rule')
|
||||
def test__wire_lrp_port_underlay_invalid_ip(self, m_ip_rule, m_ip_version):
|
||||
routing_tables_routes = {}
|
||||
ip = 'fake-ip'
|
||||
bridge_device = 'fake-bridge'
|
||||
bridge_vlan = '101'
|
||||
routing_tables = {'fake-bridge': 5}
|
||||
cr_lrp_ips = ['fake-crlrp-ip']
|
||||
m_ip_rule.side_effect = agent_exc.InvalidPortIP(ip=ip)
|
||||
|
||||
ret = wire._wire_lrp_port_underlay(routing_tables_routes, ip,
|
||||
bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
|
||||
self.assertFalse(ret)
|
||||
m_ip_rule.assert_called_once_with(ip, 5)
|
||||
m_ip_version.assert_not_called()
|
||||
|
||||
@mock.patch.object(linux_net, 'del_ip_route')
|
||||
@mock.patch.object(linux_net, 'get_ip_version')
|
||||
@mock.patch.object(linux_net, 'del_ip_rule')
|
||||
def test__unwire_lrp_port_underlay(self, m_ip_rule, m_ip_version,
|
||||
m_ip_route):
|
||||
routing_tables_routes = {}
|
||||
ip = '10.0.0.1/24'
|
||||
bridge_device = 'fake-bridge'
|
||||
bridge_vlan = '101'
|
||||
routing_tables = {'fake-bridge': 5}
|
||||
cr_lrp_ips = ['fake-crlrp-ip']
|
||||
|
||||
ret = wire._unwire_lrp_port_underlay(routing_tables_routes, ip,
|
||||
bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
self.assertTrue(ret)
|
||||
m_ip_rule.assert_called_once_with(ip, 5)
|
||||
m_ip_route.assert_called_once_with(
|
||||
routing_tables_routes, '10.0.0.1', 5, 'fake-bridge',
|
||||
vlan='101', mask='24', via='fake-crlrp-ip')
|
||||
|
||||
@mock.patch.object(linux_net, 'del_ip_rule')
|
||||
def test__unwire_lrp_port_underlay_no_bridge(self, m_ip_rule):
|
||||
routing_tables_routes = {}
|
||||
ip = 'fake-ip'
|
||||
bridge_device = None
|
||||
bridge_vlan = None
|
||||
routing_tables = {'fake-bridge': 5}
|
||||
cr_lrp_ips = ['fake-crlrp-ip']
|
||||
|
||||
ret = wire._unwire_lrp_port_underlay(routing_tables_routes, ip,
|
||||
bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
|
||||
self.assertFalse(ret)
|
||||
m_ip_rule.assert_not_called()
|
||||
|
||||
@mock.patch.object(linux_net, 'get_ip_version')
|
||||
@mock.patch.object(linux_net, 'del_ip_rule')
|
||||
def test__unwire_lrp_port_underlay_invalid_ip(self, m_ip_rule,
|
||||
m_ip_version):
|
||||
routing_tables_routes = {}
|
||||
ip = 'fake-ip'
|
||||
bridge_device = 'fake-bridge'
|
||||
bridge_vlan = '101'
|
||||
routing_tables = {'fake-bridge': 5}
|
||||
cr_lrp_ips = ['fake-crlrp-ip']
|
||||
m_ip_rule.side_effect = agent_exc.InvalidPortIP(ip=ip)
|
||||
|
||||
ret = wire._unwire_lrp_port_underlay(routing_tables_routes, ip,
|
||||
bridge_device, bridge_vlan,
|
||||
routing_tables, cr_lrp_ips)
|
||||
|
||||
self.assertFalse(ret)
|
||||
m_ip_rule.assert_called_once_with(ip, 5)
|
||||
m_ip_version.assert_not_called()
|
||||
|
@ -95,9 +95,9 @@ class TestLogicalSwitchPortProviderCreateEvent(test_base.TestCase):
|
||||
up=[True])
|
||||
ips_info = {
|
||||
'mac': 'mac',
|
||||
'cidrs': [None],
|
||||
'cidrs': [],
|
||||
'type': constants.OVN_VM_VIF_PORT_TYPE,
|
||||
'logical_switch': 'test-ls'
|
||||
'logical_switch': 'test-ls',
|
||||
}
|
||||
self.event.run(mock.Mock(), row, mock.Mock())
|
||||
self.agent.expose_ip.assert_called_once_with(['192.168.0.1'], ips_info)
|
||||
@ -188,7 +188,7 @@ class TestLogicalSwitchPortProviderDeleteEvent(test_base.TestCase):
|
||||
up=[True])
|
||||
ips_info = {
|
||||
'mac': 'mac',
|
||||
'cidrs': [None],
|
||||
'cidrs': [],
|
||||
'type': constants.OVN_VM_VIF_PORT_TYPE,
|
||||
'logical_switch': 'test-ls'
|
||||
}
|
||||
@ -550,7 +550,8 @@ class TestChassisRedirectCreateEvent(test_base.TestCase):
|
||||
ips_info = {'mac': 'fake-mac',
|
||||
'cidrs': ['192.168.0.2/24'],
|
||||
'type': constants.OVN_CR_LRP_PORT_TYPE,
|
||||
'logical_switch': 'test-ls'}
|
||||
'logical_switch': 'test-ls',
|
||||
'router': None}
|
||||
self.event.run(None, row, None)
|
||||
self.agent.expose_ip.assert_called_once_with(['192.168.0.2'], ips_info)
|
||||
|
||||
@ -622,7 +623,8 @@ class TestChassisRedirectDeleteEvent(test_base.TestCase):
|
||||
ips_info = {'mac': 'fake-mac',
|
||||
'cidrs': ['192.168.0.2/24'],
|
||||
'type': constants.OVN_CR_LRP_PORT_TYPE,
|
||||
'logical_switch': 'test-ls'}
|
||||
'logical_switch': 'test-ls',
|
||||
'router': None}
|
||||
self.event.run(None, row, None)
|
||||
self.agent.withdraw_ip.assert_called_once_with(['192.168.0.2'],
|
||||
ips_info)
|
||||
@ -635,3 +637,279 @@ class TestChassisRedirectDeleteEvent(test_base.TestCase):
|
||||
external_ids={constants.OVN_LS_NAME_EXT_ID_KEY: 'test-ls'})
|
||||
self.event.run(None, row, None)
|
||||
self.agent.withdraw_ip.assert_not_called()
|
||||
|
||||
|
||||
class TestLogicalSwitchPortSubnetAttachEvent(test_base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestLogicalSwitchPortSubnetAttachEvent, 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_cr_lrps = {
|
||||
'router1': {'bridge_device': 'br-ex',
|
||||
'bridge_vlan': None,
|
||||
'ips': ['172.24.16.2']}}
|
||||
self.event = nb_bgp_watcher.LogicalSwitchPortSubnetAttachEvent(
|
||||
self.agent)
|
||||
|
||||
def test_match_fn(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
old = utils.create_row(up=[False])
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_associate_router(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
old = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface'})
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_exception(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
|
||||
|
||||
def test_match_fn_wrong_type(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_VM_VIF_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
|
||||
|
||||
def test_match_fn_wrong_device_owner(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_gateway',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
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_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[False])
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
|
||||
|
||||
def test_match_fn_not_local_crlrp(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router2'},
|
||||
up=[True])
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
|
||||
|
||||
def test_run(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
subnet_info = {
|
||||
'associated_router': 'router1',
|
||||
'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):
|
||||
def setUp(self):
|
||||
super(TestLogicalSwitchPortSubnetDetachEventt, 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_cr_lrps = {
|
||||
'router1': {'bridge_device': 'br-ex',
|
||||
'bridge_vlan': None,
|
||||
'ips': ['172.24.16.2']}}
|
||||
self.event = nb_bgp_watcher.LogicalSwitchPortSubnetDetachEvent(
|
||||
self.agent)
|
||||
|
||||
def test_match_fn(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
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_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
self.assertTrue(self.event.match_fn(event, row, mock.Mock()))
|
||||
|
||||
def test_match_fn_delete_down(self):
|
||||
event = self.event.ROW_DELETE
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[False])
|
||||
self.assertFalse(self.event.match_fn(event, row, mock.Mock()))
|
||||
|
||||
def test_match_fn_disassociate_router(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface'},
|
||||
up=[True])
|
||||
old = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'})
|
||||
self.assertTrue(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_exception(self):
|
||||
row = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
|
||||
|
||||
def test_match_fn_wrong_type(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_VM_VIF_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, mock.Mock()))
|
||||
|
||||
def test_match_fn_wrong_device_owner(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_gateway',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
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_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
old = utils.create_row(up=[False])
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_match_fn_not_local_crlrp(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface'},
|
||||
up=[True])
|
||||
old = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'other_router'})
|
||||
self.assertFalse(self.event.match_fn(mock.Mock(), row, old))
|
||||
|
||||
def test_run(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface'},
|
||||
up=[True])
|
||||
old = utils.create_row(
|
||||
external_ids={
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'})
|
||||
subnet_info = {
|
||||
'associated_router': 'router1',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
self.event.run(None, row, old)
|
||||
self.agent.withdraw_subnet.assert_called_once_with(
|
||||
["192.168.24.1/24"], subnet_info)
|
||||
|
||||
def test_run_no_old_external_ids(self):
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
old = utils.create_row()
|
||||
subnet_info = {
|
||||
'associated_router': 'router1',
|
||||
'address_scopes': {4: None, 6: None}}
|
||||
self.event.run(None, row, old)
|
||||
self.agent.withdraw_subnet.assert_called_once_with(
|
||||
["192.168.24.1/24"], subnet_info)
|
||||
|
||||
def test_run_delete(self):
|
||||
event = self.event.ROW_DELETE
|
||||
row = utils.create_row(
|
||||
type=constants.OVN_ROUTER_PORT_TYPE,
|
||||
external_ids={
|
||||
constants.OVN_CIDRS_EXT_ID_KEY: "192.168.24.1/24",
|
||||
constants.OVN_DEVICE_OWNER_EXT_ID_KEY:
|
||||
'network:router_interface',
|
||||
constants.OVN_DEVICE_ID_EXT_ID_KEY: 'router1'},
|
||||
up=[True])
|
||||
subnet_info = {
|
||||
'associated_router': 'router1',
|
||||
'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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user