Skip to content

Commit

Permalink
utilities: Update gdb script so it works with all python versions
Browse files Browse the repository at this point in the history
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.

Tested-by: solomon <[email protected]>
Signed-off-by: Eelco Chaudron <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
chaudron authored and blp committed Jan 10, 2019
1 parent 0b4caa2 commit e33b3fe
Showing 1 changed file with 103 additions and 20 deletions.
123 changes: 103 additions & 20 deletions utilities/gdb/ovs_gdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@
# ...
# ...
#
from __future__ import print_function

import gdb
import six
import sys
import uuid


Expand All @@ -65,6 +69,13 @@
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:
Expand Down Expand Up @@ -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.
#
Expand Down Expand Up @@ -192,7 +234,7 @@ def __next(self):

raise StopIteration

def next(self):
def __next__(self):
ipml = self.cmap['impl']['p']
if ipml['n'] == 0:
raise StopIteration
Expand All @@ -206,6 +248,9 @@ def next(self):
gdb.lookup_type(self.typeobj).pointer(),
self.member)

def next(self):
return self.__next__()


#
# Class that will provide an iterator over an OVS hmap.
Expand All @@ -229,7 +274,7 @@ def __next(self, start):

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
Expand All @@ -253,6 +298,9 @@ def next(self):
gdb.lookup_type(self.typeobj).pointer(),
self.member)

def next(self):
return self.__next__()


#
# Class that will provide an iterator over an Netlink attributes
Expand All @@ -268,7 +316,7 @@ def __iter__(self):
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:
Expand All @@ -286,6 +334,9 @@ def next(self):

return attr

def next(self):
return self.__next__()


#
# Class that will provide an iterator over an OVS shash.
Expand All @@ -298,14 +349,17 @@ def __init__(self, shash, typeobj=None):
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.
Expand All @@ -315,10 +369,13 @@ def __init__(self, shash):
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.
Expand All @@ -328,10 +385,13 @@ def __init__(self, shash):
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.
Expand All @@ -346,7 +406,7 @@ def __init__(self, list, typeobj=None, member='node'):
def __iter__(self):
return self

def next(self):
def __next__(self):
if self.list.address == self.node['next']:
raise StopIteration

Expand All @@ -359,6 +419,9 @@ def next(self):
gdb.lookup_type(self.typeobj).pointer(),
self.member)

def next(self):
return self.__next__()


#
# Implements the GDB "ovs_dump_bridges" command
Expand Down Expand Up @@ -499,7 +562,7 @@ def __init__(self):
@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']))
Expand Down Expand Up @@ -597,7 +660,7 @@ def __init__(self):
@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']))
Expand Down Expand Up @@ -733,10 +796,11 @@ def invoke(self, arg, from_tty):
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,
Expand Down Expand Up @@ -774,7 +838,7 @@ def invoke(self, arg, from_tty):
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]))

Expand Down Expand Up @@ -809,7 +873,7 @@ def invoke(self, arg, from_tty):
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]))

Expand All @@ -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):
Expand All @@ -834,14 +899,22 @@ def __init__(self):

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'],
Expand Down Expand Up @@ -890,23 +963,30 @@ def dump_all_ukeys(self, udpif, indent=0, short=False):
# 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

udpifs = dict()
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:
Expand Down Expand Up @@ -1074,7 +1154,7 @@ def invoke(self, arg, from_tty):
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']))
Expand Down Expand Up @@ -1140,10 +1220,13 @@ def display_udpif_upcall(udpif, indent=0, dbg=False):

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))

Expand Down

0 comments on commit e33b3fe

Please sign in to comment.