diff --git a/ovn_bgp_agent/drivers/openstack/utils/frr.py b/ovn_bgp_agent/drivers/openstack/utils/frr.py index 0f4494b3..2d618c82 100644 --- a/ovn_bgp_agent/drivers/openstack/utils/frr.py +++ b/ovn_bgp_agent/drivers/openstack/utils/frr.py @@ -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) diff --git a/ovn_bgp_agent/drivers/openstack/utils/ovs.py b/ovn_bgp_agent/drivers/openstack/utils/ovs.py index d45a105e..ee7a7f8f 100644 --- a/ovn_bgp_agent/drivers/openstack/utils/ovs.py +++ b/ovn_bgp_agent/drivers/openstack/utils/ovs.py @@ -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): diff --git a/ovn_bgp_agent/privileged/__init__.py b/ovn_bgp_agent/privileged/__init__.py new file mode 100644 index 00000000..3c142b68 --- /dev/null +++ b/ovn_bgp_agent/privileged/__init__.py @@ -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] +) diff --git a/ovn_bgp_agent/privileged/linux_net.py b/ovn_bgp_agent/privileged/linux_net.py new file mode 100644 index 00000000..52656d7b --- /dev/null +++ b/ovn_bgp_agent/privileged/linux_net.py @@ -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 diff --git a/ovn_bgp_agent/privileged/ovs_vsctl.py b/ovn_bgp_agent/privileged/ovs_vsctl.py new file mode 100644 index 00000000..a3be14da --- /dev/null +++ b/ovn_bgp_agent/privileged/ovs_vsctl.py @@ -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 diff --git a/ovn_bgp_agent/privileged/vtysh.py b/ovn_bgp_agent/privileged/vtysh.py new file mode 100644 index 00000000..ddd9a540 --- /dev/null +++ b/ovn_bgp_agent/privileged/vtysh.py @@ -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 diff --git a/ovn_bgp_agent/utils/linux_net.py b/ovn_bgp_agent/utils/linux_net.py index acec0d34..6b7f1e33 100644 --- a/ovn_bgp_agent/utils/linux_net.py +++ b/ovn_bgp_agent/utils/linux_net.py @@ -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, diff --git a/requirements.txt b/requirements.txt index 25585d13..fa5e545b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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