Read Linux Routes Clearly with routel
routel turns the kernel's routing table into a compact, labelled view that is far easier to read than raw ip route output. You will filter to IPv4 or IPv6, pick a specific table, and learn to recognise when a strange result is your command rather than a network problem. Allow about ten minutes; these examples only read routing state and normally need no elevated privileges.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Check the installed command
This guide describes the Ubuntu package version iproute2 6.1.0-1ubuntu6.4. The installed manual page is dated 1 September 2021, and the script itself is a Python program that asks ip for JSON route data before formatting it nicely. Other package builds can differ, so check your own command first:
$ dpkg-query -W -f='${Package} ${Version}\n' iproute2
iproute2 6.1.0-1ubuntu6.4
$ command -v routel
/usr/bin/routel
On a non-Debian system, use its package manager or just run command -v routel. Missing entirely? Install iproute2 through your normal system-management process. Do not copy the version string above into an installation command: it is a host-specific observation, not an instruction.
2. List the default route view
Run routel with no arguments:
$ routel
Dst Gateway Prefsrc Protocol Scope Dev Table
default 136.243.171.1 static enp0s31f6
172.17.0.0/16 172.17.0.1 kernel link docker0
127.0.0.0/8 127.0.0.1 kernel host lo local
Your addresses, interfaces and route count will differ. The header is the useful constant. Dst is the destination prefix, Gateway the next hop where one exists, Prefsrc the preferred source address, and Protocol and Scope describe how the route was installed and where it applies. Dev is the outgoing interface and Table identifies the routing table.
Checkpoint
The no-argument form reads table 0, which is what the installed script passes to ip route list table. That is an implementation detail worth remembering, not a request to print every policy-routing table there is.
3. Separate IPv4 and IPv6 routes
Use -4 for IPv4 or -6 for IPv6; the long form is --family with inet or inet6:
$ routel -4 | head -5
Dst Gateway Prefsrc Protocol Scope Dev Table
default 136.243.171.1 static enp0s31f6
172.17.0.0/16 172.17.0.1 kernel link docker0
172.18.0.0/16 172.18.0.1 kernel link br-64a4af5f7dec
$ routel --family inet6 | head -5
Dst Gateway Prefsrc Protocol Scope Dev Table
2a01:4f8:171:2009::/64 kernel enp0s31f6
fe80::/64 kernel enp0s31f6
IPv6 gets wider columns so addresses stay readable. An empty gateway is normal for directly connected or local routes. Piping to head only shortens what you see on screen; it changes nothing in the kernel.
4. Inspect a particular routing table
Put a numeric table number first, then any raw route arguments. Table main is conventionally number 254 on Linux:
$ routel 254
Dst Gateway Prefsrc Protocol Scope Dev Table
default 136.243.171.1 static enp0s31f6
172.17.0.0/16 172.17.0.1 kernel link docker0
Reach for this when you are investigating policy routing and already know the table number: confirm it in your own routing policy first, do not assume. To pass route-list arguments after the table number, append them as ordinary ip route list arguments:
$ routel 254 match 192.0.2.10
The exact rows depend on the host. Need machine-readable data for automation? Call ip -j route list table 254 directly instead of parsing this presentation-oriented output.
5. Diagnose failures without changing routes
routel --help prints a short usage line and exits with status 64. That is expected for this script's help path, not a failure:
$ routel --help
Usage: /usr/bin/routel [tablenr [raw ip args...]]
$ printf 'exit status: %s\n' "$?"
exit status: 64
For a normal listing, check both the command status and the output:
$ routel -4 > /tmp/routel-ipv4.txt
$ status=$?
$ test "$status" -eq 0 && test -s /tmp/routel-ipv4.txt
$ printf 'status=%s, output=%s\n' "$status" "$(test -s /tmp/routel-ipv4.txt && echo present || echo empty)"
status=0, output=present
An invalid family gets passed straight to ip, so the error can be followed by a Python JSON parsing traceback. routel --family nope is not a valid way to inspect an unknown address family: stick to inet, inet6, -4 or -6.
6. Keep inspection separate from route changes
routel lists routes. It has no add, delete or replace operation of its own. The raw arguments go straight to ip route list, so every example here stays read-only. Do not turn an investigation into a change by swapping list for a write command in a copied pipeline: ip route del can interrupt connectivity and may be hard to recover remotely.
None of this needs sudo. If a restricted environment blocks route data, work out why first and use the least privilege your policy allows. Do not make a persistent routing change just to get a display command working.
Done means
- You confirmed the versions. You know which
iproute2androutelare installed. - You can read the columns. Destination, gateway, source, protocol, scope, interface and table all make sense.
- You know your tables. You can tell the default table view from an explicit table number.
- You filtered when it mattered.
-4or-6cut out distracting mixed-family output. - You checked status and output. Nothing in the routing configuration changed.