Skip to content

IP and Routing Tools

The question "why can't this server reach that host" almost always traces back to one of three layers: interface state, the IP address bound to it, or the routing table. The "read first, change second" principle from The Troubleshooting Process matters especially here — adding a wrong route can cut a whole server off the network. IP Addressing already covered the theory of IP addresses, subnet masks, and CIDR; this article covers the ip command family and routing table that Linux uses to inspect and manage those same concepts on a running system.

iproute2: the Modern Network Toolset

Linux has historically had two command-line toolsets for managing networking: the older net-tools (ifconfig, route, arp, netstat) and the newer iproute2 (ip, ss, bridge). net-tools is marked deprecated on most modern distributions, including Debian and Ubuntu, and is no longer part of a default install; newer kernel networking features — multiple routing tables, VLANs, tunnels — are only fully manageable through iproute2. This article therefore uses ip as the primary tool, but since the older commands still appear in plenty of production servers and older documentation, the modern equivalent is always shown alongside them.

The ip command follows an object + action pattern:

ip [options] OBJECT { COMMAND | help }

The most commonly used objects are link (interfaces), address (IP addresses), route (the routing table), and neigh (the ARP/ND table). Each object also has a shorthand: ip a for ip address, ip r for ip route, ip l for ip link.

ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:4a:1c:9e brd ff:ff:ff:ff:ff:ff

The fields that matter:

  • lo — the loopback interface, always present, never leaves the host, used only for communication between processes on the same machine (an application connecting to its own database on 127.0.0.1:5432, for instance);
  • UP/DOWN — whether the interface is administratively enabled or disabled;
  • LOWER_UP — whether the physical layer (cable/link) is active; UP without LOWER_UP usually means an unplugged cable or a disabled switch port;
  • link/ether — the interface's MAC address.

Enabling or disabling an interface:

sudo ip link set enp0s3 up
sudo ip link set enp0s3 down

Warning

If you're connected over SSH, bringing down the exact interface that session is running on cuts the connection immediately and may require console access to bring it back up. Only run this command from a console or a second, independent connection.

Where Interface Names Come From

Older Linux systems assigned interface names like eth0, eth1 in detection order — which meant names could swap around after a reboot. Modern systemd-based distributions use predictable network interface names: the name is derived from the device's physical location (enp0s3 — Ethernet, PCI bus 0, slot 3) or firmware information, so it stays stable across reboots. To check the current scheme and how a name was derived:

udevadm test-builtin net_id /sys/class/net/enp0s3 2>&1 | tail -n 5

This shows which rule — a PCI path or a BIOS device index, for instance — determined the name.

Viewing IP Addresses: ip address

ip address show

A shorter, more scannable form:

ip -brief address show
lo               UNKNOWN        127.0.0.1/8 ::1/128
enp0s3           UP             192.168.1.122/24 fe80::a00:27ff:fe4a:1c9e/64

ip -br a is convenient for a quick production status check: one line per interface shows its name, state, and every address (IPv4 and IPv6) it holds.

Adding and removing an IP on a specific interface:

sudo ip address add 192.168.1.50/24 dev enp0s3
sudo ip address del 192.168.1.50/24 dev enp0s3

Danger

ip address add/del and ip link set ... up/down are temporary — they only affect the kernel's currently running state and disappear on reboot. Before running these on a production server, always record the current state first:

ip -brief address show > ~/network-before.txt
ip route show >> ~/network-before.txt

Persistent (reboot-surviving) configuration is covered in NetworkManager and netplan — manage IP settings on a production server through those tools, via a file, not through ip alone.

The Routing Table: ip route

Every Linux host — even a plain workstation — has a kernel-level routing table: it decides where a packet gets sent.

ip route show
default via 192.168.1.1 dev enp0s3 proto dhcp metric 100
192.168.1.0/24 dev enp0s3 proto kernel scope link src 192.168.1.122 metric 100

Reading the lines:

  • first line — the default route: all traffic that doesn't match any other rule in the table goes through 192.168.1.1. This is the default gateway;
  • second line — the 192.168.1.0/24 network is reachable directly through enp0s3, with no gateway needed (scope link — a directly connected network, one hop away);
  • metric — when more than one route matches, this determines which one wins: a lower number is preferred.

Adding an extra static route to a specific network — for example, when a second internal network is reachable only through a different gateway:

sudo ip route add 10.20.0.0/24 via 192.168.1.254 dev enp0s3

Removing a route:

sudo ip route del 10.20.0.0/24

Adding a default gateway directly (usually not done by hand — DHCP or netplan is the recommended source):

sudo ip route add default via 192.168.1.1

Danger

Removing an existing default route, or replacing it with a bad value, on a remote server cuts the connection immediately. Always save the current state with ip route show before changing anything, so the saved value can be re-added if something goes wrong. Where possible, only test this kind of change on an isolated lab VM, or when you have access through a provider/hypervisor console that doesn't depend on the remote connection itself.

Which Route Will Actually Be Used: ip route get

