Discovering iproute2 features (Part I)


iproute2 is the standard networking toolbox for Linux, deprecating the unmaintained net-tools. iproute2 includes the known ip tool, which most admins and engineers use almost every day in order to see and manipulate a host’s network configuration. Today, I’m going to present some nice (and sometimes undocumented) features of ip that I was not aware of until lately.

The following commands were all tested on a Debian Stretch box, running iproute2 version 4.14.1-1~bpo9+1 (from stretch-backports) or iproute2-ss171113.

You’re all familiar with iproute2 commands like these, right?

# ip l
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: eno1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
    link/ether 11:22:33:44:55:66 brd ff:ff:ff:ff:ff:ff
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000
    link/ether 00:aa:bb:cc:dd:cc brd ff:ff:ff:ff:ff:ff

# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eno1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
    link/ether 11:22:33:44:55:66 brd ff:ff:ff:ff:ff:ff
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:aa:bb:cc:dd:cc brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.6/24 brd 192.168.2.255 scope global dynamic wlp3s0
       valid_lft 84101sec preferred_lft 84101sec
    inet6 fe80::1234:5678:9abc:def0/64 scope link
       valid_lft forever preferred_lft forever

Output looks a little bit ugly, right? What if you only want to know info about your IPs, quickly? Let’s try the -br and -c flags:

# ip -br -c a
lo               UNKNOWN        127.0.0.1/8 ::1/128
eno1             DOWN
wlp3s0           UP             192.168.2.6/24 fe80::1234:5678:9abc:def0/64

# ip -br -c l
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eno1             DOWN           11:22:33:44:55:66 <NO-CARRIER,BROADCAST,MULTICAST,UP>
wlp3s0           UP             00:aa:bb:cc:dd:cc <BROADCAST,MULTICAST,UP,LOWER_UP>

Quite better, right? But what if you need to parse something quickly without using C or those ugly netlink wrappers in Python?

# ip -json a | jq .
[
  {
    "ifindex": 1,
    "ifname": "lo",
    "flags": [
      "LOOPBACK",
      "UP",
      "LOWER_UP"
    ],
    "mtu": 65536,
    "qdisc": "noqueue",
    "operstate": "UNKNOWN",
    "group": "default",
    "txqlen": 1000,
    "link_type": "loopback",
    "address": "00:00:00:00:00:00",
    "broadcast": "00:00:00:00:00:00",
    "addr_info": [
      {
        "family": "inet",
        "local": "127.0.0.1",
        "prefixlen": 8,
        "scope": "host",
        "label": "lo",
        "valid_life_time": 4294967295,
        "preferred_life_time": 4294967295
      },
      {
        "family": "inet6",
        "local": "::1",
        "prefixlen": 128,
        "scope": "host",
        "valid_life_time": 4294967295,
        "preferred_life_time": 4294967295
      }
    ]
  },
  {
    "ifindex": 2,
    "ifname": "eno1",
    "flags": [
      "NO-CARRIER",
      "BROADCAST",
      "MULTICAST",
      "UP"
    ],
    "mtu": 1500,
    "qdisc": "pfifo_fast",
    "operstate": "DOWN",
    "group": "default",
    "txqlen": 1000,
    "link_type": "ether",
    "address": "11:22:33:44:55:66",
    "broadcast": "ff:ff:ff:ff:ff:ff",
    "addr_info": []
  },
  {
    "ifindex": 3,
    "ifname": "wlp3s0",
    "flags": [
      "BROADCAST",
      "MULTICAST",
      "UP",
      "LOWER_UP"
    ],
    "mtu": 1500,
    "qdisc": "mq",
    "operstate": "UP",
    "group": "default",
    "txqlen": 1000,
    "link_type": "ether",
    "address": "00:aa:bb:cc:dd:cc",
    "broadcast": "ff:ff:ff:ff:ff:ff",
    "addr_info": [
      {
        "family": "inet",
        "local": "192.168.2.6",
        "prefixlen": 24,
        "broadcast": "192.168.2.255",
        "scope": "global",
        "dynamic": true,
        "label": "wlp3s0",
        "valid_life_time": 83904,
        "preferred_life_time": 83904
      },
      {
        "family": "inet6",
        "local": "fe80::1234:5678:9abc:def0",
        "prefixlen": 64,
        "scope": "link",
        "valid_life_time": 4294967295,
        "preferred_life_time": 4294967295
      }
    ]
  }
]

Also, you like to use iproute2 to check for metrics about your interfaces, right? So, you must be familiar with this command:

# ip -s l show wlp3s0
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000
    link/ether 00:aa:bb:cc:dd:cc brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast
    199912659  156191   0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    14584622   102498   0       0       0       0

Let’s add one -s more:

# ip -s -s l show wlp3s0
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000
    link/ether 00:aa:bb:cc:dd:cc brd ff:ff:ff:ff:ff:ff
    RX: bytes  packets  errors  dropped overrun mcast
    202179501  157989   0       0       0       0
    RX errors: length   crc     frame   fifo    missed
               0        0       0       0       0
    TX: bytes  packets  errors  dropped carrier collsns
    14754983   103641   0       0       0       0
    TX errors: aborted  fifo   window heartbeat transns
               0        0       0       0       2

More data can also be seen using the -d flag on all commands:

# ip -d l show dev wlp3s0
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DORMANT group default qlen 1000
    link/ether 00:aa:bb:cc:dd:cc brd ff:ff:ff:ff:ff:ff promiscuity 0 addrgenmode none numtxqueues 4 numrxqueues 1 gso_max_size 65536 gso_max_segs 6553

# ip -d r
unicast default via 192.168.2.1 dev wlp3s0 proto static scope global metric 600
unicast 192.168.2.0/24 dev wlp3s0 proto kernel scope link src 192.168.2.6 metric 600

Finally, one last fancy feature. Let’s watch for netlink messages in the kernel while performing a DHCP request on an UP wireless interface:

# ip -d -t monitor
Timestamp: Fri May 25 16:39:14 2018 587277 usec
3: wlp3s0    inet 192.168.2.6/24 brd 192.168.2.255 scope global wlp3s0
       valid_lft forever preferred_lft forever
Timestamp: Fri May 25 16:39:14 2018 587313 usec
local 192.168.2.6 dev wlp3s0 table local proto kernel scope host src 192.168.2.6
Timestamp: Fri May 25 16:39:14 2018 587327 usec
broadcast 192.168.2.255 dev wlp3s0 table local proto kernel scope link src 192.168.2.6
Timestamp: Fri May 25 16:39:14 2018 587336 usec
unicast 192.168.2.0/24 dev wlp3s0 table main proto kernel scope link src 192.168.2.6
Timestamp: Fri May 25 16:39:14 2018 587345 usec
broadcast 192.168.2.0 dev wlp3s0 table local proto kernel scope link src 192.168.2.6
Timestamp: Fri May 25 16:39:14 2018 588963 usec
unicast default via 192.168.2.1 dev wlp3s0 table main proto boot scope global
Timestamp: Fri May 25 16:39:14 2018 597364 usec
192.168.2.1 dev wlp3s0 lladdr 11:11:11:ff:dd:bb REACHABLE

That’s all for now. On my next post, I’ll focus on bridge tool, which ships as a part of iproute2. I don’t think that you’re still using that unmaintained and deprecated tool called brctl, right? :)