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

Reply via email to