Ping – setting don't fragment bit in Linux/Windows/FreeBSD/Solaris/Cisco/Juniper


Ping.
Many times while debugging network problems of various kinds you need to send some packets of desirable size  and don’t fragment bit being set. I list below how to do it for the different equipment/OSes. Let’s start with the  most popular operating system among network folks – Linux:

Linux

By default ping in any Linux-based system (It also means any distribution – Slackware, Ubuntu, CentOS etc) is sent with Don’t fragment (df) bit set . You don’t need to add any command line switches for that. Here is what you get by default ping in Linux:
Defaults:
Don’t fragment bit  (in echo request)  - set
Ip packet size – 84 bytes
Sending interval  - 1 second

Some examples.
- sending station:

[root@lonestar ~]# ping 191.91.21.41

-   receiving station:
[root@darkstar ~]#tcpdump -s 1500 -n -vv icmp

21:23:51.598641 IP (tos 0x0, ttl  61, id 20, offset 0, flags [DF], proto: ICMP (1), length: 84) 112.225.125.100 > 10.99.99.150: ICMP echo request, id 5392, seq 20, length 64
21:23:51.598817 IP (tos 0x0, ttl  64, id 7135, offset 0, flags [none], proto: ICMP (1), length: 84) 10.99.99.150 > 112.225.125.100: ICMP echo reply, id 5392, seq 20, length 64

To change sent packet size: -s  , bytes (8 bytes of ICMP header will be added automatically).

Sending host:
[root@darkstar ~]#ping 10.99.99.158 -s 1300

PING 10.99.99.158 (10.99.99.158) 1300(1328) bytes of data.
1308 bytes from 10.99.99.158: icmp_seq=1 ttl=64 time=1.65 ms

Receiving host:
freeBSD#tcpdump -n -v -s 1500 icmp

16:15:11.901787 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 1328) 10.99.99.150 > 10.99.99.158: ICMP echo request, id 44399, seq 63, length 1308

To change sending interval (mostly used together with large packet size) :
-i 

Sending host:
[root@darkstar ~]#ping -s 1300 -i 0.2 10.99.99.158

Receiving host:
freeBSD#tcpdump -n -v -s 1500 icmp

16:20:11.223481 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 1328) 10.99.99.150 > 10.99.99.158: ICMP echo request, id 1136, seq 396, length 1308
16:20:11.223496 IP (tos 0x0, ttl 64, id 805, offset 0, flags [DF], proto ICMP (1), length 1328) 10.99.99.158 > 10.99.99.150: ICMP echo reply, id 1136, seq 396, length 1308

To force Linux to send pings with DF bit cleared (i.e. not set):
ping –M don’t

Sending host:

[root@darkstar ~]#ping -s 1300 -M dont  10.99.99.158

PING 10.99.99.158 (10.99.99.158) 1300(1328) bytes of data.
1308 bytes from 10.99.99.158: icmp_seq=1 ttl=64 time=0.560 ms

Receiving host:

freeBSD#tcpdump -n -v -s 1500 icmp

16:28:33.111903 IP (tos 0x0, ttl 64, id 41857, offset 0, flags [none], proto ICMP (1), length 1328) 10.99.99.150 > 10.99.99.158: ICMP echo request, id 33136, seq 6, length 1308
16:28:33.111920 IP (tos 0x0, ttl 64, id 9425, offset 0, flags [none], proto ICMP (1), length 1328) 10.99.99.158 > 10.99.99.150: ICMP echo reply, id 33136, seq 6, length 1308

SideNote: FreeBSD ping has a nice add-on (see below) – sweeping size of the packets, while Linux doesn’t have such extra feature, Below is script to emulate it on Linux:

awk  ' BEGIN  {for (size=100;size<1470;size++)  {
cmd = ("ping –c 3 –I 0.5 –s  " size  "  "  "10.99.99.158")
print cmd | "/bin/bash"
close("/bin/bash")  } } '

Here:
size – size of data in ICMP packet (bytes);
-I 0.5 – interval of 5 seconds (optional);
-c 3 - number of pings in each size session (NOT optional – or you will enter an endless loop which even Ctrl-C won’t be able to stop )

See it in action:
[root@darkstar ~]#awk ' BEGIN  {for (size=100;size<1470;size++)  { cmd = ("ping -c 3 -i 0.5 -s  " size  "  "  "10.99.99.158") print cmd | "/bin/bash" close("/bin/bash")  } } '

PING 10.99.99.158 (10.99.99.158) 100(128) bytes of data.
108 bytes from 10.99.99.158: icmp_seq=1 ttl=64 time=1.75 ms
108 bytes from 10.99.99.158: icmp_seq=2 ttl=64 time=0.276 ms
108 bytes from 10.99.99.158: icmp_seq=3 ttl=64 time=0.201 ms

--- 10.99.99.158 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.201/0.742/1.750/0.713 ms
PING 10.99.99.158 (10.99.99.158) 101(129) bytes of data.
109 bytes from 10.99.99.158: icmp_seq=1 ttl=64 time=0.185 ms
109 bytes from 10.99.99.158: icmp_seq=2 ttl=64 time=0.253 ms
109 bytes from 10.99.99.158: icmp_seq=3 ttl=64 time=0.230 ms

--- 10.99.99.158 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.185/0.222/0.253/0.033 ms
PING 10.99.99.158 (10.99.99.158) 102(130) bytes of data.
110 bytes from 10.99.99.158: icmp_seq=1 ttl=64 time=0.118 ms
110 bytes from 10.99.99.158: icmp_seq=2 ttl=64 time=0.201 ms
110 bytes from 10.99.99.158: icmp_seq=3 ttl=64 time=0.343 ms

--- 10.99.99.158 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.118/0.220/0.343/0.094 ms
PING 10.99.99.158 (10.99.99.158) 103(131) bytes of data.
111 bytes from 10.99.99.158: icmp_seq=1 ttl=64 time=0.565 ms
111 bytes from 10.99.99.158: icmp_seq=2 ttl=64 time=0.182 ms
111 bytes from 10.99.99.158: icmp_seq=3 ttl=64 time=0.329 ms

Windows

In Windows, you use -f in ping to set "don't fragment" bit. To discover MTU over the path, you can sweep ping sizes with an increment. For example, here I start pinging 8.8.8.8 with the size of 1450, send 2 ICMP Echo Request packets of each size, and increase size by 20 bytes each time.

for /L %A in (1450,20,2500) do ping -f -l %A -n 2  8.8.8.8

FreeBSD

Defaults: Don’t fragment bit - not set   ; use –D  option to set
IP Packet size:  84 bytes  ;  use –s option to change
Sending interval:  1 sec  ;   use  –I  secs to change

e.g. Sending pings  of data size 1300 bytes with interval 0.2 seconds with df bit set:

Sending host[10.99.99.158]: freeBSD# ping -D -s 1300 -i 0.2 10.99.99.150

Receiving host[10.99.99.150]:

[root@darkstar ~]# tcpdump -n -v -s 1500  host 10.99.99.158
20:42:57.816697 IP (tos 0x0, ttl  64, id 11630, offset 0, flags [DF], proto: ICMP (1), length: 1328) 10.99.99.158 > 10.99.99.150: ICMP echo request, id 10770, seq 23, length 1308
20:42:57.816914 IP (tos 0x0, ttl  64, id 33327, offset 0, flags [none], proto: ICMP (1), length: 1328) 10.99.99.150 > 10.99.99.158: ICMP echo reply, id 10770, seq 23, length 1308

SideNote: BSD family  has  a nice additional option  not found in most other systems  – you can  order ping to sweep size of sent packets . Example follows:

Here sweep range is from 20 bytes up to 1400 bytes, increase step is 300 bytes.

Sending host[10.99.99.158]: freeBSD#ping -D -g 20 -G 1400 -h 300 10.99.99.150

PING 10.99.99.150 (10.99.99.150): (20 ... 1400) data bytes
28 bytes from 10.99.99.150: icmp_seq=0 ttl=64 time=1.313 ms
328 bytes from 10.99.99.150: icmp_seq=1 ttl=64 time=0.531 ms
628 bytes from 10.99.99.150: icmp_seq=2 ttl=64 time=0.581 ms
928 bytes from 10.99.99.150: icmp_seq=3 ttl=64 time=0.362 ms
1228 bytes from 10.99.99.150: icmp_seq=4 ttl=64 time=0.223 ms

--- 10.99.99.150 ping statistics ---
5 packets transmitted, 5 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.223/0.602/1.313/0.377 ms

Receiving host[10.99.99.150]:

[root@darkstar ~]# tcpdump -n -v -s 1500  host 10.99.99.158
21:50:06.942165 IP (tos 0x0, ttl  10.99.99.150 64, id 12828, offset 0, flags [DF], proto: ICMP (1), length: 48) 10.99.99.158 > 10.99.99.150: ICMP echo request, id 50962, seq 0, length 28
21:50:06.944098 IP (tos 0x0, ttl  64, id 43255, offset 0, flags [none], proto: ICMP (1), length: 48) 10.99.99.150 > 10.99.99.158: ICMP echo reply, id 50962, seq 0, length 28
21:50:07.944761 IP (tos 0x0, ttl  64, id 12831, offset 0, flags [DF], proto: ICMP (1), length: 348) 10.99.99.158 > 10.99.99.150: ICMP echo request, id 50962, seq 1, length 328
21:50:07.944826 IP (tos 0x0, ttl  64, id 43256, offset 0, flags [none], proto: ICMP (1), length: 348) 10.99.99.150 > 10.99.99.158: ICMP echo reply, id 50962, seq 1, length 328
21:50:08.945815 IP (tos 0x0, ttl  64, id 12833, offset 0, flags [DF], proto: ICMP (1), length: 648) 10.99.99.158 > 10.99.99.150: ICMP echo request, id 50962, seq 2, length 628
21:50:08.945890 IP (tos 0x0, ttl  64, id 43257, offset 0, flags [none], proto: ICMP (1), length: 648) 10.99.99.150 > 10.99.99.158: ICMP echo reply, id 50962, seq 2, length 628
21:50:09.946724 IP (tos 0x0, ttl  64, id 12835, offset 0, flags [DF], proto: ICMP (1), length: 948) 10.99.99.158 > 10.99.99.150: ICMP echo request, id 50962, seq 3, length 928
21:50:09.946819 IP (tos 0x0, ttl  64, id 43258, offset 0, flags [none], proto: ICMP (1), length: 948) 10.99.99.150 > 10.99.99.158: ICMP echo reply, id 50962, seq 3, length 928

Solaris

Defaults:
Don’t fragment bit    -  not set , and not changeable , yes , it sounds strange but Solaris doesn’t support  df bit in its ping utility. You may set df bit in their traceroute program , but it has no provision for changing size of the packet and therefore is of no value for our case.

Non-verbose ; use –s to override IP packet size:  84 bytes

Pinging with defaults:
[root@solaris]:~#ping -s 10.99.99.150

PING 10.99.99.150: 56 data bytes
64 bytes from 10.99.99.150: icmp_seq=0. time=0.759 ms

Receiving host:
[root@darkstar ~]# tcpdump -n -v -s 1500  host 10.99.99.159

20:50:08.084364 IP (tos 0x0, ttl 255, id 8020, offset 0, flags [none], proto: ICMP (1), length: 84) 10.99.99.159 > 10.99.99.150: ICMP echo request, id 9096, seq 7, length 64
20:50:08.084538 IP (tos 0x0, ttl  64, id 52389, offset 0, flags [none], proto: ICMP (1), length: 84) 10.99.99.150 > 10.99.99.159: ICMP echo reply, id 9096, seq 7, length 64

To change size of sent packet, to say 1300 bytes of data:

[root@solaris]:~# ping -s 10.99.99.150  1320

PING 10.99.99.150: 1320 data bytes
1328 bytes from 10.99.99.150: icmp_seq=0. time=1.610 ms
1328 bytes from 10.99.99.150: icmp_seq=1. time=0.335 ms
**SideNote:** There is no size sweeping capability built-in , so I wrote  this script to   emulate this feature  in Solaris as well:
[root@solaris]# awk  ' BEGIN  {for (size=100;size<1470;size=size+10)  {
cmd = ("ping   -s "    "10.99.99.158 " size  " 3")
print cmd | "/bin/bash"
close("/bin/bash")  } } '

Here : size -  size of data in ICMP packet , starts at 10 bytes ends at 170 bytes
size+10 – size incrementing by 10 bytes each series of pings
3 - number of pings in each size set.

Results:
[root@solaris]# awk  ' BEGIN  {for (size=100;size<1470;size=size+10)  { cmd = ("ping   -s "    "10.99.99.158 " size  " 3") print cmd | "/bin/bash" close("/bin/bash")  } } '

PING 10.99.99.158: 100 data bytes
108 bytes from 10.99.99.158: icmp_seq=0. time=0.319 ms
108 bytes from 10.99.99.158: icmp_seq=1. time=0.460 ms
108 bytes from 10.99.99.158: icmp_seq=2. time=0.328 ms

----10.99.99.158 PING Statistics----
3 packets transmitted, 3 packets received, 0% packet loss
round-trip (ms)  min/avg/max/stddev = 0.319/0.369/0.460/0.079
PING 10.99.99.158: 110 data bytes
118 bytes from 10.99.99.158: icmp_seq=0. time=0.371 ms
118 bytes from 10.99.99.158: icmp_seq=1. time=0.370 ms
118 bytes from 10.99.99.158: icmp_seq=2. time=0.477 ms

----10.99.99.158 PING Statistics----
3 packets transmitted, 3 packets received, 0% packet loss
round-trip (ms)  min/avg/max/stddev = 0.370/0.406/0.477/0.061
PING 10.99.99.158: 120 data bytes
128 bytes from 10.99.99.158: icmp_seq=0. time=0.395 ms
128 bytes from 10.99.99.158: icmp_seq=1. time=0.361 ms
128 bytes from 10.99.99.158: icmp_seq=2. time=0.264 ms

CISCO routers (IOS)

