gdb: Move the bgp macros to their own file

Not everyone wants to load the bgp macros when debugging
a different daemon

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
This commit is contained in:
Donald Sharp 2026-01-08 19:39:38 -05:00
parent d6a266deeb
commit 9eb855ff6b
2 changed files with 482 additions and 467 deletions

482
gdb/bgp.txt Normal file
View file

@ -0,0 +1,482 @@
# GDB macros for use with FRR.
#
# Macros in this file are specific to bgpd/. Definitions here depend on the
# lib.txt macros file, which must also be loaded.
#
# The macro files can be loaded with 'source <filename>'. They can then be
# called by the user. Macros that explore more complicated structs generally
# take pointer arguments.
#
# Example:
#
# (gdb) source gdb/lib.txt
# (gdb) source gdb/bgp.txt
# (gdb) walk_bgp_table bgp->rib[0][0]
# (gdb) dump_bgp_path_info pi
define dump_bgp_path_flags
set $flags = $arg0
if ($flags & (1 << 0))
printf " IGP_CHANGED"
end
if ($flags & (1 << 1))
printf " DAMPED"
end
if ($flags & (1 << 2))
printf " HISTORY"
end
if ($flags & (1 << 3))
printf " SELECTED"
end
if ($flags & (1 << 4))
printf " VALID"
end
if ($flags & (1 << 5))
printf " ATTR_CHANGED"
end
if ($flags & (1 << 6))
printf " DMED_CHECK"
end
if ($flags & (1 << 7))
printf " DMED_SELECTED"
end
if ($flags & (1 << 8))
printf " STALE"
end
if ($flags & (1 << 9))
printf " REMOVED"
end
if ($flags & (1 << 10))
printf " COUNTED"
end
if ($flags & (1 << 11))
printf " MULTIPATH"
end
if ($flags & (1 << 12))
printf " MULTIPATH_CHG"
end
if ($flags & (1 << 13))
printf " RIB_ATTR_CHG"
end
if ($flags & (1 << 14))
printf " ANNC_NH_SELF"
end
if ($flags & (1 << 15))
printf " LINK_BW_CHG"
end
if ($flags & (1 << 16))
printf " ACCEPT_OWN"
end
if ($flags & (1 << 17))
printf " MPLSVPN_LABEL_NH"
end
if ($flags & (1 << 18))
printf " MPLSVPN_NH_LABEL_BIND"
end
if ($flags & (1 << 19))
printf " UNSORTED"
end
if ($flags & (1 << 20))
printf " MULTIPATH_NEW"
end
end
document dump_bgp_path_flags
Print human-readable BGP path info flags.
Argument: uint32_t flags value from bgp_path_info->flags
end
define dump_bgp_path_info
set $pi = (struct bgp_path_info *)$arg0
set $indent = ""
if ($argc > 1)
set $indent = $arg1
end
printf "%s bgp_path_info: 0x%lx\n", $indent, $pi
printf "%s peer: 0x%lx", $indent, $pi->peer
if ($pi->peer != 0)
printf " (%s)", $pi->peer->host
end
printf "\n"
printf "%s type: %d, sub_type: %d", $indent, $pi->type, $pi->sub_type
if ($pi->sub_type == 0)
printf " (NORMAL)"
end
if ($pi->sub_type == 1)
printf " (STATIC)"
end
if ($pi->sub_type == 2)
printf " (AGGREGATE)"
end
if ($pi->sub_type == 3)
printf " (REDISTRIBUTE)"
end
if ($pi->sub_type == 5)
printf " (IMPORTED)"
end
printf "\n"
printf "%s flags: 0x%x", $indent, $pi->flags
dump_bgp_path_flags $pi->flags
printf "\n"
printf "%s uptime: %ld", $indent, $pi->uptime
printf ", lock: %d\n", $pi->lock
if ($pi->attr != 0)
printf "%s attr: 0x%lx", $indent, $pi->attr
printf " (nexthop: "
dump_s_addr &($pi->attr->nexthop)
printf ")\n"
end
if ($pi->extra != 0)
printf "%s extra: 0x%lx", $indent, $pi->extra
if ($pi->extra->labels != 0)
printf " [has labels]"
end
if ($pi->extra->evpn != 0)
printf " [has evpn]"
end
if ($pi->extra->vrfleak != 0)
printf " [has vrfleak]"
end
printf "\n"
end
printf "%s next: 0x%lx, prev: 0x%lx\n", $indent, $pi->next, $pi->prev
end
document dump_bgp_path_info
Dump detailed information about a single bgp_path_info structure.
Arguments:
1st: (struct bgp_path_info *) pointer to the path info to dump
2nd: (optional) string for indentation
end
define walk_bgp_table_subtree
# Internal helper to walk a single BGP table
# Args: bgp_table, indent_level, is_two_level
set $_btable = (struct bgp_table *)$arg0
set $_indent_level = $arg1
set $_is_two_level = $arg2
if ($_btable == 0)
return
end
set $_rt = $_btable->route_table
if ($_rt == 0)
return
end
set $_rn = ((struct route_table *)$_rt)->top
set $_top_node = $_rn
if ($_rn == 0)
return
end
# Iterate through all nodes using the standard route table walker
while ($_rn != 0)
set $_dest = 0
if ($_rn->info != 0)
set $_dest = (struct bgp_dest *)$_rn->info
end
if ($_dest != 0)
if ($_dest->info != 0)
# Check if this is a two-level table (EVPN, MPLS VPN, ENCAP)
# In two-level tables, dest->info points to another bgp_table
if ($_is_two_level == 1)
set $_subtable = (struct bgp_table *)$_dest->info
printf "\n=== RD: "
# RD is stored as a prefix, extract and display it
set $_rd_p = &((struct route_node *)$_rn)->p
set $_rd_bytes = (unsigned char *)&$_rd_p->u
# RD format: 2 bytes type + 6 bytes value
# Type 0: 2-byte AS : 4-byte number
# Type 1: 4-byte IPv4 : 2-byte number (most common for EVPN)
# Type 2: 4-byte AS : 2-byte number
set $_rd_type = ($_rd_bytes[0] << 8) | $_rd_bytes[1]
if ($_rd_type == 1)
# Type 1: IPv4:number
printf "%d.%d.%d.%d:%d", $_rd_bytes[2], $_rd_bytes[3], $_rd_bytes[4], $_rd_bytes[5], ($_rd_bytes[6] << 8) | $_rd_bytes[7]
else
if ($_rd_type == 0)
# Type 0: AS:number
set $_rd_as = ($_rd_bytes[2] << 8) | $_rd_bytes[3]
set $_rd_num = ($_rd_bytes[4] << 24) | ($_rd_bytes[5] << 16) | ($_rd_bytes[6] << 8) | $_rd_bytes[7]
printf "%d:%d", $_rd_as, $_rd_num
else
if ($_rd_type == 2)
# Type 2: 4-byte AS:number
set $_rd_as = ($_rd_bytes[2] << 24) | ($_rd_bytes[3] << 16) | ($_rd_bytes[4] << 8) | $_rd_bytes[5]
set $_rd_num = ($_rd_bytes[6] << 8) | $_rd_bytes[7]
printf "%d:%d", $_rd_as, $_rd_num
else
# Unknown type, display raw
printf "%02x%02x:%02x%02x:%02x%02x:%02x%02x", $_rd_bytes[0], $_rd_bytes[1], $_rd_bytes[2], $_rd_bytes[3], $_rd_bytes[4], $_rd_bytes[5], $_rd_bytes[6], $_rd_bytes[7]
end
end
end
printf " ===\n"
# Recursively walk the sub-table
# Save parent state since GDB macros don't have local scope
if ($_subtable != 0)
set $_saved_rn = $_rn
set $_saved_top = $_top_node
set $_saved_is_two_level = $_is_two_level
set $_saved_indent = $_indent_level
walk_bgp_table_subtree $_subtable 1 0
# Restore parent state
set $_rn = $_saved_rn
set $_top_node = $_saved_top
set $_is_two_level = $_saved_is_two_level
set $_indent_level = $_saved_indent
end
else
# This is a regular table, dest->info points to bgp_path_info
set $_pi = (struct bgp_path_info *)$_dest->info
set $_dest_count = $_dest_count + 1
if ($_indent_level == 0)
printf "\n=== Dest #%d: 0x%lx ===\n", $_dest_count, $_dest
else
printf "\n === Dest #%d: 0x%lx ===\n", $_dest_count, $_dest
end
if ($_indent_level == 0)
printf "Prefix: "
else
printf " Prefix: "
end
# Check if this is an EVPN prefix (AF_EVPN = 47 on this system)
set $_p = &((struct route_node *)$_rn)->p
if ($_p->family == 47)
# EVPN prefix - decode the route type
set $_evpn_bytes = (unsigned char *)&$_p->u
set $_evpn_route_type = $_evpn_bytes[0]
if ($_evpn_route_type == 2)
# Type 2: MAC/IP route - format: [type]:[eth_tag]:[mac_len]:[mac]:[ip_len]:[ip]
set $_evpn_p = (struct prefix_evpn *)$_p
set $_eth_tag = $_evpn_p->prefix.macip_addr.eth_tag
set $_mac_bytes = (unsigned char *)&$_evpn_p->prefix.macip_addr.mac
printf "[%d]:[%u]:[%d]:%02x:%02x:%02x:%02x:%02x:%02x", $_evpn_route_type, $_eth_tag, 48, $_mac_bytes[0], $_mac_bytes[1], $_mac_bytes[2], $_mac_bytes[3], $_mac_bytes[4], $_mac_bytes[5]
set $_ip_type = $_evpn_p->prefix.macip_addr.ip.ipa_type
if ($_ip_type == 2)
# IPv4 (AF_INET = 2)
printf ":[32]:"
dump_s_addr &$_evpn_p->prefix.macip_addr.ip.ipaddr_v4
else
if ($_ip_type == 10)
# IPv6 (AF_INET6 = 10)
printf ":[128]:"
dump_s6_addr &$_evpn_p->prefix.macip_addr.ip.ipaddr_v6
end
end
else
if ($_evpn_route_type == 3)
# Type 3: IMET route - format: [type]:[eth_tag]:[ip_len]:[ip]
set $_evpn_p = (struct prefix_evpn *)$_p
set $_eth_tag = $_evpn_p->prefix.imet_addr.eth_tag
set $_ip_type = $_evpn_p->prefix.imet_addr.ip.ipa_type
if ($_ip_type == 2)
# IPv4 (AF_INET = 2)
printf "[%d]:[%u]:[32]:", $_evpn_route_type, $_eth_tag
dump_s_addr &$_evpn_p->prefix.imet_addr.ip.ipaddr_v4
else
if ($_ip_type == 10)
# IPv6 (AF_INET6 = 10)
printf "[%d]:[%u]:[128]:", $_evpn_route_type, $_eth_tag
dump_s6_addr &$_evpn_p->prefix.imet_addr.ip.ipaddr_v6
else
printf "[%d]:[%u]:[?]", $_evpn_route_type, $_eth_tag
end
end
else
if ($_evpn_route_type == 5)
# Type 5: IP Prefix route - format: [type]:[eth_tag]:[prefix_len]:[ip]
set $_evpn_p = (struct prefix_evpn *)$_p
set $_eth_tag = $_evpn_p->prefix.prefix_addr.eth_tag
set $_prefix_len = $_evpn_p->prefix.prefix_addr.ip_prefix_length
set $_ip_type = $_evpn_p->prefix.prefix_addr.ip.ipa_type
printf "[%d]:[%u]:[%d]:", $_evpn_route_type, $_eth_tag, $_prefix_len
if ($_ip_type == 2)
# IPv4 (AF_INET = 2)
dump_s_addr &$_evpn_p->prefix.prefix_addr.ip.ipaddr_v4
else
if ($_ip_type == 10)
# IPv6 (AF_INET6 = 10)
dump_s6_addr &$_evpn_p->prefix.prefix_addr.ip.ipaddr_v6
else
printf "Unknown-IP-Type-%d", $_ip_type
end
end
else
# Other types
printf "[%d]:[Type-%d]", $_evpn_route_type, $_evpn_route_type
end
end
end
printf "\n"
else
dump_prefix $_p
end
if ($_indent_level == 0)
printf " dest->flags: 0x%x", $_dest->flags
else
printf " dest->flags: 0x%x", $_dest->flags
end
if ($_dest->flags & (1 << 0))
printf " PROCESS_SCHEDULED"
end
if ($_dest->flags & (1 << 1))
printf " USER_CLEAR"
end
if ($_dest->flags & (1 << 3))
printf " SELECTED"
end
printf "\n"
# Walk through all path_info structures for this destination
set $_pi_num = 0
while ($_pi != 0)
set $_pi_num = $_pi_num + 1
set $_path_count = $_path_count + 1
if ($_indent_level == 0)
printf " --- Path #%d ---\n", $_pi_num
dump_bgp_path_info $_pi " "
else
printf " --- Path #%d ---\n", $_pi_num
dump_bgp_path_info $_pi " "
end
set $_pi = $_pi->next
end
end
end
end
# Move to next route node - simple left-right-up traversal
set $_next = 0
# Try going left first
if ($_rn != 0)
set $_left = ((struct route_node *)$_rn)->link[0]
if ($_left != 0)
set $_next = $_left
end
end
# If no left, try right
if ($_next == 0 && $_rn != 0)
set $_right = ((struct route_node *)$_rn)->link[1]
if ($_right != 0)
set $_next = $_right
end
end
# If no left or right, go up until we find an unvisited right branch
if ($_next == 0 && $_rn != 0)
set $_current = $_rn
set $_parent = ((struct route_node *)$_current)->parent
while ($_parent != 0 && $_next == 0)
# Check if we came from the left child
set $_parent_left = ((struct route_node *)$_parent)->link[0]
if ($_parent_left == $_current)
# Try the right child
set $_parent_right = ((struct route_node *)$_parent)->link[1]
if ($_parent_right != 0)
set $_next = $_parent_right
end
end
# Move up
if ($_next == 0)
set $_current = $_parent
if ($_parent != 0)
set $_parent = ((struct route_node *)$_current)->parent
end
end
end
end
set $_rn = $_next
end
end
document walk_bgp_table_subtree
Internal helper for walk_bgp_table - walks a route_table recursively.
end
define walk_bgp_table
set $_table = (struct bgp_table *)$arg0
set $_verbose = 0
if ($argc > 1)
set $_verbose = $arg1
end
if ($_table == 0)
printf "Error: NULL table pointer\n"
else
printf "Walking BGP table at 0x%lx\n", $_table
printf " AFI: %d, SAFI: %d\n", $_table->afi, $_table->safi
printf " Version: %lu\n", $_table->version
set $_dest_count = 0
set $_path_count = 0
# Check if this is a two-level table (EVPN=5, MPLS_VPN=128, ENCAP=7)
set $_is_two_level = 0
if ($_table->safi == 5 || $_table->safi == 128 || $_table->safi == 7)
set $_is_two_level = 1
printf " (Two-level table: RD -> Routes)\n"
end
walk_bgp_table_subtree $_table 0 $_is_two_level
printf "\n=== Summary ===\n"
printf "Total destinations with paths: %d\n", $_dest_count
printf "Total paths: %d\n", $_path_count
end
end
document walk_bgp_table
Walk through a BGP table and dump all bgp_path_info structures with their state.
This macro iterates through all route nodes in a BGP table, and for each
destination that has path information, it dumps all the bgp_path_info
structures in the linked list along with their key state information including:
- Peer information
- Route type and sub-type
- Flags (SELECTED, VALID, MULTIPATH, etc.)
- Attributes (nexthop, etc.)
- Extra information (EVPN, labels, vrfleak)
Arguments:
(struct bgp_table *) pointer to the BGP table to walk
Example usage:
(gdb) p bgp->rib[0][0]
(gdb) walk_bgp_table bgp->rib[0][0]
end

