← Interview Prep

Linux Basics & Troubleshooting

The Linux a network engineer actually needs: the modern ip/ss/ethtool toolset, virtual networking, tuning for latency, and a layer-by-layer troubleshooting drill.

As a network engineer you rarely write C on Linux, but you live on it: your traffic generators, probes, route reflectors, load balancers, containers and NFV all run there. The interview goal is to be fluent at the shell — read interface counters, follow a route, inspect sockets, capture packets, and reason about where a problem sits. This page front-loads a basics primer, then goes deep on networking.

The single most valuable habit: know the iproute2 tools (ip, ss, bridge) that replaced ifconfig/netstat/route, and be able to walk a fault L1 → L7 naming the exact command at each layer. Everything below builds to that.

Basics primer

Filesystem hierarchy

Everything hangs off a single root / (no drive letters). The directories worth knowing:

PathWhat lives there
/etcSystem config — /etc/hosts, /etc/resolv.conf, /etc/network/, /etc/netplan/, /etc/sysctl.conf, systemd units.
/proc, /sysKernel virtual filesystems — live state. /proc/net/, /sys/class/net/<if>/, tunables under /proc/sys/.
/var/logLogs — syslog/messages, plus the systemd journal under /var/log/journal.
/bin /sbin /usrBinaries; /sbin is admin tools (ip, ss historically here).
/devDevice nodes.
/home /rootUser home dirs; root's home.
/tmp /runEphemeral scratch; /run is tmpfs for runtime state (pidfiles, sockets).

Processes & signals

A process has a PID; you inspect and control it by PID. ps is a snapshot, top/htop are live.

ps aux                      # every process, BSD-style columns
ps -ef | grep bird          # find a routing daemon
top                         # live CPU/mem; press 1 to expand per-CPU, M sort by mem
htop                        # nicer top: tree view, per-core meters, F9 to kill
pidof frr ; pgrep -a snmpd  # PID by name

kill 4021                   # send SIGTERM (15) — polite "please exit"
kill -9 4021                # SIGKILL — cannot be caught, last resort
kill -HUP 4021              # SIGHUP (1) — many daemons reload config on this
pkill -f "tcpdump.*eth0"    # match on full command line
SignalNumMeaning
SIGTERM15Default kill. Graceful shutdown — the process can clean up.
SIGKILL9Force kill, uncatchable. Leaves no cleanup — use when TERM fails.
SIGHUP1Terminal hangup; by convention "reload config" for daemons.
SIGINT2Ctrl-C from the terminal.
SIGSTOP/SIGCONT19/18Pause / resume a process.

File permissions

ls -l shows rwx triads for user / group / other. Octal: r=4, w=2, x=1.

-rw-r--r--  1 root root  648  config.yaml      # 644: owner rw, others r
-rwxr-xr-x  1 root root 1.2M  /usr/sbin/ip     # 755: owner rwx, others rx

chmod 600 ~/.ssh/id_rsa      # lock a private key to owner-only
chmod +x deploy.sh           # make executable
chown netops:netops app.cfg  # change owner:group
umask 022                    # default new-file mask

Inodes & file descriptors

An inode is the on-disk record of a file: its type, permissions, owner, size, timestamps, link count, and pointers to the data blocks — everything except the name. The name lives in a directory entry that maps a filename → an inode number. That indirection explains hard links, and why mv within a filesystem is instant (it only rewrites a directory entry).

ls -i file            # show the inode number
stat file             # inode + all metadata (perms, size, atime/mtime/ctime, links)
df -i                 # inode usage per filesystem

A file descriptor (fd) is a per-process integer handle to an open file — and in Linux "everything is a file," so sockets, pipes, and devices are fds too. 0/1/2 are stdin/stdout/stderr.

ls -l /proc/<pid>/fd   # every fd a process holds (files, sockets, pipes)
lsof -p <pid>          # same, human-readable
lsof -i :179          # who has the BGP port open
ulimit -n             # this shell's open-fd limit (soft)

