2 # Copyright (c) 2018 Eelco Chaudron
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.
13 # GDB commands and functions for Open vSwitch debugging
22 # It implements the following GDB commands:
23 # - ovs_dump_bridge {ports|wanted}
24 # - ovs_dump_bridge_ports <struct bridge *>
25 # - ovs_dump_dp_netdev [ports]
26 # - ovs_dump_dp_netdev_poll_threads <struct dp_netdev *>
27 # - ovs_dump_dp_netdev_ports <struct dp_netdev *>
28 # - ovs_dump_dp_provider
30 # - ovs_dump_netdev_provider
31 # - ovs_dump_ovs_list <struct ovs_list *> {[<structure>] [<member>] {dump}]}
32 # - ovs_dump_simap <struct simap *>
33 # - ovs_dump_smap <struct smap *>
34 # - ovs_dump_udpif_keys {<udpif_name>|<udpif_address>} {short}
35 # - ovs_show_fdb {[<bridge_name>] {dbg} {hash}}
36 # - ovs_show_upcall {dbg}
39 # $ gdb $(which ovs-vswitchd) $(pidof ovs-vswitchd)
40 # (gdb) source ./utilities/gdb/ovs_gdb.py
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
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
52 # (gdb) p *(struct bridge *) 0x5615471d0420
53 # $1 = {node = {hash = 24776443, next = 0x0}, name = 0x5615471cca90 "br1",
54 # type = 0x561547163bb0 "system",
63 # Global #define's from OVS which might need updating based on a version.
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:
72 # # gdb helper commands and functions for Linux kernel debugging
76 # # Copyright (c) Siemens AG, 2011-2013
79 # # Jan Kiszka <jan.kiszka@siemens.com>
81 # # This work is licensed under the terms of the GNU GPL version 2.
84 def __init__(self
, name
):
88 def _new_objfile_handler(self
, event
):
90 gdb
.events
.new_objfile
.disconnect(self
._new
_objfile
_handler
)
93 if self
._type
is None:
94 self
._type
= gdb
.lookup_type(self
._name
)
95 if self
._type
is None:
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
)
103 long_type
= CachedType("long")
108 return long_type
.get_type()
111 def offset_of(typeobj
, field
):
112 element
= gdb
.Value(0).cast(typeobj
)
113 return int(str(element
[field
].address
).split()[0], 16)
116 def container_of(ptr
, typeobj
, member
):
117 return (ptr
.cast(get_long_type()) -
118 offset_of(typeobj
, member
)).cast(typeobj
)
121 def 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
))
127 return gdb
.parse_and_eval(name
)
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
139 # See get_time_msec() above
140 return long(get_global_variable("coverage_run_time"))/1000, -5
143 def 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]))
154 # Class that will provide an iterator over an OVS cmap.
156 class ForEachCMAP(object):
157 def __init__(self
, cmap
, typeobj
=None, member
='node'):
160 self
.typeobj
= typeobj
170 def __get_CMAP_K(self
):
171 ptr_type
= gdb
.lookup_type("void").pointer()
172 return (64 - 4) / (4 + ptr_type
.sizeof
)
175 ipml
= self
.cmap
['impl']['p']
178 self
.node
= self
.node
['next']['p']
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']
196 ipml
= self
.cmap
['impl']['p']
202 if self
.typeobj
is None:
205 return container_of(self
.node
,
206 gdb
.lookup_type(self
.typeobj
).pointer(),
211 # Class that will provide an iterator over an OVS hmap.
213 class ForEachHMAP(object):
214 def __init__(self
, hmap
, typeobj
=None, member
='node'):
218 self
.typeobj
= typeobj
224 def __next(self
, start
):
225 for i
in range(start
, (self
.hmap
['mask'] + 1)):
226 self
.node
= self
.hmap
['buckets'][i
]
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().
238 if self
.hmap
['n'] <= 0:
244 elif self
.node
['next'] != 0:
245 self
.node
= self
.node
['next']
247 self
.__next
((self
.node
['hash'] & self
.hmap
['mask']) + 1)
249 if self
.typeobj
is None:
252 return container_of(self
.node
,
253 gdb
.lookup_type(self
.typeobj
).pointer(),
258 # Class that will provide an iterator over an Netlink attributes
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
)
268 def round_up(self
, val
, round_to
):
269 return int(val
) + (round_to
- int(val
)) % round_to
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
:
276 # Invalid attr set, maybe we should raise an exception?
281 self
.attr_len
-= self
.round_up(attr
['nla_len'], 4)
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())
291 # Class that will provide an iterator over an OVS shash.
293 class ForEachSHASH(ForEachHMAP
):
294 def __init__(self
, shash
, typeobj
=None):
296 self
.data_typeobj
= typeobj
298 super(ForEachSHASH
, self
).__init
__(shash
['map'],
299 "struct shash_node", "node")
302 node
= super(ForEachSHASH
, self
).next()
304 if self
.data_typeobj
is None:
307 return node
['data'].cast(gdb
.lookup_type(self
.data_typeobj
).pointer())
311 # Class that will provide an iterator over an OVS simap.
313 class ForEachSIMAP(ForEachHMAP
):
314 def __init__(self
, shash
):
315 super(ForEachSIMAP
, self
).__init
__(shash
['map'],
316 "struct simap_node", "node")
319 node
= super(ForEachSIMAP
, self
).next()
320 return node
['name'], node
['data']
324 # Class that will provide an iterator over an OVS smap.
326 class ForEachSMAP(ForEachHMAP
):
327 def __init__(self
, shash
):
328 super(ForEachSMAP
, self
).__init
__(shash
['map'],
329 "struct smap_node", "node")
332 node
= super(ForEachSMAP
, self
).next()
333 return node
['key'], node
['value']
337 # Class that will provide an iterator over an OVS list.
340 def __init__(self
, list, typeobj
=None, member
='node'):
343 self
.typeobj
= typeobj
350 if self
.list.address
== self
.node
['next']:
353 self
.node
= self
.node
['next']
355 if self
.typeobj
is None:
358 return container_of(self
.node
,
359 gdb
.lookup_type(self
.typeobj
).pointer(),
364 # Implements the GDB "ovs_dump_bridges" command
366 class CmdDumpBridge(gdb
.Command
):
367 """Dump all configured bridges.
368 Usage: ovs_dump_bridge {ports|wanted}
371 super(CmdDumpBridge
, self
).__init
__("ovs_dump_bridge",
374 def invoke(self
, arg
, from_tty
):
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"):
381 print("usage: ovs_dump_bridge {ports|wanted}")
383 elif len(arg_list
) == 1:
384 if arg_list
[0] == "ports":
389 all_bridges
= get_global_variable('all_bridges')
390 if all_bridges
is None:
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()))
400 for port
in ForEachHMAP(node
['ports'],
401 "struct port", "hmap_node"):
402 CmdDumpBridgePorts
.display_single_port(port
, 4)
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()
413 # Implements the GDB "ovs_dump_bridge_ports" command
415 class CmdDumpBridgePorts(gdb
.Command
):
416 """Dump all ports added to a specific struct bridge*.
417 Usage: ovs_dump_bridge_ports <struct bridge *>
420 super(CmdDumpBridgePorts
, self
).__init
__("ovs_dump_bridge_ports",
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(),
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']))
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 *>")
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
)
451 # Implements the GDB "ovs_dump_dp_netdev" command
453 class CmdDumpDpNetdev(gdb
.Command
):
454 """Dump all registered dp_netdev structures.
455 Usage: ovs_dump_dp_netdev [ports]
458 super(CmdDumpDpNetdev
, self
).__init
__("ovs_dump_dp_netdev",
461 def invoke(self
, arg
, from_tty
):
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]")
468 elif len(arg_list
) == 1:
471 dp_netdevs
= get_global_variable('dp_netdevs')
472 if dp_netdevs
is None:
475 for dp
in ForEachSHASH(dp_netdevs
, typeobj
=('struct dp_netdev')):
477 print("(struct dp_netdev *) {}: name = {}, class = "
478 "(struct dpif_class *) {}".
479 format(dp
, dp
['name'].string(), dp
['class']))
482 for node
in ForEachHMAP(dp
['ports'],
483 "struct dp_netdev_port", "node"):
484 CmdDumpDpNetdevPorts
.display_single_port(node
, 4)
488 # Implements the GDB "ovs_dump_dp_netdev_poll_threads" command
490 class 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 *>
495 super(CmdDumpDpNetdevPollThreads
, self
).__init
__(
496 "ovs_dump_dp_netdev_poll_threads",
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']))
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 *>")
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
)
521 # Implements the GDB "ovs_dump_dp_netdev_ports" command
523 class CmdDumpDpNetdevPorts(gdb
.Command
):
524 """Dump all ports added to a specific struct dp_netdev*.
525 Usage: ovs_dump_dp_netdev_ports <struct dp_netdev *>
528 super(CmdDumpDpNetdevPorts
, self
).__init
__("ovs_dump_dp_netdev_ports",
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 = {}, "
540 format(indent
, port
['netdev'],
541 port
['netdev']['name'].string(),
542 port
['netdev']['n_txq'],
543 port
['netdev']['n_rxq']))
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 *>")
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
)
559 # Implements the GDB "ovs_dump_dp_provider" command
561 class CmdDumpDpProvider(gdb
.Command
):
562 """Dump all registered registered_dpif_class structures.
563 Usage: ovs_dump_dp_provider
566 super(CmdDumpDpProvider
, self
).__init
__("ovs_dump_dp_provider",
569 def invoke(self
, arg
, from_tty
):
570 dp_providers
= get_global_variable('dpif_classes')
571 if dp_providers
is None:
574 for dp_class
in ForEachSHASH(dp_providers
,
575 typeobj
="struct registered_dpif_class"):
577 print("(struct registered_dpif_class *) {}: "
578 "(struct dpif_class *) 0x{:x} = {{type = {}, ...}}, "
581 long(dp_class
['dpif_class']),
582 dp_class
['dpif_class']['type'].string(),
583 dp_class
['refcount']))
587 # Implements the GDB "ovs_dump_netdev" command
589 class CmdDumpNetdev(gdb
.Command
):
590 """Dump all registered netdev structures.
591 Usage: ovs_dump_netdev
594 super(CmdDumpNetdev
, self
).__init
__("ovs_dump_netdev",
598 def display_single_netdev(netdev
, indent
=0):
599 indent
= " " * indent
600 print("{}(struct netdev *) {}: name = {:15}, auto_classified = {:5}, "
602 format(indent
, netdev
, netdev
['name'].string(),
603 netdev
['auto_classified'], netdev
['netdev_class']))
605 def invoke(self
, arg
, from_tty
):
606 netdev_shash
= get_global_variable('netdev_shash')
607 if netdev_shash
is None:
610 for netdev
in ForEachSHASH(netdev_shash
, "struct netdev"):
611 self
.display_single_netdev(netdev
)
615 # Implements the GDB "ovs_dump_netdev_provider" command
617 class CmdDumpNetdevProvider(gdb
.Command
):
618 """Dump all registered netdev providers.
619 Usage: ovs_dump_netdev_provider
622 super(CmdDumpNetdevProvider
, self
).__init
__("ovs_dump_netdev_provider",
626 def is_class_vport_class(netdev_class
):
627 netdev_class
= netdev_class
.cast(
628 gdb
.lookup_type('struct netdev_class').pointer())
630 vport_construct
= gdb
.lookup_symbol('netdev_vport_construct')[0]
632 if netdev_class
['construct'] == vport_construct
.value():
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']))
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']))
648 if CmdDumpNetdevProvider
.is_class_vport_class(reg_class
['class']):
649 vport
= container_of(
651 gdb
.lookup_type('struct vport_class').pointer(),
654 if vport
['dpif_port'] != 0:
655 dpif_port
= vport
['dpif_port'].string()
659 print("{} (struct vport_class *) 0x{:x} = "
660 "{{ dpif_port = {}, ... }}".
661 format(indent
, long(vport
), dpif_port
))
663 def invoke(self
, arg
, from_tty
):
664 netdev_classes
= get_global_variable('netdev_classes')
665 if netdev_classes
is None:
668 for reg_class
in ForEachCMAP(netdev_classes
,
669 "struct netdev_registered_class",
671 self
.display_single_netdev_provider(reg_class
)
675 # Implements the GDB "ovs_dump_ovs_list" command
677 class CmdDumpOvsList(gdb
.Command
):
678 """Dump all nodes of an ovs_list give
679 Usage: ovs_dump_ovs_list <struct ovs_list *> {[<structure>] [<member>] {dump}]}
681 For example dump all the none quiescent OvS RCU threads:
683 (gdb) ovs_dump_ovs_list &ovsrcu_threads
684 (struct ovs_list *) 0x7f2a14000900
685 (struct ovs_list *) 0x7f2acc000900
686 (struct ovs_list *) 0x7f2a680668d0
688 This is not very useful, so please use this with the container_of mode:
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
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:
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...
702 (struct ovsrcu_perthread *) 0x7f2acc000900 =
703 {list_node = {prev = 0x7f2a14000900, next = 0x7f2a680668d0}, mutex ...
705 (struct ovsrcu_perthread *) 0x7f2a680668d0 =
706 {list_node = {prev = 0x7f2acc000900, next = 0xf48e80 <ovsrcu_threads>}, ...
709 super(CmdDumpOvsList
, self
).__init
__("ovs_dump_ovs_list",
712 def invoke(self
, arg
, from_tty
):
713 arg_list
= gdb
.string_to_argv(arg
)
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}]}")
723 header
= gdb
.parse_and_eval(arg_list
[0]).cast(
724 gdb
.lookup_type('struct ovs_list').pointer())
726 if len(arg_list
) >= 3:
727 typeobj
= arg_list
[1]
729 if len(arg_list
) == 4 and arg_list
[3] == "dump":
732 for node
in ForEachLIST(header
.dereference()):
733 if typeobj
is None or member
is None:
734 print("(struct ovs_list *) {}".format(node
))
736 print("({} *) {} =".format(
739 gdb
.lookup_type(typeobj
).pointer(), member
)))
741 print(" {}\n".format(container_of(
743 gdb
.lookup_type(typeobj
).pointer(),
744 member
).dereference()))
748 # Implements the GDB "ovs_dump_simap" command
750 class CmdDumpSimap(gdb
.Command
):
751 """Dump all key, value entries of a simap
752 Usage: ovs_dump_simap <struct simap *>
756 super(CmdDumpSimap
, self
).__init
__("ovs_dump_simap",
759 def invoke(self
, arg
, from_tty
):
760 arg_list
= gdb
.string_to_argv(arg
)
762 if len(arg_list
) != 1:
763 print("ERROR: Missing argument!\n")
767 simap
= gdb
.parse_and_eval(arg_list
[0]).cast(
768 gdb
.lookup_type('struct simap').pointer())
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())
777 for name
in sorted(values
.iterkeys()):
778 print("{}: {} / 0x{:x}".format(name
.ljust(max_name_len
),
779 values
[name
], values
[name
]))
783 # Implements the GDB "ovs_dump_smap" command
785 class CmdDumpSmap(gdb
.Command
):
786 """Dump all key, value pairs of a smap
787 Usage: ovs_dump_smap <struct smap *>
791 super(CmdDumpSmap
, self
).__init
__("ovs_dump_smap",
794 def invoke(self
, arg
, from_tty
):
795 arg_list
= gdb
.string_to_argv(arg
)
797 if len(arg_list
) != 1:
798 print("ERROR: Missing argument!\n")
802 smap
= gdb
.parse_and_eval(arg_list
[0]).cast(
803 gdb
.lookup_type('struct smap').pointer())
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())
812 for key
in sorted(values
.iterkeys()):
813 print("{}: {}".format(key
.ljust(max_key_len
),
818 # Implements the GDB "ovs_dump_udpif_keys" command
820 class CmdDumpUdpifKeys(gdb
.Command
):
821 """Dump all nodes of an ovs_list give
822 Usage: ovs_dump_udpif_keys {<udpif_name>|<udpif_address>} {short}
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
832 super(CmdDumpUdpifKeys
, self
).__init
__("ovs_dump_udpif_keys",
835 def count_all_ukeys(self
, udpif
):
837 for j
in range(0, N_UMAPS
):
838 count
+= udpif
['ukeys'][j
]['cmap']['impl']['p']['n']
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"):
850 base_str
= "{} (struct udpif_key *) {}: ". \
856 print("{}key_len = {}, mask_len = {}".
857 format(base_str
, ukey
['key_len'], ukey
['mask_len']))
859 indent_b
= " " * len(base_str
)
860 if ukey
['ufid_present']:
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]))))))
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 = {}".
875 ukey
['stats']['n_packets'],
876 ukey
['stats']['n_bytes']))
877 print("{}used = {}, tcp_flags = 0x{:04x}".
879 ukey
['stats']['used'],
880 long(ukey
['stats']['tcp_flags'])))
883 # TODO: Would like to add support for dumping key, mask
884 # actions, and xlate_cache
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))
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:
901 for udpif
in ForEachLIST(all_udpifs
, "struct udpif", "list_node"):
902 udpifs
[udpif
['dpif']['full_name'].string()] = udpif
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
)))
909 if len(arg_list
) == 0:
912 if arg_list
[0] in udpifs
:
913 udpif
= udpifs
[arg_list
[0]]
916 udpif
= gdb
.parse_and_eval(arg_list
[0]).cast(
917 gdb
.lookup_type('struct udpif').pointer())
922 print("Can't find provided udpif address!")
925 self
.dump_all_ukeys(udpif
, 0, "short" in arg_list
[1:])
929 # Implements the GDB "ovs_show_fdb" command
931 class CmdShowFDB(gdb
.Command
):
932 """Show FDB information
933 Usage: ovs_show_fdb {<bridge_name> {dbg} {hash}}
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.
943 super(CmdShowFDB
, self
).__init
__("ovs_show_fdb",
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())
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'])
958 if port_no
== 0xfff7:
960 elif port_no
== 0xfff8:
962 elif port_no
== 0xfff9:
964 elif port_no
== 0xfffa:
966 elif port_no
== 0xfffb:
968 elif port_no
== 0xfffc:
970 elif port_no
== 0xfffd:
971 port_no
= "CONTROLLER"
972 elif port_no
== 0xfffe:
974 elif port_no
== 0xffff:
977 port_no
= str(port_no
)
982 return port_name
, port_no
985 def display_ml_summary(ml
, indent
=0, dbg
=False):
986 indent
= " " * indent
991 print("[(struct mac_learning *) {}]".format(ml
))
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']))
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']))
1008 def display_mac_entry(mac_entry
, indent
=0, dbg
=False):
1009 port_name
, port_no
= CmdShowFDB
.__get
_port
_name
_num
(mac_entry
)
1011 line
= "{}{:16.16} {:-4} {} {:-9}".format(
1013 "{}[{}]".format(port_no
, port_name
),
1014 long(mac_entry
['vlan']),
1015 eth_addr_to_string(mac_entry
['mac']),
1016 long(mac_entry
['expires']))
1019 line
+= " [(struct mac_entry *) {}]".format(mac_entry
)
1024 def display_ml_entries(ml
, indent
=0, hash=False, dbg
=False):
1025 indent
= " " * indent
1029 print("\n{}FDB \"{}\" table:".format(indent
,
1030 "lrus" if not hash else "hash"))
1031 print("{}port VLAN MAC Age out @".
1033 print("{}----------------- ---- ----------------- ---------".
1039 for mac_entry
in ForEachHMAP(ml
['table'],
1042 CmdShowFDB
.display_mac_entry(mac_entry
, len(indent
), dbg
)
1045 for mac_entry
in ForEachLIST(ml
['lrus'],
1048 CmdShowFDB
.display_mac_entry(mac_entry
, len(indent
), dbg
)
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])))
1058 def invoke(self
, arg
, from_tty
):
1059 arg_list
= gdb
.string_to_argv(arg
)
1061 all_ofproto_dpifs_by_name
= get_global_variable(
1062 'all_ofproto_dpifs_by_name')
1063 if all_ofproto_dpifs_by_name
is None:
1068 for node
in ForEachHMAP(all_ofproto_dpifs_by_name
,
1069 "struct ofproto_dpif",
1070 "all_ofproto_dpifs_by_name_node"):
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())
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']))
1082 self
.display_ml_summary(all_name
[name
]['ml'], 4)
1084 if not arg_list
[0] in all_name
:
1085 print("ERROR: Given bridge name is not known!")
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:])
1095 # Implements the GDB "ovs_show_fdb" command
1097 class CmdShowUpcall(gdb
.Command
):
1098 """Show upcall information
1099 Usage: ovs_show_upcall {dbg}
1101 dbg : Will show structure address information
1105 super(CmdShowUpcall
, self
).__init
__("ovs_show_upcall",
1109 def display_udpif_upcall(udpif
, indent
=0, dbg
=False):
1110 indent
= " " * indent
1112 enable_ufid
= get_global_variable('enable_ufid')
1113 if enable_ufid
is None:
1118 dbg_str
= ", ((struct udpif *) {})".format(udpif
)
1120 print("{}{}{}:".format(
1121 indent
, udpif
['dpif']['full_name'].string(),
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']))
1133 for i
in range(0, int(udpif
['n_revalidators'])):
1134 revalidator
= udpif
['revalidators'][i
]
1138 dbg_str
= ", ((struct revalidator *) {})".\
1139 format(revalidator
.address
)
1144 count
+= udpif
['ukeys'][j
]['cmap']['impl']['p']['n']
1145 j
+= int(udpif
['n_revalidators'])
1147 print("{} {}: (keys {}){}".
1148 format(indent
, revalidator
['id'], count
, dbg_str
))
1152 def invoke(self
, arg
, from_tty
):
1153 arg_list
= gdb
.string_to_argv(arg
)
1155 all_udpifs
= get_global_variable('all_udpifs')
1156 if all_udpifs
is None:
1159 for udpif
in ForEachLIST(all_udpifs
, "struct udpif", "list_node"):
1160 self
.display_udpif_upcall(udpif
, 0, "dbg" in arg_list
)
1164 # Initialize all GDB commands
1167 CmdDumpBridgePorts()
1169 CmdDumpDpNetdevPollThreads()
1170 CmdDumpDpNetdevPorts()
1173 CmdDumpNetdevProvider()