Defaults:
IP packet size : 100 bytes ;  use size to change
Don’t fragment bit - not set  ;  use df-bit to set

Running with defaults:

Tokyo#ping 191.91.21.41
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 191.91.21.41, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/4 ms

Receiving host:
[root@darkstar ~]# tcpdump -n -v  -s 1500 icmp

22:16:53.758056 IP (tos 0x0, ttl 253, id 11, offset 0, flags [none], proto: ICMP (1), length: 100) 174.93.31.134 > 10.99.99.150: ICMP echo request, id 4, seq 0, length 80
22:16:53.758246 IP (tos 0x0, ttl  64, id 10923, offset 0, flags [none], proto: ICMP (1), length: 100) 10.99.99.150 > 174.93.31.134 : ICMP echo reply, id 4, seq 0, length 80

Set df bit and size of the packet (Note – when you set size of the ping you set IP packet size and not ICMP data size as  in Nix systems).
Repeat count is set to 3 .
Tokyo#ping 191.91.21.41 size 1300 df-bit rep 3

Type escape sequence to abort.
Sending 3, 1300-byte ICMP Echos to 191.91.21.41, timeout is 2 seconds:
Packet sent with the DF bit set
!!!
Success rate is 100 percent (3/3), round-trip min/avg/max = 4/4/4 ms

Receiving host:
[root@darkstar ~]# tcpdump -n -v  -s 1500 icmp

22:18:16.657849 IP (tos 0x0, ttl 253, id 21, offset 0, flags [DF], proto: ICMP (1), length: 1300) 174.93.31.134  > 10.99.99.150: ICMP echo request, id 6, seq 0, length 1280
22:18:16.658028 IP (tos 0x0, ttl  64, id 10933, offset 0, flags [none], proto: ICMP (1), length: 1300) 10.99.99.150 > 174.93.31.134 : ICMP echo reply, id 6, seq 0, length 1280

Sweeping ping size.
This feature is available from extended ping menu:

Rio#ping
Protocol [ip]:
Target IP address: 191.91.21.41
Repeat count [5]:
Datagram size [100]:
Timeout in seconds [2]:
Extended commands [n]: y
Source address or interface:
Type of service [0]:
Set DF bit in IP header? [no]: y
Validate reply data? [no]:
Data pattern [0xABCD]:
Loose, Strict, Record, Timestamp, Verbose[none]:
Sweep range of sizes [n]: y
Sweep min size [36]:
Sweep max size [18024]: 1700
Sweep interval [1]: 100
Type escape sequence to abort.
Sending 85, [36..1700]-byte ICMP Echos to 191.91.21.41, timeout is 2 seconds:
Packet sent with the DF bit set
!!!!!!!!!!!!!!
Receiving host:
10:35:22.563851 IP (tos 0x0, ttl 253, id 179, offset 0, flags [DF], proto: ICMP (1), length: 36) 174.93.31.134  > 10.99.99.150: ICMP echo request, id 9, seq 0, length 16
10:35:22.563891 IP (tos 0x0, ttl  64, id 46861, offset 0, flags [none], proto: ICMP (1), length: 36) 10.99.99.150 > 174.93.31.134 : ICMP echo reply, id 9, seq 0, length 16
10:35:22.566205 IP (tos 0x0, ttl 253, id 180, offset 0, flags [DF], proto: ICMP (1), length: 136) 174.93.31.134  > 10.99.99.150: ICMP echo request, id 9, seq 1, length 116
10:35:22.566223 IP (tos 0x0, ttl  64, id 46862, offset 0, flags [none], proto: ICMP (1), length: 136) 10.99.99.150 > 174.93.31.134 : ICMP echo reply, id 9, seq 1, length 116

Juniper routers (JunOS)

Defaults:
Ip packet size : 84 bytes
Don’t fragment bit – not set; use do-not-fragment to set
Interval  - 1 sec;  use interval to change
Sending pings with df bit set and size 1470 bytes
[root@Juniper] ping 192.168.37.29 do-not-fragment size 1470

ping 192.168.37.29 do-not-fragment size 1470
PING 192.168.37.29 (192.168.37.29): 1470 data bytes
1478 bytes from 192.168.37.29: icmp_seq=0 ttl=64 time=1.434 ms
1478 bytes from 192.168.37.29: icmp_seq=1 ttl=64 time=0.210 ms

--- 192.168.37.29 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.203/0.513/1.434/0.532 ms

If packet size is too large and df is set you get this:

[root@Juniper]>ping 192.168.37.29 do-not-fragment size 13000

ping 192.168.37.29 do-not-fragment size 13000
PING 192.168.37.29 (192.168.37.29): 13000 data bytes
ping: sendto: Message too long

Follow me on https://www.linkedin.com/in/yurislobodyanyuk/ not to miss what I publish on Linkedin, Github, blog, and more.