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