ZetCode

Linux ping and traceroute Commands

last modified October 23, 2026

The ping command checks whether a host is reachable and measures the round-trip time to it. The traceroute command shows the routers that packets pass on the way to a host. Together they are the first tools to reach for when a network connection is slow or does not work at all.

ping sends ICMP echo request packets and waits for echo reply packets. traceroute sends probes with an increasing time-to-live (TTL) value and collects the ICMP time exceeded messages that routers send back when the TTL runs out.

The examples were run on Debian 12 with iputils 20221126 (ping and tracepath), traceroute 2.1.2, and mtr 0.95. Except for the first example, they use a small lab network: the client machine reaches the 10.10.3.0/24 network through two routers, r1 and r2. The link behind r1 adds about 5 ms of delay, the link behind r2 about 12 ms. On the far network, server is an ordinary host, web is a web server whose firewall blocks ping and UDP, and flaky loses a quarter of its packets.

client 10.10.1.10
  |
r1     10.10.1.1 / 10.10.2.1
  |    (5 ms)
r2     10.10.2.2 / 10.10.3.1
  |    (12 ms, MTU 1400)
server 10.10.3.10    web 10.10.3.20    flaky 10.10.3.30

Pinging a host on the Internet

In its simplest form, ping takes a host name or an IP address.

ping -c 4 example.com

The -c 4 option sends four echo requests and stops. Each reply line shows the size of the reply, the sender, the sequence number icmp_seq, the TTL of the reply, and the round-trip time. The summary shows how many packets were lost and the minimum, average, and maximum round-trip times; mdev is the mean deviation, a measure of jitter. The round-trip times on a home connection to the Internet vary considerably, as the output shows.

$ ping -c 4 example.com
PING example.com (104.20.23.154) 56(84) bytes of data.
64 bytes from 104.20.23.154 (104.20.23.154): icmp_seq=1 ttl=59 time=4.55 ms
64 bytes from 104.20.23.154 (104.20.23.154): icmp_seq=2 ttl=59 time=10.9 ms
64 bytes from 104.20.23.154 (104.20.23.154): icmp_seq=3 ttl=59 time=35.5 ms
64 bytes from 104.20.23.154 (104.20.23.154): icmp_seq=4 ttl=59 time=4.22 ms

--- example.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 4.223/13.790/35.518/12.820 ms

Pinging a host in the lab

The same command against the server in the lab network.

ping -c 4 server

The round-trip time of about 17 ms is the sum of the delays on the path there and back. The TTL of the reply is 62: Linux sends packets with a TTL of 64, and each of the two routers decreased it by one. The TTL in the reply therefore hints at how many hops away a host is, as long as we know the initial value of its operating system (64 for Linux and macOS, 128 for Windows, 255 for many network devices).

$ ping -c 4 server
PING server (10.10.3.10) 56(84) bytes of data.
64 bytes from server (10.10.3.10): icmp_seq=1 ttl=62 time=18.7 ms
64 bytes from server (10.10.3.10): icmp_seq=2 ttl=62 time=16.5 ms
64 bytes from server (10.10.3.10): icmp_seq=3 ttl=62 time=17.4 ms
64 bytes from server (10.10.3.10): icmp_seq=4 ttl=62 time=17.8 ms

--- server ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 16.518/17.585/18.694/0.783 ms

Stopping ping with Ctrl+C

Without -c, Linux ping runs until it is interrupted.

ping server
echo $?

We pressed Ctrl+C after three replies; ^C marks the place. ping catches the signal, prints the statistics, and exits with status 0, because it received replies. On Windows, ping stops after four packets by default; on Linux, use -c in scripts, or it never finishes.

$ ping server
PING server (10.10.3.10) 56(84) bytes of data.
64 bytes from server (10.10.3.10): icmp_seq=1 ttl=62 time=18.0 ms
64 bytes from server (10.10.3.10): icmp_seq=2 ttl=62 time=16.8 ms
64 bytes from server (10.10.3.10): icmp_seq=3 ttl=62 time=16.9 ms
^C
--- server ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 16.832/17.229/17.961/0.518 ms
$ echo $?
0

Names and numeric output

ping resolves the host name to an address and, for every reply, the address back to a name.

cat /etc/hosts | grep 10.10
ping -c 2 10.10.3.10
ping -n -c 2 server

