Guide

ZeBGP Debugging Tools

This document describes the debugging tools available in ZeBGP for troubleshooting config parsing, BGP message encoding, and session issues.

Quick Reference

Tool Purpose Usage
ze config dump Inspect parsed config ze config dump [--json] config.conf
ze-peer --decode Decode BGP messages ze-peer --decode --sink
ze.log.* Per-subsystem logging ze.log.bgp.routes=debug ze bgp server config.conf
Functional test diff Test failure analysis Automatic on message mismatch
--server N / --client N Interactive test debugging ze-test bgp encode --server 1

1. Config Dump Command

Location: internal/component/config/cli/cmd_dump.go

Parses a config file and displays the interpreted values. Useful for verifying that config parsing works correctly.

Usage

# Human-readable output
ze config dump config.conf

# JSON output (for scripting)
ze config dump --json config.conf

Example Output

Warnings:
  line 5: freeform 'flow' contains nested block 'route match' - data may be lost

router-id: 1.2.3.4
local-as: 65000

peer 10.0.0.1:
  local-as: 65000
  peer-as: 65001
  static-routes:
    - prefix: 192.168.0.0/24
      next-hop: 10.0.0.254
      local-preference: 100

When to Use


2. BGP Message Decoder

Decodes raw BGP messages (hex) into human-readable format. Used automatically by functional tests and available via --decode flag.

Usage

# In ze-peer, show decoded messages
ze-peer --decode --sink --port 1790

Example Output

msg  recv   FFFFFFFF...:0030:02:00000014400101004002060201000000014003040A000001...
             UPDATE (len=48)
               ORIGIN: IGP
               AS_PATH: [1]
               NEXT_HOP: 10.0.0.1
               NLRI: 192.168.0.0/24

Decoded Attributes

Code Name Decoded Format
1 ORIGIN IGP, EGP, INCOMPLETE
2 AS_PATH [1 2 3] or [{1 2}] for AS_SET
3 NEXT_HOP IP address
4 MED Integer
5 LOCAL_PREF Integer
8 COMMUNITIES high:low format
16 EXT_COMMUNITIES Hex (0x...)

3. Test Failure Diff

When a functional test fails with "message mismatch", the output now includes a decoded diff showing exactly what differed.

Example Output

failed: message mismatch
--- Expected vs Received ---
Expected: UPDATE (len=64)
  ORIGIN: IGP
  AS_PATH: []
  NEXT_HOP: 10.0.0.1
  LOCAL_PREF: 100
  NLRI: 193.0.2.1/32

Received: KEEPALIVE (len=19)

Differences:
  - ORIGIN: IGP (missing)
  - AS_PATH: [] (missing)
  - NEXT_HOP: 10.0.0.1 (missing)
  - LOCAL_PREF: 100 (missing)
  ~ NLRI: expected=193.0.2.1/32, got=

Diff Symbols


4. Per-Subsystem Logging (ze.log.*)

Environment variables that enable structured logging at key points in the pipeline.

Usage

# Enable all subsystems at debug level
ze.log=debug ze bgp server config.conf

# Enable specific subsystems
ze.log.bgp.config=debug ze.log.bgp.routes=debug ze bgp server config.conf

Subsystems

Names follow <domain>.<component> convention. Run ze env for the full list.

Variable What it logs
ze.log Base level for ALL subsystems
ze.log.bgp.config Config parsing and loading
ze.log.bgp.routes Static route handling, UPDATE sending
ze.log.bgp.reactor.session BGP session handling
ze.log.bgp.reactor.peer Peer FSM transitions, session events
ze.log.bgp.reactor Reactor operations (reload, etc.)
ze.log.plugin.server Plugin RPC server
ze.log.plugin.relay Plugin stderr relay

Levels: disabled, debug, info, warn, err (case-insensitive)

Example Output

time=2024-01-15T13:53:41.182Z level=DEBUG msg="config parsed" subsystem=bgp.config warnings=0
time=2024-01-15T13:53:41.183Z level=DEBUG msg="config loaded" subsystem=bgp.config peers=1
time=2024-01-15T13:53:41.183Z level=DEBUG msg="peer routes configured" subsystem=bgp.config peer=127.0.0.1 routes=2
time=2024-01-15T13:53:41.184Z level=DEBUG msg="FSM transition" subsystem=bgp.reactor.peer peer=127.0.0.1 from=OPENSENT to=OPENCONFIRM
time=2024-01-15T13:53:41.184Z level=INFO msg="session established" subsystem=bgp.reactor.peer peer=127.0.0.1 localAS=1 peerAS=1
time=2024-01-15T13:53:41.184Z level=DEBUG msg="route sent" subsystem=bgp.routes peer=127.0.0.1 prefix=193.0.2.1/32 nextHop=10.0.0.1

Hierarchical Priority