Reading the whole table by eye and guessing which line applies to a given destination is error-prone. ip route get asks the kernel directly, running the exact same selection logic a real packet would:

ip route get 10.20.0.5
10.20.0.5 via 192.168.1.254 dev enp0s3 src 192.168.1.122 uid 1000
    cache

This resolves, in one step, three things that otherwise have to be inferred: the gateway the packet takes (via), the interface it leaves through (dev), and the source address the kernel will stamp on it (src). It is the fastest way to confirm a new static route is actually being chosen — far more reliable than reading ip route show and reasoning about it by hand.

When more than one route could match a destination, the kernel does not simply pick the lowest metric. It first selects the most specific route — the one with the longest matching prefix. A /24 route always wins over a /0 (default) route for a destination inside that /24, regardless of metric; metric only breaks ties between routes of equal prefix length. This is exactly why a missing 10.20.0.0/24 route sends traffic to the default gateway (the only remaining match) rather than the correct internal gateway — the failure in the scenario below.

The Neighbor Table: ip neigh

ip neigh (the modern replacement for arp -n) shows the MAC addresses of devices on the directly connected network — the kernel's ARP (IPv4) or NDP (IPv6) cache:

ip neigh show
192.168.1.1 dev enp0s3 lladdr 52:54:00:12:35:02 REACHABLE

States like REACHABLE, STALE, and FAILED indicate how recently an entry was confirmed; a FAILED entry usually signals that the neighboring host isn't responding.

Practical Scenario: An Internal Network Is Unreachable Due to a Missing Static Route

Problem: The application server can't connect to the database server on the 10.20.0.0/24 network, but internet access works fine.

Step 1 — check (read-only, no changes yet):

ip -brief address show
ip route show

The result shows no line at all for 10.20.0.0/24, only default via 192.168.1.1 — meaning there is no dedicated route to that network at all, and traffic is incorrectly falling through to the default gateway.

Step 2 — hypothesis: the required route was either never added, or it was lost on a previous reboot, because it was only ever added temporarily with ip route add.

Step 3 — test with one change:

sudo ip route add 10.20.0.0/24 via 192.168.1.254 dev enp0s3
ping -c 3 10.20.0.5

Step 4 — result: if ping succeeds, the hypothesis is confirmed. This route now needs to be written permanently into the netplan configuration, not left temporary — otherwise the problem returns after the next reboot.

Step 5 — documentation: record which route was missing, why (likely never written to the persistent config), and how it was made permanent, for the next administrator.

Common Mistakes

Assuming a Change Made with ip Is Permanent

ip address add and ip route add only change the current kernel state. These changes disappear after a reboot unless they are also written into netplan or NetworkManager configuration.

Cutting Off an Interface or Route in a Remote Session

Bringing down the interface an SSH session is running over, or removing the default route, works against the very connection running the command. Prepare console or a second, independent access path before attempting this.

Reading Old ifconfig/route Output as Equivalent to ip

Both tools show the same underlying data in different formats; column names and terminology don't line up exactly (for example, ifconfig's inet addr: corresponds to a separate inet field in ip). Don't copy commands or scripts between the two formats without checking.

Interpreting an Empty or FAILED Entry in ip neigh as "the Network Is Down"

The ARP cache is transient; an entry may simply not have been created yet, or may have expired. "Wake up" the neighbor with a plain ping first, then check again.

Interview angle

A common follow-up question after covering routing metrics is: "what happens if two routes match the same destination with different metrics?" The kernel always prefers the route with the lower metric — this is exactly how a system with both a wired and a wireless interface, each offering a default route, ends up consistently favoring one over the other without any manual intervention, as long as their dhcp-assigned metrics differ.

Exercises

  1. Compare the output of ip -brief address show and ip route show, and write in your own words which interface serves which network, and which one is the default gateway.
  2. On a test VM, add a temporary second IP address (ip address add), confirm it with ip -br a, then remove it with ip address del.
  3. Use udevadm test-builtin net_id to determine how your server's interface name was derived.
  4. Repeat the practical scenario above on your own test network: deliberately remove the static route, diagnose the problem through the checks shown, then re-add it.

Verification criterion: after exercise 4, ip route show must show the restored 10.20.0.0/24 (or your equivalent) route with the correct gateway and device — a route with the wrong via address will make ping fail even though the route "exists."

References

  • man7.org: ip(8): https://man7.org/linux/man-pages/man8/ip.8.html
  • man7.org: ip-address(8): https://man7.org/linux/man-pages/man8/ip-address.8.html
  • man7.org: ip-route(8): https://man7.org/linux/man-pages/man8/ip-route.8.html
  • man7.org: ip-neighbour(8): https://man7.org/linux/man-pages/man8/ip-neighbour.8.html
  • freedesktop.org: systemd.net-naming-scheme(7): https://www.freedesktop.org/software/systemd/man/latest/systemd.net-naming-scheme.html
  • Debian Wiki: NetworkConfiguration — net-tools deprecation: https://wiki.debian.org/NetworkConfiguration