ipconfig.co.uk

The ip command: Linux iproute2 reference

ip from the iproute2 package is the standard Linux tool for everything about interfaces, addresses, routes and neighbours. It has been in every mainstream distribution since around 2000 and is what ifconfig, route and arp should have become. The syntax looks intimidating because it is regular: every command is ip OBJECT ACTION [options].

Quick reference

CommandWhat it does
ip -br addrOne line per interface: name, state, addresses. The best first command.
ip addr (or ip a)All interfaces with all addresses, IPv4 and IPv6, and lifetimes
ip -4 addr / ip -6 addrIPv4 only / IPv6 only
ip addr show dev eth0One interface
ip linkInterfaces at layer 2: state, MTU, MAC, no IP addresses
ip -s linkAdd packet and byte counters
ip route (or ip r)The IPv4 routing table; the default via line is your gateway
ip -6 routeThe IPv6 routing table
ip route get 1.1.1.1Which interface, source address and gateway would be used to reach an address
ip neigh (or ip n)The ARP (IPv4) and NDP (IPv6) neighbour cache
ip -c addrColour output
ip -j addrJSON output; add -p for pretty-printing
sudo ip link set eth0 upBring an interface up (or down)
sudo ip addr add 192.168.1.50/24 dev eth0Add an address
sudo ip route add default via 192.168.1.1Set the default gateway
ip monitorWatch changes to addresses, routes and links in real time

Anatomy of the syntax

Output
ip [ OPTIONS ] OBJECT { COMMAND | help }

OBJECT := { address | addrlabel | link | maddress | monitor | mptcp | mroute | mrule |
            neighbour | netconf | netns | nexthop | ntable | route | rule | sr | tap |
            tcpmetrics | token | tunnel | tuntap | vrf | xdp }

OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] | -h[uman-readable] |
             -iec | -j[son] | -p[retty] | -f[amily] { inet | inet6 | mpls | bridge | link } |
             -4 | -6 | -M | -B | -0 | -l[oops] { maximum-addr-flush-attempts } |
             -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |
             -rc[vbuf] [size] | -n[etns] name | -N[umeric] | -a[ll] | -c[olor] | -br[ief] |
             -echo }

The objects you will use constantly are address, link, route and neighbour. The options you will use constantly are -br, -s, -4/-6, -c and -j. Every object has ip OBJECT help.

ip address

Brief view

Linux · Terminal
ip -br addr
Output
lo               UNKNOWN        127.0.0.1/8 ::1/128
enp3s0           UP             192.168.1.42/24 2a00:23c4:5f1a:8b00:a00:27ff:fe4e:66a1/64 fe80::a00:27ff:fe4e:66a1/64
wlp2s0           DOWN
docker0          DOWN           172.17.0.1/16
wg0              UNKNOWN        10.8.0.2/24

Three columns: name, operational state, addresses. UNKNOWN is normal for loopback and for tunnels that do not report carrier. ip -br link gives the same shape with MAC addresses and flags instead of IP addresses.

Full view

Linux · Terminal
ip addr show dev enp3s0
Output
2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:4e:66:a1 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.42/24 brd 192.168.1.255 scope global dynamic noprefixroute enp3s0
       valid_lft 85471sec preferred_lft 85471sec
    inet6 2a00:23c4:5f1a:8b00:a00:27ff:fe4e:66a1/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 86394sec preferred_lft 14394sec
    inet6 2a00:23c4:5f1a:8b00:5c1d:9e8f:7a6b:3c2d/64 scope global temporary dynamic
       valid_lft 86394sec preferred_lft 14394sec
    inet6 fe80::a00:27ff:fe4e:66a1/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
2:
The interface index (ifindex). Loopback is always 1. This is the number that appears as the zone ID in link-local addresses such as fe80::1%2.
<BROADCAST,MULTICAST,UP,LOWER_UP>
Flags. UP is the administrative state; LOWER_UP means the physical link is up. NO-CARRIER in this list means the cable is out or Wi-Fi is not associated. See the flag table.
mtu 1500 qdisc fq_codel state UP
MTU, the queueing discipline (fq_codel is the modern default), and the operational state: UP, DOWN, UNKNOWN, LOWERLAYERDOWN, DORMANT.
link/ether 08:00:27:4e:66:a1 brd ff:ff:ff:ff:ff:ff
Link type and MAC address, then the broadcast MAC. Other link types: link/loopback, link/none (WireGuard, tun), link/tunnel6, link/ppp.
inet 192.168.1.42/24 brd 192.168.1.255 scope global dynamic noprefixroute enp3s0
IPv4 address in CIDR form, broadcast, scope (global, link or host), then flags: dynamic = assigned by DHCP with a finite lifetime; noprefixroute = the kernel did not auto-create the subnet route because NetworkManager manages routes itself; secondary = an extra address on the same subnet; deprecated = past its preferred lifetime; tentative = duplicate detection in progress; dadfailed = duplicate detected. The trailing enp3s0 is the address label.
valid_lft / preferred_lft
Lifetimes in seconds, or forever for static addresses. A DHCP lease shows its remaining time here. When preferred_lft reaches zero the address becomes deprecated: still usable for existing connections, not chosen for new ones. That is how IPv6 temporary addresses rotate.
mngtmpaddr / temporary
mngtmpaddr marks the stable SLAAC address from which temporary privacy addresses are generated; temporary marks the privacy addresses themselves. IPv6 address types →

