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
| Command | What it does |
|---|---|
ip -br addr | One 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 addr | IPv4 only / IPv6 only |
ip addr show dev eth0 | One interface |
ip link | Interfaces at layer 2: state, MTU, MAC, no IP addresses |
ip -s link | Add packet and byte counters |
ip route (or ip r) | The IPv4 routing table; the default via line is your gateway |
ip -6 route | The IPv6 routing table |
ip route get 1.1.1.1 | Which 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 addr | Colour output |
ip -j addr | JSON output; add -p for pretty-printing |
sudo ip link set eth0 up | Bring an interface up (or down) |
sudo ip addr add 192.168.1.50/24 dev eth0 | Add an address |
sudo ip route add default via 192.168.1.1 | Set the default gateway |
ip monitor | Watch changes to addresses, routes and links in real time |
Anatomy of the syntax
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
ip -br addrlo 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/24Three 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
ip addr show dev enp3s02: 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.
UPis the administrative state;LOWER_UPmeans the physical link is up.NO-CARRIERin 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
enp3s0is 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
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 addressAdding and removing addresses
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 IPv4Unlike 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.
ip -br linklo 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
ip -s link show enp3s02: 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 0ip -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
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 offCreating virtual interfaces
This is where ip leaves ifconfig far behind. A few of the types you may need:
# 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.10Other 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
ip routedefault 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
defaultline, 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?
ip route get 1.1.1.1
ip route get 192.168.1.10
ip -6 route get 2606:4700:4700::11111.1.1.1 via 192.168.1.1 dev enp3s0 src 192.168.1.42 uid 1000
cacheThis 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
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-localMultiple 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.
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 200ip 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.
ip neigh192.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| State | Meaning |
|---|---|
| REACHABLE | Confirmed recently; in use |
| STALE | Was valid, not confirmed lately; will be re-verified when next used. Normal. |
| DELAY / PROBE | Verification in progress |
| FAILED | No reply to ARP/NDP: the host is off, unplugged or the address is wrong |
| INCOMPLETE | Resolution started, no answer yet |
| PERMANENT | Static entry added by hand |
| NOARP | No resolution needed (point-to-point) |
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 enp3s0If 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
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 namesThe -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.
ip monitor
ip monitor address
ip monitor route
ip -ts monitor all # with timestamps[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 100ip 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.
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 addrOther objects worth knowing
| Object | Purpose | Example |
|---|---|---|
ip maddr | Multicast group memberships | ip maddr show dev enp3s0 |
ip tunnel | IPv4 GRE/IPIP/SIT tunnels | sudo ip tunnel add gre1 mode gre remote 203.0.113.5 local 198.51.100.7 |
ip -6 tunnel | IPv6 tunnels | ip -6 tunnel show |
ip tuntap | Create tun/tap devices | sudo ip tuntap add dev tun0 mode tun |
ip xfrm | IPsec policies and states | sudo ip xfrm state |
ip vrf | Virtual routing and forwarding | ip vrf show |
ip nexthop | Nexthop objects for large route tables | ip nexthop |
ip netconf | Per-interface forwarding and rp_filter settings | ip netconf show dev enp3s0 |
ip token | Fixed IPv6 interface identifier for SLAAC | sudo ip token set ::53 dev enp3s0 |
ip addrlabel | Source address selection policy (RFC 6724) | ip addrlabel |
ip mptcp | Multipath TCP endpoints | ip mptcp endpoint |
ip -b file | Batch mode: run many commands from a file | sudo 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-tools | iproute2 |
|---|---|
ifconfig | ip addr, ip link, ip -s link |
route | ip route |
arp | ip neigh |
netstat -r | ip route |
netstat -i | ip -s link |
netstat -g | ip maddr |
netstat -tulpn | ss -tulpn |
iptunnel | ip tunnel |
ipmaddr | ip maddr |
brctl (bridge-utils) | ip link … type bridge, bridge |
vconfig (vlan) | ip link … type vlan |
nameif | ip link set … name |
mii-tool | ethtool |
iwconfig (wireless-tools) | iw |
Common mistakes
- Forgetting the prefix length.
ip addr add 192.168.1.50 dev eth0gives you a /32 and no subnet route. Always write/24or whatever it is. - Expecting
addto replace. It appends. Useip addr replaceor 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
ipon macOS. It is not there. Homebrew'siproute2macis 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
UNKNOWNas a problem. For lo, tun and WireGuard it just means the driver does not report carrier.