From 2a7030a6b7ae2ab2e24648727bbde91b05de82cc Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Thu, 19 Sep 2019 10:58:32 +0000 Subject: [PATCH] Change ip_lib decorators order Change the execution order of: - @privileged.default.entrypoint - @lockutils.synchronized("privileged-ip-lib") "synchronized" decorator holds the execution of the function until the lock is released. Using the current decorator ordering, this active wait is done inside the privsep context. This can exhaust the number of execution threads reserved for the privsep daemon. Closes-Bug: #1833721 Change-Id: Ifcce954003e360f620f9131a36a08ab84cbe6193 --- neutron/privileged/agent/linux/ip_lib.py | 131 ++++++++--------------- 1 file changed, 43 insertions(+), 88 deletions(-) diff --git a/neutron/privileged/agent/linux/ip_lib.py b/neutron/privileged/agent/linux/ip_lib.py index 2edecb515bf..4eae6577b6c 100644 --- a/neutron/privileged/agent/linux/ip_lib.py +++ b/neutron/privileged/agent/linux/ip_lib.py @@ -11,6 +11,7 @@ # under the License. import errno +import functools import os import socket @@ -24,6 +25,7 @@ from pyroute2.netlink.rtnl import ifinfmsg from pyroute2.netlink.rtnl import ndmsg from pyroute2 import NetlinkError from pyroute2 import netns +import six from neutron._i18n import _ from neutron import privileged @@ -34,6 +36,25 @@ _IP_VERSION_FAMILY_MAP = {4: socket.AF_INET, 6: socket.AF_INET6} NETNS_RUN_DIR = '/var/run/netns' +@lockutils.synchronized("privileged-ip-lib") +# 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 +def _sync(input_func): + # NOTE(ralonsoh): this is needed because PY2 functools.update_wrapper do + # not handle correctly partial functions (nested decorators). This could be + # removed once we abandon support for PY2. + if six.PY2 and isinstance(input_func, functools.partial): + for asig in functools.WRAPPER_ASSIGNMENTS: + setattr(input_func, asig, '') + + @six.wraps(input_func) + def sync_inner(*args, **kwargs): + return input_func(*args, **kwargs) + + return sync_inner + + def _get_scope_name(scope): """Return the name of the scope (given as a number), or the scope number if the name is unknown. @@ -116,11 +137,8 @@ def _make_route_dict(destination, nexthop, device, scope): 'scope': scope} +@_sync @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. @@ -179,11 +197,8 @@ def get_iproute(namespace): return pyroute2.IPRoute() +@_sync @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 open_namespace(namespace): """Open namespace to test if the namespace is ready to be manipulated""" with pyroute2.NetNS(namespace, flags=0): @@ -275,11 +290,8 @@ def _run_iproute_addr(command, device, namespace, **kwargs): raise +@_sync @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] @@ -298,11 +310,8 @@ def add_ip_address(ip_version, ip, prefixlen, device, namespace, scope, raise +@_sync @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: @@ -322,11 +331,8 @@ def delete_ip_address(ip_version, ip, prefixlen, device, namespace): raise +@_sync @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: @@ -339,11 +345,8 @@ def flush_ip_addresses(ip_version, device, namespace): raise +@_sync @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: @@ -363,20 +366,14 @@ def create_interface(ifname, namespace, kind, **kwargs): raise +@_sync @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) +@_sync @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) @@ -389,31 +386,22 @@ def interface_exists(ifname, namespace): raise +@_sync @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'] return _run_iproute_link("set", device, namespace, flags=new_flags) +@_sync @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) +@_sync @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 { @@ -429,11 +417,8 @@ def get_link_attributes(device, namespace): } +@_sync @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. @@ -454,11 +439,8 @@ def add_neigh_entry(ip_version, ip_address, mac_address, device, namespace, **kwargs) +@_sync @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. @@ -484,11 +466,8 @@ def delete_neigh_entry(ip_version, ip_address, mac_address, device, namespace, raise +@_sync @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. @@ -569,11 +548,8 @@ def make_serializable(value): return value +@_sync @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 @@ -603,11 +579,8 @@ def get_device_names(namespace, **kwargs): return device_names +@_sync @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 @@ -622,11 +595,8 @@ def get_ip_addresses(namespace, **kwargs): raise +@_sync @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: @@ -645,11 +615,8 @@ def list_ip_rules(namespace, ip_version, match=None, **kwargs): raise +@_sync @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: @@ -665,11 +632,8 @@ def add_ip_rule(namespace, **kwargs): raise +@_sync @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: @@ -717,11 +681,8 @@ def _make_pyroute2_route_args(namespace, ip_version, cidr, device, via, table, return args +@_sync @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_route(namespace, cidr, ip_version, device=None, via=None, table=None, metric=None, scope=None, **kwargs): """Add an IP route""" @@ -737,11 +698,8 @@ def add_ip_route(namespace, cidr, ip_version, device=None, via=None, raise +@_sync @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_routes(namespace, ip_version, device=None, table=None, **kwargs): """List IP routes""" kwargs.update(_make_pyroute2_route_args( @@ -755,11 +713,8 @@ def list_ip_routes(namespace, ip_version, device=None, table=None, **kwargs): raise +@_sync @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_route(namespace, cidr, ip_version, device=None, via=None, table=None, scope=None, **kwargs): """Delete an IP route"""