Filtering

Linux · Terminal
ip -4 addr                       # IPv4 only
ip -6 addr show scope global     # routable IPv6 only
ip addr show up                  # interfaces that are up
ip addr show type wireguard      # by link type
ip addr show to 192.168.0.0/16   # addresses within a prefix
ip -o -4 addr show | awk '{print $2, $4}'   # one line each, name and address

Adding and removing addresses

Linux · Terminal
sudo ip addr add 192.168.1.50/24 dev enp3s0
sudo ip addr add 192.168.1.51/24 dev enp3s0 label enp3s0:1   # optional label, visible to ifconfig
sudo ip addr add 2001:db8:1::50/64 dev enp3s0
sudo ip addr del 192.168.1.50/24 dev enp3s0
sudo ip addr flush dev enp3s0          # remove every address
sudo ip -4 addr flush dev enp3s0       # remove only IPv4

Unlike ifconfig, ip addr add does not replace the existing address; it adds another. To change an address, delete the old one or flush the interface. The prefix length matters: 192.168.1.50 without /24 is treated as /32, and you will be unable to reach anything on the LAN.

ip link

The link object is layer 2: the device itself, independent of any addresses.

Linux · Terminal
ip -br link
Output
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
enp3s0           UP             08:00:27:4e:66:a1 <BROADCAST,MULTICAST,UP,LOWER_UP>
wlp2s0           DOWN           3c:a0:67:1b:2c:3d <BROADCAST,MULTICAST>
docker0          DOWN           02:42:9a:1f:0b:3e <NO-CARRIER,BROADCAST,MULTICAST,UP>

Statistics

Linux · Terminal
ip -s link show enp3s0
Output
2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:4e:66:a1 brd ff:ff:ff:ff:ff:ff
    RX:  bytes packets errors dropped  missed   mcast
     231770215  184213      0       0       0    1204
    TX:  bytes packets errors dropped carrier collsns
      11284570   97312      0       0       0       0

ip -s -s link (two s) adds a breakdown of error types. ip -h -s link prints bytes in K/M/G. For the per-driver counters that these summaries hide (ring drops, PHY errors), use ethtool -S enp3s0.

Changing link settings

Linux · Terminal
sudo ip link set enp3s0 up
sudo ip link set enp3s0 down
sudo ip link set enp3s0 mtu 9000
sudo ip link set enp3s0 address 02:11:22:33:44:55    # interface must be down first on most drivers
sudo ip link set enp3s0 promisc on
sudo ip link set enp3s0 name lan0                    # rename (down first)
sudo ip link set enp3s0 alias "Uplink to switch 1"   # free-text description
sudo ip link set enp3s0 txqueuelen 2000
sudo ip link set enp3s0 multicast off
sudo ip link set enp3s0 arp off

Creating virtual interfaces

This is where ip leaves ifconfig far behind. A few of the types you may need:

Linux · Terminal
# VLAN 10 on top of enp3s0
sudo ip link add link enp3s0 name enp3s0.10 type vlan id 10
# a bridge, and enslave an interface
sudo ip link add br0 type bridge
sudo ip link set enp3s0 master br0
# a dummy interface for testing
sudo ip link add dum0 type dummy
# a veth pair (used by containers)
sudo ip link add veth0 type veth peer name veth1
# a bond
sudo ip link add bond0 type bond mode 802.3ad
# a WireGuard interface (then configure with wg)
sudo ip link add wg0 type wireguard
# a tap device for a VM
sudo ip tuntap add dev tap0 mode tap user $USER
# delete any of them
sudo ip link del enp3s0.10

Other types: macvlan, ipvlan, vxlan, gre, gretap, ip6tnl, sit, vrf, ifb, vcan, geneve, bareudp. ip link help TYPE lists the options for each. ip -d link show shows the type-specific details of existing interfaces, such as a VLAN's ID or a bridge's STP state.

