cheat sheet

ip

Modern replacement for ifconfig, route, and arp. Inspect and configure interfaces, addresses, routes, neighbour tables, and network namespaces with the iproute2 ip command.

ip — iproute2 Networking

What it is

ip is the unified Linux networking utility from the iproute2 suite, written by Alexey Kuznetsov to replace the legacy ifconfig, route, arp, and iwconfig commands with a single tool that exposes the full kernel networking API. It speaks to the kernel through netlink — the same channel iproute2's sister tool ss uses — so it sees every interface, address, route, and neighbour entry, including features the legacy tools never learned about (IPv6 properly, VRF, network namespaces, MPLS, eBPF hooks). Reach for ip whenever you need to inspect or configure Linux networking; on modern distributions the legacy tools may not even be installed, and where they are they often hide critical state. On macOS and BSD, ip is not available — use ifconfig and netstat -nr instead.

iproute2 tracks the kernel release cadence — major versions ship roughly every two months. As of 2026, recent releases (6.10 → 6.15) added support for the NO_COLOR environment variable, improved dark-background color output, and continued expanding netlink coverage for new kernel features (multi-path TCP, MPLS extensions, VRF refinements). The user-visible command surface is stable — anything in this page works on every iproute2 from the past several years.

Install

iproute2 is part of every modern Linux base install; if it's missing, install the iproute2 (Debian/Ubuntu) or iproute (RHEL) package.

bash
# Debian/Ubuntu
sudo apt install iproute2

# Fedora/RHEL
sudo dnf install iproute

# Alpine
sudo apk add iproute2

# macOS — not available; use ifconfig + netstat -nr

Output: (none — exits 0 on success)

Syntax

ip uses a noun-verb command structure: ip OBJECT COMMAND [ARGS], where OBJECT is what you're inspecting (link, addr, route, neigh, netns, …) and COMMAND is the action (show, add, del, set, flush). Object names accept short forms — ip a is ip addr show, ip l is ip link show, ip r is ip route show — which is what most experienced users actually type.

bash
ip [OPTIONS] OBJECT { COMMAND | help }

Output: (none — exits 0 on success)

Essential options

OptionMeaning
-4 / -6Restrict to IPv4 or IPv6
-sShow statistics
-dDetailed output
-brBrief one-line-per-entry table
-c / -colorColorize output
-jJSON output
-pPretty-print (combine with -j)
-n NETNSOperate inside a network namespace
-rShow numeric DNS hostnames
-hHuman-readable byte counts (with -s)

Configuration

ip itself has no traditional config file — every mutation is volatile and lives in the kernel until the next reboot. What does live on disk is a handful of name-to-number tables under /etc/iproute2/, used by ip to translate human-readable strings into the small integers the kernel actually uses.

FileWhat it mapsUsed by
/etc/iproute2/rt_tablesRouting-table ID ↔ name (e.g. 100 vpn)ip rule, ip route ... table NAME
/etc/iproute2/rt_protosRoute protocol ID ↔ name (e.g. boot, dhcp, kernel)ip route ... proto NAME
/etc/iproute2/rt_realmsRealm ID ↔ nameip route ... realm NAME
/etc/iproute2/rt_scopesScope ID ↔ name (global, link, host)ip addr ... scope NAME
/etc/iproute2/rt_dsfieldDiffServ / TOS valuesip rule ... tos NAME
/etc/iproute2/groupInterface-group ID ↔ nameip link ... group NAME

Distributions ship sensible defaults. The one you'll edit most often is rt_tables — add a line like 200 vpn so you can refer to a custom routing table by name instead of number.

bash
# Append a named table for use with policy routing
echo "200 vpn" | sudo tee -a /etc/iproute2/rt_tables

# Override per-user without root (since iproute2 5.x)
mkdir -p ~/.config/iproute2
echo "201 lab" >> ~/.config/iproute2/rt_tables

Output (after both edits, ip rule add table vpn ... and ip rule add table lab ... then ip rule):

text
0:      from all lookup local
32764:  from all lookup vpn
32765:  from all lookup lab
32766:  from all lookup main
32767:  from all lookup default

For persistence of actual interface, address, and route state — none of which ip itself remembers across reboots — see Modern alternatives below.

Objects at a glance

ObjectReplacesWhat it manages
ip linkifconfig (link layer), mii-toolInterfaces themselves: MAC, MTU, up/down
ip addrifconfig (L3)IPv4/IPv6 addresses assigned to interfaces
ip routerouteRouting table(s)
ip neigharpARP / IPv6 neighbour cache
ip rulePolicy routing rules
ip netnsNetwork namespaces
ip tunnel / ip xfrmTunnels, IPsec
ip mrouteMulticast routing

ip link manages link-layer state: which interfaces exist, their MAC addresses, MTU, up/down status, and master/slave bonding relationships. It is the right tool for "is the cable plugged in?" and "rename / bond / change MAC" tasks.

bash
ip link                          # list all interfaces
ip -br link                      # one line each
ip link show eth0                # specific interface
ip -s link show eth0             # with TX/RX stats
ip -d link show eth0             # detailed (driver, queue, etc.)

Output (ip -br link):

text
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eth0             UP             52:54:00:ab:cd:ef <BROADCAST,MULTICAST,UP,LOWER_UP>
wlan0            DOWN           a8:6d:aa:11:22:33 <BROADCAST,MULTICAST>
docker0          DOWN           02:42:1c:5b:7c:88 <NO-CARRIER,BROADCAST,MULTICAST,UP>

The <...> flags decode like this — read them as a checklist of "is this interface usable?":

FlagMeaning
UPAdministratively up (ip link set ... up)
LOWER_UPCarrier present (cable plugged, Wi-Fi associated)
BROADCASTSupports broadcast
MULTICASTSupports multicast
LOOPBACKLoopback device
POINTOPOINTPoint-to-point link (PPP, tun)
NO-CARRIERUP but no link (cable unplugged)

Bringing interfaces up/down

The most common link-layer mutation, equivalent to ifconfig eth0 up/down.

bash
sudo ip link set eth0 up
sudo ip link set eth0 down
sudo ip link set eth0 mtu 9000             # jumbo frames
sudo ip link set eth0 address 02:42:11:22:33:44   # change MAC
sudo ip link set eth0 name lan0            # rename (must be down first)
sudo ip link set eth0 promisc on           # promiscuous mode

Output: (none — exits 0 on success)

Creating virtual interfaces

ip link add creates virtual interface types — bridges, VLANs, dummies, veth pairs (used by Docker, Kubernetes, and network namespaces), and more.

bash
# VLAN 100 on eth0
sudo ip link add link eth0 name eth0.100 type vlan id 100

# Linux bridge
sudo ip link add name br0 type bridge
sudo ip link set eth0 master br0

# veth pair (back-to-back virtual cable)
sudo ip link add veth0 type veth peer name veth1

# Dummy interface (for testing)
sudo ip link add dummy0 type dummy

Output: (none — exits 0 on success)

ip addr — IP addresses

ip addr manages IPv4 and IPv6 addresses on interfaces. Unlike ifconfig, which only ever shows one address per interface, ip addr correctly displays the multiple addresses an interface usually has — typically at least one IPv4 plus one link-local + one global IPv6.

bash
ip addr                          # all interfaces, all addresses
ip a                             # same, short form
ip -br addr                      # brief table
ip addr show eth0                # specific interface
ip -4 addr                       # only IPv4
ip -6 addr                       # only IPv6
ip -j addr | jq                  # JSON

Output (ip -br addr):

text
lo               UNKNOWN        127.0.0.1/8 ::1/128
eth0             UP             10.0.0.10/24 fe80::5054:ff:feab:cdef/64
docker0          DOWN           172.17.0.1/16

