Every Linux box you inherit has the same twelve or so networking commands on it, and the ones you reach for first decide how long the outage lasts. This is the field reference for those commands: what each one is for, one real line of output from a live lab, and a link to the full article when you need the depth. No invented output, no command that only exists in a blog post.
It is the index page for the complete guide to Linux networking commands, which is the cluster this article belongs to. Everything below was captured on a Debian 13 host at 10.77.0.100 bridged into a CML topology through ens224. Three IOS XE routers sit between it and the far side: R1 at 10.77.0.1, R2 at 10.77.12.2, R3 at 10.77.23.3, with an nginx server at 10.77.2.10 and a net-tools server at 10.77.3.10 running iperf3, a DNS server and not much else. Four hops of real routing, which is exactly enough to make traceroute interesting.
How to read this reference
The commands are grouped the way you actually use them, by the question you are trying to answer: what address do I have, where does traffic go, who is listening, what resolves, can I reach that port, what is on the wire, how fast is it, and what is blocked. Within each group the cards give you the one-line purpose and a link to the deep article. The capture block after each group is the group's headline commands run back to back on the same host, so you can see what a real session looks like rather than a list of synopses.
If you are starting from nothing on a Debian or Ubuntu box, this single line installs everything used in this article that is not already present:
sudo apt-get install -y iproute2 net-tools ethtool network-manager \
traceroute mtr-tiny iputils-tracepath dnsutils curl wget netcat-openbsd \
socat tcpdump tshark ngrep nmap iperf3 iftop nload bmon vnstat nethogs \
ifstat lsof whoisOn RHEL, Rocky and Alma the package names differ a little (bind-utils rather than dnsutils, nmap-ncat rather than netcat-openbsd) but the tools are identical.
Addressing and interfaces
This is where every investigation starts, and it is also where the biggest generational split lives. ip talks to the kernel over netlink and shows you everything; ifconfig reads a legacy interface that cannot represent multiple addresses per interface properly. Both are here because you will meet both.
-br for a readable summary.ip changes are temporary and nmcli changes are the real configuration.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:20c:29ff:feb1:cc3d/64 fe80::20c:29ff:feb1:cc3d/64
ens224 UP 10.77.0.100/24
j@llmbits:~$ ip addr show ens224
3: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:b1:cc:47 brd ff:ff:ff:ff:ff:ff
inet 10.77.0.100/24 scope global ens224
valid_lft forever preferred_lft forever
j@llmbits:~$ ifconfig ens224
ens224: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.77.0.100 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:0c:29:b1:cc:47 txqueuelen 1000 (Ethernet)
RX packets 804447 bytes 75153559 (71.6 MiB)
TX packets 528439 bytes 2185104277 (2.0 GiB)
j@llmbits:~$ ethtool ens224
Settings for ens224:
Supported ports: [ TP ]
Speed: 10000Mb/s
Duplex: Full
Auto-negotiation: off
Link detected: yes
j@llmbits:~$ nmcli device status
DEVICE TYPE STATE CONNECTION
ens192 ethernet connected Wired connection 1
ens224 ethernet connected (externally) ens224 Read ens224 in that last block carefully. NetworkManager reports it as connected (externally), which is its way of saying the address on it was configured by something other than NetworkManager and it is leaving it alone. On a host where the state says connected with a named profile, anything you set with ip addr add is gone at the next reboot or the next nmcli con up.
Routing and neighbors
The routing table answers "where does this packet leave from," and the neighbor table answers "does the next hop actually exist." Nearly every "the network is down" call ends at one of those two tables.
ip route get asks the kernel which route it would actually pick for one destination, which beats reading the table by eye.j@llmbits:~$ ip route
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
j@llmbits:~$ ip rule list
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
j@llmbits:~$ ip neigh show dev ens224
10.77.0.1 lladdr aa:bb:cc:00:04:00 STALE
j@llmbits:~$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.88.1 0.0.0.0 UG 101 0 0 ens192
10.77.0.0 0.0.0.0 255.255.255.0 U 0 0 0 ens224
10.77.0.0 10.77.0.1 255.255.0.0 UG 0 0 0 ens224
192.168.88.0 0.0.0.0 255.255.255.0 U 101 0 0 ens192Those two 10.77 entries are a longest-prefix-match lesson in four lines. The /24 is connected and covers the local segment; the /16 points at R1 and covers everything behind it. A packet to 10.77.3.10 matches only the /16 and goes to the router. A packet to 10.77.0.50 matches both and takes the /24, because the more specific prefix wins regardless of the order the lines appear in. This is the same rule your routers run, expressed in a different syntax.
And the neighbor entry says STALE, which is normal and not a fault. Linux keeps a cached entry after the reachability timer expires and revalidates it on next use rather than deleting it, so STALE means "we have an answer and we will confirm it when we need it." FAILED is the state that matters.
Testing the path
Four tools, four different questions. ping asks whether the far end answers. traceroute asks which routers are in between. mtr asks which of them is losing packets, over time. tracepath asks how big a packet can be before somebody drops it.
-M do -s turns it into an MTU test.-I and TCP with -T, and the mode you pick changes which firewalls let you through.j@llmbits:~$ ping -c 4 10.77.3.10
PING 10.77.3.10 (10.77.3.10) 56(84) bytes of data.
64 bytes from 10.77.3.10: icmp_seq=1 ttl=61 time=4.98 ms
64 bytes from 10.77.3.10: icmp_seq=2 ttl=61 time=8.90 ms
64 bytes from 10.77.3.10: icmp_seq=3 ttl=61 time=5.57 ms
64 bytes from 10.77.3.10: icmp_seq=4 ttl=61 time=5.14 ms
--- 10.77.3.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 4.980/6.145/8.896/1.602 ms
j@llmbits:~$ traceroute 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 (10.77.0.1) 4.348 ms 4.385 ms 4.701 ms
2 10.77.12.2 (10.77.12.2) 5.123 ms 5.096 ms 5.149 ms
3 10.77.23.3 (10.77.23.3) 6.959 ms 6.847 ms 8.177 ms
4 10.77.3.10 (10.77.3.10) 8.356 ms 8.554 ms 8.509 ms
j@llmbits:~$ mtr -rwc 5 10.77.3.10
Start: 2026-08-19T11:04:55-0700
HOST: llmbits Loss% Snt Last Avg Best Wrst StDev
1.|-- 10.77.0.1 0.0% 5 3.1 3.1 3.1 3.3 0.1
2.|-- 10.77.12.2 0.0% 5 3.8 4.1 3.8 4.3 0.2
3.|-- 10.77.23.3 0.0% 5 5.2 5.1 4.8 5.5 0.3
4.|-- 10.77.3.10 0.0% 5 5.3 5.2 5.1 5.3 0.1
j@llmbits:~$ tracepath 10.77.3.10
1?: [LOCALHOST] pmtu 1500
1: 10.77.0.1 3.454ms
2: 10.77.12.2 4.903ms
3: 10.77.23.3 5.439ms
4: 10.77.3.10 5.823ms reached
Resume: pmtu 1500 hops 4 back 4 The ttl=61 in the ping replies is the quiet win here. The far end sent them at 64 and three routers decremented it, so the reply took three hops home, which matches the four lines traceroute printed (the fourth line is the destination itself, not a router). When a ping works but the TTL is not what you expect, traffic is not taking the path you think it is.
One caveat on traceroute -T: TCP mode needs raw sockets, so it needs root. Without it you get You do not have enough privileges to use this traceroute method and nothing else. TCP mode is the one that gets through firewalls which drop the default UDP high ports, so it is worth the sudo.
Sockets, listeners and who owns them
"Is the service up" is not a network question until you have checked whether anything is bound to the port, and on which address. Half the tickets that arrive as connectivity problems are a daemon listening on 127.0.0.1.
lsof -i :22 answers "what is holding this port" including the user, which is the question you have when a bind fails.j@llmbits:~$ sudo ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 0.0.0.0:5353 0.0.0.0:* users:(("avahi-daemon",pid=12165,fd=12))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1272,fd=6))
tcp LISTEN 0 4096 127.0.0.1:631 0.0.0.0:* users:(("cupsd",pid=10805,fd=7))
tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=1272,fd=7))
j@llmbits:~$ ss -s
Total: 253
TCP: 8 (estab 1, closed 3, orphaned 0, timewait 3)
Transport Total IP IPv6
RAW 1 0 1
UDP 5 3 2
TCP 5 3 2
INET 11 6 5
j@llmbits:~$ sudo lsof -i :22
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1272 root 6u IPv4 7039 0t0 TCP *:ssh (LISTEN)
sshd-sess 20562 root 7u IPv4 562942 0t0 TCP llmbits:ssh->192.168.88.125:61016 (ESTABLISHED)Compare lines two and three of the ss output. SSH is bound to 0.0.0.0, so it answers on every address the host owns. CUPS is bound to 127.0.0.1, so it answers on exactly one, and nothing arriving on the wire will reach it unless you deliberately relay or DNAT it there. That distinction, visible in one column, resolves an enormous share of "the port is not open" tickets before anyone opens a packet capture.
DNS from the client side
Three tools that do the same lookup and one file that decides where the lookup goes. The reason to know all four is that they disagree in useful ways: dig shows you the protocol, host and nslookup show you the answer, and /etc/resolv.conf shows you why the answer might be wrong.
@, see flags, TTLs, section counts and query time. +short when you only want the value.nsswitch.conf consults hosts and DNS. Query tools bypass this; your applications do not.j@llmbits:~$ dig @10.77.3.10 web1.pinglabz.lab +noall +answer +stats
web1.pinglabz.lab. 3600 IN A 10.77.2.10
;; Query time: 8 msec
;; SERVER: 10.77.3.10#53(10.77.3.10) (UDP)
;; WHEN: Wed Aug 19 11:05:26 PDT 2026
;; MSG SIZE rcvd: 79
j@llmbits:~$ host web1.pinglabz.lab 10.77.3.10
Using domain server:
Name: 10.77.3.10
Address: 10.77.3.10#53
web1.pinglabz.lab has address 10.77.2.10
web1.pinglabz.lab has IPv6 address 2001:db8:77:2::10
j@llmbits:~$ cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 45.90.28.181
nameserver 45.90.30.181That last block is the trap in miniature. The dig query above resolved web1.pinglabz.lab perfectly, because @10.77.3.10 sent it straight to the lab DNS server. But /etc/resolv.conf on this host points at a public resolver, so an application on the same box asking for the same name gets NXDOMAIN. Explicit server arguments are the reason "it resolves fine when I test it" and "the app cannot resolve it" are both true at once. When they disagree, test without the @.
For the offensive side of DNS (zone transfers, brute forcing, enumeration tooling) the DNS enumeration cluster covers dnsrecon, dnsenum, massdns and the rest.
Testing ports and moving data
Ping proves the host is alive. None of these commands care whether it is alive; they care whether a specific TCP port on it will complete a handshake and speak the protocol you expect. That is almost always the real question.
-I for headers, -w for a per-phase timing breakdown, --resolve to test a vhost before DNS moves.--spider for a check that touches nothing. Better than curl when you want a file tree, not a request.nc -zv host port. Also a listener, a file transfer and a way to hand-type a protocol when nothing else is installed.-D plus a SOCKS-aware client is a whole network in one command.j@llmbits:~$ curl -I http://10.77.2.10/
HTTP/1.1 200 OK
Server: nginx/1.29.8
Content-Type: text/html
Content-Length: 896
Connection: keep-alive
j@llmbits:~$ curl -o /dev/null -sS -w 'dns=%{time_namelookup} connect=%{time_connect} ttfb=%{time_starttransfer} total=%{time_total} code=%{http_code}\n' http://10.77.2.10/
dns=0.000052 connect=0.004158 ttfb=0.009251 total=0.009722 code=200
j@llmbits:~$ nc -zv -w 3 10.77.3.10 5201
Connection to 10.77.3.10 5201 port [tcp/*] succeeded!
j@llmbits:~$ nc -zv -w 3 10.77.3.10 5202
nc: connect to 10.77.3.10 port 5202 (tcp) failed: Connection refused
j@llmbits:~$ socat TCP-LISTEN:8080,reuseaddr,fork TCP:10.77.2.10:80 &
j@llmbits:~$ curl -sS -I http://127.0.0.1:8080/
HTTP/1.1 200 OK
Server: nginx/1.29.8
j@llmbits:~$ nmap -Pn -p 53,80,5201 10.77.3.10
Nmap scan report for 10.77.3.10
Host is up (0.0059s latency).
PORT STATE SERVICE
53/tcp open domain
80/tcp closed http
5201/tcp open targus-getdata1Two failures in that block and they mean different things. Connection refused from netcat and closed from nmap are the same event: the packet arrived, a host answered, and nothing was listening. That is a good failure, because it proves routing and firewalling worked all the way to the target. The bad failure is a timeout with no reply at all, which nmap calls filtered: something in the path swallowed the packet and nobody will tell you what.
The curl timing line is the other habit worth building. dns, connect and ttfb split one slow request into three measurable parts, and the gap between them tells you whether to blame the resolver, the network or the application. Here connect took 4 ms and the first byte arrived 5 ms later, which is a healthy server two routers away.
Watching the wire
Everything above asks a host what it thinks. These three ask the wire what actually happened, and the wire does not have opinions.
-T fields and protocol statistics from the terminal.j@llmbits:~$ sudo tcpdump -i ens224 -n -c 6 icmp
11:06:00.619681 IP 10.77.0.100 > 10.77.3.10: ICMP echo request, id 52, seq 1, length 64
11:06:00.625837 IP 10.77.3.10 > 10.77.0.100: ICMP echo reply, id 52, seq 1, length 64
11:06:01.621201 IP 10.77.0.100 > 10.77.3.10: ICMP echo request, id 52, seq 2, length 64
11:06:01.627580 IP 10.77.3.10 > 10.77.0.100: ICMP echo reply, id 52, seq 2, length 64
6 packets captured
6 packets received by filter
0 packets dropped by kernel
j@llmbits:~$ sudo tshark -i ens224 -n -c 6 -f 'tcp port 80'
1 0.000000000 10.77.0.100 -> 10.77.2.10 TCP 74 43666 > 80 [SYN] Seq=0 Win=64240 Len=0 MSS=1460
2 0.004204077 10.77.2.10 -> 10.77.0.100 TCP 74 80 > 43666 [SYN, ACK] Seq=0 Ack=1 Win=65160 Len=0
3 0.004299575 10.77.0.100 -> 10.77.2.10 TCP 66 43666 > 80 [ACK] Seq=1 Ack=1 Win=64256 Len=0
4 0.004511318 10.77.0.100 -> 10.77.2.10 HTTP 140 GET / HTTP/1.1
5 0.009044709 10.77.2.10 -> 10.77.0.100 TCP 66 80 > 43666 [ACK] Seq=1 Ack=75 Win=65536 Len=0
6 0.009873965 10.77.2.10 -> 10.77.0.100 HTTP 304 HTTP/1.1 200 OK
j@llmbits:~$ sudo ngrep -d ens224 -q -W byline 'GET' 'tcp port 80'
T 10.77.0.100:36384 -> 10.77.2.10:80 [AP] #4
GET / HTTP/1.1.
Host: 10.77.2.10.
User-Agent: curl/8.14.1.
Accept: */*.(The ngrep block is from a separate run against the same server, which is why its source port differs from the tshark flow.) The tshark capture is a complete HTTP transaction in six frames and it is worth being able to read at a glance: SYN, SYN-ACK, ACK, request, ack of the request, response. When a connection is failing, the frame that is missing names the problem. No SYN-ACK means nothing is listening or something dropped it. SYN-ACK then RST means a firewall killed the established flow. Request sent and nothing back means the application is thinking, and the network is done being the suspect.
One warning that costs people hours: NIC offloads mean the frames your capture sees are not always the frames on the cable. With generic receive offload on, the kernel can hand tcpdump a single "packet" of up to 64 KB that never existed as one Ethernet frame. If MSS or fragmentation is what you are investigating, turn the relevant offloads off with ethtool first and turn them back on when you are done.
Get the Linux Networking Field Reference - 10 pages, free
Every command in this cluster on ten printable pages: iproute2, sockets, DNS, capture, monitors and all three firewall front ends. Includes a ten-symptom troubleshooting decision tree and annotated real lab output. Free for PingLabz members, just sign up with your email.
Throughput and bandwidth
"The network is slow" needs a number before it needs an opinion. These tools produce numbers.
j@llmbits:~$ iperf3 -c 10.77.3.10 -t 5
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-5.00 sec 15.5 MBytes 26.0 Mbits/sec 45 sender
[ 5] 0.00-5.01 sec 15.4 MBytes 25.8 Mbits/sec receiver
j@llmbits:~$ vnstat -i ens224 --oneline
1;ens224;2026-08-19;68.06 MiB;1.91 GiB;1.98 GiB;426.00 kbit/s;2026-08;4.07 GiB;6.04 GiB;10.11 GiB;362.10 kbit/s
j@llmbits:~$ ifstat -i ens224 1 3
ens224
KB/s in KB/s out
0.00 0.00
0.00 0.00
0.00 0.00Read the Retr column before the bitrate. Forty-five retransmits in five seconds is the interesting number in that test, not 26 Mbits/sec, and it says the path is dropping packets under load. (The absolute figure here is a property of software-forwarded lab routers, not a claim about anything real. Treat lab throughput as a comparison against itself, never as a benchmark.)
Firewalling and what is blocked
Three layers of the same thing. ufw generates iptables syntax, iptables syntax is translated into nftables rules, and nftables is the engine in the kernel. Which one you use depends on the host; which one you can read determines whether you can debug it.
ip_forward = 0 and nothing more.j@llmbits:~$ sudo iptables -L INPUT -n -v
Chain INPUT (policy ACCEPT 909K packets, 80M bytes)
pkts bytes target prot opt in out source destination
5 420 DROP icmp -- ens224 * 10.77.3.10 0.0.0.0/0 icmptype 0
j@llmbits:~$ sudo nft list ruleset
table ip filter {
chain INPUT {
type filter hook input priority filter; policy accept;
}
chain FORWARD {
type filter hook forward priority filter; policy accept;
}
}
j@llmbits:~$ sysctl net.ipv4.ip_forward net.ipv4.tcp_congestion_control net.core.rmem_max
net.ipv4.ip_forward = 0
net.ipv4.tcp_congestion_control = cubic
net.core.rmem_max = 212992Two of those blocks come from different sessions on the same host: the iptables rule was captured during the firewall work, and the nft list ruleset above it is the clean state afterwards, which is why the nft output carries no rules. That iptables rule drops echo replies arriving from 10.77.3.10, not echo requests, and the effect is a ping that reports 100% loss while the far end sees every request and answers every one. Five packets, 420 bytes, counted. When a symptom does not match a rule you are reading, read the direction and the icmptype again before you blame the network.
The triage order
Commands are easy. Knowing which one to run second is the skill. This is the order that resolves the most incidents in the fewest steps, and every step narrows the problem instead of confirming what you already know.
ip -br addr then ip route get <dest>. Answers "will this packet leave the box, and out of which interface."ping <gateway> then ip neigh. A FAILED neighbor entry is a layer 2 problem and nothing above it will work.traceroute for the path, mtr if it works sometimes. Intermittent is a different bug from broken and needs the continuous view.host <name> with no server argument, then dig @<server>. If those two disagree, the resolver config is the bug.sudo ss -tulpn. Check the bind address, not just the port. From the client: nc -zv host port.sudo iptables -L -n -v or sudo nft list ruleset, and read the counters. Refused is a good failure; silence is the suspicious one.sudo tcpdump -i <iface> -n host <peer> on both ends at once. Whichever side stops seeing packets is the side of the break.Step seven is the one people skip and should not. Capturing on both ends simultaneously converts an argument into a fact in about thirty seconds, because packets either arrived or they did not.
The other side of the same link
One habit separates engineers who fix Linux networking quickly from those who guess: checking whether the router agrees with the host. Every fact the Debian box reported above has a matching fact on R1, and they line up.
R1#show ip arp | include 10.77.0
Internet 10.77.0.1 - aabb.cc00.0400 ARPA Ethernet0/0
Internet 10.77.0.100 2 000c.29b1.cc47 ARPA Ethernet0/0
R1#show ip route ospf
10.0.0.0/8 is variably subnetted, 7 subnets, 2 masks
O 10.77.2.0/24 [110/20] via 10.77.12.2, 00:04:59, Ethernet0/1
O 10.77.3.0/24 [110/30] via 10.77.12.2, 00:04:48, Ethernet0/1
O 10.77.23.0/24 [110/20] via 10.77.12.2, 00:04:52, Ethernet0/1
R1#show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
2.2.2.2 1 FULL/DR 00:00:35 10.77.12.2 Ethernet0/1The MAC in R1's ARP table (000c.29b1.cc47) is the same MAC ip addr show ens224 printed at the top of this article, in Cisco's dotted format rather than colons. The router learned the host, the host learned the router, and the routes to 10.77.2.0/24 and 10.77.3.0/24 are why the Linux side needed only one static route for the whole 10.77.0.0/16. When a Linux host cannot reach something, checking the router's ARP table for the host's MAC tells you instantly whether the problem is before or after the first hop.
FAQ
Which Linux networking commands should I learn first?
Five, in this order: ip addr, ip route, ss -tulpn, ping and tcpdump. Those five answer "what am I," "where do I send," "who is listening," "can I reach it" and "what really happened." Everything else in this reference is a sharper version of one of those questions.
Is ifconfig actually deprecated?
Yes. Debian and Red Hat deprecated net-tools in favor of iproute2 well over a decade ago, and it has been in maintenance-only mode since. It still works for a quick look at one interface, but it cannot correctly display multiple addresses on an interface, it truncates modern interface names, and it knows nothing about network namespaces or policy routing. Learn ip, and keep ifconfig for reading other people's runbooks. The full mapping is in net-tools to iproute2.
Why do my ip commands disappear after a reboot?
Because ip writes to the running kernel, not to configuration. On a NetworkManager host use nmcli, on a systemd-networkd host edit the .network file, and on a Debian host still using ifupdown edit /etc/network/interfaces. ip is for testing a change; the config layer is for keeping it.
Do I need root for all of this?
Less than you would think. Reading addresses, routes, neighbors, sockets and DNS all work as a normal user. Root is needed for packet capture, for TCP traceroute, for firewall commands, and to see the process column in ss -tulpn. If you are troubleshooting with sudo everywhere, you are borrowing risk you do not need.
What is the Linux equivalent of show ip route?
ip route, and the closer analog is ip route get 10.77.3.10, which asks the kernel for the exact decision it would make rather than making you scan the table. The concepts port directly: connected routes, static routes, longest prefix match and metrics all behave the way they do on IOS. What Linux adds is multiple routing tables selected by ip rule, which is closer to VRF and policy based routing than to a plain routing table.
Can I use these tools on containers and Kubernetes nodes?
Yes, and you should, though the interesting state lives in network namespaces. nsenter -t <pid> -n ss -tulpn runs any of these commands inside a container's namespace. Note that ip netns list usually comes back empty on a container host, because Docker and containerd do not bind-mount their namespaces into /var/run/netns. Use lsns -t net to find them instead. A pod that cannot reach a service is nearly always diagnosed with the same seven steps above, just executed one namespace to the left.
Key takeaways
- Five commands cover most incidents:
ip addr,ip route,ss -tulpn,pingandtcpdump. Learn those properly before collecting more tools. ipchanges the running kernel; NetworkManager, systemd-networkd or ifupdown change the configuration. Only one of them survives a reboot.- The bind address in
ss -tulpnmatters as much as the port. A service on 127.0.0.1 is unreachable no matter what the firewall says. - Connection refused and
closedare good failures, because they prove the packet reached a live host. Timeouts andfilteredare the ones that hide a dropping device. - Test names with and without an explicit server.
dig @serverbypasses/etc/resolv.conf, so it can succeed on a host where every application fails. - Read
Retrin iperf3 and the packet counters iniptables -L -n -vbefore you read anything else in those outputs. - The TTL in a ping reply counts the return hops, and it is free path information most people never look at.
- NIC offloads mean a capture is not always the wire. Disable the relevant offloads with ethtool when MTU or segmentation is the question.
- Capture on both ends at the same time. The side that stops seeing packets locates the break with no argument required.
- Check the router's ARP table and routing table too. The host and the network telling you different stories is itself the diagnosis.
Every command on this page has a full article behind it, and all of them are indexed in reading order in the complete guide to Linux networking commands. If you work across both worlds, the same troubleshooting logic in Cisco syntax lives in the ping cluster, the iPerf cluster and the Nmap cluster, and the scripted version of all of it is in network automation.