ip route

Linux · Terminal
ip route
Output
default via 192.168.1.1 dev enp3s0 proto dhcp src 192.168.1.42 metric 100
10.8.0.0/24 dev wg0 proto kernel scope link src 10.8.0.2
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
192.168.1.0/24 dev enp3s0 proto kernel scope link src 192.168.1.42 metric 100
default via 192.168.1.1 dev enp3s0
The default gateway and which interface reaches it. If there is no default line, you have no route to the internet. Two default lines with different metrics mean two paths (typically wired and Wi-Fi); the lower metric wins.
proto dhcp / kernel / static / boot / ra
Who created the route: the DHCP client, the kernel automatically when an address was added, an administrator, a boot script, or an IPv6 router advertisement.
scope link
Directly reachable, no gateway needed. Every subnet you have an address in gets one of these.
src 192.168.1.42
The preferred source address for traffic using this route.
metric 100
Priority; lower is preferred. NetworkManager uses 100 for Ethernet, 600 for Wi-Fi, so that a wired connection wins when both are up.
linkdown
The route exists but its interface has no carrier, so it is not usable.

Which route will be used?

Linux · Terminal
ip route get 1.1.1.1
ip route get 192.168.1.10
ip -6 route get 2606:4700:4700::1111
Output
1.1.1.1 via 192.168.1.1 dev enp3s0 src 192.168.1.42 uid 1000
    cache

This is the fastest way to answer "why is my traffic going out the wrong interface": it shows the lookup result including source address and, for VPN setups, which tunnel captured the destination.

Changing routes

Linux · Terminal
sudo ip route add default via 192.168.1.1
sudo ip route add default via 192.168.1.1 dev enp3s0 metric 50
sudo ip route replace default via 192.168.1.254          # add or change in one step
sudo ip route add 10.0.0.0/8 via 192.168.1.254
sudo ip route add 10.0.0.0/8 dev wg0                     # via an interface, no gateway
sudo ip route del default via 192.168.1.1
sudo ip route del 10.0.0.0/8
sudo ip route flush cache
sudo ip -6 route add default via fe80::1 dev enp3s0      # IPv6 gateways are usually link-local

Multiple tables and policy routing

Linux has 255 routing tables and rules that pick between them. You meet this with VPNs (WireGuard's fwmark rule, systemd-networkd's RouteTable=) and multi-homed servers.

Linux · Terminal
ip rule                          # list the policy rules
ip route show table all          # everything, all tables
ip route show table main         # the normal one
ip route show table 51820        # WireGuard's default table number
sudo ip rule add from 192.168.2.0/24 table 200
sudo ip route add default via 192.168.2.1 table 200

ip neigh

The neighbour table is the ARP cache for IPv4 and the NDP cache for IPv6: the MAC addresses of hosts you have recently talked to on the local network.

Linux · Terminal
ip neigh
Output
192.168.1.1 dev enp3s0 lladdr d4:6e:0e:11:22:33 REACHABLE
192.168.1.10 dev enp3s0 lladdr 3c:22:fb:aa:bb:cc STALE
192.168.1.99 dev enp3s0 FAILED
fe80::1 dev enp3s0 lladdr d4:6e:0e:11:22:33 router REACHABLE
StateMeaning
REACHABLEConfirmed recently; in use
STALEWas valid, not confirmed lately; will be re-verified when next used. Normal.
DELAY / PROBEVerification in progress
FAILEDNo reply to ARP/NDP: the host is off, unplugged or the address is wrong
INCOMPLETEResolution started, no answer yet
PERMANENTStatic entry added by hand
NOARPNo resolution needed (point-to-point)
Linux · Terminal
ip neigh show dev enp3s0
sudo ip neigh flush all                 # clear the cache
sudo ip neigh flush dev enp3s0
sudo ip neigh add 192.168.1.5 lladdr 00:11:22:33:44:55 dev enp3s0 nud permanent   # static entry
sudo ip neigh del 192.168.1.5 dev enp3s0

If a device shows FAILED for your gateway, the problem is at layer 2 and DNS or firewall settings are irrelevant until it is fixed. A wrong MAC for your gateway with someone else's device in the table is a sign of ARP spoofing or a duplicate IP. Duplicate address diagnosis →

Output formats for scripts

