Add privsep support
Change-Id: Iab2cb051807cbfa52f43604c93905a8d15158d44
This commit is contained in:
parent
496755d3a2
commit
05e3d1bff4
@ -15,10 +15,10 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
from oslo_concurrency import processutils
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from ovn_bgp_agent import constants
|
from ovn_bgp_agent import constants
|
||||||
|
import ovn_bgp_agent.privileged.vtysh
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -70,31 +70,9 @@ router bgp {{ bgp_as }} vrf {{ vrf_name }}
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def _run_vtysh_config(frr_config_file):
|
|
||||||
vtysh_command = "copy {} running-config".format(frr_config_file)
|
|
||||||
full_args = ['/usr/bin/vtysh', '--vty_socket', constants.FRR_SOCKET_PATH,
|
|
||||||
'-c', vtysh_command]
|
|
||||||
try:
|
|
||||||
return processutils.execute(*full_args, run_as_root=True)
|
|
||||||
except Exception as e:
|
|
||||||
LOG.exception("Unable to execute vtysh with %s. Exception: %s",
|
|
||||||
full_args, e)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def _run_vtysh_command(command):
|
|
||||||
full_args = ['/usr/bin/vtysh', '--vty_socket', constants.FRR_SOCKET_PATH,
|
|
||||||
'-c', command]
|
|
||||||
try:
|
|
||||||
return processutils.execute(*full_args, run_as_root=True)[0]
|
|
||||||
except Exception as e:
|
|
||||||
LOG.exception("Unable to execute vtysh with %s. Exception: %s",
|
|
||||||
full_args, e)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def _get_router_id(bgp_as):
|
def _get_router_id(bgp_as):
|
||||||
output = _run_vtysh_command(command='show ip bgp summary json')
|
output = ovn_bgp_agent.privileged.vtysh.run_vtysh_command(
|
||||||
|
command='show ip bgp summary json')
|
||||||
return json.loads(output).get('ipv4Unicast', {}).get('routerId')
|
return json.loads(output).get('ipv4Unicast', {}).get('routerId')
|
||||||
|
|
||||||
|
|
||||||
@ -113,7 +91,7 @@ def vrf_leak(vrf, bgp_as, bgp_router_id=None):
|
|||||||
with open(frr_config_file, 'w') as vrf_config_file:
|
with open(frr_config_file, 'w') as vrf_config_file:
|
||||||
vrf_config_file.write(vrf_config)
|
vrf_config_file.write(vrf_config)
|
||||||
|
|
||||||
_run_vtysh_config(frr_config_file)
|
ovn_bgp_agent.privileged.vtysh.run_vtysh_config(frr_config_file)
|
||||||
|
|
||||||
|
|
||||||
def vrf_reconfigure(evpn_info, action):
|
def vrf_reconfigure(evpn_info, action):
|
||||||
@ -141,4 +119,4 @@ def vrf_reconfigure(evpn_info, action):
|
|||||||
with open(frr_config_file, 'w') as vrf_config_file:
|
with open(frr_config_file, 'w') as vrf_config_file:
|
||||||
vrf_config_file.write(vrf_config)
|
vrf_config_file.write(vrf_config)
|
||||||
|
|
||||||
_run_vtysh_config(frr_config_file)
|
ovn_bgp_agent.privileged.vtysh.run_vtysh_config(frr_config_file)
|
||||||
|
@ -14,13 +14,14 @@
|
|||||||
|
|
||||||
import pyroute2
|
import pyroute2
|
||||||
|
|
||||||
from oslo_concurrency import processutils
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from ovs.db import idl
|
from ovs.db import idl
|
||||||
|
|
||||||
from ovn_bgp_agent import constants
|
from ovn_bgp_agent import constants
|
||||||
|
import ovn_bgp_agent.privileged.ovs_vsctl
|
||||||
from ovn_bgp_agent.utils import linux_net
|
from ovn_bgp_agent.utils import linux_net
|
||||||
|
|
||||||
|
|
||||||
from ovsdbapp.backend.ovs_idl import connection
|
from ovsdbapp.backend.ovs_idl import connection
|
||||||
from ovsdbapp.backend.ovs_idl import idlutils
|
from ovsdbapp.backend.ovs_idl import idlutils
|
||||||
from ovsdbapp.schema.open_vswitch import impl_idl as idl_ovs
|
from ovsdbapp.schema.open_vswitch import impl_idl as idl_ovs
|
||||||
@ -29,28 +30,16 @@ from ovsdbapp.schema.open_vswitch import impl_idl as idl_ovs
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def ovs_cmd(command, args, timeout=None):
|
|
||||||
full_args = [command]
|
|
||||||
if timeout is not None:
|
|
||||||
full_args += ['--timeout=%s' % timeout]
|
|
||||||
full_args += args
|
|
||||||
try:
|
|
||||||
return processutils.execute(*full_args, run_as_root=True)
|
|
||||||
except Exception as e:
|
|
||||||
LOG.exception("Unable to execute %s %s. Exception: %s", command,
|
|
||||||
full_args, e)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def get_ovs_flows_info(bridge, flows_info, cookie):
|
def get_ovs_flows_info(bridge, flows_info, cookie):
|
||||||
ovs_ports = ovs_cmd('ovs-vsctl',
|
ovs_ports = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
['list-ports', bridge])[0].rstrip()
|
'ovs-vsctl', ['list-ports', bridge])[0].rstrip()
|
||||||
if not ovs_ports:
|
if not ovs_ports:
|
||||||
flow = ("cookie={}/-1").format(cookie)
|
flow = ("cookie={}/-1").format(cookie)
|
||||||
ovs_cmd('ovs-ofctl', ['del-flows', bridge, flow])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['del-flows', bridge, flow])
|
||||||
return
|
return
|
||||||
for ovs_port in ovs_ports.split("\n"):
|
for ovs_port in ovs_ports.split("\n"):
|
||||||
ovs_ofport = ovs_cmd(
|
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-vsctl',
|
'ovs-vsctl',
|
||||||
['get', 'Interface', ovs_port, 'ofport'])[0].rstrip()
|
['get', 'Interface', ovs_port, 'ofport'])[0].rstrip()
|
||||||
flows_info[bridge]['in_port'].add(ovs_ofport)
|
flows_info[bridge]['in_port'].add(ovs_ofport)
|
||||||
@ -65,11 +54,13 @@ def remove_extra_ovs_flows(flows_info, cookie):
|
|||||||
flow_v6 = ("cookie={},priority=900,ipv6,in_port={},"
|
flow_v6 = ("cookie={},priority=900,ipv6,in_port={},"
|
||||||
"actions=mod_dl_dst:{},NORMAL".format(
|
"actions=mod_dl_dst:{},NORMAL".format(
|
||||||
cookie, in_port, info['mac']))
|
cookie, in_port, info['mac']))
|
||||||
ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow_v6])
|
'ovs-ofctl', ['add-flow', bridge, flow])
|
||||||
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['add-flow', bridge, flow_v6])
|
||||||
|
|
||||||
cookie_id = ("cookie={}/-1").format(cookie)
|
cookie_id = ("cookie={}/-1").format(cookie)
|
||||||
current_flows = ovs_cmd(
|
current_flows = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-ofctl', ['dump-flows', bridge, cookie_id]
|
'ovs-ofctl', ['dump-flows', bridge, cookie_id]
|
||||||
)[0].split('\n')[1:-1]
|
)[0].split('\n')[1:-1]
|
||||||
for flow in current_flows:
|
for flow in current_flows:
|
||||||
@ -83,21 +74,23 @@ def remove_extra_ovs_flows(flows_info, cookie):
|
|||||||
continue
|
continue
|
||||||
in_port = flow.split("in_port=")[1].split(" ")[0]
|
in_port = flow.split("in_port=")[1].split(" ")[0]
|
||||||
del_flow = ('{},in_port={}').format(cookie_id, in_port)
|
del_flow = ('{},in_port={}').format(cookie_id, in_port)
|
||||||
ovs_cmd('ovs-ofctl', ['del-flows', bridge, del_flow])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['del-flows', bridge, del_flow])
|
||||||
|
|
||||||
|
|
||||||
def ensure_evpn_ovs_flow(bridge, cookie, mac, port, net, strip_vlan=False):
|
def ensure_evpn_ovs_flow(bridge, cookie, mac, port, net, strip_vlan=False):
|
||||||
ovs_port = None
|
ovs_port = None
|
||||||
ovs_ports = ovs_cmd('ovs-vsctl', ['list-ports', bridge])[0].rstrip()
|
ovs_ports = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-vsctl', ['list-ports', bridge])[0].rstrip()
|
||||||
for p in ovs_ports.split('\n'):
|
for p in ovs_ports.split('\n'):
|
||||||
if p.startswith('patch-provnet-'):
|
if p.startswith('patch-provnet-'):
|
||||||
ovs_port = p
|
ovs_port = p
|
||||||
if not ovs_port:
|
if not ovs_port:
|
||||||
return
|
return
|
||||||
ovs_ofport = ovs_cmd(
|
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
||||||
)[0].rstrip()
|
)[0].rstrip()
|
||||||
vrf_ofport = ovs_cmd(
|
vrf_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-vsctl', ['get', 'Interface', port, 'ofport']
|
'ovs-vsctl', ['get', 'Interface', port, 'ofport']
|
||||||
)[0].rstrip()
|
)[0].rstrip()
|
||||||
|
|
||||||
@ -131,43 +124,48 @@ def ensure_evpn_ovs_flow(bridge, cookie, mac, port, net, strip_vlan=False):
|
|||||||
"actions=mod_dl_dst:{},output={}".format(
|
"actions=mod_dl_dst:{},output={}".format(
|
||||||
cookie, ovs_ofport, mac, net,
|
cookie, ovs_ofport, mac, net,
|
||||||
ndb.interfaces[bridge]['address'], vrf_ofport))
|
ndb.interfaces[bridge]['address'], vrf_ofport))
|
||||||
ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['add-flow', bridge, flow])
|
||||||
|
|
||||||
|
|
||||||
def remove_evpn_router_ovs_flows(bridge, cookie, mac):
|
def remove_evpn_router_ovs_flows(bridge, cookie, mac):
|
||||||
cookie_id = ("cookie={}/-1").format(cookie)
|
cookie_id = ("cookie={}/-1").format(cookie)
|
||||||
|
|
||||||
ovs_port = None
|
ovs_port = None
|
||||||
ovs_ports = ovs_cmd('ovs-vsctl', ['list-ports', bridge])[0].rstrip()
|
ovs_ports = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-vsctl', ['list-ports', bridge])[0].rstrip()
|
||||||
for p in ovs_ports.split('\n'):
|
for p in ovs_ports.split('\n'):
|
||||||
if p.startswith('patch-provnet-'):
|
if p.startswith('patch-provnet-'):
|
||||||
ovs_port = p
|
ovs_port = p
|
||||||
if not ovs_port:
|
if not ovs_port:
|
||||||
return
|
return
|
||||||
ovs_ofport = ovs_cmd(
|
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
||||||
)[0].rstrip()
|
)[0].rstrip()
|
||||||
|
|
||||||
flow = ("{},ip,in_port={},dl_src:{}".format(
|
flow = ("{},ip,in_port={},dl_src:{}".format(
|
||||||
cookie_id, ovs_ofport, mac))
|
cookie_id, ovs_ofport, mac))
|
||||||
ovs_cmd('ovs-ofctl', ['del-flows', bridge, flow])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['del-flows', bridge, flow])
|
||||||
|
|
||||||
flow_v6 = ("{},ipv6,in_port={},dl_src:{}".format(cookie_id, ovs_ofport,
|
flow_v6 = ("{},ipv6,in_port={},dl_src:{}".format(cookie_id, ovs_ofport,
|
||||||
mac))
|
mac))
|
||||||
ovs_cmd('ovs-ofctl', ['del-flows', bridge, flow_v6])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['del-flows', bridge, flow_v6])
|
||||||
|
|
||||||
|
|
||||||
def remove_evpn_network_ovs_flow(bridge, cookie, mac, net):
|
def remove_evpn_network_ovs_flow(bridge, cookie, mac, net):
|
||||||
cookie_id = ("cookie={}/-1").format(cookie)
|
cookie_id = ("cookie={}/-1").format(cookie)
|
||||||
|
|
||||||
ovs_port = None
|
ovs_port = None
|
||||||
ovs_ports = ovs_cmd('ovs-vsctl', ['list-ports', bridge])[0].rstrip()
|
ovs_ports = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-vsctl', ['list-ports', bridge])[0].rstrip()
|
||||||
for p in ovs_ports.split('\n'):
|
for p in ovs_ports.split('\n'):
|
||||||
if p.startswith('patch-provnet-'):
|
if p.startswith('patch-provnet-'):
|
||||||
ovs_port = p
|
ovs_port = p
|
||||||
if not ovs_port:
|
if not ovs_port:
|
||||||
return
|
return
|
||||||
ovs_ofport = ovs_cmd(
|
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
||||||
)[0].rstrip()
|
)[0].rstrip()
|
||||||
|
|
||||||
@ -178,20 +176,22 @@ def remove_evpn_network_ovs_flow(bridge, cookie, mac, net):
|
|||||||
else:
|
else:
|
||||||
flow = ("{},ip,in_port={},dl_src:{},nw_src={}".format(
|
flow = ("{},ip,in_port={},dl_src:{},nw_src={}".format(
|
||||||
cookie_id, ovs_ofport, mac, net))
|
cookie_id, ovs_ofport, mac, net))
|
||||||
ovs_cmd('ovs-ofctl', ['del-flows', bridge, flow])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['del-flows', bridge, flow])
|
||||||
|
|
||||||
|
|
||||||
def ensure_default_ovs_flows(ovn_bridge_mappings, cookie):
|
def ensure_default_ovs_flows(ovn_bridge_mappings, cookie):
|
||||||
cookie_id = ("cookie={}/-1").format(cookie)
|
cookie_id = ("cookie={}/-1").format(cookie)
|
||||||
for bridge in ovn_bridge_mappings:
|
for bridge in ovn_bridge_mappings:
|
||||||
ovs_port = ovs_cmd('ovs-vsctl', ['list-ports', bridge])[0].rstrip()
|
ovs_port = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-vsctl', ['list-ports', bridge])[0].rstrip()
|
||||||
if not ovs_port:
|
if not ovs_port:
|
||||||
continue
|
continue
|
||||||
ovs_ofport = ovs_cmd(
|
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
||||||
)[0].rstrip()
|
)[0].rstrip()
|
||||||
flow_filter = ('{},in_port={}').format(cookie_id, ovs_ofport)
|
flow_filter = ('{},in_port={}').format(cookie_id, ovs_ofport)
|
||||||
current_flows = ovs_cmd(
|
current_flows = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-ofctl', ['dump-flows', bridge, flow_filter]
|
'ovs-ofctl', ['dump-flows', bridge, flow_filter]
|
||||||
)[0].split('\n')[1:-1]
|
)[0].split('\n')[1:-1]
|
||||||
if len(current_flows) == 1:
|
if len(current_flows) == 1:
|
||||||
@ -208,12 +208,14 @@ def ensure_default_ovs_flows(ovn_bridge_mappings, cookie):
|
|||||||
"actions=mod_dl_dst:{},NORMAL".format(
|
"actions=mod_dl_dst:{},NORMAL".format(
|
||||||
cookie, ovs_ofport,
|
cookie, ovs_ofport,
|
||||||
ndb.interfaces[bridge]['address']))
|
ndb.interfaces[bridge]['address']))
|
||||||
ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow_v6])
|
'ovs-ofctl', ['add-flow', bridge, flow])
|
||||||
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['add-flow', bridge, flow_v6])
|
||||||
|
|
||||||
# Remove unneeded flows
|
# Remove unneeded flows
|
||||||
port = 'in_port={}'.format(ovs_ofport)
|
port = 'in_port={}'.format(ovs_ofport)
|
||||||
current_flows = ovs_cmd(
|
current_flows = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-ofctl', ['dump-flows', bridge, cookie_id]
|
'ovs-ofctl', ['dump-flows', bridge, cookie_id]
|
||||||
)[0].split('\n')[1:-1]
|
)[0].split('\n')[1:-1]
|
||||||
for flow in current_flows:
|
for flow in current_flows:
|
||||||
@ -221,32 +223,37 @@ def ensure_default_ovs_flows(ovn_bridge_mappings, cookie):
|
|||||||
continue
|
continue
|
||||||
in_port = flow.split("in_port=")[1].split(" ")[0]
|
in_port = flow.split("in_port=")[1].split(" ")[0]
|
||||||
del_flow = ('{},in_port={}').format(cookie_id, in_port)
|
del_flow = ('{},in_port={}').format(cookie_id, in_port)
|
||||||
ovs_cmd('ovs-ofctl', ['del-flows', bridge, del_flow])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['del-flows', bridge, del_flow])
|
||||||
|
|
||||||
|
|
||||||
def add_device_to_ovs_bridge(device, bridge, vlan_tag=None):
|
def add_device_to_ovs_bridge(device, bridge, vlan_tag=None):
|
||||||
if vlan_tag:
|
if vlan_tag:
|
||||||
tag = "tag={}".format(vlan_tag)
|
tag = "tag={}".format(vlan_tag)
|
||||||
ovs_cmd('ovs-vsctl', ['--may-exist', 'add-port', bridge, device, tag])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-vsctl', ['--may-exist', 'add-port', bridge, device, tag])
|
||||||
else:
|
else:
|
||||||
ovs_cmd('ovs-vsctl', ['--may-exist', 'add-port', bridge, device])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-vsctl', ['--may-exist', 'add-port', bridge, device])
|
||||||
|
|
||||||
|
|
||||||
def del_device_from_ovs_bridge(device, bridge=None):
|
def del_device_from_ovs_bridge(device, bridge=None):
|
||||||
if bridge:
|
if bridge:
|
||||||
ovs_cmd('ovs-vsctl', ['--if-exists', 'del-port', bridge, device])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-vsctl', ['--if-exists', 'del-port', bridge, device])
|
||||||
else:
|
else:
|
||||||
ovs_cmd('ovs-vsctl', ['--if-exists', 'del-port', device])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-vsctl', ['--if-exists', 'del-port', device])
|
||||||
|
|
||||||
|
|
||||||
def get_bridge_flows_by_cookie(bridge, cookie):
|
def get_bridge_flows_by_cookie(bridge, cookie):
|
||||||
cookie_id = ("cookie={}/-1").format(cookie)
|
cookie_id = ("cookie={}/-1").format(cookie)
|
||||||
return ovs_cmd('ovs-ofctl',
|
return ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
['dump-flows', bridge, cookie_id])[0].split('\n')[1:-1]
|
'ovs-ofctl', ['dump-flows', bridge, cookie_id])[0].split('\n')[1:-1]
|
||||||
|
|
||||||
|
|
||||||
def get_device_port_at_ovs(device):
|
def get_device_port_at_ovs(device):
|
||||||
return ovs_cmd(
|
return ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
'ovs-vsctl', ['get', 'Interface', device, 'ofport'])[0].rstrip()
|
'ovs-vsctl', ['get', 'Interface', device, 'ofport'])[0].rstrip()
|
||||||
|
|
||||||
|
|
||||||
@ -254,7 +261,8 @@ def del_flow(flow, bridge, cookie):
|
|||||||
cookie_id = ("cookie={}/-1").format(cookie)
|
cookie_id = ("cookie={}/-1").format(cookie)
|
||||||
f = '{},priority{}'.format(
|
f = '{},priority{}'.format(
|
||||||
cookie_id, flow.split(' actions')[0].split(' priority')[1])
|
cookie_id, flow.split(' actions')[0].split(' priority')[1])
|
||||||
ovs_cmd('ovs-ofctl', ['--strict', 'del-flows', bridge, f])
|
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||||
|
'ovs-ofctl', ['--strict', 'del-flows', bridge, f])
|
||||||
|
|
||||||
|
|
||||||
def get_flow_info(flow):
|
def get_flow_info(flow):
|
||||||
|
42
ovn_bgp_agent/privileged/__init__.py
Normal file
42
ovn_bgp_agent/privileged/__init__.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
from oslo_privsep import capabilities
|
||||||
|
from oslo_privsep import priv_context
|
||||||
|
|
||||||
|
default = priv_context.PrivContext(
|
||||||
|
__name__,
|
||||||
|
cfg_section='privsep',
|
||||||
|
pypath=__name__ + '.default',
|
||||||
|
capabilities=[capabilities.CAP_DAC_OVERRIDE,
|
||||||
|
capabilities.CAP_DAC_READ_SEARCH,
|
||||||
|
capabilities.CAP_NET_ADMIN,
|
||||||
|
capabilities.CAP_SYS_ADMIN],
|
||||||
|
)
|
||||||
|
|
||||||
|
ovs_vsctl_cmd = priv_context.PrivContext(
|
||||||
|
__name__,
|
||||||
|
cfg_section='privsep_ovs_vsctl',
|
||||||
|
pypath=__name__ + '.ovs_vsctl_cmd',
|
||||||
|
capabilities=[capabilities.CAP_SYS_ADMIN,
|
||||||
|
capabilities.CAP_NET_ADMIN]
|
||||||
|
)
|
||||||
|
|
||||||
|
vtysh_cmd = priv_context.PrivContext(
|
||||||
|
__name__,
|
||||||
|
cfg_section='privsep_vtysh',
|
||||||
|
pypath=__name__ + '.vtysh_cmd',
|
||||||
|
capabilities=[capabilities.CAP_SYS_ADMIN,
|
||||||
|
capabilities.CAP_NET_ADMIN]
|
||||||
|
)
|
88
ovn_bgp_agent/privileged/linux_net.py
Normal file
88
ovn_bgp_agent/privileged/linux_net.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# 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 os
|
||||||
|
|
||||||
|
from oslo_concurrency import processutils
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
import ovn_bgp_agent.privileged.linux_net
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ovn_bgp_agent.privileged.default.entrypoint
|
||||||
|
def set_kernel_flag(flag, value):
|
||||||
|
command = ["sysctl", "-w", "{}={}".format(flag, value)]
|
||||||
|
try:
|
||||||
|
return processutils.execute(*command)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error("Unable to execute %s. Exception: %s", command, e)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@ovn_bgp_agent.privileged.default.entrypoint
|
||||||
|
def add_ndp_proxy(ip, dev, vlan=None):
|
||||||
|
# FIXME(ltomasbo): This should use pyroute instead but I didn't find
|
||||||
|
# out how
|
||||||
|
net_ip = str(ipaddress.IPv6Network(ip, strict=False).network_address)
|
||||||
|
dev_name = dev
|
||||||
|
if vlan:
|
||||||
|
dev_name = "{}.{}".format(dev, vlan)
|
||||||
|
command = ["ip", "-6", "nei", "add", "proxy", net_ip, "dev", dev_name]
|
||||||
|
try:
|
||||||
|
return processutils.execute(*command)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error("Unable to execute %s. Exception: %s", command, e)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@ovn_bgp_agent.privileged.default.entrypoint
|
||||||
|
def del_ndp_proxy(ip, dev, vlan=None):
|
||||||
|
# FIXME(ltomasbo): This should use pyroute instead but I didn't find
|
||||||
|
# out how
|
||||||
|
net_ip = str(ipaddress.IPv6Network(ip, strict=False).network_address)
|
||||||
|
dev_name = dev
|
||||||
|
if vlan:
|
||||||
|
dev_name = "{}.{}".format(dev, vlan)
|
||||||
|
command = ["ip", "-6", "nei", "del", "proxy", net_ip, "dev", dev_name]
|
||||||
|
env = dict(os.environ)
|
||||||
|
env['LC_ALL'] = 'C'
|
||||||
|
try:
|
||||||
|
return processutils.execute(*command, env_variables=env)
|
||||||
|
except Exception as e:
|
||||||
|
if "No such file or directory" in e.stderr:
|
||||||
|
# Already deleted
|
||||||
|
return
|
||||||
|
LOG.error("Unable to execute %s. Exception: %s", command, e)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@ovn_bgp_agent.privileged.default.entrypoint
|
||||||
|
def add_unreachable_route(vrf_name):
|
||||||
|
# FIXME: This should use pyroute instead but I didn't find
|
||||||
|
# out how
|
||||||
|
env = dict(os.environ)
|
||||||
|
env['LC_ALL'] = 'C'
|
||||||
|
for ip_version in [-4, -6]:
|
||||||
|
command = ["ip", ip_version, "route", "add", "vrf", vrf_name,
|
||||||
|
"unreachable", "default", "metric", "4278198272"]
|
||||||
|
try:
|
||||||
|
return processutils.execute(*command, env_variables=env)
|
||||||
|
except Exception as e:
|
||||||
|
if "RTNETLINK answers: File exists" in e.stderr:
|
||||||
|
continue
|
||||||
|
LOG.error("Unable to execute %s. Exception: %s", command, e)
|
||||||
|
raise
|
34
ovn_bgp_agent/privileged/ovs_vsctl.py
Normal file
34
ovn_bgp_agent/privileged/ovs_vsctl.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
from oslo_concurrency import processutils
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
import ovn_bgp_agent.privileged.ovs_vsctl
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ovn_bgp_agent.privileged.ovs_vsctl_cmd.entrypoint
|
||||||
|
def ovs_cmd(command, args, timeout=None):
|
||||||
|
full_args = [command]
|
||||||
|
if timeout is not None:
|
||||||
|
full_args += ['--timeout=%s' % timeout]
|
||||||
|
full_args += args
|
||||||
|
try:
|
||||||
|
return processutils.execute(*full_args)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.exception("Unable to execute %s %s. Exception: %s", command,
|
||||||
|
full_args, e)
|
||||||
|
raise
|
46
ovn_bgp_agent/privileged/vtysh.py
Normal file
46
ovn_bgp_agent/privileged/vtysh.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
from oslo_concurrency import processutils
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from ovn_bgp_agent import constants
|
||||||
|
import ovn_bgp_agent.privileged.vtysh
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ovn_bgp_agent.privileged.vtysh_cmd.entrypoint
|
||||||
|
def run_vtysh_config(frr_config_file):
|
||||||
|
vtysh_command = "copy {} running-config".format(frr_config_file)
|
||||||
|
full_args = ['/usr/bin/vtysh', '--vty_socket', constants.FRR_SOCKET_PATH,
|
||||||
|
'-c', vtysh_command]
|
||||||
|
try:
|
||||||
|
return processutils.execute(*full_args)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.exception("Unable to execute vtysh with %s. Exception: %s",
|
||||||
|
full_args, e)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@ovn_bgp_agent.privileged.vtysh_cmd.entrypoint
|
||||||
|
def run_vtysh_command(command):
|
||||||
|
full_args = ['/usr/bin/vtysh', '--vty_socket', constants.FRR_SOCKET_PATH,
|
||||||
|
'-c', command]
|
||||||
|
try:
|
||||||
|
return processutils.execute(*full_args)[0]
|
||||||
|
except Exception as e:
|
||||||
|
LOG.exception("Unable to execute vtysh with %s. Exception: %s",
|
||||||
|
full_args, e)
|
||||||
|
raise
|
@ -13,7 +13,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import os
|
|
||||||
import pyroute2
|
import pyroute2
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
@ -23,11 +22,11 @@ from pyroute2.netlink.rtnl import ndmsg
|
|||||||
from socket import AF_INET
|
from socket import AF_INET
|
||||||
from socket import AF_INET6
|
from socket import AF_INET6
|
||||||
|
|
||||||
from oslo_concurrency import processutils
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from ovn_bgp_agent import constants
|
from ovn_bgp_agent import constants
|
||||||
from ovn_bgp_agent import exceptions as agent_exc
|
from ovn_bgp_agent import exceptions as agent_exc
|
||||||
|
import ovn_bgp_agent.privileged.linux_net
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -239,9 +238,9 @@ def ensure_vlan_device_for_network(bridge, vlan_tag):
|
|||||||
'state', constants.LINK_UP).commit()
|
'state', constants.LINK_UP).commit()
|
||||||
|
|
||||||
ipv4_flag = "net.ipv4.conf.{}/{}.proxy_arp".format(bridge, vlan_tag)
|
ipv4_flag = "net.ipv4.conf.{}/{}.proxy_arp".format(bridge, vlan_tag)
|
||||||
_set_kernel_flag(ipv4_flag, 1)
|
ovn_bgp_agent.privileged.linux_net.set_kernel_flag(ipv4_flag, 1)
|
||||||
ipv6_flag = "net.ipv6.conf.{}/{}.proxy_ndp".format(bridge, vlan_tag)
|
ipv6_flag = "net.ipv6.conf.{}/{}.proxy_ndp".format(bridge, vlan_tag)
|
||||||
_set_kernel_flag(ipv6_flag, 1)
|
ovn_bgp_agent.privileged.linux_net.set_kernel_flag(ipv6_flag, 1)
|
||||||
|
|
||||||
|
|
||||||
def delete_vlan_device_for_network(bridge, vlan_tag):
|
def delete_vlan_device_for_network(bridge, vlan_tag):
|
||||||
@ -249,15 +248,6 @@ def delete_vlan_device_for_network(bridge, vlan_tag):
|
|||||||
delete_device(vlan_device_name)
|
delete_device(vlan_device_name)
|
||||||
|
|
||||||
|
|
||||||
def _set_kernel_flag(flag, value):
|
|
||||||
command = ["sysctl", "-w", "{}={}".format(flag, value)]
|
|
||||||
try:
|
|
||||||
return processutils.execute(*command, run_as_root=True)
|
|
||||||
except Exception as e:
|
|
||||||
LOG.error("Unable to execute %s. Exception: %s", command, e)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def get_exposed_ips(nic):
|
def get_exposed_ips(nic):
|
||||||
exposed_ips = []
|
exposed_ips = []
|
||||||
with pyroute2.NDB() as ndb:
|
with pyroute2.NDB() as ndb:
|
||||||
@ -413,39 +403,11 @@ def delete_ip_routes(routes):
|
|||||||
|
|
||||||
|
|
||||||
def add_ndp_proxy(ip, dev, vlan=None):
|
def add_ndp_proxy(ip, dev, vlan=None):
|
||||||
# FIXME(ltomasbo): This should use pyroute instead but I didn't find
|
ovn_bgp_agent.privileged.linux_net.add_ndp_proxy(ip, dev, vlan)
|
||||||
# out how
|
|
||||||
net_ip = str(ipaddress.IPv6Network(ip, strict=False).network_address)
|
|
||||||
dev_name = dev
|
|
||||||
if vlan:
|
|
||||||
dev_name = "{}.{}".format(dev, vlan)
|
|
||||||
command = ["ip", "-6", "nei", "add", "proxy", net_ip, "dev", dev_name]
|
|
||||||
try:
|
|
||||||
return processutils.execute(*command, run_as_root=True)
|
|
||||||
except Exception as e:
|
|
||||||
LOG.error("Unable to execute %s. Exception: %s", command, e)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def del_ndp_proxy(ip, dev, vlan=None):
|
def del_ndp_proxy(ip, dev, vlan=None):
|
||||||
# FIXME(ltomasbo): This should use pyroute instead but I didn't find
|
ovn_bgp_agent.privileged.linux_net.del_ndp_proxy(ip, dev, vlan)
|
||||||
# out how
|
|
||||||
net_ip = str(ipaddress.IPv6Network(ip, strict=False).network_address)
|
|
||||||
dev_name = dev
|
|
||||||
if vlan:
|
|
||||||
dev_name = "{}.{}".format(dev, vlan)
|
|
||||||
command = ["ip", "-6", "nei", "del", "proxy", net_ip, "dev", dev_name]
|
|
||||||
env = dict(os.environ)
|
|
||||||
env['LC_ALL'] = 'C'
|
|
||||||
try:
|
|
||||||
return processutils.execute(*command, run_as_root=True,
|
|
||||||
env_variables=env)
|
|
||||||
except Exception as e:
|
|
||||||
if "No such file or directory" in e.stderr:
|
|
||||||
# Already deleted
|
|
||||||
return
|
|
||||||
LOG.error("Unable to execute %s. Exception: %s", command, e)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def add_ips_to_dev(nic, ips, clear_local_route_at_table=False):
|
def add_ips_to_dev(nic, ips, clear_local_route_at_table=False):
|
||||||
@ -582,21 +544,7 @@ def del_ip_rule(ip, table, dev=None, lladdr=None):
|
|||||||
|
|
||||||
|
|
||||||
def add_unreachable_route(vrf_name):
|
def add_unreachable_route(vrf_name):
|
||||||
# FIXME: This should use pyroute instead but I didn't find
|
ovn_bgp_agent.privileged.linux_net.add_unreachable_route(vrf_name)
|
||||||
# out how
|
|
||||||
env = dict(os.environ)
|
|
||||||
env['LC_ALL'] = 'C'
|
|
||||||
for ip_version in [-4, -6]:
|
|
||||||
command = ["ip", ip_version, "route", "add", "vrf", vrf_name,
|
|
||||||
"unreachable", "default", "metric", "4278198272"]
|
|
||||||
try:
|
|
||||||
return processutils.execute(*command, run_as_root=True,
|
|
||||||
env_variables=env)
|
|
||||||
except Exception as e:
|
|
||||||
if "RTNETLINK answers: File exists" in e.stderr:
|
|
||||||
continue
|
|
||||||
LOG.error("Unable to execute %s. Exception: %s", command, e)
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def add_ip_route(ovn_routing_tables_routes, ip_address, route_table, dev,
|
def add_ip_route(ovn_routing_tables_routes, ip_address, route_table, dev,
|
||||||
|
@ -9,6 +9,7 @@ neutron-lib>=2.12.0 # Apache-2.0
|
|||||||
oslo.concurrency>=3.26.0 # Apache-2.0
|
oslo.concurrency>=3.26.0 # Apache-2.0
|
||||||
oslo.config>=6.1.0 # Apache-2.0
|
oslo.config>=6.1.0 # Apache-2.0
|
||||||
oslo.log>=3.36.0 # Apache-2.0
|
oslo.log>=3.36.0 # Apache-2.0
|
||||||
|
oslo.privsep>=2.3.0 # Apache-2.0
|
||||||
oslo.service>=1.40.2 # Apache-2.0
|
oslo.service>=1.40.2 # Apache-2.0
|
||||||
ovs>=2.8.0 # Apache-2.0
|
ovs>=2.8.0 # Apache-2.0
|
||||||
ovsdbapp>=1.4.0 # Apache-2.0
|
ovsdbapp>=1.4.0 # Apache-2.0
|
||||||
|
Loading…
Reference in New Issue
Block a user