Linux - find hits of default route

The linux routing cache for IPv4 has been removed in Linux 3.6 (leaving only the use of an optimized LPC-trie). There's thus no way with a Linux system with an OS from after 2012 to get routing cache statistics.

An easy way to tag the usage of the default route is to place a realm value on this route. A packet matching this route (rather than a more specific route using the same gateway) will be identified as being with the given realm value. So if the default route was via eth0, the route would be set for example like this:

ip route add default via proto static realm 10

Or you could change a previous default route (without realm) by replacing add with change, without disruption.

This realm tag can then be reused at least in two other network subsystems: tc filter ... route or nftables' nft ... meta rtclassid.

Traffic Control

tc is quite crude and usually working at the interface level. The easiest way to attach a filter is to use the prio qdisc, the simplest classful qdisc. Its specific priority properties won't be actually used. So following on the previous example:

tc qdisc add dev eth0 root handle 1: prio

Now add the filter with an empty action (and with a pref order and a continue control to allow additional similar filters if needed), just to have statistics on it:

tc filter add dev eth0 parent 1: protocol ip pref 1 route to 10 action continue

Now every ip packet matching route realm 10, will be shown in statistics by using tc -s filter show dev eth0. Example:

# tc -s filter show dev eth0
filter parent 1: protocol all pref 1 route chain 0 
filter parent 1: protocol all pref 1 route chain 0 fh 0xffff000a to 10 
    action order 1: gact action continue
     random type none pass val 0
     index 1 ref 1 bind 1 installed 48 sec used 4 sec
    Action statistics:
    Sent 12230 bytes 79 pkt (dropped 0, overlimits 0 requeues 0) 
    backlog 0b 0p requeues 0

Note: both forwarded and locally originated packets are matching, which could be a problem for measurements.


nftables here won't be used to do any kind of firewalling, but just to increment some counters.

nftables installs only requested netfilter's hooks, rather than all available, thus usually having a lesser footprint than iptables. Here we just need a rule matching the realm - that's the role of the rtclassid expression - with a counter on it. If it's for locally originated packets, then just use the output hook. The forward hook will match only forwarded packets.

nft add table ip mystats
nft add chain ip mystats forward '{ type filter hook forward priority 0; policy accept; }'
nft add rule ip mystats forward meta rtclassid 10 counter

Which would give for example later:

# nft list ruleset
table ip stats {
    chain forward {
        type filter hook forward priority filter; policy accept;
        meta rtclassid 10 counter packets 1453 bytes 118264

Zeroing the value is possible only if storing it in a named object, the ruleset would be instead (to load with nft -f file):

table ip mystats {
    counter defaultroutecount { }

    chain forward {
        type filter hook forward priority filter; policy accept;
        meta rtclassid 10 counter name "defaultroutecount"

Then nft list counters or nft reset counters will display (or display and reset) its content.