A busy network daemon (many connections = many socket fds) can hit EMFILE "too many open files" — raise the per-process limit (ulimit -n / a systemd unit's LimitNOFILE=) and the system ceiling (fs.file-max). A classic production outage.

Package managers

FamilyToolCommon commands
Debian / Ubuntuapt (dpkg)apt update, apt install tcpdump, apt list --installed, dpkg -l
RHEL / CentOS / Fedoradnf (was yum)dnf install iproute-tc, dnf list installed, rpm -qa
SUSEzypperzypper in wireshark

which tcpdump / dpkg -S $(which ip) / rpm -qf $(which ip) tell you which package owns a binary — handy when a tool is missing.

systemd & the journal

systemd is the init system and service manager on nearly all modern distros. Services are "units."

systemctl status frr             # is it running? recent log lines, PID, memory
systemctl start  frr             # start now
systemctl stop   frr             # stop now
systemctl restart frr            # bounce it
systemctl reload frr             # re-read config without a full restart (if supported)
systemctl enable  frr            # start automatically at boot
systemctl disable frr            # don't start at boot
systemctl enable --now frr       # enable + start in one shot
systemctl list-units --type=service --state=running

journalctl -u frr                # all logs for one unit
journalctl -u frr -f             # follow (tail -f) live
journalctl -u frr --since "10 min ago"
journalctl -k -b                 # kernel messages, this boot (like dmesg)
journalctl -p err -b             # only errors this boot

The boot process

The chain from power-on to a login prompt — know it so you can say where a boot hangs:

StageWhat happens
Firmware (UEFI/BIOS)POST, then loads the bootloader from the EFI system partition / MBR.
Bootloader (GRUB)Presents kernels, loads the selected vmlinuz + initramfs into memory, passes the kernel cmdline (e.g. root=).
Kernel + initramfsKernel initializes hardware/drivers; the initramfs is a temporary root with just enough drivers to find and mount the real root filesystem.
PID 1 (systemd)Kernel mounts real root and execs /sbin/initsystemd, the first userspace process.
Default targetsystemd activates units up to the default target (multi-user.target for servers, graphical.target for desktops) — networking, sshd, your daemons.
systemctl get-default            # multi-user.target (≈ old runlevel 3)
systemd-analyze                  # total boot time (firmware/loader/kernel/userspace)
systemd-analyze blame            # slowest units — find what delays boot
systemd-analyze critical-chain   # the dependency path that gated boot
journalctl --list-boots          # every recorded boot
journalctl -k -b -1              # kernel log of the *previous* boot (diagnose a crash)

systemd targets replaced SysV runlevels; a unit starts at boot when it's enabled (a symlink into the target's .wants). Networking is brought up here by whatever's in use — systemd-networkd, NetworkManager, netplan, or ifupdown.

Users & sudo

whoami ; id                      # who am I; my uid/gid/groups
sudo ip link set eth0 down       # run one command as root
sudo -i                          # interactive root shell
usermod -aG sudo alice           # add user to a group (needs re-login)
visudo                           # edit /etc/sudoers safely (syntax-checked)

Most networking commands that change state (bring a link up, add a route, capture packets) need root or sudo; read-only inspection (ip addr, ss) usually does not.

Modern networking commands (old → new)

The classic net-tools suite (ifconfig, route, arp, netstat) is deprecated and often not even installed on new systems. Learn the iproute2 replacements — interviewers notice when you reach for ifconfig.

Old (net-tools)New (iproute2 / modern)Does what
ifconfigip addr, ip linkShow/set IP addresses and interface (link) state.
route -nip routeShow/manipulate the routing table.
arp -aip neighARP / NDP neighbor cache (L2↔L3 mappings).
netstat -tulpnss -tulpnListening/established sockets, owning process.
netstat -iip -s linkPer-interface packet/byte/error counters.
brctlbridge, ip link ... type bridgeLinux bridge / FDB management.
iptunnel, vconfigip tunnel, ip link ... type vlanTunnels and 802.1Q VLAN subinterfaces.

Beyond iproute2, the tools you carry everywhere:

ToolUse it for
ethtoolNIC-level truth: link/speed/duplex, driver counters (-S), optics DOM (-m), offloads (-k), ring buffers (-g), coalescing (-c).
tcpdump / tsharkPacket capture and decode at the CLI. tshark = Wireshark's engine headless.
ping / traceroute / mtrReachability, path, and continuous per-hop loss/latency.
dig / hostDNS queries (forward, reverse, specific record types, specific servers).
nc (netcat) / ncatOpen a TCP/UDP connection, test a port, throw a quick listener.
curl / wgetHTTP(S) client — curl -v shows the whole L4→L7 exchange.
nmcli / networkctlManage NetworkManager / systemd-networkd connections and state.
iperf3Throughput testing between two hosts.
# Addresses & links
ip addr show                       # all interfaces + IPs (short: ip a)
ip -br addr                        # one tidy line per interface (-brief)
ip link show eth0                  # L2 state: UP/DOWN, MTU, MAC
ip link set eth0 up                # admin-up the interface
ip addr add 10.0.0.5/24 dev eth0   # add an IP
ip link set eth0 mtu 9000          # jumbo frames

