Linux Networking Commands: The Complete Guide

The command set that replaced ifconfig, how the kernel makes a forwarding decision, and how any of it survives a reboot. All output captured live.

Dark terminal graphic reading Linux Networking Commands, with real ip and traceroute output from a CML lab

Somewhere in the last decade, the network stopped being a thing made only of routers and switches. The load balancer is a Linux box. The firewall is a Linux box. The DNS server, the VPN concentrator, the container host with four hundred virtual interfaces, the SD-WAN edge device: Linux, all of them, and increasingly the thing on the other end of your show cdp neighbors output too. An engineer who can read a routing table on IOS but not on Debian is working with one eye closed.

This guide is the map for the Linux side. It covers the command set that replaced ifconfig, how the kernel actually makes a forwarding decision, the neighbor table and its state machine, the layer below the kernel where the NIC driver lives, and how any of it survives a reboot. Every command and every block of output on this page and across the cluster was captured on a Debian 13 host wired into a Cisco Modeling Labs topology, so all of it is reproducible and none of it is transcribed from a man page. Read it top to bottom for the model, or jump to the section that matches what is currently broken.

What this toolset solves

Two problems, and they are different.

The first is translation. If your instincts were trained on Cisco, you already know what you want to see; you just do not know which command shows it. You want show ip interface brief, show ip route, show arp, show interfaces. Those all exist on Linux under different names, and most of them are better. The mapping is short enough to learn in an afternoon.

The second is that Linux exposes things a router never did. Multiple routing tables consulted in a configurable order, per-neighbor reachability states, per-queue NIC statistics, offloads that make packet captures disagree with the wire, and a strict separation between what is running now and what will be running after a reboot. None of those have an IOS equivalent, and all of them will eventually cost you an outage if you do not know they exist.

The tools split cleanly into layers, and knowing which layer owns a question is most of the diagnosis:

Which tool owns which layer
NIC and driverethtool - speed, duplex, offloads, rings, per-queue counters
Kernel interfaces and forwardingip - addresses, links, routes, neighbors, rules, namespaces
Sockets and connectionsss, netstat -s - what is listening, what is connected, protocol counters
Reachability and pathping, traceroute, mtr, tracepath - does it work, and where does it stop
Name resolutiondig, host, nslookup, resolvectl - what the client asked and what it got back
On the wiretcpdump, tshark, ngrep - the packets themselves
Persistencenmcli, systemd-networkd, netplan - what is still true after a reboot

The commands you may have learned first (ifconfig, route, arp, netstat) come from the net-tools package and read kernel state through /proc text files and legacy ioctls. Those interfaces still work. They also stopped being extended around 2001, so everything Linux networking gained afterward is invisible to them.

The replacement set (ip, ss, bridge, tc, all from iproute2) talks to the kernel over netlink: a structured, versioned socket protocol that new kernel features get wired into as they land. That is the whole argument for the switch, and it is not aesthetic. It is the difference between seeing your configuration and seeing part of it.

Here is the single most important consequence, stated plainly: ifconfig can report an address as absent when it is configured and working. Linux has supported multiple addresses per interface for decades. ifconfig has no model for that and only sees additional addresses carrying an alias label like eth0:1. Add an address the normal way, with ip addr add and no label, and ifconfig will not show it at all.

That is not a display quirk. It means a tool you are using to diagnose a problem can tell you a working thing is broken. Everything else in the migration argument (address lifetimes, neighbor states, policy routing, VRFs) is a matter of missing detail. This one is a matter of being actively misled, and it is why the translation from net-tools to iproute2 is worth doing properly rather than aliasing your way around.

The reference cards

These are the two you will keep scrolling back to. First, the command translation.

Legacy to modern, and the Cisco equivalent
ip -br addrwas ifconfig, is show ip interface brief
ip -s link showwas netstat -i, is show interfaces
ip route showwas route -n or netstat -rn, is show ip route
ip route get x.x.x.xno legacy equivalent, is show ip route x.x.x.x
ip neigh showwas arp -n, is show ip arp
ss -tulpnwas netstat -tulpn, is show control-plane host open-ports
ethtool eth0no legacy equivalent, is the speed/duplex half of show interfaces
ip rule showno legacy equivalent, is PBR and show ip policy

Second, the lab every capture in this cluster came from, so you can rebuild it and follow along.

The lab topology and addressing
Linux hostDebian 13 (trixie), kernel 6.12, iproute2 6.15.0, net-tools 2.10
Management NICens192, DHCP, NetworkManager-managed
Lab NICens224, 10.77.0.100/24, configured with iproute2, bridged into CML
Edge routerR1 Et0/0 10.77.0.1, IOS XE 17.18.2
Core linksR1 to R2 10.77.12.0/24, R2 to R3 10.77.23.0/24, OSPF area 0
Web serverWEB1 10.77.2.10 (nginx), two hops in
App serverSRV1 10.77.3.10, three hops in

The one idea that matters most

If you take a single thing from this guide, take this: on Linux, running state and saved configuration are two different things, and no command touches both.

Every command in this cluster that changes something (ip addr add, ip route add, ip link set, ethtool -G, ethtool -K, sysctl -w) writes to the running kernel and nowhere else. There is no configuration file behind any of them. Reboot the host and every one of those changes is gone, replaced by whatever the interface manager thinks the world should look like.

Coming from IOS, where copy running-config startup-config is an explicit, memorable step, this is the trap. There is no write mem on Linux, and there is nothing to remind you. A change you made at 2am and verified working is simply absent after the next maintenance window, and the outage looks like it came from nowhere.

The upside, once you internalize it, is real. A reboot is a guaranteed rollback. You can make an aggressive change on a production host knowing that the worst case, if console access still exists, is a power cycle. That is a much better safety net than most network operating systems give you, and experienced Linux engineers lean on it deliberately.

The workflow that follows from it: use ip and ethtool to find the configuration that works, then write that exact configuration into whichever manager owns the interface, then reactivate and verify. On most modern distributions that manager is NetworkManager and the tool is nmcli. On minimal server images it may be systemd-networkd, on Ubuntu it may be netplan generating one of the two, and on older Debian it may be /etc/network/interfaces. Find out which before you need to know.

The minimum viable session

Six commands cover most of what you will do on an unfamiliar Linux host. Here they are against the lab, in the order you would actually run them.

What addresses does this box have:

j@llmbits:~$ ip -br addr show
lo               UNKNOWN        127.0.0.1/8 ::1/128
ens192           UP             192.168.88.156/24 fd64:f725:df42:4f01:8498:4c62:15f0:8139/64 fd64:f725:df42:4f01:20c:29ff:feb1:cc3d/64 fe80::20c:29ff:feb1:cc3d/64
ens224           UP             10.77.0.100/24

Where does it send traffic:

j@llmbits:~$ ip route show
default via 192.168.88.1 dev ens192 proto dhcp src 192.168.88.156 metric 101
10.77.0.0/24 dev ens224 proto kernel scope link src 10.77.0.100
10.77.0.0/16 via 10.77.0.1 dev ens224
192.168.88.0/24 dev ens192 proto kernel scope link src 192.168.88.156 metric 101

Where would it send traffic to one specific destination, which is a different and better question:

j@llmbits:~$ ip route get 10.77.3.10
10.77.3.10 via 10.77.0.1 dev ens224 src 10.77.0.100 uid 1000
    cache

Has it resolved its next hop:

j@llmbits:~$ ip neigh show dev ens224
10.77.0.1 lladdr aa:bb:cc:00:04:00 REACHABLE

Does the path work, and where does it go:

j@llmbits:~$ traceroute -n 10.77.3.10
traceroute to 10.77.3.10 (10.77.3.10), 30 hops max, 60 byte packets
 1  10.77.0.1  4.452 ms  4.379 ms  4.437 ms
 2  10.77.12.2  4.686 ms  6.932 ms  6.960 ms
 3  10.77.23.3  7.029 ms  7.022 ms  8.543 ms
 4  10.77.3.10  8.506 ms  10.428 ms  10.354 ms

Does the service on the far end actually answer:

j@llmbits:~$ curl -s -o /dev/null -w '%{http_code} %{time_total}s\n' http://10.77.2.10/
200 0.009585s

Six commands, and you now know the host's addressing, its forwarding decisions, its layer 2 adjacency, the path across three routers and whether the application at the end responds. That is a complete first pass and it takes under a minute.

The reason this cluster is built on a real router topology rather than a single host is that the interesting mistakes happen at the boundary. Here is R1's ARP table, taken at the same moment as the ip neigh output above:

R1#show ip arp
Protocol  Address          Age (min)  Hardware Addr   Type   Interface
Internet  10.77.0.1               -   aabb.cc00.0400  ARPA   Ethernet0/0
Internet  10.77.0.100             0   000c.29b1.cc47  ARPA   Ethernet0/0
Internet  10.77.12.1              -   aabb.cc00.0410  ARPA   Ethernet0/1
Internet  10.77.12.2              4   aabb.cc00.0300  ARPA   Ethernet0/1

000c.29b1.cc47 on the router is 00:0c:29:b1:cc:47 on the host. One MAC address, two vendors' formatting conventions, one adjacency. That is the entire trick to working across both worlds: the protocols on the wire are identical, only the presentation changed.

The genuine differences are in behavior rather than syntax, and there are three worth carrying in your head. IOS ages ARP entries on a fixed four hour timer and does not track per-entry reachability; Linux tracks reachability continuously and notices a dead neighbor within about thirty seconds of trying to use it. IOS compares routes across protocols using administrative distance; the Linux kernel has no such concept and compares only metric within a table, leaving protocol preference to whatever daemon is installing routes. And IOS has one routing table per VRF, while Linux has an arbitrary number of tables consulted in a configurable order, which is both more flexible and much easier to misconfigure.

The operational concern: offloads make your captures lie

This one costs people entire afternoons and it belongs on the pillar rather than buried in a subsidiary article.

Modern NICs do work the CPU used to do. TCP segmentation offload lets the kernel hand the NIC a buffer far larger than the MTU and have the NIC cut it into frames. Generic receive offload does the reverse, merging incoming frames into larger buffers before the stack sees them. Both are on by default and both are a substantial CPU saving.

They also mean the host's own view of its traffic does not match the wire. From this host's NIC statistics:

j@llmbits:~$ sudo ethtool -S ens224
     Tx Queue#: 1
       TSO pkts tx: 2532
       TSO bytes tx: 8251296
       ucast pkts tx: 3247
       ucast bytes tx: 9317987

2532 segmentation-offload packets carrying 8,251,296 bytes, on a link with a 1500 byte MTU. That averages 3258 bytes per "packet". The switch at the other end counted several times as many frames, and neither counter is wrong.

Two practical consequences. First, comparing a host's packet count to a switch port's packet count is not a valid diagnostic while TSO is on, and people reach for it constantly. Second, tcpdump taps above the NIC, so a capture taken on the host shows those oversized pre-segmentation buffers on transmit and merged buffers on receive, plus checksums marked invalid on outbound packets because the NIC had not filled them in yet. If you need the capture to reflect what a span port would see, disable the offloads for the duration:

sudo ethtool -K ens224 tso off gso off gro off lro off
# capture
sudo ethtool -K ens224 tso on gso on gro on lro on

The full treatment, including ring buffers, coalescing and the host-side drop counters, is in ethtool: link speed, duplex, offloads and NIC stats, and it pairs directly with tcpdump for network engineers.

Hardening: what to check on a Linux box you inherited

A Linux host on your network is an attack surface with a shell on it. Four checks, none of which take long.

What is listening, and on which address. ss -tulpn is the whole answer, and the address column is the part people skip. A service bound to 127.0.0.1 is reachable only from the host; one bound to 0.0.0.0 is reachable from every network the box touches, including the management network you did not intend to expose it on. On the host in this lab, cups is bound to loopback and sshd is not, which is the correct arrangement for both.

Whether it is forwarding. sysctl net.ipv4.ip_forward tells you whether this host will route between its interfaces. On a server it should be 0. Container runtimes turn it on, sometimes without anybody noticing, and a dual-homed host that forwards is a bridge between two security zones that no firewall rule accounted for.

Whether it accepts redirects and source routing. net.ipv4.conf.all.accept_redirects and accept_source_route should both be 0 on anything that is not a router. ICMP redirect acceptance is a genuinely usable attack on a flat network.

Reverse path filtering. net.ipv4.conf.all.rp_filter drops packets arriving on an interface the host would not use to reply. Strict mode breaks legitimate asymmetric routing, which is precisely why the policy routing approach of one table and one source-based rule per interface is the correct fix for multihoming rather than turning the protection off.

Scanning the host from outside is the other half of this, and it belongs to a real attacker's toolkit rather than the host's own. The Nmap cluster covers that side against lab gear you own.

Troubleshooting order

When a Linux host cannot reach something, work up the stack rather than guessing. Each step tells you whether to continue or stop.

From the NIC upward
1. Carrierip link show for LOWER_UP, or ethtool eth0 for Link detected. No carrier means stop and look at the cable or the switch port.
2. Addressip -br addr. Wrong prefix length is the classic, and it looks fine until you try to reach something just outside it.
3. Neighborip neigh show. FAILED or INCOMPLETE on the gateway is a layer 2 problem: wrong VLAN, blocked port, host down.
4. Routeip route get <dest>. Not show. This runs the real lookup including policy rules and source selection.
5. Pathping then traceroute or mtr. Which hop stops answering, and whether loss is at one hop or from one hop onward.
6. Portnc -vz or curl. Reachable host with a dead service is a completely different ticket.
7. Namedig against the configured resolver, then against a known-good one. Half of "the network is down" is DNS.
8. Wiretcpdump, with offloads disabled. The last resort, and the one that settles arguments.

Step 4 deserves emphasis because it is the one people substitute for. ip route show prints the table and leaves you to do longest-prefix match by eye against possibly several tables. ip route get asks the kernel what it will actually do. On any host with policy routing, a VPN, or a container bridge, those two can give you different answers and only one of them is the truth.

The Full Cluster, in Reading Order

Six articles so far, all built on the same Debian host and the same CML topology. Read in order for the model, or jump to whatever is currently on fire.

The iproute2 core

Below and around the kernel

Already covered elsewhere on PingLabz

Coming next in this cluster

Path testing and sockets (traceroute, mtr, tracepath, ss), DNS client tools (dig, host, nslookup, and how Linux actually resolves a name), transfer and swiss-army tools (curl, wget, netcat, socat, SSH tunneling), traffic monitoring (tshark, ngrep, the live bandwidth monitors, /proc/net), and firewalling (iptables, nftables, ufw). This page is updated as each publishes.

FAQ

Do I actually need to stop using ifconfig?

For reading a simple host, no, and it will keep working for years. For diagnosis, yes, and the reason is specific: it cannot see addresses added without an alias label, so it can report a working address as absent. It also cannot show address lifetimes, neighbor states, policy routing or VRFs. Any of those being invisible during an incident costs more than the twenty minutes it takes to learn ip.

What is the single most useful Linux networking command?

ip route get <destination>. It performs a real forwarding lookup through policy rules, longest-prefix match and source address selection, and reports the exit interface, next hop and source address the kernel will actually use. It is the command that ends arguments, and it has no net-tools equivalent.

Why do my network changes disappear after a reboot?

Because ip, ethtool and sysctl -w write to the running kernel and have no configuration file behind them. There is no write mem. Whatever manages your interfaces at boot reapplies its own view and yours is gone. Find out whether that is NetworkManager, systemd-networkd, netplan or /etc/network/interfaces, and write the change there.

How different is Linux routing from Cisco routing?

The forwarding logic is the same: longest-prefix match, then metric. The differences are that Linux has no administrative distance in the kernel (protocol preference is the routing daemon's problem), Linux can have any number of routing tables consulted in a configurable order, and the local table that recognizes the host's own addresses is a separate visible table rather than the L entries IOS shows inline.

Which tools should I install on a new server?

iproute2 is almost always already there. Add ethtool, tcpdump, dnsutils or bind-utils for dig, mtr, netcat-openbsd and curl. That set handles nearly every host-side network problem you will meet. On a minimal container image, expect none of them and plan to debug from the host namespace with nsenter instead of installing tools into the container.

Does any of this apply to containers and Kubernetes?

All of it, and more so. A container is a network namespace with veth pairs, bridges and its own routing table, all built with the same ip commands documented here. ip netns, ip link add type veth and per-namespace routing tables are the primitives every container network plugin is built on. Understanding them on one host is what makes a CNI make sense.

Key takeaways

Start with the Linux ip command guide if you are new to the toolset, or with the net-tools translation if you have twenty years of ifconfig in your fingers and need the map.