Adding and removing addresses

ip addr add puts a new address on an interface; multiple addresses on one interface are fully supported (the alias-IP use case).

bash
sudo ip addr add 10.0.0.50/24 dev eth0
sudo ip addr add 10.0.0.50/24 dev eth0 label eth0:1   # legacy alias name
sudo ip addr add 2001:db8::42/64 dev eth0
sudo ip addr del 10.0.0.50/24 dev eth0
sudo ip addr flush dev eth0                            # remove all
sudo ip -4 addr flush dev eth0                         # only IPv4

Output (ip -br addr show eth0):

text
eth0             UP             10.0.0.10/24 10.0.0.50/24 2001:db8::42/64 fe80::5054:ff:feab:cdef/64

Address scopes

Each address has a scope describing how far it can reach. The most common are global (routable across the internet), link (link-local, e.g. fe80::/10), and host (loopback). Setting scope explicitly is rarely needed but useful when adding addresses for special purposes.

bash
sudo ip addr add 169.254.1.1/16 dev eth0 scope link
sudo ip addr add 127.0.0.42/8   dev lo   scope host

Output: (none — exits 0 on success)

ip route — routing table

ip route reads and writes the kernel routing table. The default route is what packets use when no more specific route matches — usually pointing at your gateway — and you'll inspect it in every "why can't this host reach the internet?" investigation.

bash
ip route                         # main routing table
ip r                             # short form
ip -br route                     # brief one-line table (newer iproute2)
ip route show default            # just the default route
ip -6 route                      # IPv6 routes
ip route show table all          # every routing table
ip route get 8.8.8.8             # which route would be used?

Output (ip route):

text
default via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.10 metric 100
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.10
169.254.0.0/16 dev eth0 scope link metric 1000
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown

Output (ip route get 8.8.8.8):

text
8.8.8.8 via 10.0.0.1 dev eth0 src 10.0.0.10 uid 1000
    cache

Adding and removing routes

ip route add adds a static route; ip route replace is the idempotent variant — replaces an existing entry or adds a new one.

bash
# Static route to a remote subnet via a specific gateway
sudo ip route add 192.168.10.0/24 via 10.0.0.254

# Route via an interface (no gateway, for point-to-point links)
sudo ip route add 192.168.10.0/24 dev tun0

# Default route
sudo ip route add default via 10.0.0.1 dev eth0

# Replace (won't fail if exists)
sudo ip route replace 192.168.10.0/24 via 10.0.0.254

# Delete
sudo ip route del 192.168.10.0/24

# Blackhole — drop traffic to a network silently
sudo ip route add blackhole 198.51.100.0/24

# Unreachable — return ICMP "destination unreachable"
sudo ip route add unreachable 198.51.100.0/24

Output: (none — exits 0 on success)

Route metrics and source addresses

When multiple routes match the same destination, the kernel picks the one with the lowest metric. src pins the source address used for outgoing packets — useful on multi-homed hosts to control which IP shows up at the remote end.

bash
sudo ip route add default via 10.0.0.1 dev eth0 metric 100
sudo ip route add default via 10.0.0.2 dev eth1 metric 200    # backup
sudo ip route add 192.168.10.0/24 via 10.0.0.254 src 10.0.0.50

Output: (none — exits 0 on success)

ip neigh — ARP / neighbour cache

ip neigh shows the kernel's ARP table (IPv4) and IPv6 neighbour cache — the MAC ↔ IP mappings the kernel learned by sending ARP/NDISC requests. Stale entries during a router failover or after MAC changes are diagnosable here.

bash
ip neigh                         # all entries
ip n                             # short form
ip -br neigh                     # brief
ip neigh show dev eth0           # only on one interface
ip neigh show 10.0.0.1           # specific neighbour

Output (ip neigh):