The lab names are defined in /etc/hosts. When we give a numeric address, ping does not look up names at all. The -n option prints numeric addresses even when a name was given. Use it when the reverse lookups are slow, which happens when DNS is broken, the very situation in which ping is usually needed.

$ cat /etc/hosts | grep 10.10
10.10.1.1	r1
10.10.2.2	r2
10.10.3.10	server
10.10.3.20	web
10.10.3.30	flaky
10.10.1.10	client
$ ping -c 2 10.10.3.10
PING 10.10.3.10 (10.10.3.10) 56(84) bytes of data.
64 bytes from 10.10.3.10: icmp_seq=1 ttl=62 time=18.2 ms
64 bytes from 10.10.3.10: icmp_seq=2 ttl=62 time=16.2 ms

--- 10.10.3.10 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 16.239/17.214/18.190/0.975 ms
$ ping -n -c 2 server
PING server (10.10.3.10) 56(84) bytes of data.
64 bytes from 10.10.3.10: icmp_seq=1 ttl=62 time=16.2 ms
64 bytes from 10.10.3.10: icmp_seq=2 ttl=62 time=16.1 ms

--- server ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1003ms
rtt min/avg/max/mdev = 16.139/16.150/16.162/0.011 ms

Interval and quiet output

By default, ping sends one packet per second. The -i option sets a different interval in seconds.

ping -c 5 -i 0.2 -q server
ping -c 5 -i 0.001 server

Five packets with an interval of 0.2 seconds take 0.8 seconds. The -q option (quiet) prints only the first line and the summary. Ordinary users cannot send faster than once every 2 ms; smaller intervals are only allowed for root.

$ ping -c 5 -i 0.2 -q server
PING server (10.10.3.10) 56(84) bytes of data.

--- server ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 803ms
rtt min/avg/max/mdev = 15.088/17.232/19.354/1.600 ms
$ ping -c 5 -i 0.001 server
PING server (10.10.3.10) 56(84) bytes of data.
ping: cannot flood; minimal interval allowed for user is 2ms

Packet size

The -s option sets the number of data bytes in each echo request. The default is 56.

ping -c 2 -s 1000 server
ping -c 2 -s 0 server

The first line shows two sizes: 1000 data bytes, and 1028 bytes of the whole IP packet, which adds an 8-byte ICMP header and a 20-byte IP header. The replies show 1008 bytes, the ICMP part. With fewer than 16 data bytes, there is no room for the timestamp that ping puts into each packet, so no round-trip times are shown.

$ ping -c 2 -s 1000 server
PING server (10.10.3.10) 1000(1028) bytes of data.
1008 bytes from server (10.10.3.10): icmp_seq=1 ttl=62 time=18.7 ms
1008 bytes from server (10.10.3.10): icmp_seq=2 ttl=62 time=16.2 ms

--- server ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 16.241/17.495/18.749/1.254 ms
$ ping -c 2 -s 0 server
PING server (10.10.3.10) 0(28) bytes of data.
8 bytes from server (10.10.3.10): icmp_seq=1 ttl=62
8 bytes from server (10.10.3.10): icmp_seq=2 ttl=62

--- server ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms

Deadline and timeout

Two options limit how long ping runs. -w is a deadline for the whole command, -W the time to wait for each reply.

time ping -w 3 server
time ping -c 2 -W 1 web

With -w 3, ping stops after three seconds regardless of the number of packets. The web host drops echo requests silently, so there are no replies at all, just 100% packet loss. With -W 1, ping waits only one second for the last reply instead of the default ten seconds.

$ time ping -w 3 server
PING server (10.10.3.10) 56(84) bytes of data.
64 bytes from server (10.10.3.10): icmp_seq=1 ttl=62 time=16.2 ms
64 bytes from server (10.10.3.10): icmp_seq=2 ttl=62 time=19.3 ms
64 bytes from server (10.10.3.10): icmp_seq=3 ttl=62 time=17.9 ms

--- server ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 16.243/17.827/19.335/1.263 ms

real	0m3.003s
user	0m0.000s
sys	0m0.004s
$ time ping -c 2 -W 1 web
PING web (10.10.3.20) 56(84) bytes of data.

--- web ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1004ms


real	0m2.007s
user	0m0.001s
sys	0m0.002s

Error messages

Not every failure is silent. Routers report problems with ICMP error messages, which ping prints.

ping -c 2 10.10.3.99
ping -c 1 192.0.2.1
ping -c 1 nosuchhost

No host has the address 10.10.3.99; the last router, r2, tries to find it with ARP, gives up, and sends Destination Host Unreachable. The address 192.0.2.1 is outside any network that the routers know about; r2 has a route of type unreachable for it and reports the same error. The +2 errors in the statistics counts these messages. The last command fails before sending anything, because the name cannot be resolved.

$ ping -c 2 10.10.3.99
PING 10.10.3.99 (10.10.3.99) 56(84) bytes of data.
From 10.10.2.2 icmp_seq=1 Destination Host Unreachable
From 10.10.2.2 icmp_seq=2 Destination Host Unreachable

--- 10.10.3.99 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1046ms
pipe 2
$ ping -c 1 192.0.2.1
PING 192.0.2.1 (192.0.2.1) 56(84) bytes of data.
From 10.10.2.2 icmp_seq=1 Destination Host Unreachable

--- 192.0.2.1 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

$ ping -c 1 nosuchhost
ping: nosuchhost: Temporary failure in name resolution

Exit status

ping reports the result in its exit status: 0 when at least one reply arrived, 1 when no reply arrived, and 2 for other errors.

ping -c 1 -W 1 server > /dev/null; echo $?
ping -c 1 -W 1 web > /dev/null; echo $?
ping -c 1 -W 1 nosuchhost > /dev/null; echo $?

The error about the unknown name goes to standard error, so it is shown despite the redirection. The exit status makes ping easy to use in scripts.

$ ping -c 1 -W 1 server > /dev/null; echo $?
0
$ ping -c 1 -W 1 web > /dev/null; echo $?
1
$ ping -c 1 -W 1 nosuchhost > /dev/null; echo $?
ping: nosuchhost: Temporary failure in name resolution
2

Checking hosts in a script

The following script checks a list of hosts.

cat check-hosts.sh
bash check-hosts.sh

Each host gets one packet and one second to answer. The script reports web as not responding, although the web server on it runs fine: its firewall only blocks ping. A failed ping does not prove that a host is down, and a successful ping does not prove that a service works; see the section about firewalls below.

$ cat check-hosts.sh
#!/bin/bash

for host in r1 r2 server web flaky; do
    if ping -c 1 -W 1 "$host" > /dev/null 2>&1; then
        echo "$host is up"
    else
        echo "$host is not responding"
    fi
done
$ bash check-hosts.sh
r1 is up
r2 is up
server is up
web is not responding
flaky is up

Time to live

The -t option sets the TTL of the outgoing packets. Every router decreases the TTL by one and discards the packet when it reaches zero, sending a Time to live exceeded message back.

ping -c 1 -t 1 server
ping -c 1 -t 2 server
ping -c 1 -t 3 server

With a TTL of 1, the packet dies at the first router, r1. With 2, it dies at r2. With 3, it reaches the server. This is exactly how traceroute discovers the path: it sends packets with TTL 1, 2, 3, and so on, and records who reports the expired TTL.

$ ping -c 1 -t 1 server
PING server (10.10.3.10) 56(84) bytes of data.
From r1 (10.10.1.1) icmp_seq=1 Time to live exceeded

--- server ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

$ ping -c 1 -t 2 server
PING server (10.10.3.10) 56(84) bytes of data.
From r2 (10.10.2.2) icmp_seq=1 Time to live exceeded

--- server ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

$ ping -c 1 -t 3 server
PING server (10.10.3.10) 56(84) bytes of data.
64 bytes from server (10.10.3.10): icmp_seq=1 ttl=62 time=19.2 ms

--- server ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 19.224/19.224/19.224/0.000 ms

Packet loss

Packet loss is best measured with more packets. The flaky host drops a quarter of its outgoing packets.

ping -c 20 -q flaky

Of 20 packets, 14 came back, so the measured loss is 30%. Losses are random, so a small sample only gives a rough estimate of the real rate. A few lost packets on a busy network are normal; consistent loss of several percent causes noticeable problems, especially for TCP throughput, voice, and video.

$ ping -c 20 -q flaky
PING flaky (10.10.3.30) 56(84) bytes of data.

--- flaky ping statistics ---
20 packets transmitted, 14 received, 30% packet loss, time 19158ms
rtt min/avg/max/mdev = 14.629/16.991/19.414/1.333 ms

Timestamps and missing replies

The -D option prefixes each line with a Unix timestamp, which is useful when ping runs for a long time and its output is logged. The -O option reports requests that got no reply before the next one is sent.

ping -c 3 -D server
ping -c 6 -O -i 0.5 flaky

Without -O, a lost packet only shows up as a gap in the icmp_seq numbers. With it, ping prints no answer yet for icmp_seq=4. The timestamps can be converted with date -d @1792783736.

$ ping -c 3 -D server
PING server (10.10.3.10) 56(84) bytes of data.
[1792784494.845978] 64 bytes from server (10.10.3.10): icmp_seq=1 ttl=62 time=17.3 ms
[1792784495.848863] 64 bytes from server (10.10.3.10): icmp_seq=2 ttl=62 time=19.2 ms
[1792784496.849858] 64 bytes from server (10.10.3.10): icmp_seq=3 ttl=62 time=19.3 ms

--- server ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 17.316/18.599/19.270/0.907 ms
$ ping -c 6 -O -i 0.5 flaky
PING flaky (10.10.3.30) 56(84) bytes of data.
64 bytes from flaky (10.10.3.30): icmp_seq=1 ttl=62 time=16.2 ms
64 bytes from flaky (10.10.3.30): icmp_seq=2 ttl=62 time=18.7 ms
64 bytes from flaky (10.10.3.30): icmp_seq=3 ttl=62 time=16.6 ms
no answer yet for icmp_seq=4
64 bytes from flaky (10.10.3.30): icmp_seq=5 ttl=62 time=16.7 ms
64 bytes from flaky (10.10.3.30): icmp_seq=6 ttl=62 time=18.5 ms

--- flaky ping statistics ---
6 packets transmitted, 5 received, 16.6667% packet loss, time 2509ms
rtt min/avg/max/mdev = 16.245/17.359/18.746/1.036 ms

Finding the path MTU

The maximum transmission unit (MTU) is the largest packet a link can carry. The link between r2 and the server has an MTU of 1400 bytes, while the other links have the usual 1500. The -M do option sets the Don't Fragment flag, so routers must not split the packet.

ping -c 2 -M do -s 1472 server
ping -c 2 -M do -s 1372 server

1472 data bytes plus 28 bytes of headers make a 1500-byte packet. r2 cannot forward it and reports Frag needed and DF set with the MTU of the next link. The kernel remembers the path MTU for the destination, so the second packet is refused locally with message too long. With 1372 data bytes, the packet has 1400 bytes and passes. Path MTU problems typically show up as connections that establish but hang on larger transfers, for example with VPNs and tunnels.

$ ping -c 2 -M do -s 1472 server
PING server (10.10.3.10) 1472(1500) bytes of data.
From r2 (10.10.2.2) icmp_seq=1 Frag needed and DF set (mtu = 1400)
ping: local error: message too long, mtu=1400

--- server ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1001ms

$ ping -c 2 -M do -s 1372 server
PING server (10.10.3.10) 1372(1400) bytes of data.
1380 bytes from server (10.10.3.10): icmp_seq=1 ttl=62 time=16.7 ms
1380 bytes from server (10.10.3.10): icmp_seq=2 ttl=62 time=18.0 ms

--- server ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 16.651/17.314/17.977/0.663 ms

Flood ping

The -f option sends packets as fast as replies come back, or 100 times per second, whichever is more. It is restricted to root.

ping -f -c 200 server
sudo ping -f -c 200 server

For every request, ping prints a dot, and for every reply, it removes one, so the number of dots shows how many requests are outstanding. The summary adds ipg, the inter-packet gap, and ewma, a moving average of the round-trip time. A flood ping is a load test; use it only on networks you are responsible for.

$ ping -f -c 200 server
PING server (10.10.3.10) 56(84) bytes of data.
ping: cannot flood; minimal interval allowed for user is 2ms
$ sudo ping -f -c 200 server
PING server (10.10.3.10) 56(84) bytes of data.
..  .. . . . . . . . . . . . . . . . . . . . . . . . . . .  .. . . . . . . . . . . . . .  .. . . . . . .  ..  .. . . . . . . . . . . .  .. . . . . . . . . . . . . . . .  ..  ..  ..  ..  ..  ..  .. . . . . . . . . . . . .  .. . .  .. . . . . . . . . . . . . . . . .  ..  ..  ..  .. . . . . . . . . . . . .  ..  .. . . . . . . . . . . . . . . . . . . . . .  ..  .. . . . .  .. . . . . . . . . . . . .  
--- server ping statistics ---
200 packets transmitted, 200 received, 0% packet loss, time 2790ms
rtt min/avg/max/mdev = 14.647/17.296/19.782/1.241 ms, pipe 2, ipg/ewma 14.021/17.402 ms

IPv6

The ping from iputils handles both IPv4 and IPv6. The -4 and -6 options force one of them when a name has both kinds of addresses.

ping -c 2 ::1
ping -6 -c 1 localhost

::1 is the IPv6 loopback address. Older systems have a separate ping6 command for IPv6; on current distributions, it is a link to ping or is missing.

$ ping -c 2 ::1
PING ::1(::1) 56 data bytes
64 bytes from ::1: icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from ::1: icmp_seq=2 ttl=64 time=0.044 ms

--- ::1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1051ms
rtt min/avg/max/mdev = 0.041/0.042/0.044/0.001 ms
$ ping -6 -c 1 localhost
PING localhost(localhost (::1)) 56 data bytes
64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.029 ms

--- localhost ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.029/0.029/0.029/0.000 ms

Tracing the route

The traceroute command shows every router on the path to a host.

traceroute server

Each line is a hop: the router that sent back the time exceeded message, and the round-trip times of three probes. By default, traceroute on Linux sends UDP packets to high ports, starting at 33434. The final host answers with port unreachable, which tells traceroute that the destination is reached.

$ traceroute server
traceroute to server (10.10.3.10), 30 hops max, 60 byte packets
 1  r1 (10.10.1.1)  0.069 ms  0.017 ms  0.014 ms
 2  r2 (10.10.2.2)  5.502 ms  4.327 ms  5.263 ms
 3  server (10.10.3.10)  15.748 ms  16.764 ms  17.413 ms

Traceroute options

The -n option disables name lookups, -q sets the number of probes per hop, and -m the maximum number of hops.

traceroute -n -q 1 server
traceroute -m 2 server

With -m 2, the trace stops after the second hop. The asterisks in its output are probes without an answer. They are not lost packets: traceroute sends up to 16 probes at once, and the Linux kernel limits how many ICMP error messages it sends per second, so the routers did not answer every probe. Rate limiting like this is common on the Internet, on routers and hosts alike. The -N option lowers the number of simultaneous probes.

$ traceroute -n -q 1 server
traceroute to server (10.10.3.10), 30 hops max, 60 byte packets
 1  10.10.1.1  0.048 ms
 2  10.10.2.2  5.712 ms
 3  10.10.3.10  15.964 ms
$ traceroute -m 2 server
traceroute to server (10.10.3.10), 2 hops max, 60 byte packets
 1  r1 (10.10.1.1)  0.052 ms  0.016 ms *
 2  r2 (10.10.2.2)  5.501 ms  4.658 ms *

Firewalls and probe types

Many hosts and firewalls drop UDP probes and pings. The -I option makes traceroute use ICMP echo requests, like ping, and -T uses TCP SYN packets to a given port. Both need root privileges.

traceroute -m 6 web
sudo traceroute -I -m 6 web
sudo traceroute -T -p 80 web
nc -zv web 80

The firewall of web drops UDP and echo requests, so the default trace and the ICMP trace end with lines of asterisks after the second router. This looks like a network problem behind r2, but it is not. A TCP probe to port 80, which the firewall allows, reaches the host. To check a service, test the service itself; here, nc -zv confirms that the web server accepts connections.

$ traceroute -m 6 web
traceroute to web (10.10.3.20), 6 hops max, 60 byte packets
 1  * * *
 2  * * *
 3  * * *
 4  * * *
 5  * * *
 6  * * *
$ sudo traceroute -I -m 6 web
traceroute to web (10.10.3.20), 6 hops max, 60 byte packets
 1  r1 (10.10.1.1)  0.227 ms  0.777 ms  0.787 ms
 2  r2 (10.10.2.2)  5.685 ms  4.783 ms  5.684 ms
 3  * * *
 4  * * *
 5  * * *
 6  * * *
$ sudo traceroute -T -p 80 web
traceroute to web (10.10.3.20), 30 hops max, 60 byte packets
 1  r1 (10.10.1.1)  0.049 ms  0.009 ms  0.007 ms
 2  r2 (10.10.2.2)  4.601 ms  4.446 ms  4.463 ms
 3  web (10.10.3.20)  16.155 ms  15.310 ms  17.852 ms
