Printing just the datapath on each upcall gives little information (most
often, there will only be one well-known datapath). Instead, print both
the input port name (plus the datapath).

In order to do this, refactor decode_nla to always generate the dump
that only gets printed if needed. That way it can be called earlier on.

Signed-off-by: Adrian Moreno <amore...@redhat.com>
---
 utilities/usdt-scripts/upcall_cost.py    |   4 +-
 utilities/usdt-scripts/upcall_monitor.py | 110 +++++++++++++----------
 utilities/usdt-scripts/usdt_lib.py       |  20 ++++-
 3 files changed, 84 insertions(+), 50 deletions(-)

diff --git a/utilities/usdt-scripts/upcall_cost.py 
b/utilities/usdt-scripts/upcall_cost.py
index 53028f059..d1948dae7 100755
--- a/utilities/usdt-scripts/upcall_cost.py
+++ b/utilities/usdt-scripts/upcall_cost.py
@@ -354,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 = dp_map.get(dpif_name, port)
+        self.dp_port = dp_map.get_port_number(dpif_name, port)
         if self.dp_port is None:
             #
             # As we only identify interfaces at startup, new interfaces could
@@ -447,7 +447,7 @@ class RecvUpcall(Event):
                 self.pkt_len)
 
     def get_system_dp_port(dpif_name):
-        return dp_map.get_map().get(dpif_name, {}).get("ovs-system", None)
+        return dp_map.get_port_number(dpif_name, "ovs-system")
 
     def decode_nlm(msg, indent=4, dump=True):
         bytes_left = len(msg)
diff --git a/utilities/usdt-scripts/upcall_monitor.py 
b/utilities/usdt-scripts/upcall_monitor.py
index 917892b0e..b09fe1820 100755
--- a/utilities/usdt-scripts/upcall_monitor.py
+++ b/utilities/usdt-scripts/upcall_monitor.py
@@ -20,10 +20,10 @@
 # packets sent by the kernel to ovs-vswitchd. By default, it will show all
 # upcall events, which looks something like this:
 #
-# TIME               CPU  COMM      PID      DPIF_NAME          TYPE PKT_LEN...
-# 5952147.003848809  2    handler4  1381158  system@ovs-system  0    98     132
-# 5952147.003879643  2    handler4  1381158  system@ovs-system  0    70     160
-# 5952147.003914924  2    handler4  1381158  system@ovs-system  0    98     152
+# TIME               CPU  COMM      PID      PORT_NAME                TYPE ..
+# 5952147.003848809  2    handler4  1381158  eth0 (system@ovs-system)  0
+# 5952147.003879643  2    handler4  1381158  eth0 (system@ovs-system)  0
+# 5952147.003914924  2    handler4  1381158  eth0 (system@ovs-system)  0
 #
 # Also, upcalls dropped by the kernel (e.g: because the netlink buffer is full)
 # are reported. This requires the kernel version to be greater or equal to 
5.14.
@@ -70,7 +70,7 @@
 #
 #  $ ./upcall_monitor.py --packet-decode decode --flow-key-decode nlraw \
 #      --packet-size 128 --flow-key-size 256
-#  TIME               CPU  COMM             PID        DPIF_NAME          ...
+#  TIME               CPU  COMM             PID        PORT_NAME          ...
 #  5953013.333214231  2    handler4         1381158    system@ovs-system  ...
 #    Flow key size 132 bytes, size captured 132 bytes.
 #      nla_len 8, nla_type OVS_KEY_ATTR_RECIRC_ID[20], data: 00 00 00 00
@@ -120,6 +120,8 @@ from os.path import exists
 from scapy.all import hexdump, wrpcap
 from scapy.layers.l2 import Ether
 
+from usdt_lib import DpPortMapping
+
 import argparse
 import psutil
 import re
@@ -276,7 +278,7 @@ int kretprobe__ovs_dp_upcall(struct pt_regs *ctx)
 #
 # print_key()
 #
-def print_key(event):
+def print_key(event, decode_dump):
     if event.key_size < options.flow_key_size:
         key_len = event.key_size
     else:
@@ -297,39 +299,48 @@ def print_key(event):
                                            dump=True),
                      flags=re.MULTILINE))
 
-    if options.flow_key_decode == 'nlraw':
-        nla = decode_nlm(bytes(event.key)[:key_len])
-    else:
-        nla = decode_nlm(bytes(event.key)[:key_len], dump=False)
-
-    if "OVS_KEY_ATTR_IN_PORT" in nla:
-        port = struct.unpack("=I", nla["OVS_KEY_ATTR_IN_PORT"])[0]
-    else:
-        port = "Unknown"
-
-    return port
+    if options.flow_key_decode == "nlraw":
+        for line in decode_dump:
+            print(line)
 
 
 #
 # print_event()
 #
 def print_event(ctx, data, size):