text
10.0.0.1 dev eth0 lladdr 00:1a:2b:3c:4d:5e REACHABLE
10.0.0.5 dev eth0 lladdr aa:bb:cc:11:22:33 STALE
fe80::1 dev eth0 lladdr 00:1a:2b:3c:4d:5e router REACHABLE
StateMeaning
REACHABLERecently confirmed reachable
STALEOld entry — kernel may probe before use
DELAYProbe scheduled
PROBEProbe in flight
FAILEDNo response — entry is bad
INCOMPLETEFirst lookup pending
PERMANENTManually configured, never expires

Managing the cache

Static ARP entries are occasionally useful for embedded targets that don't answer ARP, or to defeat ARP poisoning on a trusted LAN.

bash
sudo ip neigh add 10.0.0.42 lladdr 02:42:11:22:33:44 dev eth0
sudo ip neigh replace 10.0.0.42 lladdr 02:42:99:88:77:66 dev eth0
sudo ip neigh del 10.0.0.42 dev eth0
sudo ip neigh flush dev eth0                # clear all entries on eth0
sudo ip neigh flush all                     # clear everything

Output: (none — exits 0 on success)

ip rule — policy routing

Policy routing lets the kernel pick between multiple routing tables based on source address, mark, or interface — the foundation of VPN split-tunnels, multi-WAN setups, and Linux VRFs. ip rule lists and edits the matching rules; the tables themselves live in /etc/iproute2/rt_tables.

bash
ip rule                                  # list rules
ip rule show
sudo ip rule add from 10.0.0.50 table 100   # source-based
sudo ip rule add fwmark 1 table 100         # mark-based
sudo ip rule del from 10.0.0.50
sudo ip route add default via 10.0.0.254 table 100
ip route show table 100

Output (ip rule):

text
0:    from all lookup local
32766:    from all lookup main
32767:    from all lookup default

ip netns — network namespaces

Network namespaces are isolated Linux networking stacks — each has its own interfaces, routing tables, and firewall rules. They're the kernel feature that makes containers possible, and you can use them directly without Docker or any container runtime. ip netns is the user-space management tool.

bash
sudo ip netns add red                                # create namespace "red"
ip netns list                                        # show namespaces
sudo ip netns exec red ip addr                       # run a command inside
sudo ip netns exec red ip link set lo up             # bring up loopback inside
sudo ip netns del red                                # delete namespace

Output (ip netns list):

text
red

Connect two namespaces with veth

The veth pair is a "back-to-back virtual cable" — one end in one namespace, the other end in the other. This is how containers reach the outside world.

bash
# Create namespaces and veth pair
sudo ip netns add red
sudo ip netns add blue
sudo ip link add veth-red type veth peer name veth-blue

# Move each end into its namespace
sudo ip link set veth-red  netns red
sudo ip link set veth-blue netns blue

# Configure addresses inside each namespace
sudo ip -n red  addr add 10.10.0.1/24 dev veth-red
sudo ip -n blue addr add 10.10.0.2/24 dev veth-blue
sudo ip -n red  link set veth-red  up
sudo ip -n blue link set veth-blue up
sudo ip -n red  link set lo up
sudo ip -n blue link set lo up

# Test
sudo ip netns exec red ping -c 2 10.10.0.2

Output:

text
PING 10.10.0.2 (10.10.0.2) 56(84) bytes of data.
64 bytes from 10.10.0.2: icmp_seq=1 ttl=64 time=0.045 ms
64 bytes from 10.10.0.2: icmp_seq=2 ttl=64 time=0.038 ms

ip -n NAME OBJECT ... is shorthand for ip netns exec NAME ip OBJECT ... — saves typing inside scripts that touch many namespaces.

JSON and brief output

The -j (JSON) and -br (brief) flags transform any ip query into pipeline-friendly output. -j is the right choice when feeding state to a tool; -br is best for human dashboards.

