The upcall_cost.py script has a useful port mapping cache that can be very useful for other scripts.
Move it into a library file (usdt_lib.py). While we're at it, refactor it into a class since setting attributes to functions and having it return different types depending on input is not very clean. This patch should not introduce any functional change. Signed-off-by: Adrian Moreno <amore...@redhat.com> --- utilities/automake.mk | 7 ++- utilities/usdt-scripts/upcall_cost.py | 71 ++++----------------------- utilities/usdt-scripts/usdt_lib.py | 70 ++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 63 deletions(-) create mode 100644 utilities/usdt-scripts/usdt_lib.py diff --git a/utilities/automake.mk b/utilities/automake.mk index 22260b254..fcd353109 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -28,7 +28,8 @@ usdt_SCRIPTS += \ utilities/usdt-scripts/kernel_delay.rst \ utilities/usdt-scripts/reval_monitor.py \ utilities/usdt-scripts/upcall_cost.py \ - utilities/usdt-scripts/upcall_monitor.py + utilities/usdt-scripts/upcall_monitor.py \ + utilities/usdt-scripts/usdt_lib.py completion_SCRIPTS += \ utilities/ovs-appctl-bashcomp.bash \ @@ -78,7 +79,9 @@ EXTRA_DIST += \ utilities/usdt-scripts/kernel_delay.rst \ utilities/usdt-scripts/reval_monitor.py \ utilities/usdt-scripts/upcall_cost.py \ - utilities/usdt-scripts/upcall_monitor.py + utilities/usdt-scripts/upcall_monitor.py \ + utilities/usdt-scripts/usdt_lib.py + MAN_ROOTS += \ utilities/ovs-testcontroller.8.in \ utilities/ovs-dpctl.8.in \ diff --git a/utilities/usdt-scripts/upcall_cost.py b/utilities/usdt-scripts/upcall_cost.py index 1a3608d5b..53028f059 100755 --- a/utilities/usdt-scripts/upcall_cost.py +++ b/utilities/usdt-scripts/upcall_cost.py @@ -58,12 +58,13 @@ from strenum import StrEnum from text_histogram3 import histogram from time import process_time +from usdt_lib import DpPortMapping + import argparse import ast import psutil import re import struct -import subprocess import sys import time @@ -353,7 +354,7 @@ class DpUpcall(Event): pkt_frag_len): super(DpUpcall, self).__init__(ts, pid, comm, cpu, EventType.DP_UPCALL) self.dpif_name = dpif_name - self.dp_port = get_dp_mapping(dpif_name, port) + self.dp_port = dp_map.get(dpif_name, port) if self.dp_port is None: # # As we only identify interfaces at startup, new interfaces could @@ -446,13 +447,7 @@ class RecvUpcall(Event): self.pkt_len) def get_system_dp_port(dpif_name): - dp_map = get_dp_mapping(dpif_name, "ovs-system", return_map=True) - if dpif_name not in dp_map: - return None - try: - return dp_map[dpif_name]["ovs-system"] - except KeyError: - return None + return dp_map.get_map().get(dpif_name, {}).get("ovs-system", None) def decode_nlm(msg, indent=4, dump=True): bytes_left = len(msg) @@ -621,54 +616,6 @@ class OpFlowExecute(Event): return event -# -# get_dp_mapping() -# -def get_dp_mapping(dp, port, return_map=False, dp_map=None): - if options.unit_test: - return port - - if dp_map is not None: - get_dp_mapping.dp_port_map_cache = dp_map - - # - # Build a cache, so we do not have to execue the ovs command each time. - # - if not hasattr(get_dp_mapping, "dp_port_map_cache"): - try: - output = subprocess.check_output(['ovs-appctl', 'dpctl/show'], - encoding='utf8').split("\n") - except subprocess.CalledProcessError: - output = "" - pass - - current_dp = None - get_dp_mapping.dp_port_map_cache = {} - - for line in output: - match = re.match("^system@(.*):$", line) - if match is not None: - current_dp = match.group(1) - - match = re.match("^ port ([0-9]+): ([^ /]*)", line) - if match is not None and current_dp is not None: - try: - get_dp_mapping.dp_port_map_cache[ - current_dp][match.group(2)] = int(match.group(1)) - except KeyError: - get_dp_mapping.dp_port_map_cache[current_dp] = \ - {match.group(2): int(match.group(1))} - - if return_map: - return get_dp_mapping.dp_port_map_cache - - if dp not in get_dp_mapping.dp_port_map_cache or \ - port not in get_dp_mapping.dp_port_map_cache[dp]: - return None - - return get_dp_mapping.dp_port_map_cache[dp][port] - - # # event_to_dict() # @@ -1429,6 +1376,9 @@ def main(): global events_received global event_count global export_file + global dp_map + + dp_map = DpPortMapping() # # Argument parsing @@ -1531,9 +1481,9 @@ def main(): event_count = {'total': {}, 'valid': {}, 'miss': {}} if options.read_events is None: # - # Call get_dp_mapping() to prepare the cache + # Prepare the datapath port mapping cache # - dp_port_map = get_dp_mapping("ovs-system", "eth0", return_map=True) + dp_port_map = dp_map.get_map() if export_file is not None: export_file.write("dp_port_map = {}\n".format(dp_port_map)) @@ -1642,8 +1592,7 @@ def main(): if entry.startswith('dp_port_map = {'): if not dp_port_mapping_valid: dp_port_mapping_valid = True - get_dp_mapping("", "", - dp_map=ast.literal_eval(entry[14:])) + dp_map.set_map(ast.literal_eval(entry[14:])) elif (entry.startswith('event = {') and dp_port_mapping_valid): event = ast.literal_eval(entry[8:]) diff --git a/utilities/usdt-scripts/usdt_lib.py b/utilities/usdt-scripts/usdt_lib.py new file mode 100644 index 000000000..cf6fa576a --- /dev/null +++ b/utilities/usdt-scripts/usdt_lib.py @@ -0,0 +1,70 @@ +# Copyright (c) 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 re +import subprocess + + +class DpPortMapping: + """Class used to retrieve and cache datapath port numbers to port names.""" + + def __init__(self): + self.cache_map = None + + def get_map(self): + """Get the cache map.""" + if not self.cache_map: + self._get_mapping() + + return self.cache_map + + def set_map(self, cache_map): + """Override the internal cache map.""" + self.cache_map = cache_map + + def get(self, dp, port_no): + """Get the portname from a port number.""" + if self.cache_map is None: + self._get_mapping() + + return self.cache_map.get(dp, {}).get(port_no, None) + + def _get_mapping(self): + """Get the datapath port mapping from the running OVS.""" + try: + output = subprocess.check_output( + ["ovs-appctl", "dpctl/show"], encoding="utf8" + ).split("\n") + except subprocess.CalledProcessError: + output = "" + return + + current_dp = None + self.cache_map = {} + + for line in output: + match = re.match("^system@(.*):$", line) + if match: + current_dp = match.group(1) + + match = re.match("^ port ([0-9]+): ([^ /]*)", line) + if match and current_dp: + try: + self.cache_map[current_dp][match.group(2)] = int( + match.group(1) + ) + except KeyError: + self.cache_map[current_dp] = { + match.group(2): int(match.group(1)) + } -- 2.48.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev