There is a particular kind of stubborn loyalty in the Linux community. It lives in muscle memory, in decades of documentation, in the hand-worn commands that sysadmins type without even thinking. ifconfig is one of those commands. It has been a fixture of Unix-like systems since its appearance in 4.2BSD in 1983 -- nearly as old as the TCP/IP stack itself. It feels reliable because it is familiar. But familiarity is not the same as fitness, and clinging to ifconfig in 2026 is not an act of professionalism. It is a habit that costs you.
This article is not a cheat sheet. There are plenty of those. This is an examination of what is actually happening underneath these tools, why the architectural decisions made in the 1980s are now technical liabilities, and what you gain -- concretely, specifically, measurably -- when you make the switch to ip and the iproute2 suite.
The History Nobody Tells You
ifconfig was not born on Linux. It came from BSD Unix, developed at UC Berkeley as part of the BSD TCP/IP toolkit during the early 1980s. When Linux began incorporating TCP/IP networking in the early 1990s, it borrowed heavily from that BSD heritage, including ifconfig. The entire net-tools package -- which includes ifconfig, route, arp, netstat, and related utilities -- was essentially an adaptation of those BSD tools for the Linux kernel.
For years, this worked fine. The networking model was relatively simple: a machine had a handful of interfaces, each with one IP address, and you needed to query or configure them. ifconfig did that job.
But Linux's kernel networking stack did not stand still. Through the 1990s and into the 2000s, the kernel gained capabilities that net-tools was never designed to handle: multiple IP addresses per interface, policy-based routing, traffic shaping and QoS, VLAN tagging, bonding and bridging, tunnels, network namespaces, and eventually Virtual Routing and Forwarding (VRF). The net-tools codebase, still built on the same ioctl-based kernel communication model from the 1980s, could not gracefully accommodate these advances.
The Linux kernel networking community recognized this. Alexey Kuznetsov, best known for his QoS implementation in the Linux kernel and his contributions to the IPv4/IPv6 routing code in kernel 2.2, developed iproute2 as the answer. The ip utility was added in Linux 2.2 (released January 1999), and iproute2 introduced a fundamentally different architecture: instead of using ioctl system calls to communicate with the kernel, it used a new interface called Netlink. The difference between these two approaches is not cosmetic. It is architectural.
ioctl vs Netlink: The Technical Foundation
When ifconfig wants to learn about or change a network interface, it makes an ioctl (input/output control) system call. ioctl is a general-purpose mechanism that has been part of Unix since the early days. You call it with a file descriptor (typically a socket), a request code, and a pointer to a data structure. The kernel reads that structure, does the work, and writes results back into the same memory.
There are several problems with this approach in a modern networking context.
First, ioctl is synchronous and strictly one-directional in terms of session initiation. Only user-space applications can initiate ioctl calls. The kernel cannot push information to user-space asynchronously. This means that if a network interface goes down, your application cannot receive a kernel-initiated notification. It must poll, which is expensive.
Second, ioctl uses fixed-format C structures. When you want to extend the interface to pass new parameters, you have to change the structure definition. This creates ABI (Application Binary Interface) compatibility nightmares. Every extension risks breaking existing code.
Third, ioctl calls are blocking. The system call enters the kernel, the kernel does its work synchronously, and control returns to user-space only when the operation completes.
Netlink solves all of these problems with a different model. Netlink is a socket-based inter-process communication mechanism using the AF_NETLINK address family. With Netlink, the kernel and user-space communicate through a full-duplex socket interface. Communication is asynchronous: the kernel can initiate messages to user-space without waiting for a request. A single Netlink socket can subscribe to multicast groups and receive notifications about network events -- interfaces going up or down, routes being added or removed, ARP table changes -- all pushed from the kernel without polling.
Netlink messages use a Type-Length-Value (TLV) format. Adding a new attribute to a Netlink message requires adding only a new attribute type. Applications that do not know about the new attribute simply ignore it. Backward compatibility is preserved automatically.
The specific Netlink protocol family used for routing and interface management is RTNETLINK (routing netlink), defined in include/linux/rtnetlink.h. When you run ip addr show, iproute2 opens an AF_NETLINK socket with protocol NETLINK_ROUTE, sends an RTM_GETADDR message, and processes the RTM_NEWADDR messages the kernel sends back.
The performance difference this creates is measurable and verifiable on any Linux system with a significant number of interfaces. You can observe it directly:
$ time ifconfig -a >/dev/null $ time ip addr show >/dev/null
On a workstation with a small number of interfaces, the difference is modest. The ioctl overhead compounds with each additional interface, because ifconfig must issue a separate blocking ioctl call per interface per attribute. On hypervisors, container hosts, and systems with dozens or hundreds of virtual links, the gap becomes pronounced -- with ifconfig spending nearly all of its wall time in kernel-mode ioctl calls while ip addr show issues a single Netlink request and receives a dump in one pass. The sys time column in time output makes this visible: ifconfig accumulates kernel time proportional to interface count; ip does not.
The Death of net-tools: A Timeline
The net-tools package saw its last significant upstream development in 2001 with version 1.60. After two decades of dormancy, a single minor release (version 2.10) appeared in January 2021, but it brought no meaningful new functionality and the project remains effectively stagnant. Major distributions began acting on this reality years before the 2021 release. ArchLinux dropped net-tools from its default install. Red Hat Enterprise Linux dropped it from RHEL 7. CentOS followed. Fedora dropped it from default installs around version 30. Ubuntu 20.04 and later no longer include it by default.
This matters for a reason that goes beyond aesthetics. A package that sees no active development carries risk. If a vulnerability is discovered in ifconfig or netstat, there is no maintainer positioned to issue a timely patch.
NetworkManager, the daemon that manages network configuration on virtually every major desktop and server Linux distribution, depends on iproute2. The tools that replaced net-tools are not experimental alternatives. They are the foundation of how modern Linux handles networking at every level.
What ifconfig Cannot Do
There is a common misconception that ifconfig and ip are functionally equivalent -- that ip is just a newer syntax for the same operations. This is wrong, and the gap is widening.
Multiple addresses per interface. ifconfig was built on the assumption that an interface has one IP address. To assign a second address, you had to create a subinterface (eth0:0, eth0:1). That is not how modern Linux networking works. The kernel maintains a list of addresses per interface. ip addr add can assign multiple addresses natively:
$ ip addr add 192.168.1.10/24 dev eth0 $ ip addr add 192.168.1.11/24 dev eth0 $ ip addr add 2001:db8::1/64 dev eth0
Policy-based routing. Standard routing looks at a packet's destination and picks a route from the main routing table. Policy-based routing (PBR) allows routing decisions based on source address, destination address, TOS field, firewall marks, or any combination. A server with two ISP connections where traffic from different internal subnets must leave through different uplinks is impossible to configure with ifconfig and route. It requires ip rule and ip route operating on separate tables:
$ ip rule add from 10.0.1.0/24 table 100 $ ip rule add from 10.0.2.0/24 table 200 $ ip route add default via 203.0.113.1 table 100 $ ip route add default via 198.51.100.1 table 200
Network namespaces. A network namespace is a complete, isolated copy of the Linux networking stack -- its own interfaces, routing tables, iptables rules, and socket table. Network namespaces are the foundation of container networking (Docker, LXC, Kubernetes network isolation). They are managed exclusively through iproute2:
$ ip netns add production $ ip netns add testing $ ip link add veth0 type veth peer name veth1 $ ip link set veth1 netns production $ ip netns exec production ip addr add 10.0.0.1/24 dev veth1 $ ip netns exec production ip link set veth1 up
ifconfig has no concept of network namespaces and cannot interact with them at all.
Link monitoring and event streaming. Because iproute2 uses Netlink, it can subscribe to and display live kernel networking events. This command streams real-time events -- interface state changes, address additions and deletions, routing table modifications, neighbor table changes. There is no equivalent in net-tools. ifconfig shows you a snapshot; ip monitor shows you a live feed.
JSON output. Modern infrastructure relies on automation. Scripts need to parse tool output. ifconfig's output is a human-readable blob with no structured format. iproute2 supports JSON output natively (introduced in version 4.14):
$ ip -j addr show $ ip -j -p route show
The -j flag produces valid JSON. The -p flag prettifies it. This is directly usable by Python's json module, jq, Ansible, and any other automation tool.
The Command Mapping You Actually Need
For those making the transition, here is a direct mapping of the operations you use every day.
# Old $ ifconfig -a # New (shows ALL interfaces, including down ones) $ ip addr show
ifconfig without -a shows only active interfaces. ip addr show shows all interfaces by default. This catches downed interfaces that ifconfig silently hides.
# Assign an IP address # Old $ ifconfig eth0 192.168.1.100 netmask 255.255.255.0 # New (CIDR notation) $ ip addr add 192.168.1.100/24 dev eth0 # Bring interface up/down $ ip link set eth0 up $ ip link set eth0 down # Change MTU $ ip link set eth0 mtu 9000 # Change MAC address $ ip link set eth0 address 00:11:22:33:44:55
# Show routing table # Old: route -n or netstat -rn $ ip route show # Add default gateway $ ip route add default via 192.168.1.1 # Show ARP table # Old: arp -n $ ip neigh show # Show socket statistics (replacing netstat) # Old: netstat -tulnp $ ss -tulnp
ss (socket statistics) is part of iproute2 and is dramatically faster than netstat, particularly on systems with thousands of open connections. It queries the kernel via the NETLINK_SOCK_DIAG socket interface (the kernel's socket diagnostics subsystem, renamed from NETLINK_INET_DIAG in Linux 3.3) rather than reading /proc/net/tcp and related files sequentially -- which is how netstat obtains its data.
The Unified Object Model: Why ip Makes Sense
One of the most underappreciated aspects of ip is its consistent syntax:
The objects are: link, address, route, rule, neigh, tunnel, monitor, netns, vrf, and others. The commands are: add, delete, show, flush, set. Once you know how to add an address, you know the pattern for adding a route, a neighbor entry, or a tunnel. The syntax is generalized.
Command abbreviation is another practical feature. iproute2 allows any unambiguous prefix:
$ ip address show # full $ ip addr show # abbreviated object $ ip a show # further abbreviated $ ip a s # maximally abbreviated $ ip a # implicit show
Installing iproute2 and Verifying Your Environment
On virtually any modern Linux distribution, iproute2 is already installed. Verify with ip -V, which will print the installed version and the kernel it was built against. If it is not present:
# Debian/Ubuntu $ sudo apt install iproute2 # RHEL/CentOS/Fedora $ sudo dnf install iproute # Arch Linux $ sudo pacman -S iproute2
Check whether any scripts on your system still reference ifconfig, route, or netstat:
$ grep -r 'ifconfig\|netstat\|route' /etc/init.d/ /etc/network/ /usr/local/bin/ 2>/dev/null # Broader search across the whole system (slower but thorough) $ grep -rE '\bifconfig\b|\bnetstat\b' /etc /usr/local /opt 2>/dev/null
Any hits need to be updated. This is not optional if you want a maintainable system.
A Deeper Look: How ip addr Reads Interface Data
When you run ip addr show, the following sequence occurs at the kernel interface level:
- iproute2 opens a
NETLINK_ROUTEsocket:socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE). - It constructs an
RTM_GETADDRNetlink message with theNLM_F_REQUEST | NLM_F_DUMPflags. - The message is sent to the kernel via
send(). - The kernel's
rtnetlinksubsystem iterates through all address entries in the current network namespace of the calling process. - For each address, the kernel constructs an
RTM_NEWADDRmessage containingstruct ifaddrmsgfollowed by TLV attributes:IFA_ADDRESS,IFA_LOCAL,IFA_LABEL,IFA_BROADCAST, and others. - These messages are sent back over the Netlink socket as a multipart sequence, terminated by
NLMSG_DONE. - iproute2 receives and parses each message, then formats the output.
Compare this to what ifconfig -a does: it opens a socket and calls a separate ioctl() for each piece of information for each interface -- flags, address, netmask, broadcast, MAC -- then reads IPv6 addresses from /proc/net/if_inet6, a separate kernel interface entirely. That cascade of synchronous blocking calls explains the performance disparity measured earlier.
To query addresses across all network namespaces at once, use ip -all-namespaces addr show (or ip -an addr show). Without this flag, ip addr show operates only on the current namespace -- which is the correct default for nearly all use cases.
The Security Dimension
Effectively unmaintained software in a privileged context is a security concern. net-tools saw its last significant development in 2001. A minor release appeared in 2021 after two decades of dormancy, but there is no active maintainer conducting systematic security review, issuing patches for newly discovered vulnerability classes, or adapting the codebase to kernel changes that may alter its security properties.
Security tools like vulnerability scanners flag unmaintained packages. Compliance frameworks including CIS Benchmarks and STIG guidance for Linux systems increasingly reference the use of iproute2 tools rather than net-tools. In environments where you are managing systems to any compliance standard -- PCI DSS, HIPAA, FedRAMP, ISO 27001 -- running unmaintained networking utilities is a finding.
The fact that ifconfig reads from /proc/net/ for some information is also relevant. The /proc filesystem was always intended as a debugging aid, not a stable programmatic interface. Its format can change between kernel versions without notice. Netlink is a stable, versioned protocol. Code built on Netlink is more robust across kernel updates.
The Resistance and Why It Is Understandable
It is worth acknowledging why people resist this transition, because the resistance is not irrational.
Documentation for iproute2 has historically been sparse. Many users continue using ifconfig out of habit and familiarity and miss out on the powerful features of the newer tools because there has been limited beginner-friendly documentation. That has improved substantially. The iproute2 user guide at baturin.org is comprehensive and task-centered. The man pages for ip-address(8), ip-link(8), ip-route(8), ip-rule(8), ip-netns(8), and ip-vrf(8) cover the full feature set.
There is also legitimate concern about scripts and automation. Decades of shell scripts, monitoring tools, and documentation have ifconfig hardcoded into them. The cost of auditing and updating those scripts is real. The transition is not free.
But the JSON output support in modern iproute2 actually makes new scripts simpler and more robust than their ifconfig-based counterparts -- no more fragile regex parsing of human-readable output. The rewritten versions are faster, more reliable across kernel versions, and easier to maintain.
Practical Transition Strategy
For individuals: spend one week forcing yourself to use ip exclusively. The first day will be slow. By the end of the week, you will not miss ifconfig.
For teams: add an alias as a transitional aid -- alias ifconfig='echo "Use: ip addr show" && ip addr show' -- to gently redirect habits without breaking workflows. Then remove the alias after a month.
For scripts: audit all shell scripts for net-tools commands. Rewrite them using ip with -j JSON output where parsing is required. Replace netstat with ss. Replace route with ip route.
For CI/CD and automation: ensure base images do not include net-tools. Minimal container base images (Alpine, distroless) do not include it by default. Make sure your Dockerfiles and Ansible playbooks do not install it.
What You Are Really Choosing
The debate between ifconfig and ip is not really about command syntax. It is about what mental model you carry of how Linux networking works.
ifconfig presents networking as a static snapshot: interfaces have names, addresses, and flags. It speaks to the kernel through a mechanism designed for a different era, pulls information from fragmented sources, and cannot represent the full complexity of what the kernel is actually doing.
ip presents networking as the kernel actually implements it: a dynamic graph of objects -- links, addresses, routes, rules, neighbors, tunnels, namespaces -- all queryable and modifiable through a consistent, extensible protocol. The NETLINK_ROUTE socket that iproute2 uses is the same interface that NetworkManager uses, that container runtimes use, that routing daemons use. When you use ip, you are speaking the same language as the rest of the modern Linux networking ecosystem.
The tools you use shape how you think. Moving to
ipis not a syntax change. It is a conceptual upgrade that aligns your understanding with the actual architecture of the system you are administering.
The switch costs you a few days of muscle memory adjustment. What you gain is access to the full capability of the Linux networking stack -- and the confidence that comes from using tools the kernel developers actually built for the job.
Reference: Quick Command Table
A complete mapping of net-tools commands to their iproute2 equivalents:
# Show all interfaces ifconfig -a ip addr show # Show one interface ifconfig eth0 ip addr show dev eth0 # Assign IP address ifconfig eth0 192.168.1.1 netmask 255.255.255.0 ip addr add 192.168.1.1/24 dev eth0 # Bring interface up / down ifconfig eth0 up ip link set eth0 up ifconfig eth0 down ip link set eth0 down # Change MTU ifconfig eth0 mtu 9000 ip link set eth0 mtu 9000 # Change MAC ifconfig eth0 hw ether AA:BB:CC:DD:EE:FF ip link set eth0 address AA:BB:CC:DD:EE:FF # Show routing table route -n ip route show # Add default gateway route add default gw 192.168.1.1 ip route add default via 192.168.1.1 # Add static route route add -net 10.0.0.0/8 gw 192.168.1.254 ip route add 10.0.0.0/8 via 192.168.1.254 # Show ARP table arp -n ip neigh show # Show sockets netstat -tulnp ss -tulnp # Monitor events (no net-tools equivalent) ip monitor all # JSON output (no net-tools equivalent) ip -j addr show # Network namespaces (no net-tools equivalent) ip netns add foo # Policy routing rules (no net-tools equivalent) ip rule add from 10.0.0.0/8 table 100 # VRF management (no net-tools equivalent) ip link add vrf0 type vrf table 10