# Neighbors (ARP/NDP)
ip neigh show                      # REACHABLE / STALE / FAILED entries
ip neigh flush dev eth0            # clear the cache (force re-ARP)

# Sockets
ss -tulpn                          # TCP+UDP listeners, numeric, with PID
ss -tn state established           # established TCP, no name resolution
ss -s                              # summary totals by state

Interface state & counters

When someone says "the link looks flaky," this is where you go. Two sources: the kernel's per-interface counters (ip -s link) and the driver's detailed counters (ethtool -S).

ip -s link show eth0
# 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
#     RX: bytes  packets  errors  dropped  missed  mcast
#     ...        ...      0       0        0       ...
#     TX: bytes  packets  errors  dropped  carrier collsns
#     ...        ...      0       0        0       0

UP = admin-up; LOWER_UP = physical carrier present. Admin-up but no LOWER_UP means no light / no link partner — a Layer-1 problem.

Driver counters with ethtool -S

ethtool eth0                 # Speed, Duplex, Link detected: yes/no, autoneg
ethtool -S eth0 | grep -E "err|drop|crc|miss|no_buffer|fifo"
CounterPoints to
rx_crc_errors, rx_errorsBad frames on the wire — cabling, optics, duplex mismatch, dirty fiber. Classic L1.
rx_missed_errors, rx_no_buffer_count, rx_fifo_errorsNIC received but the host couldn't drain fast enough — ring buffer / CPU / IRQ pressure. Bump ring size, fix IRQ affinity.
rx_dropped / tx_droppedKernel dropped (no buffer, qdisc full, bad VLAN). Cross-check with ip -s link.
tx_carrier_errorsLost carrier during TX — physical/link flapping.
collisionsShould be 0 on any modern full-duplex link; non-zero = duplex mismatch (half-duplex somewhere).

Ring buffers, MTU, optics, flaps

ethtool -g eth0              # ring buffer: current vs max (RX/TX descriptors)
ethtool -G eth0 rx 4096      # enlarge RX ring to reduce rx_missed under bursts

ethtool -m eth0             # SFP/QSFP DOM: Rx/Tx optical power, temp, vendor
                            # low/absent Rx power => dirty/bent fiber or dead far end

ip link show eth0 | grep mtu # confirm MTU matches both ends (mismatch => black-holed
                             # large frames: small pings work, big transfers hang)

dmesg -T | grep -i eth0     # link up/down events with timestamps == flaps
journalctl -k | grep -i "link is"   # same from the journal

Reading errors like an engineer

Routing on Linux

Linux is a real router. The kernel keeps a FIB (forwarding table) you read with ip route, and it can consult multiple tables selected by policy rules.

ip route                        # main table: default via ..., connected + static
ip route get 8.8.8.8            # which route/source/dev would be used for this dst
ip route add 10.20.0.0/16 via 10.0.0.1 dev eth0 metric 100
ip route add default via 10.0.0.1
ip route replace default via 10.0.0.1 metric 100  # idempotent change

# Lower metric wins between two candidate routes of equal prefix length;
# longest-prefix match wins across different prefix lengths.

Policy routing (multiple tables)

Beyond the destination, Linux can route on source address, incoming interface, fwmark, etc. Rules (ip rule) map traffic to routing tables (in /etc/iproute2/rt_tables).

ip rule show
#   0:      from all lookup local
#   32766:  from all lookup main
#   32767:  from all lookup default

# Source-based routing: traffic sourced from 10.0.0.5 uses table 100
echo "100 uplink2" >> /etc/iproute2/rt_tables
ip route add default via 10.0.1.1 dev eth1 table 100
ip rule add from 10.0.0.5 table 100 priority 1000

ip route show table 100         # inspect a specific table
ip rule show                    # confirm rule priority ordering (lower = first)

Multiple gateways / ECMP: give default several nexthops for load-sharing, or use ip rule for deterministic policy. Always verify with ip route get <dst> — it resolves rules + tables + metrics and tells you the actual forwarding decision, source IP included. That one command settles most "why did it go out the wrong interface" questions.

