Rodolfo Alonso Hernandez 1cbfe7823c Add new privileged method implementations
This patch add the following new privileged methods implementations:
* create_interface: this method will be used to create dummy, vlan,
  vxlan, bridge and vrf interfaces.
* delete_interface: to delete a interface
* set_link_attribute: to set UP the interface
* add_ip_address: to add an IP address on a interface
* delete_ip_address: to delete an IP address on a interface
* set_master_for_device: defines a master device for a second one

These new method use pyroute2 IPRoute class, replacing the use of the
NDB class.

This patch is creating the functional test framework, in order to
test these new methods.

This patch is also adding a new CI job to the gate (to be defined).

Partial-Bug: #2022357
Change-Id: I40d70829bfccb2df98b822afacbdab7da5a5ab7f
2023-06-15 12:12:08 +02:00

738 lines
27 KiB
Python

# Copyright 2021 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import ipaddress
import random
import re
import sys
from socket import AF_INET
from socket import AF_INET6
from oslo_log import log as logging
import pyroute2
from pyroute2.netlink import exceptions as netlink_exceptions
import tenacity
from ovn_bgp_agent import constants
from ovn_bgp_agent import exceptions as agent_exc
import ovn_bgp_agent.privileged.linux_net
LOG = logging.getLogger(__name__)
def get_ip_version(ip):
return ipaddress.ip_address(ip.split('/')[0]).version
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def get_interfaces(filter_out=[]):
with pyroute2.NDB() as ndb:
return [iface.ifname for iface in ndb.interfaces
if iface.ifname not in filter_out]
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def get_interface_index(nic):
with pyroute2.NDB() as ndb:
return ndb.interfaces[nic]['index']
def ensure_vrf(vrf_name, vrf_table):
ovn_bgp_agent.privileged.linux_net.ensure_vrf(vrf_name, vrf_table)
def ensure_bridge(bridge_name):
ovn_bgp_agent.privileged.linux_net.ensure_bridge(bridge_name)
def ensure_vxlan(vxlan_name, vni, local_ip, dstport):
ovn_bgp_agent.privileged.linux_net.ensure_vxlan(vxlan_name, vni, local_ip,
dstport)
def ensure_veth(veth_name, veth_peer):
ovn_bgp_agent.privileged.linux_net.ensure_veth(veth_name, veth_peer)
def set_master_for_device(device, master):
ovn_bgp_agent.privileged.linux_net.set_master_for_device(device, master)
def ensure_dummy_device(device):
ovn_bgp_agent.privileged.linux_net.ensure_dummy_device(device)
def ensure_ovn_device(ovn_ifname, vrf_name):
ensure_dummy_device(ovn_ifname)
set_master_for_device(ovn_ifname, vrf_name)
def delete_device(device):
ovn_bgp_agent.privileged.linux_net.delete_device(device)
def ensure_arp_ndp_enabled_for_bridge(bridge, offset, vlan_tag=None):
ipv4 = constants.ARP_IPV4_PREFIX + str(int(offset / 256)) + "." + str(
offset % 256)
ipv6 = constants.NDP_IPV6_PREFIX + "%x" % offset
try:
ovn_bgp_agent.privileged.linux_net.add_ip_to_dev(ipv4, bridge)
except agent_exc.IpAddressAlreadyExists:
LOG.debug("IP %s already added on bridge %s", ipv4, bridge)
except KeyError as e:
if "object exists" not in str(e):
LOG.error("Unable to add IP on bridge %s to enable arp/ndp. "
"Exception: %s", bridge, e)
raise
try:
ovn_bgp_agent.privileged.linux_net.add_ip_to_dev(ipv6, bridge)
except agent_exc.IpAddressAlreadyExists:
LOG.debug("IP %s already added on bridge %s", ipv6, bridge)
except KeyError as e:
if "object exists" not in str(e):
LOG.error("Unable to add IP on bridge %s to enable arp/ndp. "
"Exception: %s", bridge, e)
raise
if not vlan_tag:
enable_proxy_arp(bridge)
enable_proxy_ndp(bridge)
def ensure_routing_table_for_bridge(ovn_routing_tables, bridge, vrf_table):
# check a routing table with the bridge name exists on
# /etc/iproute2/rt_tables
regex = r'^[0-9]*[\s]*{}$'.format(bridge)
matching_table = [line.replace('\t', ' ')
for line in open('/etc/iproute2/rt_tables')
if re.findall(regex, line)]
if matching_table:
table_info = matching_table[0].strip().split()
ovn_routing_tables[table_info[1]] = int(table_info[0])
LOG.debug("Found routing table for %s with: %s", bridge,
table_info)
# if not configured, add random number for the table
else:
LOG.debug("Routing table for bridge %s not configured "
"at /etc/iproute2/rt_tables", bridge)
regex = r'^[0-9]+[\s]*'
existing_routes = [int(line.replace('\t', ' ').split(' ')[0])
for line in open('/etc/iproute2/rt_tables')
if re.findall(regex, line)]
# pick a number between 1 and 252
try:
table_number = random.choice(list(
set([x for x in range(1, 253)
if x != int(vrf_table)]).difference(
set(existing_routes))))
except IndexError:
LOG.error("No more routing tables available for bridge %s "
"at /etc/iproute2/rt_tables", bridge)
sys.exit()
ovn_bgp_agent.privileged.linux_net.create_routing_table_for_bridge(
table_number, bridge)
ovn_routing_tables[bridge] = int(table_number)
LOG.debug("Added routing table for %s with number: %s", bridge,
table_number)
return _ensure_routing_table_routes(ovn_routing_tables, bridge)
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def _ensure_routing_table_routes(ovn_routing_tables, bridge):
# add default route on that table if it does not exist
extra_routes = []
with pyroute2.NDB() as ndb:
table_route_dsts = set(
[
(r.dst, r.dst_len)
for r in ndb.routes.summary().filter(
table=ovn_routing_tables[bridge]
)
]
)
if not table_route_dsts:
r1 = {'dst': 'default', 'oif': ndb.interfaces[bridge]['index'],
'table': ovn_routing_tables[bridge], 'scope': 253,
'proto': 3}
ovn_bgp_agent.privileged.linux_net.route_create(r1)
r2 = {'dst': 'default', 'oif': ndb.interfaces[bridge]['index'],
'table': ovn_routing_tables[bridge], 'family': AF_INET6,
'proto': 3}
ovn_bgp_agent.privileged.linux_net.route_create(r2)
else:
route_missing = True
route6_missing = True
for (dst, dst_len) in table_route_dsts:
if not dst: # default route
try:
route = ndb.routes[
{'table': ovn_routing_tables[bridge],
'dst': '',
'family': AF_INET}]
if (bridge ==
ndb.interfaces[{'index': route['oif']}][
'ifname']):
route_missing = False
else:
extra_routes.append(route)
except KeyError:
pass # no ipv4 default rule
try:
route_6 = ndb.routes[
{'table': ovn_routing_tables[bridge],
'dst': '',
'family': AF_INET6}]
if (bridge ==
ndb.interfaces[{'index': route_6['oif']}][
'ifname']):
route6_missing = False
else:
extra_routes.append(route_6)
except KeyError:
pass # no ipv6 default rule
else:
if get_ip_version(dst) == constants.IP_VERSION_6:
extra_routes.append(
ndb.routes[{'table': ovn_routing_tables[bridge],
'dst': dst,
'dst_len': dst_len,
'family': AF_INET6}]
)
else:
extra_routes.append(
ndb.routes[{'table': ovn_routing_tables[bridge],
'dst': dst,
'dst_len': dst_len,
'family': AF_INET}]
)
if route_missing:
r = {'dst': 'default', 'oif': ndb.interfaces[bridge]['index'],
'table': ovn_routing_tables[bridge], 'scope': 253,
'proto': 3}
ovn_bgp_agent.privileged.linux_net.route_create(r)
if route6_missing:
r = {'dst': 'default', 'oif': ndb.interfaces[bridge]['index'],
'table': ovn_routing_tables[bridge], 'family': AF_INET6,
'proto': 3}
ovn_bgp_agent.privileged.linux_net.route_create(r)
return extra_routes
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def get_extra_routing_table_for_bridge(ovn_routing_tables, bridge):
extra_routes = []
with pyroute2.NDB() as ndb:
table_route_dsts = set(
[
(r.dst, r.dst_len)
for r in ndb.routes.summary().filter(
table=ovn_routing_tables[bridge]
)
]
)
if not table_route_dsts:
return extra_routes
for (dst, dst_len) in table_route_dsts:
if not dst: # default route
try:
route = ndb.routes[
{'table': ovn_routing_tables[bridge],
'dst': '',
'family': AF_INET}]
if (bridge != ndb.interfaces[{'index': route['oif']}][
'ifname']):
extra_routes.append(route)
except KeyError:
pass # no ipv4 default rule
try:
route_6 = ndb.routes[
{'table': ovn_routing_tables[bridge],
'dst': '',
'family': AF_INET6}]
if (bridge != ndb.interfaces[{'index': route_6['oif']}][
'ifname']):
extra_routes.append(route_6)
except KeyError:
pass # no ipv6 default rule
else:
if get_ip_version(dst) == constants.IP_VERSION_6:
extra_routes.append(
ndb.routes[{'table': ovn_routing_tables[bridge],
'dst': dst,
'dst_len': dst_len,
'family': AF_INET6}]
)
else:
extra_routes.append(
ndb.routes[{'table': ovn_routing_tables[bridge],
'dst': dst,
'dst_len': dst_len,
'family': AF_INET}]
)
return extra_routes
def ensure_vlan_device_for_network(bridge, vlan_tag):
ovn_bgp_agent.privileged.linux_net.ensure_vlan_device_for_network(bridge,
vlan_tag)
device = "{}/{}".format(bridge, vlan_tag)
enable_proxy_arp(device)
enable_proxy_ndp(device)
def delete_vlan_device_for_network(bridge, vlan_tag):
vlan_device_name = '{}.{}'.format(bridge, vlan_tag)
delete_device(vlan_device_name)
def enable_proxy_ndp(device):
flag = "net.ipv6.conf.{}.proxy_ndp".format(device)
ovn_bgp_agent.privileged.linux_net.set_kernel_flag(flag, 1)
def enable_proxy_arp(device):
flag = "net.ipv4.conf.{}.proxy_arp".format(device)
ovn_bgp_agent.privileged.linux_net.set_kernel_flag(flag, 1)
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def get_exposed_ips(nic):
exposed_ips = []
with pyroute2.NDB() as ndb:
exposed_ips = [ip.address
for ip in ndb.interfaces[nic].ipaddr.summary()
if ip.prefixlen == 32 or ip.prefixlen == 128]
return exposed_ips
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def get_nic_ip(nic, prefixlen_filter=None):
exposed_ips = []
with pyroute2.NDB() as ndb:
if prefixlen_filter:
exposed_ips = [ip.address
for ip in ndb.interfaces[nic].ipaddr.summary(
).filter(prefixlen=prefixlen_filter)]
else:
exposed_ips = [ip.address
for ip in ndb.interfaces[nic].ipaddr.summary()]
return exposed_ips
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def get_exposed_ips_on_network(nic, network):
exposed_ips = []
with pyroute2.NDB() as ndb:
try:
exposed_ips = [ip.address
for ip in ndb.interfaces[nic].ipaddr.summary()
if ((ip.prefixlen == 32 or ip.prefixlen == 128) and
ipaddress.ip_address(ip.address) in network)]
except KeyError:
# Nic does not exists
LOG.debug("Nic %s does not yet exists, so it does not have "
"exposed IPs", nic)
return exposed_ips
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def get_exposed_routes_on_network(table_ids, network):
with pyroute2.NDB() as ndb:
# NOTE: skip bgp routes (proto 186)
return [
r
for r in ndb.routes.dump()
if r.table in table_ids and
r.dst != "" and
r.gateway is not None and
r.proto != 186 and
ipaddress.ip_address(r.gateway) in network
]
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def get_ovn_ip_rules(routing_table):
# get the rules pointing to ovn bridges
ovn_ip_rules = {}
with pyroute2.NDB() as ndb:
rules_info = [(rule.table,
"{}/{}".format(rule.dst, rule.dst_len),
rule.family) for rule in ndb.rules.dump()
if rule.table in routing_table]
for table, dst, family in rules_info:
ovn_ip_rules[dst] = {'table': table, 'family': family}
return ovn_ip_rules
def delete_exposed_ips(ips, nic):
ovn_bgp_agent.privileged.linux_net.delete_exposed_ips(ips, nic)
def delete_ip_rules(ip_rules):
ovn_bgp_agent.privileged.linux_net.delete_ip_rules(ip_rules)
def delete_bridge_ip_routes(routing_tables, routing_tables_routes,
extra_routes):
with pyroute2.NDB() as ndb:
for device, routes_info in routing_tables_routes.items():
if not extra_routes.get(device):
continue
for route_info in routes_info:
oif = ndb.interfaces[device]['index']
if route_info['vlan']:
vlan_device_name = '{}.{}'.format(device,
route_info['vlan'])
oif = ndb.interfaces[vlan_device_name]['index']
if 'gateway' in route_info['route'].keys(): # subnet route
possible_matchings = [
r for r in extra_routes[device]
if (r['dst'] == route_info['route']['dst'] and
r['dst_len'] == route_info['route']['dst_len'] and
r['gateway'] == route_info['route']['gateway'])]
else: # cr-lrp
possible_matchings = [
r for r in extra_routes[device]
if (r['dst'] == route_info['route']['dst'] and
r['dst_len'] == route_info['route']['dst_len'] and
r['oif'] == oif)]
for r in possible_matchings:
extra_routes[device].remove(r)
for bridge, routes in extra_routes.items():
for route in routes:
r_info = {'dst': route['dst'],
'dst_len': route['dst_len'],
'family': route['family'],
'oif': route['oif'],
'gateway': route['gateway'],
'table': routing_tables[bridge]}
ovn_bgp_agent.privileged.linux_net.route_delete(r_info)
def delete_routes_from_table(table):
table_routes = _get_table_routes(table)
delete_ip_routes(table_routes)
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def _get_table_routes(table):
with pyroute2.NDB() as ndb:
# FIXME: problem in pyroute2 removing routes with local (254) scope
return [r for r in ndb.routes.dump().filter(table=table)
if r.scope != 254 and r.proto != 186]
@tenacity.retry(
retry=tenacity.retry_if_exception_type(
netlink_exceptions.NetlinkDumpInterrupted),
wait=tenacity.wait_exponential(multiplier=0.02, max=1),
stop=tenacity.stop_after_delay(8),
reraise=True)
def get_routes_on_tables(table_ids):
with pyroute2.NDB() as ndb:
# NOTE: skip bgp routes (proto 186)
return [r for r in ndb.routes.dump()
if r.table in table_ids and r.dst != '' and r.proto != 186]
def delete_ip_routes(routes):
for route in routes:
r_info = {'dst': route['dst'],
'dst_len': route['dst_len'],
'family': route['family'],
'oif': route['oif'],
'gateway': route['gateway'],
'table': route['table']}
ovn_bgp_agent.privileged.linux_net.route_delete(r_info)
def add_ndp_proxy(ip, dev, vlan=None):
ovn_bgp_agent.privileged.linux_net.add_ndp_proxy(ip, dev, vlan)
def del_ndp_proxy(ip, dev, vlan=None):
ovn_bgp_agent.privileged.linux_net.del_ndp_proxy(ip, dev, vlan)
def add_ips_to_dev(nic, ips, clear_local_route_at_table=False):
already_added_ips = []
for ip in ips:
try:
ovn_bgp_agent.privileged.linux_net.add_ip_to_dev(ip, nic)
except agent_exc.IpAddressAlreadyExists:
# NDB raises KeyError: 'object exists'
# if the ip is already added
already_added_ips.append(ip)
if clear_local_route_at_table:
for ip in ips:
if ip in already_added_ips:
continue
with pyroute2.NDB() as ndb:
oif = ndb.interfaces[nic]['index']
route = {'table': clear_local_route_at_table,
'proto': 2,
'scope': 254,
'dst': ip,
'oif': oif}
ovn_bgp_agent.privileged.linux_net.route_delete(route)
def del_ips_from_dev(nic, ips):
for ip in ips:
ovn_bgp_agent.privileged.linux_net.del_ip_from_dev(ip, nic)
def add_ip_rule(ip, table, dev=None, lladdr=None):
ip_version = get_ip_version(ip)
ip_info = ip.split("/")
if len(ip_info) == 1:
rule = {'dst': ip_info[0], 'table': table, 'dst_len': 32}
if ip_version == constants.IP_VERSION_6:
rule['dst_len'] = 128
rule['family'] = AF_INET6
elif len(ip_info) == 2:
rule = {'dst': ip_info[0], 'table': table, 'dst_len': int(ip_info[1])}
if ip_version == constants.IP_VERSION_6:
rule['family'] = AF_INET6
else:
raise agent_exc.InvalidPortIP(ip=ip)
ovn_bgp_agent.privileged.linux_net.rule_create(rule)
if lladdr:
add_ip_nei(ip, lladdr, dev)
def add_ip_nei(ip, lladdr, dev):
"""Add ip neighbor permament entry
param ip: IP of the neighbor to add an entry for
param lladdr: link layer address of the neighbor to associate to that IP
param dev: the interface to which the neighbor is attached
"""
# FIXME: There is no support for creating neighbours in NDB
# So we are using iproute here
ovn_bgp_agent.privileged.linux_net.add_ip_nei(ip, lladdr, dev)
def del_ip_rule(ip, table, dev=None, lladdr=None):
ip_version = get_ip_version(ip)
ip_info = ip.split("/")
if len(ip_info) == 1:
rule = {'dst': ip_info[0], 'table': table, 'dst_len': 32}
if ip_version == constants.IP_VERSION_6:
rule['dst_len'] = 128
rule['family'] = AF_INET6
elif len(ip_info) == 2:
rule = {'dst': ip_info[0], 'table': table, 'dst_len': int(ip_info[1])}
if ip_version == constants.IP_VERSION_6:
rule['family'] = AF_INET6
else:
raise agent_exc.InvalidPortIP(ip=ip)
ovn_bgp_agent.privileged.linux_net.rule_delete(rule)
if lladdr:
del_ip_nei(ip, lladdr, dev)
def del_ip_nei(ip, lladdr, dev):
"""Del ip neighbor permament entry
param ip: IP of the neighbor to delete the entry
param lladdr: link layer address of the neighbor to disassociate
param dev: the interface to which the neighbor is attached
"""
# FIXME: There is no support for deleting neighbours in NDB
# So we are using iproute here
ovn_bgp_agent.privileged.linux_net.del_ip_nei(ip, lladdr, dev)
def add_unreachable_route(vrf_name):
ovn_bgp_agent.privileged.linux_net.add_unreachable_route(vrf_name)
def add_ip_route(ovn_routing_tables_routes, ip_address, route_table, dev,
vlan=None, mask=None, via=None):
net_ip = ip_address
if not mask: # default /32 or /128
if get_ip_version(ip_address) == constants.IP_VERSION_6:
mask = 128
else:
mask = 32
else:
ip = '{}/{}'.format(ip_address, mask)
if get_ip_version(ip_address) == constants.IP_VERSION_6:
net_ip = '{}'.format(ipaddress.IPv6Network(
ip, strict=False).network_address)
else:
net_ip = '{}'.format(ipaddress.IPv4Network(
ip, strict=False).network_address)
with pyroute2.NDB() as ndb:
if vlan:
oif_name = '{}.{}'.format(dev, vlan)
try:
oif = ndb.interfaces[oif_name]['index']
except KeyError:
# Most provider network was recently created an
# there has not been a sync since then, therefore
# the vlan device has not yet been created
# Trying to create the device and retrying
ensure_vlan_device_for_network(dev, vlan)
oif = ndb.interfaces[oif_name]['index']
else:
oif = ndb.interfaces[dev]['index']
route = {'dst': net_ip, 'dst_len': int(mask), 'oif': oif,
'table': int(route_table), 'proto': 3}
if via:
route['gateway'] = via
route['scope'] = 0
else:
route['scope'] = 253
if get_ip_version(net_ip) == constants.IP_VERSION_6:
route['family'] = AF_INET6
del route['scope']
with pyroute2.NDB() as ndb:
try:
with ndb.routes[route]:
LOG.debug("Route already existing: %s", route)
except KeyError:
LOG.debug("Creating route at table %s: %s", route_table, route)
ovn_bgp_agent.privileged.linux_net.route_create(route)
LOG.debug("Route created at table %s: %s", route_table, route)
route_info = {'vlan': vlan, 'route': route}
ovn_routing_tables_routes.setdefault(dev, []).append(route_info)
def del_ip_route(ovn_routing_tables_routes, ip_address, route_table, dev,
vlan=None, mask=None, via=None):
net_ip = ip_address
if not mask: # default /32 or /128
if get_ip_version(ip_address) == constants.IP_VERSION_6:
mask = 128
else:
mask = 32
else:
ip = '{}/{}'.format(ip_address, mask)
if get_ip_version(ip_address) == constants.IP_VERSION_6:
net_ip = '{}'.format(ipaddress.IPv6Network(
ip, strict=False).network_address)
else:
net_ip = '{}'.format(ipaddress.IPv4Network(
ip, strict=False).network_address)
with pyroute2.NDB() as ndb:
try:
if vlan:
oif_name = '{}.{}'.format(dev, vlan)
oif = ndb.interfaces[oif_name]['index']
else:
oif = ndb.interfaces[dev]['index']
except KeyError:
LOG.debug("Device %s does not exists, so the associated "
"routes should have been automatically deleted.", dev)
ovn_routing_tables_routes.pop(dev, None)
return
route = {'dst': net_ip, 'dst_len': int(mask), 'oif': oif,
'table': int(route_table), 'proto': 3}
if via:
route['gateway'] = via
route['scope'] = 0
else:
route['scope'] = 253
if get_ip_version(net_ip) == constants.IP_VERSION_6:
route['family'] = AF_INET6
del route['scope']
LOG.debug("Deleting route at table %s: %s", route_table, route)
ovn_bgp_agent.privileged.linux_net.route_delete(route)
LOG.debug("Route deleted at table %s: %s", route_table, route)
route_info = {'vlan': vlan, 'route': route}
if route_info in ovn_routing_tables_routes.get(dev, []):
ovn_routing_tables_routes[dev].remove(route_info)
def set_device_status(device, status, ndb=None):
ovn_bgp_agent.privileged.linux_net.set_device_status(
device, status, ndb=ndb)