View file

@ -364,470 +364,3 @@ Print the capacity of the given dynamic array, and store in $_.
Argument: a pointer to a darr dynamic array.
Returns: capacity of the array.
end
define dump_bgp_path_flags
set $flags = $arg0
if ($flags & (1 << 0))
printf " IGP_CHANGED"
end
if ($flags & (1 << 1))
printf " DAMPED"
end
if ($flags & (1 << 2))
printf " HISTORY"
end
if ($flags & (1 << 3))
printf " SELECTED"
end
if ($flags & (1 << 4))
printf " VALID"
end
if ($flags & (1 << 5))
printf " ATTR_CHANGED"
end
if ($flags & (1 << 6))
printf " DMED_CHECK"
end
if ($flags & (1 << 7))
printf " DMED_SELECTED"
end
if ($flags & (1 << 8))
printf " STALE"
end
if ($flags & (1 << 9))
printf " REMOVED"
end
if ($flags & (1 << 10))
printf " COUNTED"
end
if ($flags & (1 << 11))
printf " MULTIPATH"
end
if ($flags & (1 << 12))
printf " MULTIPATH_CHG"
end
if ($flags & (1 << 13))
printf " RIB_ATTR_CHG"
end
if ($flags & (1 << 14))
printf " ANNC_NH_SELF"
end
if ($flags & (1 << 15))
printf " LINK_BW_CHG"
end
if ($flags & (1 << 16))
printf " ACCEPT_OWN"
end
if ($flags & (1 << 17))
printf " MPLSVPN_LABEL_NH"
end
if ($flags & (1 << 18))
printf " MPLSVPN_NH_LABEL_BIND"
end
if ($flags & (1 << 19))
printf " UNSORTED"
end
if ($flags & (1 << 20))
printf " MULTIPATH_NEW"
end
end
document dump_bgp_path_flags
Print human-readable BGP path info flags.
Argument: uint32_t flags value from bgp_path_info->flags
end
define dump_bgp_path_info
set $pi = (struct bgp_path_info *)$arg0
set $indent = ""
if ($argc > 1)
set $indent = $arg1
end
printf "%s bgp_path_info: 0x%lx\n", $indent, $pi
printf "%s peer: 0x%lx", $indent, $pi->peer
if ($pi->peer != 0)
printf " (%s)", $pi->peer->host
end
printf "\n"
printf "%s type: %d, sub_type: %d", $indent, $pi->type, $pi->sub_type
if ($pi->sub_type == 0)
printf " (NORMAL)"
end
if ($pi->sub_type == 1)
printf " (STATIC)"
end
if ($pi->sub_type == 2)
printf " (AGGREGATE)"
end
if ($pi->sub_type == 3)
printf " (REDISTRIBUTE)"
end
if ($pi->sub_type == 5)
printf " (IMPORTED)"
end
printf "\n"
printf "%s flags: 0x%x", $indent, $pi->flags
dump_bgp_path_flags $pi->flags
printf "\n"
printf "%s uptime: %ld", $indent, $pi->uptime
printf ", lock: %d\n", $pi->lock
if ($pi->attr != 0)
printf "%s attr: 0x%lx", $indent, $pi->attr
printf " (nexthop: "
dump_s_addr &($pi->attr->nexthop)
printf ")\n"
end
if ($pi->extra != 0)
printf "%s extra: 0x%lx", $indent, $pi->extra
if ($pi->extra->labels != 0)
printf " [has labels]"
end
if ($pi->extra->evpn != 0)
printf " [has evpn]"
end
if ($pi->extra->vrfleak != 0)
printf " [has vrfleak]"
end
printf "\n"
end
printf "%s next: 0x%lx, prev: 0x%lx\n", $indent, $pi->next, $pi->prev
end
document dump_bgp_path_info
Dump detailed information about a single bgp_path_info structure.
Arguments:
1st: (struct bgp_path_info *) pointer to the path info to dump
2nd: (optional) string for indentation
end
define walk_bgp_table_subtree
# Internal helper to walk a single BGP table
# Args: bgp_table, indent_level, is_two_level
set $_btable = (struct bgp_table *)$arg0
set $_indent_level = $arg1
set $_is_two_level = $arg2
if ($_btable == 0)
return
end
set $_rt = $_btable->route_table
if ($_rt == 0)
return
end
set $_rn = ((struct route_table *)$_rt)->top
set $_top_node = $_rn
if ($_rn == 0)
return
end
# Iterate through all nodes using the standard route table walker
while ($_rn != 0)
set $_dest = 0
if ($_rn->info != 0)
set $_dest = (struct bgp_dest *)$_rn->info
end
if ($_dest != 0)
if ($_dest->info != 0)
# Check if this is a two-level table (EVPN, MPLS VPN, ENCAP)
# In two-level tables, dest->info points to another bgp_table
if ($_is_two_level == 1)
set $_subtable = (struct bgp_table *)$_dest->info
printf "\n=== RD: "
# RD is stored as a prefix, extract and display it
set $_rd_p = &((struct route_node *)$_rn)->p
set $_rd_bytes = (unsigned char *)&$_rd_p->u
# RD format: 2 bytes type + 6 bytes value
# Type 0: 2-byte AS : 4-byte number
# Type 1: 4-byte IPv4 : 2-byte number (most common for EVPN)
# Type 2: 4-byte AS : 2-byte number
set $_rd_type = ($_rd_bytes[0] << 8) | $_rd_bytes[1]
if ($_rd_type == 1)
# Type 1: IPv4:number
printf "%d.%d.%d.%d:%d", $_rd_bytes[2], $_rd_bytes[3], $_rd_bytes[4], $_rd_bytes[5], ($_rd_bytes[6] << 8) | $_rd_bytes[7]
else
if ($_rd_type == 0)
# Type 0: AS:number
set $_rd_as = ($_rd_bytes[2] << 8) | $_rd_bytes[3]
set $_rd_num = ($_rd_bytes[4] << 24) | ($_rd_bytes[5] << 16) | ($_rd_bytes[6] << 8) | $_rd_bytes[7]
printf "%d:%d", $_rd_as, $_rd_num
else
if ($_rd_type == 2)
# Type 2: 4-byte AS:number
set $_rd_as = ($_rd_bytes[2] << 24) | ($_rd_bytes[3] << 16) | ($_rd_bytes[4] << 8) | $_rd_bytes[5]
set $_rd_num = ($_rd_bytes[6] << 8) | $_rd_bytes[7]
printf "%d:%d", $_rd_as, $_rd_num
else
# Unknown type, display raw
printf "%02x%02x:%02x%02x:%02x%02x:%02x%02x", $_rd_bytes[0], $_rd_bytes[1], $_rd_bytes[2], $_rd_bytes[3], $_rd_bytes[4], $_rd_bytes[5], $_rd_bytes[6], $_rd_bytes[7]
end
end
end
printf " ===\n"
# Recursively walk the sub-table
# Save parent state since GDB macros don't have local scope
if ($_subtable != 0)
set $_saved_rn = $_rn
set $_saved_top = $_top_node
set $_saved_is_two_level = $_is_two_level
set $_saved_indent = $_indent_level
walk_bgp_table_subtree $_subtable 1 0
# Restore parent state
set $_rn = $_saved_rn
set $_top_node = $_saved_top
set $_is_two_level = $_saved_is_two_level
set $_indent_level = $_saved_indent
end
else
# This is a regular table, dest->info points to bgp_path_info
set $_pi = (struct bgp_path_info *)$_dest->info
set $_dest_count = $_dest_count + 1
if ($_indent_level == 0)
printf "\n=== Dest #%d: 0x%lx ===\n", $_dest_count, $_dest
else
printf "\n === Dest #%d: 0x%lx ===\n", $_dest_count, $_dest
end
if ($_indent_level == 0)
printf "Prefix: "
else
printf " Prefix: "
end
# Check if this is an EVPN prefix (AF_EVPN = 47 on this system)
set $_p = &((struct route_node *)$_rn)->p
if ($_p->family == 47)
# EVPN prefix - decode the route type
set $_evpn_bytes = (unsigned char *)&$_p->u
set $_evpn_route_type = $_evpn_bytes[0]
if ($_evpn_route_type == 2)
# Type 2: MAC/IP route - format: [type]:[eth_tag]:[mac_len]:[mac]:[ip_len]:[ip]
set $_evpn_p = (struct prefix_evpn *)$_p
set $_eth_tag = $_evpn_p->prefix.macip_addr.eth_tag
set $_mac_bytes = (unsigned char *)&$_evpn_p->prefix.macip_addr.mac
printf "[%d]:[%u]:[%d]:%02x:%02x:%02x:%02x:%02x:%02x", $_evpn_route_type, $_eth_tag, 48, $_mac_bytes[0], $_mac_bytes[1], $_mac_bytes[2], $_mac_bytes[3], $_mac_bytes[4], $_mac_bytes[5]
set $_ip_type = $_evpn_p->prefix.macip_addr.ip.ipa_type
if ($_ip_type == 2)
# IPv4 (AF_INET = 2)
printf ":[32]:"
dump_s_addr &$_evpn_p->prefix.macip_addr.ip.ipaddr_v4
else
if ($_ip_type == 10)
# IPv6 (AF_INET6 = 10)
printf ":[128]:"
dump_s6_addr &$_evpn_p->prefix.macip_addr.ip.ipaddr_v6
end
end
else
if ($_evpn_route_type == 3)
# Type 3: IMET route - format: [type]:[eth_tag]:[ip_len]:[ip]
set $_evpn_p = (struct prefix_evpn *)$_p
set $_eth_tag = $_evpn_p->prefix.imet_addr.eth_tag
set $_ip_type = $_evpn_p->prefix.imet_addr.ip.ipa_type
if ($_ip_type == 2)
# IPv4 (AF_INET = 2)
printf "[%d]:[%u]:[32]:", $_evpn_route_type, $_eth_tag
dump_s_addr &$_evpn_p->prefix.imet_addr.ip.ipaddr_v4
else
if ($_ip_type == 10)
# IPv6 (AF_INET6 = 10)
printf "[%d]:[%u]:[128]:", $_evpn_route_type, $_eth_tag
dump_s6_addr &$_evpn_p->prefix.imet_addr.ip.ipaddr_v6
else
printf "[%d]:[%u]:[?]", $_evpn_route_type, $_eth_tag
end
end
else
if ($_evpn_route_type == 5)
# Type 5: IP Prefix route - format: [type]:[eth_tag]:[prefix_len]:[ip]
set $_evpn_p = (struct prefix_evpn *)$_p
set $_eth_tag = $_evpn_p->prefix.prefix_addr.eth_tag
set $_prefix_len = $_evpn_p->prefix.prefix_addr.ip_prefix_length
set $_ip_type = $_evpn_p->prefix.prefix_addr.ip.ipa_type
printf "[%d]:[%u]:[%d]:", $_evpn_route_type, $_eth_tag, $_prefix_len
if ($_ip_type == 2)
# IPv4 (AF_INET = 2)
dump_s_addr &$_evpn_p->prefix.prefix_addr.ip.ipaddr_v4
else
if ($_ip_type == 10)
# IPv6 (AF_INET6 = 10)
dump_s6_addr &$_evpn_p->prefix.prefix_addr.ip.ipaddr_v6
else
printf "Unknown-IP-Type-%d", $_ip_type
end
end
else
# Other types
printf "[%d]:[Type-%d]", $_evpn_route_type, $_evpn_route_type
end
end
end
printf "\n"
else
dump_prefix $_p
end
if ($_indent_level == 0)
printf " dest->flags: 0x%x", $_dest->flags
else
printf " dest->flags: 0x%x", $_dest->flags
end
if ($_dest->flags & (1 << 0))
printf " PROCESS_SCHEDULED"
end
if ($_dest->flags & (1 << 1))
printf " USER_CLEAR"
end
if ($_dest->flags & (1 << 3))
printf " SELECTED"
end
printf "\n"
# Walk through all path_info structures for this destination
set $_pi_num = 0
while ($_pi != 0)
set $_pi_num = $_pi_num + 1
set $_path_count = $_path_count + 1
if ($_indent_level == 0)
printf " --- Path #%d ---\n", $_pi_num
dump_bgp_path_info $_pi " "
else
printf " --- Path #%d ---\n", $_pi_num
dump_bgp_path_info $_pi " "
end
set $_pi = $_pi->next
end
end
end
end
# Move to next route node - simple left-right-up traversal
set $_next = 0
# Try going left first
if ($_rn != 0)
set $_left = ((struct route_node *)$_rn)->link[0]
if ($_left != 0)
set $_next = $_left
end
end
# If no left, try right
if ($_next == 0 && $_rn != 0)
set $_right = ((struct route_node *)$_rn)->link[1]
if ($_right != 0)
set $_next = $_right
end
end
# If no left or right, go up until we find an unvisited right branch
if ($_next == 0 && $_rn != 0)
set $_current = $_rn
set $_parent = ((struct route_node *)$_current)->parent
while ($_parent != 0 && $_next == 0)
# Check if we came from the left child
set $_parent_left = ((struct route_node *)$_parent)->link[0]
if ($_parent_left == $_current)
# Try the right child
set $_parent_right = ((struct route_node *)$_parent)->link[1]
if ($_parent_right != 0)
set $_next = $_parent_right
end
end
# Move up
if ($_next == 0)
set $_current = $_parent
if ($_parent != 0)
set $_parent = ((struct route_node *)$_current)->parent
end
end
end
end
set $_rn = $_next
end
end
document walk_bgp_table_subtree
Internal helper for walk_bgp_table - walks a route_table recursively.
end
define walk_bgp_table
set $_table = (struct bgp_table *)$arg0
set $_verbose = 0
if ($argc > 1)
set $_verbose = $arg1
end
if ($_table == 0)
printf "Error: NULL table pointer\n"
else
printf "Walking BGP table at 0x%lx\n", $_table
printf " AFI: %d, SAFI: %d\n", $_table->afi, $_table->safi
printf " Version: %lu\n", $_table->version
set $_dest_count = 0
set $_path_count = 0
# Check if this is a two-level table (EVPN=5, MPLS_VPN=128, ENCAP=7)
set $_is_two_level = 0
if ($_table->safi == 5 || $_table->safi == 128 || $_table->safi == 7)
set $_is_two_level = 1
printf " (Two-level table: RD -> Routes)\n"
end
walk_bgp_table_subtree $_table 0 $_is_two_level
printf "\n=== Summary ===\n"
printf "Total destinations with paths: %d\n", $_dest_count
printf "Total paths: %d\n", $_path_count
end
end
document walk_bgp_table
Walk through a BGP table and dump all bgp_path_info structures with their state.
This macro iterates through all route nodes in a BGP table, and for each
destination that has path information, it dumps all the bgp_path_info
structures in the linked list along with their key state information including:
- Peer information
- Route type and sub-type
- Flags (SELECTED, VALID, MULTIPATH, etc.)
- Attributes (nexthop, etc.)
- Extra information (EVPN, labels, vrfleak)
Arguments:
(struct bgp_table *) pointer to the BGP table to walk
Example usage:
(gdb) p bgp->rib[0][0]
(gdb) walk_bgp_table bgp->rib[0][0]
end