Newer versions of Python require a different iterator function. This
change will make the iterator classes work with all Python versions.

Adds a fix for python3 as it does not support the long() type.
The fix guaranties the script still works on Python 2.7.

The uKey walker is rather slow on python3, so added a spinner to
indicate we are still busy processing entries.

Fix functions using the iterkeys() function on dictionaries.

Signed-off-by: Eelco Chaudron <[email protected]>
---

v3: Fixing iterkeys, and adding a spinner
v2: Adding fix for python3 compatibility as it does not support long()

utilities/gdb/ovs_gdb.py | 123 ++++++++++++++++++++++++++++++++-------
 1 file changed, 103 insertions(+), 20 deletions(-)

diff --git a/utilities/gdb/ovs_gdb.py b/utilities/gdb/ovs_gdb.py
index cb9778c69..e8fb44c19 100644
--- a/utilities/gdb/ovs_gdb.py
+++ b/utilities/gdb/ovs_gdb.py
@@ -55,7 +55,11 @@
 #    ...
 #    ...
 #
+from __future__ import print_function
+
 import gdb
+import six
+import sys
 import uuid
 
 
@@ -65,6 +69,13 @@ import uuid
 N_UMAPS = 512
 
 
+#
+# For Python2-3 compatibility define long as int
+#
+if six.PY3:
+    long = int
+
+
 #
 # The container_of code below is a copied from the Linux kernel project file,
 # scripts/gdb/linux/utils.py. It has the following copyright header:
@@ -150,6 +161,37 @@ def eth_addr_to_string(eth_addr):
         long(eth_addr['ea'][5]))
 
 
+#
+# Simple class to print a spinner on the console
+#
+class ProgressIndicator(object):
+    def __init__(self, message=None):
+        self.spinner = "/-\|"
+        self.spinner_index = 0
+        self.message = message
+
+        if self.message is not None:
+            print(self.message, end='')
+
+    def update(self):
+        print("{}\b".format(self.spinner[self.spinner_index]), end='')
+        sys.stdout.flush()
+        self.spinner_index += 1
+        if self.spinner_index >= len(self.spinner):
+            self.spinner_index = 0
+
+    def pause(self):
+        print("\r\033[K", end='')
+
+    def resume(self):
+        if self.message is not None:
+            print(self.message, end='')
+        self.update()
+
+    def done(self):
+        self.pause()
+
+
 #
 # Class that will provide an iterator over an OVS cmap.
 #
@@ -192,7 +234,7 @@ class ForEachCMAP(object):
 
         raise StopIteration
 
-    def next(self):
+    def __next__(self):
         ipml = self.cmap['impl']['p']
         if ipml['n'] == 0:
             raise StopIteration
@@ -206,6 +248,9 @@ class ForEachCMAP(object):
                             gdb.lookup_type(self.typeobj).pointer(),
                             self.member)
 
+    def next(self):
+        return self.__next__()
+
 
 #
 # Class that will provide an iterator over an OVS hmap.
@@ -229,7 +274,7 @@ class ForEachHMAP(object):
 
         raise StopIteration
 
-    def next(self):
+    def __next__(self):
         #
         # In the real implementation the n values is never checked,
         # however when debugging we do, as we might try to access
@@ -253,6 +298,9 @@ class ForEachHMAP(object):
                             gdb.lookup_type(self.typeobj).pointer(),
                             self.member)
 
+    def next(self):
+        return self.__next__()
+
 
 #
 # Class that will provide an iterator over an Netlink attributes
@@ -268,7 +316,7 @@ class ForEachNL():
     def round_up(self, val, round_to):
         return int(val) + (round_to - int(val)) % round_to
 
-    def next(self):
+    def __next__(self):
         if self.attr is None or \
            self.attr_len < 4 or self.attr['nla_len'] < 4 or  \
            self.attr['nla_len'] > self.attr_len:
@@ -286,6 +334,9 @@ class ForEachNL():
 
         return attr
 
+    def next(self):
+        return self.__next__()
+
 
 #
 # Class that will provide an iterator over an OVS shash.
