How to Programmatically List All Active Linux Routing Tables for Network Configuration Management


11 views

When managing advanced network configurations on Linux systems, we often need to identify all active routing tables beyond the default ones (local, main, and default). The standard ip route show command only displays specific tables when explicitly requested.

The traditional approach of checking /etc/iproute2/rt_tables only shows pre-configured table names, not dynamically created ones. As shown in the example:

# cat /etc/iproute2/rt_tables
#
# reserved values
#
255 local
254 main
253 default
0   unspec

We can parse the output of ip rule list to discover all referenced tables:

# ip rule list | awk '/lookup/ {print $NF}' | sort -u
local
main
default
104

Here's a bash function to list and manage non-standard tables:

function list_routing_tables() {
    # Get all active table IDs
    local tables=$(ip rule list | awk '/lookup/ {print $NF}' | sort -u)
    
    # Filter out default tables
    local default_tables="local main default unspec"
    for table in $tables; do
        if [[ ! " $default_tables " =~ " $table " ]]; then
            echo "Found custom table: $table"
            ip route show table $table
        fi
    done
}

function flush_non_default_tables() {
    # Get all active table IDs
    local tables=$(ip rule list | awk '/lookup/ {print $NF}' | sort -u)
    
    # Filter out default tables
    local default_tables="local main default unspec"
    for table in $tables; do
        if [[ ! " $default_tables " =~ " $table " ]]; then
            echo "Flushing table: $table"
            ip route flush table $table
        fi
    done
}

For more robust parsing in production environments:

# Get numeric table IDs including those referenced by name
ip -o rule list | awk '{print $NF}' | while read table; do
    if [[ $table =~ ^[0-9]+$ ]]; then
        echo $table
    else
        grep -w "$table" /etc/iproute2/rt_tables | awk '{print $1}'
    fi
done | sort -un

Here's how to apply this in a multi-table VPN configuration:

# Create tables
ip rule add fwmark 0x1 table vpn1
ip rule add fwmark 0x2 table vpn2

# Add routes
ip route add default via 10.8.0.1 dev tun0 table vpn1
ip route add default via 10.8.1.1 dev tun1 table vpn2

# List all active tables
list_routing_tables

# Output would show:
# Found custom table: vpn1
# default via 10.8.0.1 dev tun0
# Found custom table: vpn2
# default via 10.8.1.1 dev tun1

Some important considerations:

  • Table IDs can range from 1-255 (0 is unspec)
  • Tables can be referenced by either ID or name
  • Some systems may have tables referenced in rules but with no routes
  • Always check both ip rule and ip route outputs

For systems with hundreds of routing tables, use more efficient parsing:

# Single-pass awk solution
ip -o rule list | awk '!seen[$NF]++ {print $NF}' | grep -vE 'local|main|default|unspec'

When working with advanced Linux networking, particularly with policy routing, we often need to manage custom route tables beyond the standard local, main, and default tables. The key challenge arises when these custom tables persist even after their corresponding rules are deleted.

The standard method of checking /etc/iproute2/rt_tables only shows predefined tables. To discover all active routing tables in the system, we need a different approach:

ip rule list | awk '/lookup/ {print $NF}' | sort -u

This command extracts all table references from the current routing rules. However, it won't show tables that have routes but no active rules.

To get a comprehensive list of all tables that actually contain routes (including orphaned tables), use:

for table in $(echo 104 105 106 200); do
    ip route show table $table 2>/dev/null | grep -q . && echo "Table $table exists with routes";
done

For automated cleanup of all non-standard tables:

standard_tables="local main default unspec"
for table in $(ip route show table all | awk '/table/ {print $NF}' | sort -u); do
    if [[ ! " $standard_tables " =~ " $table " ]]; then
        echo "Flushing table $table"
        ip route flush table $table
    fi
done

Let's walk through a complete workflow:

# Create custom table and route
ip route add 10.0.0.0/24 via 192.168.1.1 table 200
ip rule add from 192.168.1.100 table 200

# Verify
ip rule list | grep 200
ip route show table 200

# Delete rule but route remains
ip rule del table 200

# Discover hidden table
grep -l "table 200" /proc/net/route /proc/net/rt_cache 2>/dev/null || \
echo "Table 200 might exist"

For systems with many tables, we can optimize the discovery process:

# Find all tables with active routes
ls /proc/net/ipv6_route /proc/net/route 2>/dev/null | \
xargs awk '{print $9}' | sort -u | grep -v '^$'

# Cross-reference with defined tables
comm -12 \
  <(ip rule list | awk '/lookup/ {print $NF}' | sort -u) \
  <(ip route show table all | awk '/table/ {print $NF}' | sort -u)

Remember that some tables might exist in the IPv6 space only, so check both IPv4 and IPv6 routes when doing comprehensive cleanup.