Add privsep support

Change-Id: Iab2cb051807cbfa52f43604c93905a8d15158d44
This commit is contained in:
Luis Tomas Bolivar 2021-09-03 16:50:21 +02:00
parent 496755d3a2
commit 05e3d1bff4
8 changed files with 278 additions and 133 deletions

View File

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

View 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):

View 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]
)

View 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

View 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

View 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

View File

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

View File

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