You type ifconfig, get "command not found", and briefly consider a career change. It happens on a fresh container, a minimal cloud image, or any recent distribution that stopped installing net-tools by default. The commands are not gone, exactly. They are just no longer the ones the system expects you to use, and they have not been able to show you the whole truth for about twenty years.
This article is the translation layer. It maps ifconfig, route, netstat and arp onto their iproute2 and ss replacements, shows the same host through both sets of tools so you can see exactly what the old ones omit, and is honest about the one thing the new tools do not replace. Everything below was captured on a Debian 13 host running net-tools 2.10 and iproute2 6.15, wired into a Cisco Modeling Labs topology. It is part of the Linux networking commands cluster.
Why the change happened
net-tools is genuinely old. The package on this host reports:
j@llmbits:~$ dpkg -s net-tools | grep -E '^(Package|Version|Status)'
Package: net-tools
Status: install ok installed
Version: 2.10-1.3Version 2.10 was released in 2021, but that release was largely maintenance. The design dates to the mid nineties and the tools read kernel state through /proc text files and legacy ioctls. Those interfaces still exist for compatibility, and the kernel still populates them, but nothing added to Linux networking since roughly 2001 is exposed through them.
iproute2 talks netlink, which is structured, extensible and where all the new features land. That is the whole argument. It is not that ifconfig is broken. It is that ifconfig is reading an API that stopped growing, so anything modern is either missing or displayed misleadingly.
The practical consequence is that you cannot trust old tools on modern configurations, and the rest of this article shows you where.
The commands, mapped
ifconfigip addr show or ip -br addr
ifconfig eth0 10.0.0.1/24ip addr add 10.0.0.1/24 dev eth0
ifconfig eth0 up / downip link set dev eth0 up / down
ifconfig eth0 mtu 9000ip link set dev eth0 mtu 9000
route -nip route show
route add default gw 10.0.0.1ip route add default via 10.0.0.1
arp -nip neigh show
arp -s 10.0.0.5 aa:bb:cc:dd:ee:ffip neigh add 10.0.0.5 lladdr aa:bb:cc:dd:ee:ff dev eth0 nud permanent
netstat -tulpnss -tulpn
netstat -rnip route show
netstat -iip -s link show
vconfig add eth0 50ip link add link eth0 name eth0.50 type vlan id 50
netstat -sNo direct replacement. Keep netstat -s or read /proc/net/snmp.
Memorize the top row and the rest follows, because ip uses one grammar throughout: object, command, arguments. The full object model is in the Linux ip command guide.
ifconfig against ip addr, on the same interface
j@llmbits:~$ ifconfig ens224
ens224: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.77.0.100 netmask 255.255.255.0 broadcast 0.0.0.0
ether 00:0c:29:b1:cc:47 txqueuelen 1000 (Ethernet)
RX packets 3690 bytes 250868 (244.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3398 bytes 9332942 (8.9 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0Two things in that output are worth stopping on.
First, broadcast 0.0.0.0. That is not a bug in this capture. The address was set with ip addr add 10.77.0.100/24 dev ens224 and no brd +, so no broadcast address was ever installed on the interface. ifconfig prints the empty field without comment, so it reads as though the interface has a broadcast address of 0.0.0.0. It does not have one at all. This is exactly the class of misleading display the old tools produce on configurations they were not designed for.
Second, the netmask is presented in dotted decimal. Fine for a /24, considerably less fine for a /22 or a /26 at three in the morning.
Now the same interface through ip:
j@llmbits:~$ ip addr show dev ens224
3: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:b1:cc:47 brd ff:ff:ff:ff:ff:ff
altname enp19s0
altname enx000c29b1cc47
inet 10.77.0.100/24 scope global ens224
valid_lft forever preferred_lft foreverWhat ifconfig did not show you, in order: the interface index (3), the LOWER_UP flag that distinguishes "admin up" from "carrier present", the queueing discipline, the alternative interface names the kernel also answers to, the address scope, and the address lifetimes.
The LOWER_UP omission is the one that costs time. ifconfig shows RUNNING, which is derived from the same flag, but an interface that is administratively up with no carrier simply drops RUNNING and there is nothing in the output telling you those are two separate conditions. ip shows UP and LOWER_UP as distinct flags, which is the Linux equivalent of reading "up / up" versus "up / down" on a Cisco interface.
The lifetimes matter on any DHCP-managed interface. Look at the management NIC on the same host:
inet 192.168.88.156/24 brd 192.168.88.255 scope global dynamic noprefixroute ens192
valid_lft 6409sec preferred_lft 6409secThat address expires in 6409 seconds unless the lease is renewed. Through ifconfig, a host about to lose its address looks identical to one with a static configuration.
The secondary address problem
This is where ifconfig stops being merely incomplete and starts being actively wrong.
Linux has supported multiple addresses per interface natively for decades. ifconfig has no model for that, so it invented aliases: eth0:0, eth0:1, presented as separate interfaces. They are not separate interfaces. They are labels on additional addresses of one interface, kept only so that ifconfig can see them at all.
j@llmbits:~$ sudo ip addr add 10.77.0.200/24 dev ens224 label ens224:1
j@llmbits:~$ ip addr show dev ens224 | grep inet
inet 10.77.0.100/24 scope global ens224
inet 10.77.0.200/24 scope global secondary ens224:1One interface, two addresses, and ip marks the second as secondary so you know which is primary for source address selection. Add an address without a label, which is the normal way to do it, and ifconfig will not show it at all. On a host with a handful of service addresses configured properly, ifconfig reports one address per interface and you conclude the others are missing.
That is the strongest single reason not to trust ifconfig for diagnosis: it does not just omit detail, it can tell you an address is absent when it is configured and working.
The routing table, three ways
j@llmbits:~$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.88.1 0.0.0.0 UG 101 0 0 ens192
10.77.0.0 0.0.0.0 255.255.255.0 U 0 0 0 ens224
10.77.0.0 10.77.0.1 255.255.0.0 UG 0 0 0 ens224
192.168.88.0 0.0.0.0 255.255.255.0 U 101 0 0 ens192
j@llmbits:~$ netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 192.168.88.1 0.0.0.0 UG 0 0 0 ens192
10.77.0.0 0.0.0.0 255.255.255.0 U 0 0 0 ens224
10.77.0.0 10.77.0.1 255.255.0.0 UG 0 0 0 ens224
192.168.88.0 0.0.0.0 255.255.255.0 U 0 0 0 ens192
j@llmbits:~$ ip route show
default via 192.168.88.1 dev ens192 proto dhcp src 192.168.88.156 metric 101
10.77.0.0/24 dev ens224 proto kernel scope link src 10.77.0.100
10.77.0.0/16 via 10.77.0.1 dev ens224
192.168.88.0/24 dev ens192 proto kernel scope link src 192.168.88.156 metric 101Read the middle two lines of each. In route -n and netstat -rn they both start 10.77.0.0 and differ only in the Genmask column, so you have to convert 255.255.255.0 and 255.255.0.0 in your head to notice one is a /24 and the other a /16. In ip route they read 10.77.0.0/24 and 10.77.0.0/16. On an overlapping-prefix problem, that difference is the whole diagnosis.
Then the fields. netstat -rn silently dropped the metric column that route -n at least shows, so two routes with different metrics look identical. Neither shows proto, so you cannot tell that the default route came from DHCP and the lab route was typed by hand. Neither shows src, so you cannot tell which source address the host will use. And neither can see a second routing table at all, which means a policy-routed host is completely opaque to both. That side is covered in ip route: managing the Linux routing table.
Interface counters
j@llmbits:~$ netstat -i
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
ens192 1500 24431 0 2969 0 5901 0 0 0 BMRU
ens224 1500 3690 0 0 0 3398 0 0 0 BMRU
lo 65536 30 0 0 0 30 0 0 0 LRU
j@llmbits:~$ ip -s link show dev ens224
3: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:b1:cc:47 brd ff:ff:ff:ff:ff:ff
RX: bytes packets errors dropped missed mcast
250454 3685 0 0 0 0
TX: bytes packets errors dropped carrier collsns
9332264 3388 0 0 0 0netstat -i is a decent one-screen summary and gives you packet counts but no byte counts. ip -s link gives you both, plus missed and mcast, and doubling the flag to -s -s expands the errors into per-cause columns (CRC, frame, FIFO, overrun, carrier transitions) that tell you which layer to suspect. For anything below that (speed, duplex, offloads, driver counters) neither tool helps and you want ethtool.
Sockets: netstat against ss
j@llmbits:~$ netstat -tulpn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 ::1:631 :::* LISTEN -
udp 0 0 0.0.0.0:57029 0.0.0.0:* -
udp 0 0 0.0.0.0:5353 0.0.0.0:* -
udp6 0 0 :::43891 :::* -
udp6 0 0 :::5353 :::* -
j@llmbits:~$ ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
udp UNCONN 0 0 0.0.0.0:57029 0.0.0.0:*
udp UNCONN 0 0 0.0.0.0:5353 0.0.0.0:*
udp UNCONN 0 0 [::]:43891 [::]:*
udp UNCONN 0 0 [::]:5353 [::]:*
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:631 0.0.0.0:*
tcp LISTEN 0 128 [::]:22 [::]:*
tcp LISTEN 0 4096 [::1]:631 [::]:*The flags are deliberately identical, which is the single kindest thing about this migration: -t TCP, -u UDP, -l listening, -p process, -n numeric. Muscle memory transfers intact.
What you gain is the Send-Q column, which on a listening socket is the accept backlog: 128 for sshd, 4096 for cups. A service whose backlog is saturated under load is a real production failure mode and netstat has no column for it. You also gain filtering that reads like a language rather than a pipeline into grep: ss -t state established '( dport = :443 or sport = :443 )', or ss -ti for per-connection congestion window, RTT and retransmit counts pulled straight from the kernel's TCP state.
The performance difference matters at scale too. netstat reads and parses /proc/net/tcp, which is a text file the kernel regenerates on every read; on a box with a hundred thousand sockets it is genuinely slow. ss queries the socket layer directly over netlink.
The one thing that does not have a replacement
netstat -s prints per-protocol counters, and nothing in iproute2 reproduces it:
j@llmbits:~$ netstat -s | head -25
Ip:
Forwarding: 2
16250 total packets received
2 with invalid addresses
0 forwarded
0 incoming packets discarded
16236 incoming packets delivered
8951 requests sent out
132 dropped because of missing route
OutTransmits: 8972
Icmp:
52 ICMP messages received
3 input ICMP message failed
ICMP input histogram:
destination unreachable: 7
timeout in transit: 24
echo replies: 21
38 ICMP messages sent
0 ICMP messages failed
ICMP output histogram:
destination unreachable: 1
echo requests: 37
IcmpMsg:
InType0: 21
InType3: 7That output is doing real work. "132 dropped because of missing route" is a routing gap you would otherwise have to catch in a capture. The ICMP histogram distinguishes 24 time exceeded messages (that traceroute run) from 7 destination unreachables. TCP retransmission and out-of-order counters live further down the same output.
Reaching for netstat -s is correct. Just be aware you are reading /proc/net/snmp and /proc/net/netstat through a formatter, which is exactly what nstat does with better delta handling if you want counters between two points in time rather than since boot.
ARP
j@llmbits:~$ arp -n
Address HWtype HWaddress Flags Mask Iface
192.168.88.124 ether 34:9f:7b:7f:ca:ee C ens192
10.77.0.1 ether aa:bb:cc:00:04:00 C ens224
192.168.88.1 ether 98:ba:5f:11:1b:3a C ens192
192.168.88.125 ether 58:ef:68:e7:26:1a C ens192
10.77.0.55 (incomplete) ens224
j@llmbits:~$ ip neigh show
192.168.88.124 dev ens192 lladdr 34:9f:7b:7f:ca:ee STALE
10.77.0.1 dev ens224 lladdr aa:bb:cc:00:04:00 STALE
192.168.88.1 dev ens192 lladdr 98:ba:5f:11:1b:3a REACHABLE
192.168.88.125 dev ens192 lladdr 58:ef:68:e7:26:1a REACHABLESame table, same moment. arp collapses every resolved entry to the flag C. ip neigh distinguishes REACHABLE (confirmed within the last thirty seconds) from STALE (cached, unverified), which is precisely the distinction you want when something is intermittently unreachable. And arp shows no IPv6 entries at all, because it predates neighbor discovery. The states, the tunables and the failure modes are covered in ARP on Linux: ip neigh, arp and neighbor states.
What to do about it in practice
Do not alias ifconfig to ip addr. The output formats are different enough that the alias will confuse you at the worst moment, and you will still hit hosts where the real ifconfig exists and behaves differently.
Do learn ip -br addr, ip -br link, ip route show, ip route get, ip neigh show and ss -tulpn. That is six commands and it covers the overwhelming majority of what the old set did.
Do keep net-tools installed where you can, for netstat -s and for the times you are handed a runbook written in 2009.
Do remember that on a minimal container image none of the old tools exist and ip frequently does not either. ip -j from the host into the container's namespace, or nsenter, is a more reliable habit than expecting a debugging toolchain inside the image.
FAQ
Has ifconfig been removed from Linux?
No. It has been deprecated, meaning it is no longer developed and several distributions stopped installing net-tools by default. Install the package and it works exactly as it always did. What it cannot do is show you anything the kernel added after its API stopped being extended.
Why does ifconfig not show all my IP addresses?
Because Linux supports multiple addresses per interface and ifconfig has no model for that. It only sees additional addresses that carry an alias label like eth0:1. Addresses added with ip addr add and no label are invisible to it while being fully configured and working. Use ip addr show.
Is ss really faster than netstat?
Substantially, on any host with a lot of sockets. netstat reads and parses /proc/net/tcp, a text file the kernel regenerates per read. ss queries the socket layer over netlink and can filter kernel-side. On a small host you will not notice; on a busy load balancer the difference is seconds against milliseconds.
What replaces netstat -s?
Nothing in iproute2, and that is the honest answer. Keep using netstat -s, or use nstat, which reads the same /proc/net/snmp and /proc/net/netstat counters and is better at showing deltas between two moments rather than totals since boot.
Do I need to relearn all the flags?
For ss, no: -t, -u, -l, -p and -n mean the same things they did in netstat. For ip, yes, but the grammar is regular. Once you internalize object then command, the rest is guessable, and every object accepts help.
Key takeaways
net-toolsreads a kernel API that stopped being extended around 2001. It is not broken, it is blind to anything modern.ifconfigcannot see addresses added without an alias label, so it can report an address as absent when it is configured and working.ifconfigdoes not distinguish admin-up from carrier-present, does not show address lifetimes, and prints empty fields as though they held values (broadcast 0.0.0.0).route -nandnetstat -rnprint netmasks in dotted decimal and hideproto,srcand any table other thanmain.sskeepsnetstat's flags, adds the accept backlog inSend-Q, supports real filter expressions, and is far faster at scale.netstat -shas noiproute2replacement. Keep it, or usenstatfor deltas.- Six commands replace nearly all of it:
ip -br addr,ip -br link,ip route show,ip route get,ip neigh show,ss -tulpn.
Next, go one layer down to the NIC itself with ethtool: link speed, duplex, offloads and NIC stats, or make your configuration survive a reboot with nmcli and nmtui. The full grammar of the replacement tool is in the Linux ip command guide, and everything in this cluster is indexed on the Linux networking commands guide.