Linux · Terminal
ip -j addr                                  # JSON
ip -j -p addr show enp3s0                   # pretty JSON
ip -j -4 addr | jq -r '.[] | select(.ifname=="enp3s0") | .addr_info[0].local'
ip -o -4 addr show enp3s0 | awk '{print $4}' | cut -d/ -f1     # without jq
ip -j route | jq -r '.[] | select(.dst=="default") | .gateway'
ip -o link show | awk -F': ' '{print $2}'   # just the names

The -j flag arrived in iproute2 4.13 (2017) and is available on any supported distribution. -o (oneline) is older and works everywhere, replacing newlines with backslashes so each interface is one line.

ip monitor

Streams every change the kernel makes to links, addresses, routes and neighbours. Invaluable when something keeps changing your configuration behind your back.

Linux · Terminal
ip monitor
ip monitor address
ip monitor route
ip -ts monitor all         # with timestamps
Output
[2026-09-10T09:12:44.118] Deleted 192.168.1.42/24 dev enp3s0 ...
[2026-09-10T09:12:44.120] Deleted default via 192.168.1.1 dev enp3s0 ...
[2026-09-10T09:12:47.402] 2: enp3s0    inet 192.168.1.42/24 brd 192.168.1.255 scope global dynamic noprefixroute enp3s0
[2026-09-10T09:12:47.403] default via 192.168.1.1 dev enp3s0 proto dhcp src 192.168.1.42 metric 100

ip netns: network namespaces

A network namespace is a separate copy of the whole network stack: its own interfaces, addresses, routes and firewall. Containers are built from them. ip netns manages named namespaces and runs commands inside them.

Linux · Terminal
sudo ip netns add blue
ip netns list
sudo ip netns exec blue ip addr             # run any command inside
sudo ip link set veth1 netns blue           # move an interface in
sudo ip -n blue addr add 10.0.0.2/24 dev veth1
sudo ip -n blue link set veth1 up
sudo ip netns del blue
# inspect a running container's namespace by PID
sudo nsenter -t $(docker inspect -f '{{.State.Pid}}' mycontainer) -n ip addr

Other objects worth knowing

ObjectPurposeExample
ip maddrMulticast group membershipsip maddr show dev enp3s0
ip tunnelIPv4 GRE/IPIP/SIT tunnelssudo ip tunnel add gre1 mode gre remote 203.0.113.5 local 198.51.100.7
ip -6 tunnelIPv6 tunnelsip -6 tunnel show
ip tuntapCreate tun/tap devicessudo ip tuntap add dev tun0 mode tun
ip xfrmIPsec policies and statessudo ip xfrm state
ip vrfVirtual routing and forwardingip vrf show
ip nexthopNexthop objects for large route tablesip nexthop
ip netconfPer-interface forwarding and rp_filter settingsip netconf show dev enp3s0
ip tokenFixed IPv6 interface identifier for SLAACsudo ip token set ::53 dev enp3s0
ip addrlabelSource address selection policy (RFC 6724)ip addrlabel
ip mptcpMultipath TCP endpointsip mptcp endpoint
ip -b fileBatch mode: run many commands from a filesudo ip -b setup.txt

The companion tools in iproute2 are ss (sockets, replaces netstat), tc (traffic control), bridge (bridge FDB and VLAN filtering), devlink, rdma and nstat. ss is covered on the Linux tools page →

Migrating from net-tools

net-toolsiproute2
ifconfigip addr, ip link, ip -s link
routeip route
arpip neigh
netstat -rip route
netstat -iip -s link
netstat -gip maddr
netstat -tulpnss -tulpn
iptunnelip tunnel
ipmaddrip maddr
brctl (bridge-utils)ip link … type bridge, bridge
vconfig (vlan)ip link … type vlan
nameifip link set … name
mii-toolethtool
iwconfig (wireless-tools)iw

Common mistakes

  • Forgetting the prefix length. ip addr add 192.168.1.50 dev eth0 gives you a /32 and no subnet route. Always write /24 or whatever it is.
  • Expecting add to replace. It appends. Use ip addr replace or delete first.
  • Fighting NetworkManager. If your change vanishes within seconds, NetworkManager reapplied its profile. Either make the change with nmcli, or mark the interface unmanaged. Details →
  • Using ip on macOS. It is not there. Homebrew's iproute2mac is a thin wrapper that emulates a subset (ip addr, ip route, ip link) on top of BSD tools; it is convenient but not complete.
  • Reading UNKNOWN as a problem. For lo, tun and WireGuard it just means the driver does not report carrier.

Related pages

Last reviewed . Command syntax verified against Windows 11, Ubuntu 24.04, macOS 15 and FreeBSD 14 unless noted otherwise.

Spotted a mistake or a switch we have missed? Every page on this site is written to be checked against real output, so please test on your own machine and compare.