-    event = b['events'].event(data)
-    print("{:<18.9f} {:<4} {:<16} {:<10} {:<32} {:<4} {:<10} {:<12} {:<8}".
-          format(event.ts / 1000000000,
-                 event.cpu,
-                 event.comm.decode("utf-8"),
-                 event.pid,
-                 event.dpif_name.decode("utf-8"),
-                 event.upcall_type,
-                 event.pkt_size,
-                 event.key_size,
-                 event.result))
+    event = b["events"].event(data)
+    dp = event.dpif_name.decode("utf-8")
+
+    nla, key_dump = decode_nlm(
+        bytes(event.key)[: min(event.key_size, options.flow_key_size)]
+    )
+    if "OVS_KEY_ATTR_IN_PORT" in nla:
+        port_no = struct.unpack("=I", nla["OVS_KEY_ATTR_IN_PORT"])[0]
+        port = dp_map.get_port_name(dp.partition("@")[-1], port_no)
+        if not port:
+            port = str(port_no)
+    else:
+        port = "Unknown"
+
+    print(
+        "{:<18.9f} {:<4} {:<16} {:<10} {:<40} {:<4} {:<10} {:<12} {:<8}".
+        format(
+            event.ts / 1000000000,
+            event.cpu,
+            event.comm.decode("utf-8"),
+            event.pid,
+            "{} ({})".format(port, dp),
+            event.upcall_type,
+            event.pkt_size,
+            event.key_size,
+            event.result,
+        )
+    )
 
     #
     # Dump flow key information
     #
-    port = print_key(event)
+    print_key(event, key_dump)
 
     #
     # Decode packet only if there is data
@@ -368,23 +379,26 @@ def print_event(ctx, data, size):
 #
 # decode_nlm()
 #
-def decode_nlm(msg, indent=4, dump=True):
+def decode_nlm(msg, indent=4):
     bytes_left = len(msg)
     result = {}
+    dump = []
 
     while bytes_left:
         if bytes_left < 4:
-            if dump:
-                print("{}WARN: decode truncated; can't read header".format(
-                    ' ' * indent))
+            dump.append(
+                "{}WARN: decode truncated; can't read header".format(
+                    " " * indent
+                )
+            )
             break
 
         nla_len, nla_type = struct.unpack("=HH", msg[:4])
 
         if nla_len < 4:
-            if dump:
-                print("{}WARN: decode truncated; nla_len < 4".format(
-                    ' ' * indent))
+            dump.append(
+                "{}WARN: decode truncated; nla_len < 4".format(" " * indent)
+            )
             break
 
         nla_data = msg[4:nla_len]
@@ -396,16 +410,19 @@ def decode_nlm(msg, indent=4, dump=True):
         else:
             result[get_ovs_key_attr_str(nla_type)] = nla_data
 
-        if dump:
-            print("{}nla_len {}, nla_type {}[{}], data: {}{}".format(
+        dump.append(
+            "{}nla_len {}, nla_type {}[{}], data: {}{}".format(
                 ' ' * indent, nla_len, get_ovs_key_attr_str(nla_type),
                 nla_type,
-                "".join("{:02x} ".format(b) for b in nla_data), trunc))
+                "".join("{:02x} ".format(b) for b in nla_data), trunc)
+        )
 
         if trunc != "":
-            if dump:
-                print("{}WARN: decode truncated; nla_len > msg_len[{}] ".
-                      format(' ' * indent, bytes_left))
+            dump.append(
+                "{}WARN: decode truncated; nla_len > msg_len[{}] ".format(
+                    " " * indent, bytes_left
+                )
+            )
             break
 
         # update next offset, but make sure it's aligned correctly
@@ -413,7 +430,7 @@ def decode_nlm(msg, indent=4, dump=True):
         msg = msg[next_offset:]
         bytes_left -= next_offset
 
-    return result
+    return result, dump
 
 
 #
@@ -498,6 +515,9 @@ def main():
     #
     global b
     global options
+    global dp_map
+
+    dp_map = DpPortMapping()
 
     #
     # Argument parsing
@@ -606,8 +626,8 @@ def main():
     #
     # Print header
     #
-    print("{:<18} {:<4} {:<16} {:<10} {:<32} {:<4} {:<10} {:<12} {:<8}".format(
-        "TIME", "CPU", "COMM", "PID", "DPIF_NAME", "TYPE", "PKT_LEN",
+    print("{:<18} {:<4} {:<16} {:<10} {:<40} {:<4} {:<10} {:<12} {:<8}".format(
+        "TIME", "CPU", "COMM", "PID", "PORT_NAME", "TYPE", "PKT_LEN",
         "FLOW_KEY_LEN", "RESULT"))
 
     #
diff --git a/utilities/usdt-scripts/usdt_lib.py 
b/utilities/usdt-scripts/usdt_lib.py
index cf6fa576a..d8659102f 100644
--- a/utilities/usdt-scripts/usdt_lib.py
+++ b/utilities/usdt-scripts/usdt_lib.py
@@ -33,12 +33,26 @@ class DpPortMapping:
         """Override the internal cache map."""
         self.cache_map = cache_map
 
-    def get(self, dp, port_no):
-        """Get the portname from a port number."""
+    def get_port_name(self, dp, port_no):
+        """Get the port name from a port number."""
         if self.cache_map is None:
             self._get_mapping()
 
-        return self.cache_map.get(dp, {}).get(port_no, None)
+        if not self.cache_map.get(dp):
+            return None
+
+        for name, num in self.cache_map[dp].items():
+            if num == port_no:
+                return name
+
+        return None
+
+    def get_port_number(self, dp, port):
+        """Get the port number from a port name."""
+        if self.cache_map is None:
+            self._get_mapping()
+
+        return self.cache_map.get(dp, {}).get(port, None)
 
     def _get_mapping(self):
         """Get the datapath port mapping from the running OVS."""
-- 
2.48.1

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to