$ nc -zv web 80
Connection to web (10.10.3.20) 80 port [tcp/http] succeeded!

The tracepath command

The tracepath command from iputils traces the route without root privileges and also discovers the path MTU.

tracepath server
tracepath -n -b server

The first line shows the MTU of the local interface, 1500 bytes. At hop 3, r2 reports that the next link only carries 1400 bytes, and tracepath continues with smaller probes; the Resume line shows the MTU of the whole path. The kernel remembers the discovered path MTU, so the second run starts with 1400 right away. -n prints addresses and -b both names and addresses.

$ tracepath server
 1?: [LOCALHOST]                      pmtu 1500
 1:  r1                                                    0.051ms
 1:  r1                                                    0.018ms
 2:  r2                                                    5.029ms
 3:  r2                                                    4.457ms pmtu 1400
 3:  server                                               17.037ms reached
     Resume: pmtu 1400 hops 3 back 3
$ tracepath -n -b server
 1?: [LOCALHOST]                      pmtu 1400
 1:  10.10.1.1 (r1)                                        0.044ms
 1:  10.10.1.1 (r1)                                        0.076ms
 2:  10.10.2.2 (r2)                                        4.593ms
 3:  10.10.3.10 (server)                                  17.834ms reached
     Resume: pmtu 1400 hops 3 back 3

The mtr command

The mtr command combines traceroute and ping: it traces the path and then keeps sending probes to all hops, collecting statistics. Run without options, it shows a live, full-screen view; the --report (-r) option runs a fixed number of cycles and prints a table.

mtr --report -c 10 server
mtr -r -n -c 20 flaky

The first report shows 20% loss at r1 but none at the hops after it. Packets that reached the server passed through r1, so the loss is not real; the router only limited its ICMP replies. Loss matters only when it continues to the final hop, as in the second report, where flaky loses 20% of the packets while the routers before it lose none. This is the most common mistake when reading mtr and traceroute output.

$ mtr --report -c 10 server
Start: 2026-10-23T21:41:59+0200
HOST: client                      Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- r1                        20.0%    10    0.1   0.1   0.0   0.1   0.0
  2.|-- r2                         0.0%    10    5.0   5.5   4.8   6.2   0.5
  3.|-- server                     0.0%    10   15.1  16.8  14.8  18.9   1.5
$ mtr -r -n -c 20 flaky
Start: 2026-10-23T21:42:14+0200
HOST: client                      Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 10.10.1.1                  0.0%    20    0.1   0.1   0.0   0.1   0.0
  2.|-- 10.10.2.2                  0.0%    20    4.6   5.4   4.2   6.2   0.7
  3.|-- 10.10.3.30                20.0%    20   18.5  18.0  16.5  19.6   0.9

Unreachable networks in traceroute

When a router reports an error, traceroute marks the probe with an annotation after the time.

traceroute -n 192.0.2.1

!H means host unreachable. Other annotations are !N (network unreachable), !P (protocol unreachable), and !X (communication administratively prohibited, typically a firewall that rejects the packet). The trace stops at the router that reported the error.

$ traceroute -n 192.0.2.1
traceroute to 192.0.2.1 (192.0.2.1), 30 hops max, 60 byte packets
 1  10.10.1.1  0.465 ms  0.377 ms  0.349 ms
 2  10.10.2.2  4.282 ms !H  4.196 ms !H *

Troubleshooting with ping and traceroute

A common order of checks when a host cannot be reached:

  1. Ping the default gateway; if it does not answer, the problem is local (cable, Wi-Fi, address configuration). See the ip command.
  2. Ping a well-known IP address; if this works but names do not, the problem is DNS.
  3. Ping the target by name and by address.
  4. Trace the route to see where packets stop. Asterisks at the end may mean a firewall rather than a broken network; try -T with the port of the service.
  5. Test the service itself, for example with nc -zv or curl.

Source

ping(8) manual page, traceroute(8) manual page

In this article, we have used ping to check reachability, measure round-trip times, packet loss, and the path MTU, and traceroute, tracepath, and mtr to follow the path to a host, and we have seen how firewalls and ICMP rate limiting affect their output. See also the ss command article.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Linux tutorials.