@@ -298,14 +349,17 @@ class ForEachSHASH(ForEachHMAP):
         super(ForEachSHASH, self).__init__(shash['map'],
                                            "struct shash_node", "node")
 
-    def next(self):
-        node = super(ForEachSHASH, self).next()
+    def __next__(self):
+        node = super(ForEachSHASH, self).__next__()
 
         if self.data_typeobj is None:
             return node
 
         return node['data'].cast(gdb.lookup_type(self.data_typeobj).pointer())
 
+    def next(self):
+        return self.__next__()
+
 
 #
 # Class that will provide an iterator over an OVS simap.
@@ -315,10 +369,13 @@ class ForEachSIMAP(ForEachHMAP):
         super(ForEachSIMAP, self).__init__(shash['map'],
                                            "struct simap_node", "node")
 
-    def next(self):
-        node = super(ForEachSIMAP, self).next()
+    def __next__(self):
+        node = super(ForEachSIMAP, self).__next__()
         return node['name'], node['data']
 
+    def next(self):
+        return self.__next__()
+
 
 #
 # Class that will provide an iterator over an OVS smap.
@@ -328,10 +385,13 @@ class ForEachSMAP(ForEachHMAP):
         super(ForEachSMAP, self).__init__(shash['map'],
                                           "struct smap_node", "node")
 
-    def next(self):
-        node = super(ForEachSMAP, self).next()
+    def __next__(self):
+        node = super(ForEachSMAP, self).__next__()
         return node['key'], node['value']
 
+    def next(self):
+        return self.__next__()
+
 
 #
 # Class that will provide an iterator over an OVS list.
@@ -346,7 +406,7 @@ class ForEachLIST():
     def __iter__(self):
         return self
 
-    def next(self):
+    def __next__(self):
         if self.list.address == self.node['next']:
             raise StopIteration
 
@@ -359,6 +419,9 @@ class ForEachLIST():
                             gdb.lookup_type(self.typeobj).pointer(),
                             self.member)
 
+    def next(self):
+        return self.__next__()
+
 
 #
 # Implements the GDB "ovs_dump_bridges" command
@@ -499,7 +562,7 @@ class CmdDumpDpNetdevPollThreads(gdb.Command):
     @staticmethod
     def display_single_poll_thread(pmd_thread, indent=0):
         indent = " " * indent
