Skip to content

Network Interface Card (NIC)

Every device this module has covered forwards, filters, or translates traffic between other devices. A NIC is different: it's the hardware inside the machine itself that actually gets bits onto a physical medium and back — the component every other device in this module ultimately depends on to have any traffic to work with at all.

Where a NIC sits

A NIC (Network Interface Card) is the hardware that connects a computer to a network — an Ethernet port and its supporting chipset, or a Wi-Fi radio and its chipset, built into a laptop's motherboard, added as a PCIe card in a server, or virtualized entirely in software inside a hypervisor. It operates primarily at the Physical and Data Link layers, Layers 1 and 2 — turning outbound frames into an electrical, optical, or radio signal, and turning an incoming signal back into frames the operating system can hand up the stack.

The MAC address article already covered where a NIC's hardware address comes from: burned in by the manufacturer at production, from an OUI block the IEEE assigned to that vendor. A machine with both a Wi-Fi card and an Ethernet port has two NICs and, correspondingly, two distinct MAC addresses — they're separate physical interfaces, each with its own identity on whatever network it's connected to.

Reading a NIC's own state

Linux exposes every NIC as a named interface — eth0, enp3s0, wlan0, whatever the kernel's naming scheme assigns it — and ip link show, already introduced in the MAC address article, lists them:

ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <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

UP and LOWER_UP together mean the interface is administratively enabled and has a live physical link — a cable plugged in and negotiated, or a Wi-Fi association established. UP alone, without LOWER_UP, is the signature of an enabled interface with nothing actually connected to it: the operating system wants to use it, but there's no physical link there to use.

For deeper hardware detail — link speed, duplex mode, and the driver-level statistics that matter for performance troubleshooting — ethtool reads directly from the NIC's driver:

sudo ethtool eth0
Settings for eth0:
    Speed: 1000Mb/s
    Duplex: Full
    Port: Twisted Pair
    Link detected: yes

A NIC negotiating half-duplex or a speed far below what both the card and the switch on the other end are capable of is a real, common cause of poor performance that shows up nowhere in application logs — everything above the NIC looks completely normal, because as far as the operating system's network stack is concerned, packets are still going in and out successfully, just far more slowly than the hardware should allow.

Physical NICs and virtual NICs

Everything above describes a physical card. Virtualization introduces a second kind entirely: a virtual NIC (vNIC), implemented entirely in software by a hypervisor or container runtime, presenting a virtual machine or container with what looks, from the guest's point of view, like an ordinary network interface — complete with its own MAC address, assigned by the virtualization platform rather than burned in by any physical manufacturer (which is exactly why a whole block of MAC OUIs, like the one covered in the MAC address article, is registered specifically to virtualization vendors). A physical NIC ultimately still does the real work of getting bits onto a real wire; a vNIC's traffic gets switched entirely in software until it reaches whichever physical NIC the host uses to actually reach the outside network — the key point is just that "NIC" no longer implies physical hardware the way it did for the entire history of Ethernet before virtualization became routine.

Offloading: work the NIC does so the CPU doesn't have to

Modern NICs aren't dumb signal converters — many of the tasks that used to run entirely in the operating system's networking stack can be pushed down onto the NIC's own hardware, freeing the CPU for other work:

  • Checksum offload — computing and verifying the TCP/UDP/IP checksums in hardware instead of in the kernel's networking code.
  • TSO/LRO (TCP Segmentation Offload / Large Receive Offload) — letting the operating system hand the NIC one large chunk of outbound data and have the NIC itself split it into properly sized segments matching the negotiated MSS, or the reverse on receive: coalescing multiple incoming segments into one larger buffer before handing it to the kernel, cutting the per-segment CPU overhead substantially.
  • RSS (Receive Side Scaling) — spreading incoming traffic across multiple hardware receive queues, each tied to a different CPU core, so a single busy NIC doesn't bottleneck on one core's interrupt-handling capacity while the rest of the machine sits idle.

These settings are visible and, on Linux, directly configurable through ethtool -k (offload features) and ethtool -l (queue/RSS configuration) — and they matter well beyond desktop use. A database server or a high-throughput API gateway pushing tens of thousands of connections a second can be measurably CPU-bound on network processing alone if these offloads are disabled or misconfigured, long before the application code itself becomes the bottleneck.

Practical scenario: a server that saturates one core under load

An API server handles moderate traffic fine, but under a real production load spike, response latency climbs sharply while overall CPU usage across the machine's sixteen cores stays under 40%. top shows something odd: one specific core is pinned near 100%, while the other fifteen are nearly idle.

This is the signature of a NIC receiving traffic on a single hardware queue, tied to a single CPU core, with RSS either unsupported by the driver or not properly configured. Every incoming packet's interrupt handling and initial processing lands on that one core no matter how many others are free, because the NIC never distributed the work across multiple queues in the first place. The rest of the machine has capacity to spare; it's simply never asked to use it, because the bottleneck is the NIC's queue configuration, not application code or overall CPU capacity.

ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:             8
TX:             8
Combined:       0
Current hardware settings:
RX:             1
TX:             1
Combined:       0

The NIC supports up to eight receive queues but is currently configured to use only one — confirming the diagnosis directly, and pointing at the fix: reconfiguring the interface to use multiple queues (ethtool -L eth0 combined 8, or the RX/TX equivalent depending on the driver) so RSS can actually distribute incoming traffic across cores as the hardware was built to allow.

Practice exercises

  1. Run ip link show on a machine you control and identify which interfaces show LOWER_UP and which don't. For any interface without it, explain what that specifically means about its physical connection state.
  2. A NIC is negotiated at 100 Mb/s half-duplex on a link where both the card and the switch port support 1000 Mb/s full-duplex. Name two ways this mismatch could plausibly have happened, and explain why nothing in an application's own logs would reveal it.
  3. Explain, in your own words, what TSO offload actually saves the CPU from doing, and why a NIC receiving one enormous piece of outbound data to split up itself is less expensive than the kernel splitting it before handing it over.

Every device this module covered — from the modem converting a signal at the edge of your network to the reverse proxy deciding which backend answers a request — ultimately depends on a NIC somewhere turning bits into a signal and back. The tools this course covers next put that whole chain to direct, practical use: the command-line utilities that let you actually see what these devices are doing, one command at a time.

Sources