Virtual networking — the container/VM building blocks

Containers and VMs are built from a handful of kernel primitives. Knowing them explains how Docker/Kubernetes/OpenStack networking works under the hood.

PrimitiveWhat it is
Network namespaceAn isolated copy of the whole network stack — its own interfaces, routes, ARP table, sockets. This is the "network" of a container.
veth pairA virtual cable: two linked interfaces. Put one end in a namespace, the other on a bridge — that's how a container reaches the host.
Linux bridgeA software L2 switch. Learns MACs into an FDB, floods unknowns. Docker's default docker0 is a bridge.
VLAN subinterface802.1Q tag on a parent NIC — eth0.100 carries tagged VLAN 100 traffic.
Bond / teamAggregate several NICs for redundancy (active-backup) or throughput (LACP / 802.3ad).
# Network namespaces
ip netns add red
ip netns exec red ip addr        # run a command inside the namespace
ip netns list

# veth pair connecting host to namespace
ip link add veth0 type veth peer name veth1
ip link set veth1 netns red
ip addr add 10.10.0.1/24 dev veth0 ; ip link set veth0 up
ip netns exec red ip addr add 10.10.0.2/24 dev veth1
ip netns exec red ip link set veth1 up

# Linux bridge (software switch)
ip link add br0 type bridge
ip link set eth0 master br0      # enslave a port
ip link set br0 up
bridge link                      # bridge ports + state
bridge fdb show                  # learned MAC table (forwarding database)

# 802.1Q VLAN subinterface
ip link add link eth0 name eth0.100 type vlan id 100
ip addr add 192.168.100.2/24 dev eth0.100

# Bonding (active-backup)
ip link add bond0 type bond mode active-backup
ip link set eth1 master bond0 ; ip link set eth2 master bond0
cat /proc/net/bonding/bond0      # active slave, link status, failover count

Performance & latency tuning

On a trading or HFT box, the NIC and kernel path are tuned for predictable low latency, sometimes trading throughput and CPU for it. See Low-Latency & Trading Networks for the market-data context; here are the Linux knobs.

IRQ affinity & RSS

RSS (Receive Side Scaling) spreads incoming flows across multiple RX queues, each with its own interrupt, so multiple cores share the load. IRQ affinity pins each queue's interrupt to a specific core — you keep NIC interrupts off your latency-critical application cores (and on the same NUMA node as the NIC).

ethtool -l eth0                  # number of RX/TX queues (channels)
cat /proc/interrupts | grep eth0 # which CPU services each queue's IRQ
# pin IRQ 129 to CPU 2:
echo 4 > /proc/irq/129/smp_affinity      # bitmask: bit2 = CPU2
# (disable irqbalance so it doesn't move them back)

NIC offloads — GRO/GSO/TSO/LRO

Offloads batch packets to cut per-packet CPU. Great for throughput, but they add and hide latency and can mangle what a local capture shows.

OffloadWhat it doesLatency stance
TSO (TCP Segmentation Offload)Kernel hands the NIC a big buffer; NIC cuts it into MSS segments on TX.Often disabled for low latency / determinism.
GSOSoftware equivalent of TSO, done just before the driver.Disable alongside TSO.
GRO / LRO (Receive coalescing)Merge many small RX packets into one before the stack sees them.Disable — coalescing delays delivery and distorts captures.
ethtool -k eth0                  # list offload states
ethtool -K eth0 tso off gso off gro off lro off   # turn them off (note -K = set)

Interrupt coalescing & busy-poll

ethtool -c eth0                  # current coalescing settings
ethtool -C eth0 rx-usecs 0 rx-frames 1   # fire an IRQ per packet: lowest latency,
                                          # highest CPU/interrupt rate

Coalescing waits to batch interrupts (good for throughput, bad for latency). Setting rx-usecs 0 minimizes delay. Busy-polling goes further: the app spins asking the NIC for packets instead of sleeping on an interrupt — set net.core.busy_poll/busy_read, or use SO_BUSY_POLL. Zero interrupt latency at the cost of a pegged core.

Relevant sysctls

