Add privsep support
Change-Id: Iab2cb051807cbfa52f43604c93905a8d15158d44
This commit is contained in:
parent
496755d3a2
commit
05e3d1bff4
@ -15,10 +15,10 @@
|
||||
import json
|
||||
|
||||
from jinja2 import Template
|
||||
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__)
|
||||
|
||||
@ -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):
|
||||
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')
|
||||
|
||||
|
||||
@ -113,7 +91,7 @@ def vrf_leak(vrf, bgp_as, bgp_router_id=None):
|
||||
with open(frr_config_file, 'w') as vrf_config_file:
|
||||
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):
|
||||
@ -141,4 +119,4 @@ def vrf_reconfigure(evpn_info, action):
|
||||
with open(frr_config_file, 'w') as vrf_config_file:
|
||||
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
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
from ovs.db import idl
|
||||
|
||||
from ovn_bgp_agent import constants
|
||||
import ovn_bgp_agent.privileged.ovs_vsctl
|
||||
from ovn_bgp_agent.utils import linux_net
|
||||
|
||||
|
||||
from ovsdbapp.backend.ovs_idl import connection
|
||||
from ovsdbapp.backend.ovs_idl import idlutils
|
||||
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__)
|
||||
|
||||
|
||||
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):
|
||||
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()
|
||||
if not ovs_ports:
|
||||
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
|
||||
for ovs_port in ovs_ports.split("\n"):
|
||||
ovs_ofport = ovs_cmd(
|
||||
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-vsctl',
|
||||
['get', 'Interface', ovs_port, 'ofport'])[0].rstrip()
|
||||
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={},"
|
||||
"actions=mod_dl_dst:{},NORMAL".format(
|
||||
cookie, in_port, info['mac']))
|
||||
ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow])
|
||||
ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow_v6])
|
||||
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'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)
|
||||
current_flows = ovs_cmd(
|
||||
current_flows = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-ofctl', ['dump-flows', bridge, cookie_id]
|
||||
)[0].split('\n')[1:-1]
|
||||
for flow in current_flows:
|
||||
@ -83,21 +74,23 @@ def remove_extra_ovs_flows(flows_info, cookie):
|
||||
continue
|
||||
in_port = flow.split("in_port=")[1].split(" ")[0]
|
||||
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):
|
||||
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'):
|
||||
if p.startswith('patch-provnet-'):
|
||||
ovs_port = p
|
||||
if not ovs_port:
|
||||
return
|
||||
ovs_ofport = ovs_cmd(
|
||||
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
||||
)[0].rstrip()
|
||||
vrf_ofport = ovs_cmd(
|
||||
vrf_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-vsctl', ['get', 'Interface', port, 'ofport']
|
||||
)[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(
|
||||
cookie, ovs_ofport, mac, net,
|
||||
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):
|
||||
cookie_id = ("cookie={}/-1").format(cookie)
|
||||
|
||||
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'):
|
||||
if p.startswith('patch-provnet-'):
|
||||
ovs_port = p
|
||||
if not ovs_port:
|
||||
return
|
||||
ovs_ofport = ovs_cmd(
|
||||
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
||||
)[0].rstrip()
|
||||
|
||||
flow = ("{},ip,in_port={},dl_src:{}".format(
|
||||
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,
|
||||
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):
|
||||
cookie_id = ("cookie={}/-1").format(cookie)
|
||||
|
||||
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'):
|
||||
if p.startswith('patch-provnet-'):
|
||||
ovs_port = p
|
||||
if not ovs_port:
|
||||
return
|
||||
ovs_ofport = ovs_cmd(
|
||||
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
||||
)[0].rstrip()
|
||||
|
||||
@ -178,20 +176,22 @@ def remove_evpn_network_ovs_flow(bridge, cookie, mac, net):
|
||||
else:
|
||||
flow = ("{},ip,in_port={},dl_src:{},nw_src={}".format(
|
||||
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):
|
||||
cookie_id = ("cookie={}/-1").format(cookie)
|
||||
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:
|
||||
continue
|
||||
ovs_ofport = ovs_cmd(
|
||||
ovs_ofport = ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport']
|
||||
)[0].rstrip()
|
||||
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]
|
||||
)[0].split('\n')[1:-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(
|
||||
cookie, ovs_ofport,
|
||||
ndb.interfaces[bridge]['address']))
|
||||
ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow])
|
||||
ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow_v6])
|
||||
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-ofctl', ['add-flow', bridge, flow])
|
||||
ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-ofctl', ['add-flow', bridge, flow_v6])
|
||||
|
||||
# Remove unneeded flows
|
||||
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]
|
||||
)[0].split('\n')[1:-1]
|
||||
for flow in current_flows:
|
||||
@ -221,32 +223,37 @@ def ensure_default_ovs_flows(ovn_bridge_mappings, cookie):
|
||||
continue
|
||||
in_port = flow.split("in_port=")[1].split(" ")[0]
|
||||
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):
|
||||
if 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:
|
||||
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):
|
||||
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:
|
||||
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):
|
||||
cookie_id = ("cookie={}/-1").format(cookie)
|
||||
return ovs_cmd('ovs-ofctl',
|
||||
['dump-flows', bridge, cookie_id])[0].split('\n')[1:-1]
|
||||
return ovn_bgp_agent.privileged.ovs_vsctl.ovs_cmd(
|
||||
'ovs-ofctl', ['dump-flows', bridge, cookie_id])[0].split('\n')[1:-1]
|
||||
|
||||
|
||||
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()
|
||||
|
||||
|
||||
@ -254,7 +261,8 @@ def del_flow(flow, bridge, cookie):
|
||||
cookie_id = ("cookie={}/-1").format(cookie)
|
||||
f = '{},priority{}'.format(
|
||||
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):
|
||||
|
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.
|
||||
|
||||
import ipaddress
|
||||
import os
|
||||
import pyroute2
|
||||
import random
|
||||
import re
|
||||
@ -23,11 +22,11 @@ from pyroute2.netlink.rtnl import ndmsg
|
||||
from socket import AF_INET
|
||||
from socket import AF_INET6
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
|
||||
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__)
|
||||
|
||||
@ -239,9 +238,9 @@ def ensure_vlan_device_for_network(bridge, vlan_tag):
|
||||
'state', constants.LINK_UP).commit()
|
||||
|
||||
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)
|
||||
_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):
|
||||
@ -249,15 +248,6 @@ def delete_vlan_device_for_network(bridge, vlan_tag):
|
||||
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):
|
||||
exposed_ips = []
|
||||
with pyroute2.NDB() as ndb:
|
||||
@ -413,39 +403,11 @@ def delete_ip_routes(routes):
|
||||
|
||||
|
||||
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, run_as_root=True)
|
||||
except Exception as e:
|
||||
LOG.error("Unable to execute %s. Exception: %s", command, e)
|
||||
raise
|
||||
ovn_bgp_agent.privileged.linux_net.add_ndp_proxy(ip, dev, vlan)
|
||||
|
||||
|
||||
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, 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
|
||||
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):
|
||||
@ -582,21 +544,7 @@ def del_ip_rule(ip, table, dev=None, lladdr=None):
|
||||
|
||||
|
||||
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, 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
|
||||
ovn_bgp_agent.privileged.linux_net.add_unreachable_route(vrf_name)
|
||||
|
||||
|
||||
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.config>=6.1.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
|
||||
ovs>=2.8.0 # Apache-2.0
|
||||
ovsdbapp>=1.4.0 # Apache-2.0
|
||||
|
Loading…
Reference in New Issue
Block a user