bash
ip -j -p addr | jq '.[] | {name: .ifname, addrs: [.addr_info[].local]}'
ip -j route | jq '.[] | select(.dst == "default") | .gateway'

Output (ip -j route | jq):

text
"10.0.0.1"

Statistics

-s adds packet and byte counters; -s -s adds detailed error counters; -h makes the numbers human-readable.

bash
ip -s link show eth0
ip -s -s link show eth0          # extended error counters
ip -h -s link show eth0          # human-readable bytes

Output (ip -h -s link show eth0):

text
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
    link/ether 52:54:00:ab:cd:ef
    RX:  bytes  packets  errors  dropped overrun mcast
        12.4M    98.2K       0        0       0     0
    TX:  bytes  packets  errors  dropped carrier collsns
        45.1M    72.8K       0        0       0     0

Monitoring changes

ip monitor watches kernel networking events in real time — interface up/down, address changes, route changes — useful for debugging DHCP or VPN clients that mutate state silently.

bash
ip monitor                       # everything
ip monitor link                  # link state only
ip monitor route                 # route changes
ip monitor neigh                 # neighbour cache changes
ip monitor address               # address changes

Output: (none — exits 0 on success)

ip vs the legacy tools

OldNewNotes
ifconfigip addr, ip linkip shows multiple IPs per interface, full IPv6
ifconfig eth0 upip link set eth0 up
ifconfig eth0 10.0.0.10/24ip addr add 10.0.0.10/24 dev eth0
route -nip route
route add default gw 10.0.0.1ip route add default via 10.0.0.1
arp -nip neigh
arp -s 10.0.0.42 ...ip neigh add ...
iptunnelip tunnelabsorbed into iproute2

Modern alternatives

ip is the low-level imperative tool — every change is volatile and dies at reboot. On real systems you usually pair it with one of three higher-level declarative network managers, each of which still ultimately drives the same netlink API. Knowing which one your distro uses is the difference between a change that sticks and a change that gets clobbered five minutes later by a reconciliation loop.