-        print("{}(struct dp_netdev_pmd_thread *) {}: core_id = {:s}, "
+        print("{}(struct dp_netdev_pmd_thread *) {}: core_id = {}, "
               "numa_id {}".format(indent,
                                   pmd_thread, pmd_thread['core_id'],
                                   pmd_thread['numa_id']))
@@ -597,7 +660,7 @@ class CmdDumpNetdev(gdb.Command):
     @staticmethod
     def display_single_netdev(netdev, indent=0):
         indent = " " * indent
-        print("{}(struct netdev *) {}: name = {:15}, auto_classified = {:5}, "
+        print("{}(struct netdev *) {}: name = {:15}, auto_classified = {}, "
               "netdev_class = {}".
               format(indent, netdev, netdev['name'].string(),
                      netdev['auto_classified'], netdev['netdev_class']))
@@ -733,10 +796,11 @@ class CmdDumpOvsList(gdb.Command):
             if typeobj is None or member is None:
                 print("(struct ovs_list *) {}".format(node))
             else:
-                print("({} *) {} =".format(
+                print("({} *) {} {}".format(
                     typeobj,
                     container_of(node,
-                                 gdb.lookup_type(typeobj).pointer(), member)))
+                                 gdb.lookup_type(typeobj).pointer(), member),
+                    "=" if dump else ""))
                 if dump:
                     print("  {}\n".format(container_of(
                         node,
@@ -774,7 +838,7 @@ class CmdDumpSimap(gdb.Command):
             if len(name.string()) > max_name_len:
                 max_name_len = len(name.string())
 
-        for name in sorted(values.iterkeys()):
+        for name in sorted(six.iterkeys(values)):
             print("{}: {} / 0x{:x}".format(name.ljust(max_name_len),
                                            values[name], values[name]))
 
@@ -809,7 +873,7 @@ class CmdDumpSmap(gdb.Command):
             if len(key.string()) > max_key_len:
                 max_key_len = len(key.string())
 
-        for key in sorted(values.iterkeys()):
+        for key in sorted(six.iterkeys(values)):
             print("{}: {}".format(key.ljust(max_key_len),
                                   values[key]))
 
@@ -826,6 +890,7 @@ class CmdDumpUdpifKeys(gdb.Command):
                         <udpif_name> and <udpif_address> are omitted the
                         available udpif structures are displayed.
       short           : Only dump ukey structure addresses, no content details
+      no_count        : Do not count the number of ukeys, as it might be slow
     """
 
     def __init__(self):
@@ -834,14 +899,22 @@ class CmdDumpUdpifKeys(gdb.Command):
 
     def count_all_ukeys(self, udpif):
         count = 0
+        spinner = ProgressIndicator("Counting all ukeys: ")
+
         for j in range(0, N_UMAPS):
+            spinner.update()
             count += udpif['ukeys'][j]['cmap']['impl']['p']['n']
+
+        spinner.done()
         return count
 
     def dump_all_ukeys(self, udpif, indent=0, short=False):
         indent = " " * indent
+        spinner = ProgressIndicator("Walking ukeys: ")
         for j in range(0, N_UMAPS):
+            spinner.update()
             if udpif['ukeys'][j]['cmap']['impl']['p']['n'] != 0:
+                spinner.pause()
                 print("{}(struct umap *) {}:".
                       format(indent, udpif['ukeys'][j].address))
                 for ukey in ForEachCMAP(udpif['ukeys'][j]['cmap'],
@@ -890,10 +963,14 @@ class CmdDumpUdpifKeys(gdb.Command):
                     #         nlattr['nla_type'].cast(
                     #             gdb.lookup_type('enum ovs_key_attr')))
                     # print("{}key attributes = {}".format(indent_b, key))
+                spinner.resume()
+        spinner.done()
 
     def invoke(self, arg, from_tty):
         arg_list = gdb.string_to_argv(arg)
         all_udpifs = get_global_variable('all_udpifs')
+        no_count = "no_count" in arg_list
+
         if all_udpifs is None:
             return
 
@@ -901,12 +978,15 @@ class CmdDumpUdpifKeys(gdb.Command):
         for udpif in ForEachLIST(all_udpifs, "struct udpif", "list_node"):
             udpifs[udpif['dpif']['full_name'].string()] = udpif
 
-            if len(arg_list) == 0:
+            if len(arg_list) == 0 or (
+                    len(arg_list) == 1 and arg_list[0] == "no_count"):
                 print("(struct udpif *) {}: name = {}, total keys = {}".
                       format(udpif, udpif['dpif']['full_name'].string(),
-                             self.count_all_ukeys(udpif)))
+                             self.count_all_ukeys(udpif) if not no_count
+                             else "<not counted!>"))
 
-        if len(arg_list) == 0:
+        if len(arg_list) == 0 or (
+                len(arg_list) == 1 and arg_list[0] == "no_count"):
             return
 
         if arg_list[0] in udpifs:
@@ -1074,7 +1154,7 @@ class CmdShowFDB(gdb.Command):
                 max_name_len = len(node['up']['name'].string())
 
         if len(arg_list) == 0:
-            for name in sorted(all_name.iterkeys()):
+            for name in sorted(six.iterkeys(all_name)):
                 print("{}: (struct mac_learning *) {}".
                       format(name.ljust(max_name_len),
                              all_name[name]['ml']))
@@ -1140,10 +1220,13 @@ class CmdShowUpcall(gdb.Command):
 
             count = 0
             j = i
+            spinner = ProgressIndicator("Counting all ukeys: ")
             while j < N_UMAPS:
+                spinner.update()
                 count += udpif['ukeys'][j]['cmap']['impl']['p']['n']
                 j += int(udpif['n_revalidators'])
 
+            spinner.done()
             print("{}  {}: (keys {}){}".
                   format(indent, revalidator['id'], count, dbg_str))
 
-- 
2.17.2

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to