sysctl net.core.rmem_max net.core.wmem_max      # max socket buffer sizes
sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem      # min/default/max TCP buffers
sysctl net.ipv4.tcp_congestion_control          # cubic (default) / bbr
sysctl net.core.netdev_max_backlog              # per-CPU input queue depth
sysctl -w net.ipv4.tcp_low_latency=1            # (legacy) favor latency
sysctl -w net.ipv4.tcp_timestamps=1             # RTT/PAWS; sometimes off for HFT
# persist in /etc/sysctl.conf or /etc/sysctl.d/

For a fat, high-RTT path you raise rmem/wmem so the TCP window can reach the bandwidth-delay product. For low latency you keep buffers modest to avoid bufferbloat, and pick the right congestion control (BBR on lossy/buffered paths, CUBIC otherwise).

NUMA & kernel bypass

Troubleshooting methodology — layer by layer, with the command

When something "can't connect," walk the stack bottom-up and stop at the first layer that fails. Name the command at each step — that structure is what interviewers are grading.

LayerQuestionCommand
L1 — physicalLink up? Right speed/duplex? Optics OK? Errors climbing?ethtool eth0, ethtool -m eth0, ethtool -S eth0, ip -s link
L2 — link/ARPDo I have the neighbor's MAC? Bridge learning it? Right VLAN?ip neigh, bridge fdb show, bridge vlan
L3 — routing/IPRight route & source? Gateway reachable?ip route get <dst>, ping <gw>, traceroute/mtr <dst>
L4 — transportIs the port open / listening? SYN getting through?ss -tnp, nc -vz host 443, ss -tn state syn-sent
DNSDoes the name resolve, from the right server?dig A host, dig @8.8.8.8 host, cat /etc/resolv.conf
L7 — applicationDoes the service actually answer? TLS? Redirects?curl -v https://host/, curl -Iv, openssl s_client -connect host:443

Still stuck? Capture the packets — the ground truth:

tcpdump -ni eth0 host 10.0.0.5 and port 443   # numeric, one iface, filtered
tcpdump -ni eth0 'tcp[tcpflags] & (tcp-syn|tcp-rst) != 0'  # SYNs and RSTs only
tcpdump -ni eth0 -w /tmp/cap.pcap host 10.0.0.5           # write for Wireshark
tshark -ni eth0 -f "port 179" -Y "bgp"                    # capture + decode BGP

Where the logs are: journalctl -u <svc> -f (a service), journalctl -k / dmesg -T (kernel — link flaps, OOM, drops), /var/log/syslog or /var/log/messages (general), and the app's own log under /var/log/.

Reflex checks: a lost SYN with no RST = firewall/ACL dropping silently (compare with an RST, which means "port closed / reachable but refused"). ping works but the app doesn't = it's L4+ (port/firewall/service), not the network path. Big transfers hang while small ones work = MTU/PMTU black hole.

Firewall basics — iptables, nftables, conntrack

Linux packet filtering runs in netfilter. The old front-end is iptables (per-protocol, ordered rules in chains); the modern replacement is nftables (nft) with one unified syntax, sets, and maps. On new distros iptables is often a compatibility shim over nftables.

iptablesnftables
StructureBuilt-in tables (filter, nat, mangle) with fixed chains (INPUT, FORWARD, OUTPUT, PRE/POSTROUTING)You create tables and chains; hook chains to netfilter points
IPv4/IPv6Separate (iptables / ip6tables)Unified (inet family)
Matching setsNeeds ipsetNative sets/maps — faster, atomic updates
# iptables — inspect & add
iptables -L -n -v --line-numbers        # list filter table with counters
iptables -t nat -L -n -v                # inspect NAT rules
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -I INPUT 1 -s 10.0.0.0/8 -j DROP

# nftables — inspect & add
nft list ruleset                        # everything, current state
nft add rule inet filter input tcp dport 22 accept

# conntrack — the stateful connection table (NAT + stateful rules rely on it)
conntrack -L                            # list tracked flows
conntrack -S                            # per-CPU stats: inserts, drops, early_drop
sysctl net.netfilter.nf_conntrack_max   # table size limit
sysctl net.netfilter.nf_conntrack_count # current entries (full table => new
                                         # connections dropped — a subtle outage)

Conntrack is the state engine behind NAT and -m state ESTABLISHED,RELATED rules. A conntrack table filling up (count nearing max, rising drops) silently drops new connections on busy boxes — a favorite "the load balancer randomly refuses connections" scenario.

Follow-up questions

Related: TCP — Theory & Mechanisms · Low-Latency & Trading Networks.