Most specific wins: 1. ze.log.bgp.reactor.peer=warn - Peer logging at WARN 2. ze.log.bgp.reactor=debug - All reactor. at DEBUG 3. ze.log.bgp=info - All bgp. at INFO 4. ze.log=debug - All subsystems at DEBUG

Shell-compatible: ze_log_bgp_routes=debug also works (dot→underscore)

Logging Locations

Currently instrumented: - internal/component/config/loader.go: Config parsing, peer routes (configLogger) - internal/component/bgp/reactor/peer.go: FSM, session, route operations (peerLogger, routesLogger) - internal/component/bgp/reactor/session.go: RFC 7606 handling (sessionLogger) - internal/component/bgp/reactor/reactor.go: Reload, route operations (reactorLogger, routesLogger)


5. Parser Warnings

The parser now collects warnings for potentially problematic patterns, accessible via Parser.Warnings().

Warning Types

Pattern Warning
Nested block in Freeform freeform 'X' contains nested block 'Y' - data may be lost

Viewing Warnings

# config-dump shows warnings
ze config dump config.conf
# Output:
# Warnings:
#   line 5: freeform 'flow' contains nested block 'route match' - data may be lost

# Also visible with debug logging
ze.log.config=debug ze bgp server config.conf

5. Granular Debug (runtime)

Set debug per-module with filters and named profiles (verb-first, VyOS-style):

ze set debug module bgp.reactor                        # Enable debug
ze set debug module bgp.reactor flag update            # Add a flag filter
ze set debug module bgp.reactor scope neighbor 192.0.2.1  # Add a scope filter
ze delete debug module bgp.reactor                     # Disable debug
ze show debug profile name default                     # Show stored profile (offline)
show debug                                              # Show live daemon state (YANG RPC)
ze set debug profile name deep-trace                   # Save named profile
ze set debug active name deep-trace                    # Apply a saved profile after restart

show debug profile name <name> reads from debug.zefs (works offline). show debug queries the running daemon's actual slogutil state (requires daemon).


Debugging Workflow

1. Config Issues

# Step 1: Check parsed config
ze config dump config.conf

# Step 2: Look for warnings
ze config dump config.conf 2>&1 | grep -i warning

# Step 3: Check JSON for exact values
ze config dump --json config.conf | jq '.Neighbors[0].StaticRoutes'

2. Route Not Being Sent

# Step 1: Enable route logging
ze.log.bgp.routes=debug ze.log.bgp.config=debug ze bgp server config.conf

# Expected output when working:
# level=DEBUG msg="peer routes configured" subsystem=bgp.config peer=X routes=2
# level=DEBUG msg="route sent" subsystem=bgp.routes peer=X prefix=10.0.0.0/24 nextHop=192.168.0.1

3. Session Issues

# Step 1: Enable session + peer logging
ze.log.bgp.reactor.peer=debug ze.log.bgp.reactor.session=debug ze bgp server config.conf

# Look for FSM transitions and session establishment

4. Test Failures

# Run single test
ze-test bgp encode 1

# Output now includes decoded diff automatically
# Look at "Differences:" section to see what's wrong

5. Interactive Functional Test Debugging

Run server and client separately to see live output:

# Terminal 1: Start test server (ze-peer)
ze-test bgp encode --server 1

# Terminal 2: Start test client (zebgp)
ze-test bgp encode --client 1

Behavior: - Server waits for client, prints messages received, exits when test completes - Client connects, sends configured messages, exits when server disconnects

Press Ctrl+C in the client terminal once the server has finished validating: the runner sends SIGTERM to ze for a graceful shutdown.

Use --port to avoid conflicts:

ze-test bgp encode --server 1 --port 11790
ze-test bgp encode --client 1 --port 11790

Adding New Logging

To add logging to new code:

import "github.com/ze-software/ze/internal/core/slogutil"

// Create a subsystem logger (once per package)
var myLogger = slogutil.Logger("my.subsystem")

// Log with structured key-value pairs
myLogger.Debug("operation completed", "peer", addr, "count", n)
myLogger.Info("session established", "peer", addr, "localAS", localAS)
myLogger.Warn("unexpected state", "state", state, "expected", expected)

Subsystem naming convention: ze.log. + simplified package path (e.g., bgp.reactor.peer).


File Locations

File Purpose
internal/test/runner/decode.go BGP message decoder
internal/test/peer/peer.go Test peer with decode support
internal/core/slogutil/slogutil.go Logging infrastructure
internal/component/config/cli/cmd_dump.go config dump command
internal/test/cli/cmd_peer.go --decode flag
internal/component/config/parser.go Parser warnings
internal/component/bgp/config/loader.go Config logging (configLogger)
internal/component/bgp/reactor/peer.go Peer/route logging (peerLogger, routesLogger)
internal/component/bgp/reactor/session.go Session logging (sessionLogger)
internal/component/bgp/reactor/reactor.go Reactor logging (reactorLogger, routesLogger)