ToolWhere you find itPersistenceWhen to reach for it
ip (iproute2)EverywhereNone — kernel-only until rebootDiagnostics, scripts, container setup, one-off testing
nmcli (NetworkManager)Fedora, RHEL, Arch, desktop Ubuntu/etc/NetworkManager/system-connections/Laptops, Wi-Fi, VPN, GUI integration, frequent network swaps
networkctl (systemd-networkd)Server Ubuntu, Debian, embedded, containers/etc/systemd/network/*.network, *.netdev, *.linkServers, containers, minimal/headless systems
netplanUbuntu 18.04+ (default)/etc/netplan/*.yaml → rendererUbuntu — writes config that NetworkManager or systemd-networkd then enacts

nmcli — NetworkManager CLI

nmcli creates, modifies, activates, and deletes named connection profiles — persistent recipes for "this interface, this IP, this DNS, this VPN". It is fully scriptable, the default on Fedora/RHEL/Arch desktops, and the right answer whenever you need persistence on those distros.

bash
nmcli device status                                      # interface status
nmcli connection show                                    # list saved profiles
nmcli connection show "Wired connection 1"               # full detail
nmcli device wifi list                                   # scan Wi-Fi
sudo nmcli device wifi connect MyAP password 'sekret'

# Persistent static address on eth0
sudo nmcli connection modify "Wired connection 1" \
    ipv4.method manual ipv4.addresses 10.0.0.10/24 \
    ipv4.gateway 10.0.0.1 ipv4.dns 1.1.1.1
sudo nmcli connection up "Wired connection 1"

Output (nmcli device status):

text
DEVICE  TYPE      STATE      CONNECTION
eth0    ethernet  connected  Wired connection 1
wlan0   wifi      connected  MyAP
lo      loopback  unmanaged  --

networkctl — systemd-networkd CLI

networkctl is the inspection-and-control front end for systemd-networkd. Configuration is purely file-based — drop *.network / *.netdev / *.link files in /etc/systemd/network/, then use networkctl reload and networkctl reconfigure IFACE to apply. Common on server installs, containers, and anywhere systemd is already running but a full NetworkManager stack is overkill.

bash
networkctl                            # list managed interfaces
networkctl status                     # overall daemon state
networkctl status eth0                # per-interface detail
networkctl lldp                       # show LLDP neighbours
sudo networkctl reload                # re-read config files
sudo networkctl reconfigure eth0      # apply config to one interface
sudo networkctl renew eth0            # renew DHCP lease
sudo networkctl up eth0               # bring link up
networkctl monitor                    # watch state changes in real time

Output (networkctl):

text
IDX LINK    TYPE     OPERATIONAL SETUP
  1 lo      loopback carrier     unmanaged
  2 eth0    ether    routable    configured
  3 wlan0   wlan     no-carrier  unmanaged

The two state columns are the most useful diagnostic: OPERATIONAL is the kernel's view (carrier, addresses, routes), SETUP is systemd-networkd's view (did it find a matching .network file?). When something isn't working, the combination of networkctl status IFACE and journalctl -u systemd-networkd tells you everything.

A minimal /etc/systemd/network/10-eth0.network:

ini
[Match]
Name=eth0

[Network]
Address=10.0.0.10/24
Gateway=10.0.0.1
DNS=1.1.1.1

Which to use

If you ran nmcli device status and it returned interfaces, you're on NetworkManager — make changes there. If networkctl returned configured interfaces, you're on systemd-networkd — drop .network files. If you're on Ubuntu and /etc/netplan/ has YAML, edit that and run sudo netplan apply (netplan generates the underlying NM or networkd config for you). Never mix tools: writing ip addr add while NetworkManager owns the interface buys you about 30 seconds before NM erases your change.

Common pitfalls

  1. Changes aren't persistentip mutations live only until the next reboot or interface restart. Use NetworkManager, systemd-networkd, /etc/netplan/, or distribution-specific configs to make them stick.
  2. ifconfig shows different state than ip — only when both are installed. ifconfig only displays the first IPv4 alias and the first IPv6 address; ip shows everything. Always trust ip.
  3. Missing sudo — read commands (ip addr, ip route) work as any user; write commands (ip ... add/del/set) require root and fail with RTNETLINK answers: Operation not permitted otherwise.
  4. Flushing loip addr flush dev lo will break 127.0.0.1. Don't do that, and re-add 127.0.0.1/8 if you did.
  5. linkdown in routes — when an interface is down, routes via it still appear in ip route but are marked linkdown and aren't used. The fix is usually ip link set IFACE up, not editing routes.
  6. MAC address change requires DOWNip link set eth0 address ... only works when the interface is administratively down. ip link set eth0 down first.
  7. Namespaces are kernel-only — opening a file or socket inside a namespace doesn't escape it; this is the foundation of container isolation. nsenter -t PID -n is the way to drop into another process's namespace.
  8. ip route get is not a ping — it shows the route the kernel would use but doesn't actually send traffic. Combine with ping -c 1 -I IFACE to confirm reachability.
  9. macOS / BSD have no ip — scripts that need to be portable should detect the OS and fall back to ifconfig + netstat -nr.

Real-world recipes

Add an alias IP to eth0

The classic "I need a second IP for testing" scenario. The address sticks until reboot; for permanence, edit your distro's network config.

bash
sudo ip addr add 10.0.0.50/24 dev eth0 label eth0:1
ip -br addr show eth0

Output:

text
eth0  UP  10.0.0.10/24 10.0.0.50/24 fe80::5054:ff:feab:cdef/64

Find your default gateway

Useful in scripts that need to know where outbound traffic is heading.

bash
ip route show default | awk '/default/ {print $3}'

Output:

text
10.0.0.1

Find the interface used for a specific destination

ip route get walks the routing table the way the kernel will, including policy-routing rules — the canonical "which NIC will this packet leave?" answer.

bash
ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}'

Output:

text
eth0

Reset a stuck NIC

The 90 % cure for "the network is acting weird" — down, flush, up. Equivalent to ifdown eth0 && ifup eth0 on legacy systems.

bash
sudo ip link set eth0 down
sudo ip addr flush dev eth0
sudo ip link set eth0 up
sudo dhclient -r eth0 && sudo dhclient eth0   # re-acquire DHCP lease

Output: (none — exits 0 on success)

Two default gateways with metrics

A common multi-WAN setup: primary link with lower metric is preferred, secondary takes over when primary goes down. The kernel automatically promotes the lower-metric route only if its interface is up.

bash
sudo ip route add default via 10.0.0.1 dev eth0 metric 100
sudo ip route add default via 10.0.1.1 dev eth1 metric 200
ip route show default

Output:

text
default via 10.0.0.1 dev eth0 metric 100
default via 10.0.1.1 dev eth1 metric 200

Source-based policy routing

Route traffic from a specific source address through a different gateway — the building block of VPN split-tunnels.

bash
# 1. Create a custom routing table (or just use an integer)
echo "200 vpn" | sudo tee -a /etc/iproute2/rt_tables

# 2. Send traffic from 10.0.0.50 through the VPN gateway
sudo ip route add default via 192.168.99.1 table vpn
sudo ip rule add from 10.0.0.50 table vpn

# 3. Verify
ip rule
ip route show table vpn

Output (ip rule):

text
0:      from all lookup local
32765:  from 10.0.0.50 lookup vpn
32766:  from all lookup main
32767:  from all lookup default

Trace a packet path on a multi-homed box

ip route get repeated for several destinations is the quickest way to confirm policy routing is doing what you think.

bash
for dst in 8.8.8.8 192.168.1.1 10.0.0.5; do
  echo -n "$dst -> "; ip route get $dst | awk '{print $3, $4, $5}'
done

Output:

text
8.8.8.8 -> via 10.0.0.1 dev eth0
192.168.1.1 -> via 10.0.1.1 dev eth1
10.0.0.5 -> dev eth0 src

Clear a stale ARP entry

After a router swap or DHCP lease move, the old MAC can sit in the cache long enough to break connectivity. Force a refresh.

bash
sudo ip neigh flush 10.0.0.1
ping -c 1 10.0.0.1                  # triggers re-ARP
ip neigh show 10.0.0.1

Output:

text
10.0.0.1 dev eth0 lladdr 00:1a:2b:99:88:77 REACHABLE

Dump everything for a bug report

When asking for help, paste this. It's enough state to debug 99 % of Linux networking questions.

bash
{ ip -br link; echo; ip -br addr; echo; ip route; echo; ip -6 route; echo; ip neigh; } | tee net-state.txt

Output:

text
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eth0             UP             52:54:00:ab:cd:ef <BROADCAST,MULTICAST,UP,LOWER_UP>

lo               UNKNOWN        127.0.0.1/8 ::1/128
eth0             UP             10.0.0.10/24 fe80::5054:ff:feab:cdef/64

default via 10.0.0.1 dev eth0
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.10

10.0.0.1 dev eth0 lladdr 00:1a:2b:3c:4d:5e REACHABLE

Tips

The -br (brief) and -c (color) flags make ip output dramatically more readable. Add alias ip='ip -c' to your shell rc to always get color in interactive use.

ip and ss are siblings from the iproute2 suite — they both speak netlink and they both replace older /proc-scraping tools (ifconfig, netstat). If you have one, you have the other. Pair ip route get DEST with ss -tn dst DEST to see both the routing decision and the actual active connections in two commands.

Network namespace experiments are completely safe — they can't affect your host's main network. Use ip netns add scratch and ip netns exec scratch bash to drop into an isolated networking sandbox and play with any of these commands without risk.

Sources