]> git.proxmox.com Git - mirror_ovs.git/blame - utilities/gdb/ovs_gdb.py
ovsdb-cluster: Use ovs-vsctl instead of ovn-nbctl and ovn-sbctl.
[mirror_ovs.git] / utilities / gdb / ovs_gdb.py
CommitLineData
0a3348d1
EC
1#
2# Copyright (c) 2018 Eelco Chaudron
3#
4# This program is free software; you can redistribute it and/or
5# modify it under the terms of the GNU General Public License
6# as published by the Free Software Foundation; either version
7# 2 of the License, or (at your option) any later version.
8#
9# Files name:
10# ovs_gdb.py
11#
12# Description:
13# GDB commands and functions for Open vSwitch debugging
14#
15# Author:
16# Eelco Chaudron
17#
18# Initial Created:
19# 23 April 2018
20#
21# Notes:
22# It implements the following GDB commands:
ef557e2c 23# - ovs_dump_bridge {ports|wanted}
0a3348d1
EC
24# - ovs_dump_bridge_ports <struct bridge *>
25# - ovs_dump_dp_netdev [ports]
5d0a6267 26# - ovs_dump_dp_netdev_poll_threads <struct dp_netdev *>
0a3348d1 27# - ovs_dump_dp_netdev_ports <struct dp_netdev *>
b9683ff0 28# - ovs_dump_dp_provider
0a3348d1 29# - ovs_dump_netdev
42562061 30# - ovs_dump_netdev_provider
5d0a6267 31# - ovs_dump_ovs_list <struct ovs_list *> {[<structure>] [<member>] {dump}]}
42562061 32# - ovs_dump_simap <struct simap *>
cd5b89a5 33# - ovs_dump_smap <struct smap *>
b23d42a6 34# - ovs_dump_udpif_keys {<udpif_name>|<udpif_address>} {short}
ef557e2c 35# - ovs_show_fdb {[<bridge_name>] {dbg} {hash}}
b23d42a6 36# - ovs_show_upcall {dbg}
0a3348d1
EC
37#
38# Example:
39# $ gdb $(which ovs-vswitchd) $(pidof ovs-vswitchd)
40# (gdb) source ./utilities/gdb/ovs_gdb.py
41#
42# (gdb) ovs_dump_<TAB>
43# ovs_dump_bridge ovs_dump_bridge_ports ovs_dump_dp_netdev
44# ovs_dump_dp_netdev_ports ovs_dump_netdev
45#
46# (gdb) ovs_dump_bridge
47# (struct bridge *) 0x5615471ed2e0: name = br2, type = system
48# (struct bridge *) 0x561547166350: name = br0, type = system
49# (struct bridge *) 0x561547216de0: name = ovs_pvp_br0, type = netdev
50# (struct bridge *) 0x5615471d0420: name = br1, type = system
51#
52# (gdb) p *(struct bridge *) 0x5615471d0420
53# $1 = {node = {hash = 24776443, next = 0x0}, name = 0x5615471cca90 "br1",
54# type = 0x561547163bb0 "system",
55# ...
56# ...
57#
e33b3fec
EC
58from __future__ import print_function
59
0a3348d1 60import gdb
e33b3fec
EC
61import six
62import sys
b23d42a6
EC
63import uuid
64
65
66#
67# Global #define's from OVS which might need updating based on a version.
68#
69N_UMAPS = 512
0a3348d1
EC
70
71
e33b3fec
EC
72#
73# For Python2-3 compatibility define long as int
74#
75if six.PY3:
76 long = int
77
78
0a3348d1
EC
79#
80# The container_of code below is a copied from the Linux kernel project file,
81# scripts/gdb/linux/utils.py. It has the following copyright header:
82#
83# # gdb helper commands and functions for Linux kernel debugging
84# #
85# # common utilities
86# #
87# # Copyright (c) Siemens AG, 2011-2013
88# #
89# # Authors:
90# # Jan Kiszka <jan.kiszka@siemens.com>
91# #
92# # This work is licensed under the terms of the GNU GPL version 2.
93#
94class CachedType:
95 def __init__(self, name):
96 self._type = None
97 self._name = name
98
99 def _new_objfile_handler(self, event):
100 self._type = None
101 gdb.events.new_objfile.disconnect(self._new_objfile_handler)
102
103 def get_type(self):
104 if self._type is None:
105 self._type = gdb.lookup_type(self._name)
106 if self._type is None:
107 raise gdb.GdbError(
108 "cannot resolve type '{0}'".format(self._name))
109 if hasattr(gdb, 'events') and hasattr(gdb.events, 'new_objfile'):
110 gdb.events.new_objfile.connect(self._new_objfile_handler)
111 return self._type
112
113
114long_type = CachedType("long")
115
116
117def get_long_type():
118 global long_type
119 return long_type.get_type()
120
121
122def offset_of(typeobj, field):
123 element = gdb.Value(0).cast(typeobj)
124 return int(str(element[field].address).split()[0], 16)
125
126
127def container_of(ptr, typeobj, member):
128 return (ptr.cast(get_long_type()) -
129 offset_of(typeobj, member)).cast(typeobj)
130
131
b9683ff0
EC
132def get_global_variable(name):
133 var = gdb.lookup_symbol(name)[0]
134 if var is None or not var.is_variable:
135 print("Can't find {} global variable, are you sure "
ed47794c 136 "you are debugging OVS?".format(name))
b9683ff0
EC
137 return None
138 return gdb.parse_and_eval(name)
139
140
ef557e2c
EC
141def get_time_msec():
142 # There is no variable that stores the current time each iteration,
143 # to get a decent time time_now() value. For now we take the global
144 # "coverage_run_time" value, which is the current time + max 5 seconds
145 # (COVERAGE_RUN_INTERVAL)
146 return long(get_global_variable("coverage_run_time")), -5000
147
148
149def get_time_now():
150 # See get_time_msec() above
151 return long(get_global_variable("coverage_run_time"))/1000, -5
152
153
154def eth_addr_to_string(eth_addr):
155 return "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}".format(
156 long(eth_addr['ea'][0]),
157 long(eth_addr['ea'][1]),
158 long(eth_addr['ea'][2]),
159 long(eth_addr['ea'][3]),
160 long(eth_addr['ea'][4]),
161 long(eth_addr['ea'][5]))
162
b23d42a6 163
e33b3fec
EC
164#
165# Simple class to print a spinner on the console
166#
167class ProgressIndicator(object):
168 def __init__(self, message=None):
169 self.spinner = "/-\|"
170 self.spinner_index = 0
171 self.message = message
172
173 if self.message is not None:
174 print(self.message, end='')
175
176 def update(self):
177 print("{}\b".format(self.spinner[self.spinner_index]), end='')
178 sys.stdout.flush()
179 self.spinner_index += 1
180 if self.spinner_index >= len(self.spinner):
181 self.spinner_index = 0
182
183 def pause(self):
184 print("\r\033[K", end='')
185
186 def resume(self):
187 if self.message is not None:
188 print(self.message, end='')
189 self.update()
190
191 def done(self):
192 self.pause()
193
194
5d0a6267
EC
195#
196# Class that will provide an iterator over an OVS cmap.
197#
198class ForEachCMAP(object):
199 def __init__(self, cmap, typeobj=None, member='node'):
200 self.cmap = cmap
201 self.first = True
202 self.typeobj = typeobj
203 self.member = member
204 # Cursor values
205 self.node = 0
206 self.bucket_idx = 0
207 self.entry_idx = 0
208
209 def __iter__(self):
210 return self
211
212 def __get_CMAP_K(self):
213 ptr_type = gdb.lookup_type("void").pointer()
214 return (64 - 4) / (4 + ptr_type.sizeof)
215
216 def __next(self):
217 ipml = self.cmap['impl']['p']
218
219 if self.node != 0:
220 self.node = self.node['next']['p']
221 if self.node != 0:
222 return
223
224 while self.bucket_idx <= ipml['mask']:
225 buckets = ipml['buckets'][self.bucket_idx]
226 while self.entry_idx < self.__get_CMAP_K():
227 self.node = buckets['nodes'][self.entry_idx]['next']['p']
228 self.entry_idx += 1
229 if self.node != 0:
230 return
231
232 self.bucket_idx += 1
233 self.entry_idx = 0
234
235 raise StopIteration
236
e33b3fec 237 def __next__(self):
5d0a6267
EC
238 ipml = self.cmap['impl']['p']
239 if ipml['n'] == 0:
240 raise StopIteration
241
242 self.__next()
243
244 if self.typeobj is None:
245 return self.node
246
247 return container_of(self.node,
248 gdb.lookup_type(self.typeobj).pointer(),
249 self.member)
250
e33b3fec
EC
251 def next(self):
252 return self.__next__()
253
5d0a6267 254
0a3348d1
EC
255#
256# Class that will provide an iterator over an OVS hmap.
257#
258class ForEachHMAP(object):
259 def __init__(self, hmap, typeobj=None, member='node'):
260 self.hmap = hmap
261 self.node = None
262 self.first = True
263 self.typeobj = typeobj
264 self.member = member
265
266 def __iter__(self):
267 return self
268
269 def __next(self, start):
270 for i in range(start, (self.hmap['mask'] + 1)):
271 self.node = self.hmap['buckets'][i]
272 if self.node != 0:
273 return
274
275 raise StopIteration
276
e33b3fec 277 def __next__(self):
0a3348d1
EC
278 #
279 # In the real implementation the n values is never checked,
280 # however when debugging we do, as we might try to access
281 # a hmap that has been cleared/hmap_destroy().
282 #
283 if self.hmap['n'] <= 0:
284 raise StopIteration
285
286 if self.first:
287 self.first = False
288 self.__next(0)
289 elif self.node['next'] != 0:
290 self.node = self.node['next']
291 else:
292 self.__next((self.node['hash'] & self.hmap['mask']) + 1)
293
294 if self.typeobj is None:
295 return self.node
296
297 return container_of(self.node,
298 gdb.lookup_type(self.typeobj).pointer(),
299 self.member)
300
e33b3fec
EC
301 def next(self):
302 return self.__next__()
303
0a3348d1 304
b23d42a6
EC
305#
306# Class that will provide an iterator over an Netlink attributes
307#
308class ForEachNL():
309 def __init__(self, nlattrs, nlattrs_len):
310 self.attr = nlattrs.cast(gdb.lookup_type('struct nlattr').pointer())
311 self.attr_len = long(nlattrs_len)
312
313 def __iter__(self):
314 return self
315
316 def round_up(self, val, round_to):
317 return int(val) + (round_to - int(val)) % round_to
318
e33b3fec 319 def __next__(self):
b23d42a6
EC
320 if self.attr is None or \
321 self.attr_len < 4 or self.attr['nla_len'] < 4 or \
322 self.attr['nla_len'] > self.attr_len:
323 #
324 # Invalid attr set, maybe we should raise an exception?
325 #
326 raise StopIteration
327
328 attr = self.attr
329 self.attr_len -= self.round_up(attr['nla_len'], 4)
330
331 self.attr = self.attr.cast(gdb.lookup_type('void').pointer()) \
332 + self.round_up(attr['nla_len'], 4)
333 self.attr = self.attr.cast(gdb.lookup_type('struct nlattr').pointer())
334
335 return attr
336
e33b3fec
EC
337 def next(self):
338 return self.__next__()
339
b23d42a6 340
0a3348d1
EC
341#
342# Class that will provide an iterator over an OVS shash.
343#
344class ForEachSHASH(ForEachHMAP):
345 def __init__(self, shash, typeobj=None):
346
347 self.data_typeobj = typeobj
348
349 super(ForEachSHASH, self).__init__(shash['map'],
350 "struct shash_node", "node")
351
e33b3fec
EC
352 def __next__(self):
353 node = super(ForEachSHASH, self).__next__()
0a3348d1
EC
354
355 if self.data_typeobj is None:
356 return node
357
358 return node['data'].cast(gdb.lookup_type(self.data_typeobj).pointer())
359
e33b3fec
EC
360 def next(self):
361 return self.__next__()
362
0a3348d1 363
42562061
EC
364#
365# Class that will provide an iterator over an OVS simap.
366#
367class ForEachSIMAP(ForEachHMAP):
368 def __init__(self, shash):
369 super(ForEachSIMAP, self).__init__(shash['map'],
370 "struct simap_node", "node")
371
e33b3fec
EC
372 def __next__(self):
373 node = super(ForEachSIMAP, self).__next__()
42562061
EC
374 return node['name'], node['data']
375
e33b3fec
EC
376 def next(self):
377 return self.__next__()
378
42562061 379
cd5b89a5
EC
380#
381# Class that will provide an iterator over an OVS smap.
382#
383class ForEachSMAP(ForEachHMAP):
384 def __init__(self, shash):
385 super(ForEachSMAP, self).__init__(shash['map'],
386 "struct smap_node", "node")
387
e33b3fec
EC
388 def __next__(self):
389 node = super(ForEachSMAP, self).__next__()
cd5b89a5
EC
390 return node['key'], node['value']
391
e33b3fec
EC
392 def next(self):
393 return self.__next__()
394
cd5b89a5 395
0a3348d1
EC
396#
397# Class that will provide an iterator over an OVS list.
398#
399class ForEachLIST():
400 def __init__(self, list, typeobj=None, member='node'):
401 self.list = list
402 self.node = list
403 self.typeobj = typeobj
404 self.member = member
405
406 def __iter__(self):
407 return self
408
e33b3fec 409 def __next__(self):
0a3348d1
EC
410 if self.list.address == self.node['next']:
411 raise StopIteration
412
413 self.node = self.node['next']
414
415 if self.typeobj is None:
416 return self.node
417
418 return container_of(self.node,
419 gdb.lookup_type(self.typeobj).pointer(),
420 self.member)
421
e33b3fec
EC
422 def next(self):
423 return self.__next__()
424
0a3348d1
EC
425
426#
427# Implements the GDB "ovs_dump_bridges" command
428#
429class CmdDumpBridge(gdb.Command):
430 """Dump all configured bridges.
ef557e2c 431 Usage: ovs_dump_bridge {ports|wanted}
0a3348d1
EC
432 """
433 def __init__(self):
434 super(CmdDumpBridge, self).__init__("ovs_dump_bridge",
435 gdb.COMMAND_DATA)
436
437 def invoke(self, arg, from_tty):
438 ports = False
439 wanted = False
440 arg_list = gdb.string_to_argv(arg)
441 if len(arg_list) > 1 or \
442 (len(arg_list) == 1 and arg_list[0] != "ports" and
443 arg_list[0] != "wanted"):
ef557e2c 444 print("usage: ovs_dump_bridge {ports|wanted}")
0a3348d1
EC
445 return
446 elif len(arg_list) == 1:
447 if arg_list[0] == "ports":
448 ports = True
449 else:
450 wanted = True
451
b9683ff0
EC
452 all_bridges = get_global_variable('all_bridges')
453 if all_bridges is None:
0a3348d1 454 return
b9683ff0 455
0a3348d1
EC
456 for node in ForEachHMAP(all_bridges,
457 "struct bridge", "node"):
458 print("(struct bridge *) {}: name = {}, type = {}".
459 format(node, node['name'].string(),
460 node['type'].string()))
461
462 if ports:
463 for port in ForEachHMAP(node['ports'],
464 "struct port", "hmap_node"):
465 CmdDumpBridgePorts.display_single_port(port, 4)
466
467 if wanted:
468 for port in ForEachSHASH(node['wanted_ports'],
469 typeobj="struct ovsrec_port"):
470 print(" (struct ovsrec_port *) {}: name = {}".
471 format(port, port['name'].string()))
472 # print port.dereference()
473
474
475#
476# Implements the GDB "ovs_dump_bridge_ports" command
477#
478class CmdDumpBridgePorts(gdb.Command):
479 """Dump all ports added to a specific struct bridge*.
480 Usage: ovs_dump_bridge_ports <struct bridge *>
481 """
482 def __init__(self):
483 super(CmdDumpBridgePorts, self).__init__("ovs_dump_bridge_ports",
484 gdb.COMMAND_DATA)
485
486 @staticmethod
487 def display_single_port(port, indent=0):
488 indent = " " * indent
489 port = port.cast(gdb.lookup_type('struct port').pointer())
ed47794c 490 print("{}(struct port *) {}: name = {}, bridge = (struct bridge *) {}".
0a3348d1
EC
491 format(indent, port, port['name'].string(),
492 port['bridge']))
493
494 indent += " " * 4
495 for iface in ForEachLIST(port['ifaces'], "struct iface", "port_elem"):
496 print("{}(struct iface *) {}: name = {}, ofp_port = {}, "
497 "netdev = (struct netdev *) {}".
498 format(indent, iface, iface['name'],
499 iface['ofp_port'], iface['netdev']))
500
501 def invoke(self, arg, from_tty):
502 arg_list = gdb.string_to_argv(arg)
503 if len(arg_list) != 1:
504 print("usage: ovs_dump_bridge_ports <struct bridge *>")
505 return
506 bridge = gdb.parse_and_eval(arg_list[0]).cast(
507 gdb.lookup_type('struct bridge').pointer())
508 for node in ForEachHMAP(bridge['ports'],
509 "struct port", "hmap_node"):
510 self.display_single_port(node)
511
512
513#
514# Implements the GDB "ovs_dump_dp_netdev" command
515#
516class CmdDumpDpNetdev(gdb.Command):
517 """Dump all registered dp_netdev structures.
518 Usage: ovs_dump_dp_netdev [ports]
519 """
520 def __init__(self):
521 super(CmdDumpDpNetdev, self).__init__("ovs_dump_dp_netdev",
522 gdb.COMMAND_DATA)
523
524 def invoke(self, arg, from_tty):
525 ports = False
526 arg_list = gdb.string_to_argv(arg)
527 if len(arg_list) > 1 or \
528 (len(arg_list) == 1 and arg_list[0] != "ports"):
529 print("usage: ovs_dump_dp_netdev [ports]")
530 return
531 elif len(arg_list) == 1:
532 ports = True
533
b9683ff0
EC
534 dp_netdevs = get_global_variable('dp_netdevs')
535 if dp_netdevs is None:
0a3348d1 536 return
b9683ff0
EC
537
538 for dp in ForEachSHASH(dp_netdevs, typeobj=('struct dp_netdev')):
0a3348d1
EC
539
540 print("(struct dp_netdev *) {}: name = {}, class = "
541 "(struct dpif_class *) {}".
b9683ff0 542 format(dp, dp['name'].string(), dp['class']))
0a3348d1
EC
543
544 if ports:
545 for node in ForEachHMAP(dp['ports'],
546 "struct dp_netdev_port", "node"):
547 CmdDumpDpNetdevPorts.display_single_port(node, 4)
548
549
5d0a6267
EC
550#
551# Implements the GDB "ovs_dump_dp_netdev_poll_threads" command
552#
553class CmdDumpDpNetdevPollThreads(gdb.Command):
554 """Dump all poll_thread info added to a specific struct dp_netdev*.
555 Usage: ovs_dump_dp_netdev_poll_threads <struct dp_netdev *>
556 """
557 def __init__(self):
558 super(CmdDumpDpNetdevPollThreads, self).__init__(
559 "ovs_dump_dp_netdev_poll_threads",
560 gdb.COMMAND_DATA)
561
562 @staticmethod
563 def display_single_poll_thread(pmd_thread, indent=0):
564 indent = " " * indent
e33b3fec 565 print("{}(struct dp_netdev_pmd_thread *) {}: core_id = {}, "
5d0a6267
EC
566 "numa_id {}".format(indent,
567 pmd_thread, pmd_thread['core_id'],
568 pmd_thread['numa_id']))
569
570 def invoke(self, arg, from_tty):
571 arg_list = gdb.string_to_argv(arg)
572 if len(arg_list) != 1:
573 print("usage: ovs_dump_dp_netdev_poll_threads "
574 "<struct dp_netdev *>")
575 return
576 dp_netdev = gdb.parse_and_eval(arg_list[0]).cast(
577 gdb.lookup_type('struct dp_netdev').pointer())
578 for node in ForEachCMAP(dp_netdev['poll_threads'],
579 "struct dp_netdev_pmd_thread", "node"):
580 self.display_single_poll_thread(node)
581
582
0a3348d1
EC
583#
584# Implements the GDB "ovs_dump_dp_netdev_ports" command
585#
586class CmdDumpDpNetdevPorts(gdb.Command):
587 """Dump all ports added to a specific struct dp_netdev*.
588 Usage: ovs_dump_dp_netdev_ports <struct dp_netdev *>
589 """
590 def __init__(self):
591 super(CmdDumpDpNetdevPorts, self).__init__("ovs_dump_dp_netdev_ports",
592 gdb.COMMAND_DATA)
593
594 @staticmethod
595 def display_single_port(port, indent=0):
596 indent = " " * indent
597 print("{}(struct dp_netdev_port *) {}:".format(indent, port))
598 print("{} port_no = {}, n_rxq = {}, type = {}".
599 format(indent, port['port_no'], port['n_rxq'],
600 port['type'].string()))
601 print("{} netdev = (struct netdev *) {}: name = {}, "
602 "n_txq/rxq = {}/{}".
603 format(indent, port['netdev'],
604 port['netdev']['name'].string(),
605 port['netdev']['n_txq'],
606 port['netdev']['n_rxq']))
607
608 def invoke(self, arg, from_tty):
609 arg_list = gdb.string_to_argv(arg)
610 if len(arg_list) != 1:
611 print("usage: ovs_dump_dp_netdev_ports <struct dp_netdev *>")
612 return
613 dp_netdev = gdb.parse_and_eval(arg_list[0]).cast(
614 gdb.lookup_type('struct dp_netdev').pointer())
615 for node in ForEachHMAP(dp_netdev['ports'],
616 "struct dp_netdev_port", "node"):
617 # print node.dereference()
618 self.display_single_port(node)
619
620
b9683ff0
EC
621#
622# Implements the GDB "ovs_dump_dp_provider" command
623#
624class CmdDumpDpProvider(gdb.Command):
625 """Dump all registered registered_dpif_class structures.
626 Usage: ovs_dump_dp_provider
627 """
628 def __init__(self):
629 super(CmdDumpDpProvider, self).__init__("ovs_dump_dp_provider",
630 gdb.COMMAND_DATA)
631
632 def invoke(self, arg, from_tty):
b9683ff0
EC
633 dp_providers = get_global_variable('dpif_classes')
634 if dp_providers is None:
635 return
636
637 for dp_class in ForEachSHASH(dp_providers,
638 typeobj="struct registered_dpif_class"):
639
640 print("(struct registered_dpif_class *) {}: "
641 "(struct dpif_class *) 0x{:x} = {{type = {}, ...}}, "
642 "refcount = {}".
643 format(dp_class,
644 long(dp_class['dpif_class']),
645 dp_class['dpif_class']['type'].string(),
646 dp_class['refcount']))
647
648
0a3348d1
EC
649#
650# Implements the GDB "ovs_dump_netdev" command
651#
652class CmdDumpNetdev(gdb.Command):
653 """Dump all registered netdev structures.
654 Usage: ovs_dump_netdev
655 """
656 def __init__(self):
657 super(CmdDumpNetdev, self).__init__("ovs_dump_netdev",
658 gdb.COMMAND_DATA)
659
660 @staticmethod
661 def display_single_netdev(netdev, indent=0):
662 indent = " " * indent
e33b3fec 663 print("{}(struct netdev *) {}: name = {:15}, auto_classified = {}, "
0a3348d1
EC
664 "netdev_class = {}".
665 format(indent, netdev, netdev['name'].string(),
666 netdev['auto_classified'], netdev['netdev_class']))
667
668 def invoke(self, arg, from_tty):
b9683ff0
EC
669 netdev_shash = get_global_variable('netdev_shash')
670 if netdev_shash is None:
0a3348d1 671 return
b9683ff0 672
0a3348d1
EC
673 for netdev in ForEachSHASH(netdev_shash, "struct netdev"):
674 self.display_single_netdev(netdev)
675
676
42562061
EC
677#
678# Implements the GDB "ovs_dump_netdev_provider" command
679#
680class CmdDumpNetdevProvider(gdb.Command):
681 """Dump all registered netdev providers.
682 Usage: ovs_dump_netdev_provider
683 """
684 def __init__(self):
685 super(CmdDumpNetdevProvider, self).__init__("ovs_dump_netdev_provider",
686 gdb.COMMAND_DATA)
687
688 @staticmethod
689 def is_class_vport_class(netdev_class):
690 netdev_class = netdev_class.cast(
691 gdb.lookup_type('struct netdev_class').pointer())
692
693 vport_construct = gdb.lookup_symbol('netdev_vport_construct')[0]
694
695 if netdev_class['construct'] == vport_construct.value():
696 return True
697 return False
698
699 @staticmethod
700 def display_single_netdev_provider(reg_class, indent=0):
701 indent = " " * indent
702 print("{}(struct netdev_registered_class *) {}: refcnt = {},".
703 format(indent, reg_class, reg_class['refcnt']))
704
705 print("{} (struct netdev_class *) 0x{:x} = {{type = {}, "
706 "is_pmd = {}, ...}}, ".
707 format(indent, long(reg_class['class']),
708 reg_class['class']['type'].string(),
709 reg_class['class']['is_pmd']))
710
711 if CmdDumpNetdevProvider.is_class_vport_class(reg_class['class']):
712 vport = container_of(
713 reg_class['class'],
714 gdb.lookup_type('struct vport_class').pointer(),
715 'netdev_class')
716
717 if vport['dpif_port'] != 0:
718 dpif_port = vport['dpif_port'].string()
719 else:
720 dpif_port = "\"\""
721
722 print("{} (struct vport_class *) 0x{:x} = "
723 "{{ dpif_port = {}, ... }}".
724 format(indent, long(vport), dpif_port))
725
726 def invoke(self, arg, from_tty):
727 netdev_classes = get_global_variable('netdev_classes')
728 if netdev_classes is None:
729 return
730
731 for reg_class in ForEachCMAP(netdev_classes,
732 "struct netdev_registered_class",
733 "cmap_node"):
734 self.display_single_netdev_provider(reg_class)
735
736
5d0a6267
EC
737#
738# Implements the GDB "ovs_dump_ovs_list" command
739#
740class CmdDumpOvsList(gdb.Command):
741 """Dump all nodes of an ovs_list give
742 Usage: ovs_dump_ovs_list <struct ovs_list *> {[<structure>] [<member>] {dump}]}
743
744 For example dump all the none quiescent OvS RCU threads:
745
746 (gdb) ovs_dump_ovs_list &ovsrcu_threads
747 (struct ovs_list *) 0x7f2a14000900
748 (struct ovs_list *) 0x7f2acc000900
749 (struct ovs_list *) 0x7f2a680668d0
750
751 This is not very useful, so please use this with the container_of mode:
752
753 (gdb) ovs_dump_ovs_list &ovsrcu_threads 'struct ovsrcu_perthread' list_node
754 (struct ovsrcu_perthread *) 0x7f2a14000900
755 (struct ovsrcu_perthread *) 0x7f2acc000900
756 (struct ovsrcu_perthread *) 0x7f2a680668d0
757
758 Now you can manually use the print command to show the content, or use the
759 dump option to dump the structure for all nodes:
760
761 (gdb) ovs_dump_ovs_list &ovsrcu_threads 'struct ovsrcu_perthread' list_node dump
762 (struct ovsrcu_perthread *) 0x7f2a14000900 =
763 {list_node = {prev = 0xf48e80 <ovsrcu_threads>, next = 0x7f2acc000900}, mutex...
764
765 (struct ovsrcu_perthread *) 0x7f2acc000900 =
766 {list_node = {prev = 0x7f2a14000900, next = 0x7f2a680668d0}, mutex ...
767
768 (struct ovsrcu_perthread *) 0x7f2a680668d0 =
769 {list_node = {prev = 0x7f2acc000900, next = 0xf48e80 <ovsrcu_threads>}, ...
770 """
771 def __init__(self):
772 super(CmdDumpOvsList, self).__init__("ovs_dump_ovs_list",
773 gdb.COMMAND_DATA)
774
775 def invoke(self, arg, from_tty):
776 arg_list = gdb.string_to_argv(arg)
777 typeobj = None
778 member = None
779 dump = False
780
781 if len(arg_list) != 1 and len(arg_list) != 3 and len(arg_list) != 4:
782 print("usage: ovs_dump_ovs_list <struct ovs_list *> "
783 "{[<structure>] [<member>] {dump}]}")
784 return
785
786 header = gdb.parse_and_eval(arg_list[0]).cast(
787 gdb.lookup_type('struct ovs_list').pointer())
788
789 if len(arg_list) >= 3:
790 typeobj = arg_list[1]
791 member = arg_list[2]
792 if len(arg_list) == 4 and arg_list[3] == "dump":
793 dump = True
794
795 for node in ForEachLIST(header.dereference()):
796 if typeobj is None or member is None:
797 print("(struct ovs_list *) {}".format(node))
798 else:
e33b3fec 799 print("({} *) {} {}".format(
5d0a6267
EC
800 typeobj,
801 container_of(node,
e33b3fec
EC
802 gdb.lookup_type(typeobj).pointer(), member),
803 "=" if dump else ""))
5d0a6267
EC
804 if dump:
805 print(" {}\n".format(container_of(
806 node,
807 gdb.lookup_type(typeobj).pointer(),
808 member).dereference()))
809
810
42562061
EC
811#
812# Implements the GDB "ovs_dump_simap" command
813#
814class CmdDumpSimap(gdb.Command):
cd5b89a5
EC
815 """Dump all key, value entries of a simap
816 Usage: ovs_dump_simap <struct simap *>
42562061
EC
817 """
818
819 def __init__(self):
820 super(CmdDumpSimap, self).__init__("ovs_dump_simap",
821 gdb.COMMAND_DATA)
822
823 def invoke(self, arg, from_tty):
824 arg_list = gdb.string_to_argv(arg)
825
826 if len(arg_list) != 1:
827 print("ERROR: Missing argument!\n")
828 print(self.__doc__)
829 return
830
831 simap = gdb.parse_and_eval(arg_list[0]).cast(
832 gdb.lookup_type('struct simap').pointer())
833
834 values = dict()
835 max_name_len = 0
836 for name, value in ForEachSIMAP(simap.dereference()):
837 values[name.string()] = long(value)
838 if len(name.string()) > max_name_len:
839 max_name_len = len(name.string())
840
e33b3fec 841 for name in sorted(six.iterkeys(values)):
42562061
EC
842 print("{}: {} / 0x{:x}".format(name.ljust(max_name_len),
843 values[name], values[name]))
844
845
b23d42a6 846#
cd5b89a5
EC
847# Implements the GDB "ovs_dump_smap" command
848#
849class CmdDumpSmap(gdb.Command):
850 """Dump all key, value pairs of a smap
851 Usage: ovs_dump_smap <struct smap *>
852 """
853
854 def __init__(self):
855 super(CmdDumpSmap, self).__init__("ovs_dump_smap",
856 gdb.COMMAND_DATA)
857
858 def invoke(self, arg, from_tty):
859 arg_list = gdb.string_to_argv(arg)
860
861 if len(arg_list) != 1:
862 print("ERROR: Missing argument!\n")
863 print(self.__doc__)
864 return
865
866 smap = gdb.parse_and_eval(arg_list[0]).cast(
867 gdb.lookup_type('struct smap').pointer())
868
869 values = dict()
870 max_key_len = 0
871 for key, value in ForEachSMAP(smap.dereference()):
872 values[key.string()] = value.string()
873 if len(key.string()) > max_key_len:
874 max_key_len = len(key.string())
875
e33b3fec 876 for key in sorted(six.iterkeys(values)):
cd5b89a5
EC
877 print("{}: {}".format(key.ljust(max_key_len),
878 values[key]))
879
880
881#
882# Implements the GDB "ovs_dump_udpif_keys" command
b23d42a6
EC
883#
884class CmdDumpUdpifKeys(gdb.Command):
885 """Dump all nodes of an ovs_list give
886 Usage: ovs_dump_udpif_keys {<udpif_name>|<udpif_address>} {short}
887
888 <udpif_name> : Full name of the udpif's dpif to dump
889 <udpif_address> : Address of the udpif structure to dump. If both the
890 <udpif_name> and <udpif_address> are omitted the
891 available udpif structures are displayed.
892 short : Only dump ukey structure addresses, no content details
e33b3fec 893 no_count : Do not count the number of ukeys, as it might be slow
b23d42a6
EC
894 """
895
896 def __init__(self):
897 super(CmdDumpUdpifKeys, self).__init__("ovs_dump_udpif_keys",
898 gdb.COMMAND_DATA)
899
900 def count_all_ukeys(self, udpif):
901 count = 0
e33b3fec
EC
902 spinner = ProgressIndicator("Counting all ukeys: ")
903
b23d42a6 904 for j in range(0, N_UMAPS):
e33b3fec 905 spinner.update()
b23d42a6 906 count += udpif['ukeys'][j]['cmap']['impl']['p']['n']
e33b3fec
EC
907
908 spinner.done()
b23d42a6
EC
909 return count
910
911 def dump_all_ukeys(self, udpif, indent=0, short=False):
912 indent = " " * indent
e33b3fec 913 spinner = ProgressIndicator("Walking ukeys: ")
b23d42a6 914 for j in range(0, N_UMAPS):
e33b3fec 915 spinner.update()
b23d42a6 916 if udpif['ukeys'][j]['cmap']['impl']['p']['n'] != 0:
e33b3fec 917 spinner.pause()
b23d42a6
EC
918 print("{}(struct umap *) {}:".
919 format(indent, udpif['ukeys'][j].address))
920 for ukey in ForEachCMAP(udpif['ukeys'][j]['cmap'],
921 "struct udpif_key", "cmap_node"):
922
923 base_str = "{} (struct udpif_key *) {}: ". \
924 format(indent, ukey)
925 if short:
926 print(base_str)
927 continue
928
929 print("{}key_len = {}, mask_len = {}".
930 format(base_str, ukey['key_len'], ukey['mask_len']))
931
932 indent_b = " " * len(base_str)
933 if ukey['ufid_present']:
934 print("{}ufid = {}".
935 format(
936 indent_b, str(uuid.UUID(
937 "{:08x}{:08x}{:08x}{:08x}".
938 format(long(ukey['ufid']['u32'][3]),
939 long(ukey['ufid']['u32'][2]),
940 long(ukey['ufid']['u32'][1]),
941 long(ukey['ufid']['u32'][0]))))))
942
943 print("{}hash = 0x{:8x}, pmd_id = {}".
944 format(indent_b, long(ukey['hash']), ukey['pmd_id']))
945 print("{}state = {}".format(indent_b, ukey['state']))
946 print("{}n_packets = {}, n_bytes = {}".
947 format(indent_b,
948 ukey['stats']['n_packets'],
949 ukey['stats']['n_bytes']))
950 print("{}used = {}, tcp_flags = 0x{:04x}".
951 format(indent_b,
952 ukey['stats']['used'],
953 long(ukey['stats']['tcp_flags'])))
954
955 #
956 # TODO: Would like to add support for dumping key, mask
957 # actions, and xlate_cache
958 #
959 # key = ""
960 # for nlattr in ForEachNL(ukey['key'], ukey['key_len']):
961 # key += "{}{}".format(
962 # "" if len(key) == 0 else ", ",
963 # nlattr['nla_type'].cast(
964 # gdb.lookup_type('enum ovs_key_attr')))
965 # print("{}key attributes = {}".format(indent_b, key))
e33b3fec
EC
966 spinner.resume()
967 spinner.done()
b23d42a6
EC
968
969 def invoke(self, arg, from_tty):
970 arg_list = gdb.string_to_argv(arg)
971 all_udpifs = get_global_variable('all_udpifs')
e33b3fec
EC
972 no_count = "no_count" in arg_list
973
b23d42a6
EC
974 if all_udpifs is None:
975 return
976
977 udpifs = dict()
978 for udpif in ForEachLIST(all_udpifs, "struct udpif", "list_node"):
979 udpifs[udpif['dpif']['full_name'].string()] = udpif
980
e33b3fec
EC
981 if len(arg_list) == 0 or (
982 len(arg_list) == 1 and arg_list[0] == "no_count"):
b23d42a6
EC
983 print("(struct udpif *) {}: name = {}, total keys = {}".
984 format(udpif, udpif['dpif']['full_name'].string(),
e33b3fec
EC
985 self.count_all_ukeys(udpif) if not no_count
986 else "<not counted!>"))
b23d42a6 987
e33b3fec
EC
988 if len(arg_list) == 0 or (
989 len(arg_list) == 1 and arg_list[0] == "no_count"):
b23d42a6
EC
990 return
991
992 if arg_list[0] in udpifs:
993 udpif = udpifs[arg_list[0]]
994 else:
995 try:
996 udpif = gdb.parse_and_eval(arg_list[0]).cast(
997 gdb.lookup_type('struct udpif').pointer())
998 except Exception:
999 udpif = None
1000
1001 if udpif is None:
1002 print("Can't find provided udpif address!")
1003 return
1004
1005 self.dump_all_ukeys(udpif, 0, "short" in arg_list[1:])
1006
1007
ef557e2c
EC
1008#
1009# Implements the GDB "ovs_show_fdb" command
1010#
1011class CmdShowFDB(gdb.Command):
1012 """Show FDB information
1013 Usage: ovs_show_fdb {<bridge_name> {dbg} {hash}}
1014
1015 <bridge_name> : Optional bridge name, if not supplied FDB summary
1016 information is displayed for all bridges.
1017 dbg : Will show structure address information
1018 hash : Will display the forwarding table using the hash
1019 table, rather than the rlu list.
1020 """
1021
1022 def __init__(self):
1023 super(CmdShowFDB, self).__init__("ovs_show_fdb",
1024 gdb.COMMAND_DATA)
1025
1026 @staticmethod
1027 def __get_port_name_num(mac_entry):
1028 if mac_entry['mlport'] is not None:
1029 port = mac_entry['mlport']['port'].cast(
1030 gdb.lookup_type('struct ofbundle').pointer())
1031
1032 port_name = port['name'].string()
1033 port_no = long(container_of(
1034 port['ports']['next'],
1035 gdb.lookup_type('struct ofport_dpif').pointer(),
1036 'bundle_node')['up']['ofp_port'])
1037
1038 if port_no == 0xfff7:
1039 port_no = "UNSET"
1040 elif port_no == 0xfff8:
1041 port_no = "IN_PORT"
1042 elif port_no == 0xfff9:
1043 port_no = "TABLE"
1044 elif port_no == 0xfffa:
1045 port_no = "NORMAL"
1046 elif port_no == 0xfffb:
1047 port_no = "FLOOD"
1048 elif port_no == 0xfffc:
1049 port_no = "ALL"
1050 elif port_no == 0xfffd:
1051 port_no = "CONTROLLER"
1052 elif port_no == 0xfffe:
1053 port_no = "LOCAL"
1054 elif port_no == 0xffff:
1055 port_no = "NONE"
1056 else:
1057 port_no = str(port_no)
1058 else:
1059 port_name = "-"
1060 port_no = "?"
1061
1062 return port_name, port_no
1063
1064 @staticmethod
1065 def display_ml_summary(ml, indent=0, dbg=False):
1066 indent = " " * indent
1067 if ml is None:
1068 return
1069
1070 if dbg:
1071 print("[(struct mac_learning *) {}]".format(ml))
1072
1073 print("{}table.n : {}".format(indent, ml['table']['n']))
1074 print("{}secret : 0x{:x}".format(indent, long(ml['secret'])))
1075 print("{}idle_time : {}".format(indent, ml['idle_time']))
1076 print("{}max_entries : {}".format(indent, ml['max_entries']))
1077 print("{}ref_count : {}".format(indent, ml['ref_cnt']['count']))
1078 print("{}need_revalidate : {}".format(indent, ml['need_revalidate']))
1079 print("{}ports_by_ptr.n : {}".format(indent, ml['ports_by_ptr']['n']))
1080 print("{}ports_by_usage.n: {}".format(indent,
1081 ml['ports_by_usage']['n']))
4ef1edf0
EC
1082 print("{}total_learned : {}".format(indent, ml['total_learned']))
1083 print("{}total_expired : {}".format(indent, ml['total_expired']))
1084 print("{}total_evicted : {}".format(indent, ml['total_evicted']))
1085 print("{}total_moved : {}".format(indent, ml['total_moved']))
ef557e2c
EC
1086
1087 @staticmethod
1088 def display_mac_entry(mac_entry, indent=0, dbg=False):
1089 port_name, port_no = CmdShowFDB.__get_port_name_num(mac_entry)
1090
1091 line = "{}{:16.16} {:-4} {} {:-9}".format(
1092 indent,
1093 "{}[{}]".format(port_no, port_name),
1094 long(mac_entry['vlan']),
1095 eth_addr_to_string(mac_entry['mac']),
1096 long(mac_entry['expires']))
1097
1098 if dbg:
1099 line += " [(struct mac_entry *) {}]".format(mac_entry)
1100
1101 print(line)
1102
1103 @staticmethod
1104 def display_ml_entries(ml, indent=0, hash=False, dbg=False):
1105 indent = " " * indent
1106 if ml is None:
1107 return
1108
1109 print("\n{}FDB \"{}\" table:".format(indent,
1110 "lrus" if not hash else "hash"))
1111 print("{}port VLAN MAC Age out @".
1112 format(indent))
1113 print("{}----------------- ---- ----------------- ---------".
1114 format(indent))
1115
1116 mac_entries = 0
1117
1118 if hash:
1119 for mac_entry in ForEachHMAP(ml['table'],
1120 "struct mac_entry",
1121 "hmap_node"):
1122 CmdShowFDB.display_mac_entry(mac_entry, len(indent), dbg)
1123 mac_entries += 1
1124 else:
1125 for mac_entry in ForEachLIST(ml['lrus'],
1126 "struct mac_entry",
1127 "lru_node"):
1128 CmdShowFDB.display_mac_entry(mac_entry, len(indent), dbg)
1129 mac_entries += 1
1130
1131 print("\nTotal MAC entries: {}".format(mac_entries))
1132 time_now = list(get_time_now())
1133 time_now[1] = time_now[0] + time_now[1]
1134 print("\n{}Current time is between {} and {} seconds.\n".
1135 format(indent, min(time_now[0], time_now[1]),
1136 max(time_now[0], time_now[1])))
1137
1138 def invoke(self, arg, from_tty):
1139 arg_list = gdb.string_to_argv(arg)
1140
1141 all_ofproto_dpifs_by_name = get_global_variable(
1142 'all_ofproto_dpifs_by_name')
1143 if all_ofproto_dpifs_by_name is None:
1144 return
1145
1146 all_name = dict()
1147 max_name_len = 0
1148 for node in ForEachHMAP(all_ofproto_dpifs_by_name,
1149 "struct ofproto_dpif",
1150 "all_ofproto_dpifs_by_name_node"):
1151
1152 all_name[node['up']['name'].string()] = node
1153 if len(node['up']['name'].string()) > max_name_len:
1154 max_name_len = len(node['up']['name'].string())
1155
1156 if len(arg_list) == 0:
e33b3fec 1157 for name in sorted(six.iterkeys(all_name)):
ef557e2c
EC
1158 print("{}: (struct mac_learning *) {}".
1159 format(name.ljust(max_name_len),
1160 all_name[name]['ml']))
1161
1162 self.display_ml_summary(all_name[name]['ml'], 4)
1163 else:
1164 if not arg_list[0] in all_name:
1165 print("ERROR: Given bridge name is not known!")
1166 return
1167
1168 ml = all_name[arg_list[0]]['ml']
1169 self.display_ml_summary(ml, 0, "dbg" in arg_list[1:])
1170 self.display_ml_entries(ml, 0, "hash" in arg_list[1:],
1171 "dbg" in arg_list[1:])
1172
b23d42a6
EC
1173
1174#
1175# Implements the GDB "ovs_show_fdb" command
1176#
1177class CmdShowUpcall(gdb.Command):
1178 """Show upcall information
1179 Usage: ovs_show_upcall {dbg}
1180
1181 dbg : Will show structure address information
1182 """
1183
1184 def __init__(self):
1185 super(CmdShowUpcall, self).__init__("ovs_show_upcall",
1186 gdb.COMMAND_DATA)
1187
1188 @staticmethod
1189 def display_udpif_upcall(udpif, indent=0, dbg=False):
1190 indent = " " * indent
1191
1192 enable_ufid = get_global_variable('enable_ufid')
1193 if enable_ufid is None:
1194 return
1195
1196 dbg_str = ""
1197 if dbg:
1198 dbg_str = ", ((struct udpif *) {})".format(udpif)
1199
1200 print("{}{}{}:".format(
1201 indent, udpif['dpif']['full_name'].string(),
1202 dbg_str))
1203
1204 print("{} flows : (current {}) (avg {}) (max {}) (limit {})".
1205 format(indent, udpif['n_flows'], udpif['avg_n_flows'],
1206 udpif['max_n_flows'], udpif['flow_limit']))
1207 print("{} dump duration : {}ms".
1208 format(indent, udpif['dump_duration']))
1209 print("{} ufid enabled : {}\n".
1210 format(indent, enable_ufid &
1211 udpif['backer']['rt_support']['ufid']))
1212
1213 for i in range(0, int(udpif['n_revalidators'])):
1214 revalidator = udpif['revalidators'][i]
1215
1216 dbg_str = ""
1217 if dbg:
1218 dbg_str = ", ((struct revalidator *) {})".\
1219 format(revalidator.address)
1220
1221 count = 0
1222 j = i
e33b3fec 1223 spinner = ProgressIndicator("Counting all ukeys: ")
b23d42a6 1224 while j < N_UMAPS:
e33b3fec 1225 spinner.update()
b23d42a6
EC
1226 count += udpif['ukeys'][j]['cmap']['impl']['p']['n']
1227 j += int(udpif['n_revalidators'])
1228
e33b3fec 1229 spinner.done()
b23d42a6
EC
1230 print("{} {}: (keys {}){}".
1231 format(indent, revalidator['id'], count, dbg_str))
1232
1233 print("")
1234
1235 def invoke(self, arg, from_tty):
1236 arg_list = gdb.string_to_argv(arg)
1237
1238 all_udpifs = get_global_variable('all_udpifs')
1239 if all_udpifs is None:
1240 return
1241
1242 for udpif in ForEachLIST(all_udpifs, "struct udpif", "list_node"):
1243 self.display_udpif_upcall(udpif, 0, "dbg" in arg_list)
1244
1245
0a3348d1
EC
1246#
1247# Initialize all GDB commands
1248#
1249CmdDumpBridge()
1250CmdDumpBridgePorts()
1251CmdDumpDpNetdev()
5d0a6267 1252CmdDumpDpNetdevPollThreads()
0a3348d1 1253CmdDumpDpNetdevPorts()
b9683ff0 1254CmdDumpDpProvider()
0a3348d1 1255CmdDumpNetdev()
42562061 1256CmdDumpNetdevProvider()
5d0a6267 1257CmdDumpOvsList()
42562061 1258CmdDumpSimap()
cd5b89a5 1259CmdDumpSmap()
b23d42a6 1260CmdDumpUdpifKeys()
ef557e2c 1261CmdShowFDB()
b23d42a6 1262CmdShowUpcall()