From 284afcf24f2dfd3af20a803ada79c69205249f25 Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Wed, 16 Jan 2019 17:13:08 +0100 Subject: [PATCH] Lock privileged.agent.linux.ip_lib functions It is workaround of bug in pyroute2 library which, when running in multithread environment, sometimes have issues with NetNS class. When NetNS.__init__() is called, it uses os.pipe() function to create 2 file descriptors which are used to communicated between 2 processes. In some cases when multiple threads are running it might happen that in two instances of NetNS() class there will be same file descriptors used and that leads to problems when one thread closes file descriptor and second still wants to use it. With this patch functions which uses instance of pyroute2.NetNS class are locked thus there shouldn't be risk of using same file descriptors in 2 separate threads. Co-Authored-By: Rodolfo Alonso Hernandez Change-Id: Id5e6f2f8e9c31a7138da9cd6792e9d75845b81c5 Closes-Bug: #1811515 --- neutron/privileged/agent/linux/ip_lib.py | 85 ++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/neutron/privileged/agent/linux/ip_lib.py b/neutron/privileged/agent/linux/ip_lib.py index b061e4b5ad1..872b280f2e9 100644 --- a/neutron/privileged/agent/linux/ip_lib.py +++ b/neutron/privileged/agent/linux/ip_lib.py @@ -14,6 +14,7 @@ import errno import socket from neutron_lib import constants +from oslo_concurrency import lockutils import pyroute2 from pyroute2 import netlink from pyroute2.netlink import exceptions as netlink_exceptions @@ -113,6 +114,10 @@ def _make_route_dict(destination, nexthop, device, scope): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def get_routing_table(ip_version, namespace=None): """Return a list of dictionaries, each representing a route. @@ -230,6 +235,10 @@ def _run_iproute_addr(command, device, namespace, **kwargs): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def add_ip_address(ip_version, ip, prefixlen, device, namespace, scope, broadcast=None): family = _IP_VERSION_FAMILY_MAP[ip_version] @@ -249,6 +258,10 @@ def add_ip_address(ip_version, ip, prefixlen, device, namespace, scope, @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def delete_ip_address(ip_version, ip, prefixlen, device, namespace): family = _IP_VERSION_FAMILY_MAP[ip_version] try: @@ -269,6 +282,10 @@ def delete_ip_address(ip_version, ip, prefixlen, device, namespace): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def flush_ip_addresses(ip_version, device, namespace): family = _IP_VERSION_FAMILY_MAP[ip_version] try: @@ -282,6 +299,10 @@ def flush_ip_addresses(ip_version, device, namespace): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def create_interface(ifname, namespace, kind, **kwargs): ifname = ifname[:constants.DEVICE_NAME_MAX_LEN] try: @@ -302,11 +323,19 @@ def create_interface(ifname, namespace, kind, **kwargs): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def delete_interface(ifname, namespace, **kwargs): _run_iproute_link("del", ifname, namespace, **kwargs) @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def interface_exists(ifname, namespace): try: idx = _get_link_id(ifname, namespace) @@ -320,6 +349,10 @@ def interface_exists(ifname, namespace): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def set_link_flags(device, namespace, flags): link = _run_iproute_link("get", device, namespace)[0] new_flags = flags | link['flags'] @@ -327,11 +360,19 @@ def set_link_flags(device, namespace, flags): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def set_link_attribute(device, namespace, **attributes): return _run_iproute_link("set", device, namespace, **attributes) @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def get_link_attributes(device, namespace): link = _run_iproute_link("get", device, namespace)[0] return { @@ -347,6 +388,10 @@ def get_link_attributes(device, namespace): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def add_neigh_entry(ip_version, ip_address, mac_address, device, namespace, **kwargs): """Add a neighbour entry. @@ -368,6 +413,10 @@ def add_neigh_entry(ip_version, ip_address, mac_address, device, namespace, @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def delete_neigh_entry(ip_version, ip_address, mac_address, device, namespace, **kwargs): """Delete a neighbour entry. @@ -394,6 +443,10 @@ def delete_neigh_entry(ip_version, ip_address, mac_address, device, namespace, @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def dump_neigh_entries(ip_version, device, namespace, **kwargs): """Dump all neighbour entries. @@ -423,6 +476,10 @@ def dump_neigh_entries(ip_version, device, namespace, **kwargs): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def create_netns(name, **kwargs): """Create a network namespace. @@ -436,6 +493,10 @@ def create_netns(name, **kwargs): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def remove_netns(name, **kwargs): """Remove a network namespace. @@ -449,6 +510,10 @@ def remove_netns(name, **kwargs): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def list_netns(**kwargs): """List network namespaces. @@ -475,6 +540,10 @@ def _make_serializable(value): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def get_link_devices(namespace, **kwargs): """List interfaces in a namespace @@ -505,6 +574,10 @@ def get_device_names(namespace, **kwargs): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def get_ip_addresses(namespace, **kwargs): """List of IP addresses in a namespace @@ -520,6 +593,10 @@ def get_ip_addresses(namespace, **kwargs): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def list_ip_rules(namespace, ip_version, match=None, **kwargs): """List all IP rules""" try: @@ -539,6 +616,10 @@ def list_ip_rules(namespace, ip_version, match=None, **kwargs): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def add_ip_rule(namespace, **kwargs): """Add a new IP rule""" try: @@ -555,6 +636,10 @@ def add_ip_rule(namespace, **kwargs): @privileged.default.entrypoint +# NOTE(slaweq): Because of issue with pyroute2.NetNS objects running in threads +# we need to lock this function to workaround this issue. +# For details please check https://bugs.launchpad.net/neutron/+bug/1811515 +@lockutils.synchronized("privileged-ip-lib") def delete_ip_rule(namespace, **kwargs): """Delete an IP rule""" try: