Network configuration on Linux — theory with ip, ifcfg and resolv.conf (and the IP that vanished on reboot)

In the second networks lab I got my workstation pinging the gateway at the first attempt. ip addr add, ip route add, ping, all green. I switched the computer off feeling pleased. The following week I switched it on, pinged… nothing: the card had no IP. Everything I’d configured had evaporated. The lesson: ip commands change the network now, in memory; whatever you want to survive a reboot goes in a configuration file.

In the vi article we edited ifcfg-enp2s0 without fully knowing what each line meant. Today we find out: how to look at a Linux machine’s network, how to configure it on the spot with ip and how to make it stick with ifcfg and /etc/resolv.conf. Then, in the practice, we set up a whole workstation.

This topic’s lab

Reconfiguring your own computer’s network to run tests is the fastest way to lose your internet connection. That’s why everything in this article was run in an isolated virtual lab: three machines simulated inside one Linux with network namespaces (each has its own network stack) joined by virtual cables (veth). It reproduces the IC2 lab setup: a workstation, a gateway and the lab router.

This topic's labThe workstation (enp2s0, 10.110.7.4/24) connects to the gateway (enp2s0 10.110.7.1 and enp3s0 10.110.1.7), which forwards packets to the lab router (10.110.1.1).desk 7 network: 10.110.7.0/24lab network: 10.110.1.0/24Workstationenp2s010.110.7.4/24Gatewayenp2s0 10.110.7.1enp3s0 10.110.1.7forwards (ip_forward=1)Lab routerenp2s010.110.1.1/24  the workstation's default gateway→ rest of the network
The workstation only sees its own network directly; to reach the router it needs the gateway as its default gateway.

The workstation is desk 7: its network is 10.110.7.0/24 and its IP will be 10.110.7.4. The gateway has two cards, one on each network, and forwards packets from one to the other. Every output you’ll see is real, from a single run.

Since the cards are virtual, the outputs show two details you won’t see in the lab: an @if49 suffix (the number of the card at the other end of the cable) and link-netns gateway (which machine that other end is on). Commands are run as root (# prompt): changing the network requires being an administrator. Your ping times and card numbers will differ.

Four ideas before typing

  • Interface (card): the machine’s door to a network. lo is special: the loopback, the machine itself (127.0.0.1).
  • IP address and mask: 10.110.7.4/24 says “I’m 10.110.7.4 and my network is the addresses that share the first 24 bits”. /24 is the same as the mask 255.255.255.0: 8 + 8 + 8 + 0 = 24 bits set. My network runs from 10.110.7.0 to 10.110.7.255.
  • Default gateway: the machine on my network I send everything that isn’t on my network to. Here, the gateway 10.110.7.1.
  • DNS: the server that translates names into IPs. It’s configured in /etc/resolv.conf.

How cards are named

Cards used to be called eth0, eth1 (wired) and wlan0 (wireless). The problem: the number depended on the order the system detected them at boot, and today’s eth1 could be eth0 tomorrow. Now the name says what it is and where it is:

PartMeansExample
en / wlEthernet (cable) / WLAN (wifi)
p<bus>s<slot>physical position on the PCI busenp2s0: Ethernet, bus 2, slot 0
o<index>built into the motherboardeno1
loloopback, the machine itself

So wlp9s0 is the wifi on bus 9, slot 0. The name doesn’t change from one boot to the next.

The ip command: looking at the network

The modern command is ip (from the iproute2 package). Its form is:

ip [options] object command

The object is what you’re talking about: link (the cards), address (the IPs), route (the routes). It can be shortened: address, addr and a are the same. If you give no command, show is assumed. Options go before the object: -br (brief, one line per card), -s (statistics), -c (colours). And ip address help shows the help for each object.

This is the workstation just switched on, with nothing configured:

# @lab base
# A workstation just switched on: the card exists, but it's down and has no IP
ip link                           # link object: the cards and their state
ip addr                           # address object: the same plus the IPs
ip -br addr                       # -br (brief): one line per card
ip route                          # the routing table: empty

The real session:

# ip link
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
50: enp2s0@if49: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 08:00:27:a1:07:04 brd ff:ff:ff:ff:ff:ff link-netns gateway
# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
50: enp2s0@if49: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 08:00:27:a1:07:04 brd ff:ff:ff:ff:ff:ff link-netns gateway
# ip -br addr
lo               UNKNOWN        127.0.0.1/8 
enp2s0@if49      DOWN           
# ip route

Let’s read it piece by piece:

  • ip link shows two cards: lo and enp2s0. The network card has state DOWN and UP is missing from its flags: it’s switched off.
  • ip addr repeats the same and adds the IPs: lo has 127.0.0.1/8, enp2s0 has none (there’s no inet line).
  • ip -br addr sums it up as a table: name, state, addresses.
  • ip route prints nothing: the routing table is empty. This machine doesn’t know how to get anywhere.

ip -br addr is the command you’ll use most. In one line you see whether the card is UP and what IP it has.

For the workstation to talk to the gateway it takes three steps: bring the card up, give it an IP with a mask and, to leave its network, a default gateway.

# @lab base
ip link set enp2s0 up                    # bring the card up
ip addr add 10.110.7.4/24 dev enp2s0     # IP and mask (/24 = 255.255.255.0)
ip addr show enp2s0                      # just that card
ip route                                 # the kernel has added a route by itself
ping -c 3 10.110.7.1                     # the gateway, on my own network
ping -c 1 10.110.1.1                     # the router, on ANOTHER network
ip route add default via 10.110.7.1      # default gateway: anything not on my network goes to the gateway
ip route
ping -c 3 10.110.1.1                     # now it works

The real session:

# ip link set enp2s0 up
# ip addr add 10.110.7.4/24 dev enp2s0
# ip addr show enp2s0
54: enp2s0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 08:00:27:a1:07:04 brd ff:ff:ff:ff:ff:ff link-netns gateway
    inet 10.110.7.4/24 scope global enp2s0
       valid_lft forever preferred_lft forever
# ip route
10.110.7.0/24 dev enp2s0 proto kernel scope link src 10.110.7.4 
# ping -c 3 10.110.7.1
PING 10.110.7.1 (10.110.7.1) 56(84) bytes of data.
64 bytes from 10.110.7.1: icmp_seq=1 ttl=64 time=0.342 ms
64 bytes from 10.110.7.1: icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from 10.110.7.1: icmp_seq=3 ttl=64 time=0.043 ms

--- 10.110.7.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2050ms
rtt min/avg/max/mdev = 0.043/0.149/0.342/0.136 ms
# ping -c 1 10.110.1.1
ping: connect: Network is unreachable
# ip route add default via 10.110.7.1
# ip route
default via 10.110.7.1 dev enp2s0 
10.110.7.0/24 dev enp2s0 proto kernel scope link src 10.110.7.4 
# ping -c 3 10.110.1.1
PING 10.110.1.1 (10.110.1.1) 56(84) bytes of data.
64 bytes from 10.110.1.1: icmp_seq=1 ttl=63 time=0.386 ms
64 bytes from 10.110.1.1: icmp_seq=2 ttl=63 time=0.067 ms
64 bytes from 10.110.1.1: icmp_seq=3 ttl=63 time=0.072 ms

--- 10.110.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2039ms
rtt min/avg/max/mdev = 0.067/0.175/0.386/0.149 ms

Line by line:

  1. ip link set enp2s0 up prints nothing (in Linux, silence means success), but the card now has UP,LOWER_UP: switched on and with a cable.
  2. ip addr add 10.110.7.4/24 dev enp2s0 adds the IP. ip addr show enp2s0 shows it on the inet line.
  3. ip route is no longer empty: the kernel has added the route 10.110.7.0/24 dev enp2s0 by itself. Told “I’m .4 of a /24”, it understands that the 256 addresses of that network are reached directly through enp2s0.
  4. ping -c 3 10.110.7.1 (3 packets) works: the gateway is on my network. ttl=64 is Linux’s typical starting value: the packet hasn’t crossed any router.
  5. ping -c 1 10.110.1.1 fails with Network is unreachable: the router is on another network and the table has no route that covers it. The ping doesn’t even get to send anything.
  6. ip route add default via 10.110.7.1 adds the default route: “anything you don’t know where to send, send to the gateway”.
  7. Now the router replies, with ttl=63: 64 − 1, because the packet went through a router (the gateway) on the way.

Here is the output of ip addr show taken apart:

How to read ip addr show enp2s0The real output of ip addr show enp2s0 with each part marked: number and name, flags, UP state, MAC (link/ether), IP with prefix (inet) and lifetime.54: enp2s0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP …link/ether 08:00:27:a1:07:04 brd ff:ff:ff:ff:ff:ff link-netns gatewayinet 10.110.7.4/24 scope global enp2s0valid_lft forever preferred_lft forever1number and name12flags: UP = switched on, LOWER_UP = cable present23state34the card's MAC45IP / prefix56valid forever (no DHCP lease)6
What you look at most: state UP, the link/ether line (MAC) and the inet line (IP/prefix).

Notice our inet line has no brd (broadcast address). ip only adds it if you ask with brd +, which works it out from the mask (you’ll see it in the exercises).

I want to…Command
bring the card up / downip link set enp2s0 up / down
change the MAC (with the card down)ip link set enp2s0 address 12:34:56:78:90:ab
add / remove an IPip addr add 10.110.7.4/24 dev enp2s0 / ip addr del …
remove every IP from the cardip addr flush dev enp2s0
add / remove the default gatewayip route add default via 10.110.7.1 / ip route del default
see which path a packet would takeip route get 10.110.1.1

Forgetting the /24. ip addr add 10.110.7.4 dev enp2s0 sets /32: a network of a single address. The network route isn’t created and not even the gateway replies. You’ll see it live in the exercises.

Undoing: removing the IP and bringing the card down

Knowing what happens when you remove things matters just as much. We start from the configured workstation:

# @lab conf
ip addr del 10.110.7.4/24 dev enp2s0     # remove the IP
ip route                                 # the routes that depended on it go too
ip addr add 10.110.7.4/24 dev enp2s0     # we put it back
ip link set enp2s0 down                  # and now we bring the card down
ip -br addr                              # the IP is still there, but the card is DOWN
ip route
ping -c 1 10.110.7.1

The real session:

# ip addr del 10.110.7.4/24 dev enp2s0
# ip route
# ip addr add 10.110.7.4/24 dev enp2s0
# ip link set enp2s0 down
# ip -br addr
lo               UNKNOWN        127.0.0.1/8 
enp2s0@if61      DOWN           10.110.7.4/24 
# ip route
# ping -c 1 10.110.7.1
ping: connect: Network is unreachable

Two surprising things:

  • When you remove the IP with ip addr del, ip route ends up empty: the network route and the default route depended on that IP and the kernel deletes them with it. If you put the IP back, the default gateway has to be added again.
  • When you bring the card down with ip link set enp2s0 down, the IP stays (ip -br addr shows it next to DOWN), but the routes disappear and ping fails with Network is unreachable. A card that’s down is like an unplugged cable.

ifconfig and route: the old commands

In plenty of notes, tutorials and older machines you’ll see ifconfig and route (net-tools package). They’re obsolete, but worth being able to read. With the workstation configured:

# @lab conf
# The old commands (net-tools package) still work on many machines
ifconfig enp2s0                   # the same as ip addr show enp2s0, in another format
route -n                          # the same as ip route, as a table

The real session:

# ifconfig enp2s0
enp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.110.7.4  netmask 255.255.255.0  broadcast 0.0.0.0
        ether 08:00:27:a1:07:04  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.110.7.1      0.0.0.0         UG    0      0        0 enp2s0
10.110.7.0      0.0.0.0         255.255.255.0   U     0      0        0 enp2s0

ifconfig gives the same information in another format: inet and netmask separately (the mask written out in full, 255.255.255.0), ether for the MAC, and packet counters. The broadcast 0.0.0.0 is what we mentioned: we didn’t ask for a broadcast address. route -n shows the routing table: the 0.0.0.0 line with Gateway 10.110.7.1 and the G flag is the default route; the 10.110.7.0 line with U and no gateway is the directly connected network. -n asks for numbers instead of names.

net-tools (old)iproute2 (current)
ifconfigip addr (ip a)
ifconfig enp2s0 upip link set enp2s0 up
ifconfig enp2s0 192.168.0.2 netmask 255.255.255.0ip addr add 192.168.0.2/24 dev enp2s0
route -nip route
route add default gw 10.110.7.1ip route add default via 10.110.7.1

Temporary versus permanent

Everything we’ve done with ip lives in the kernel’s memory: it works instantly and disappears on reboot (the story at the start). To make the configuration permanent it’s written to files the system reads at boot:

Temporary versus permanent configurationOn the left, ip commands change the kernel's configuration straight away but it is lost on reboot. On the right, the ifcfg and resolv.conf files are read at boot and issue the same commands again.TEMPORARYip commands (or ifconfig)  change the kernel's configuration, in memory  take effect at once  lost on rebootPERMANENTconfiguration filesifcfg-enp2s0: IP, mask, gateway, ONBOOT/etc/resolv.conf: DNS serversapplied at boot (or with systemctl restart network)kernelat boot, if ONBOOT=yes
With ip you test; with the ifcfg you make it stick. The usual way: test with ip and, once it works, write it to the file.

On CentOS (the system used in the labs), each card has its own file /etc/sysconfig/network-scripts/ifcfg-<name>. This is our workstation’s, with the values we just tested by hand:

# @lab conf
cat ifcfg-enp2s0                  # the permanent configuration (on CentOS, in /etc/sysconfig/network-scripts/)
cat /etc/resolv.conf              # the DNS servers that get asked
cat /etc/hosts                    # names resolved without asking anyone
ping -c 2 router                  # a name instead of an IP

The real session:

# cat ifcfg-enp2s0
DEVICE=enp2s0
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.110.7.4
NETMASK=255.255.255.0
GATEWAY=10.110.7.1
# cat /etc/resolv.conf
nameserver 193.145.147.22
nameserver 193.145.138.100
nameserver 193.145.138.200
# cat /etc/hosts
127.0.0.1 localhost
10.110.7.4 workstation
10.110.7.1 gateway
10.110.1.1 router
# ping -c 2 router
PING router (10.110.1.1) 56(84) bytes of data.
64 bytes from router (10.110.1.1): icmp_seq=1 ttl=63 time=0.372 ms
64 bytes from router (10.110.1.1): icmp_seq=2 ttl=63 time=0.065 ms

--- router ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1025ms
rtt min/avg/max/mdev = 0.065/0.218/0.372/0.153 ms

The ifcfg keys:

KeyWhat it saysValues
DEVICEthe card’s nameenp2s0
BOOTPROTOwhere the IP comes fromnone (the one in the file), dhcp (a server hands it out), bootp
ONBOOTwhether it’s brought up at bootyes / no
IPADDRthe IP10.110.7.4
NETMASKthe mask (or PREFIX=24)255.255.255.0
GATEWAYthe default gateway10.110.7.1
NETWORKthe network address (optional)10.110.7.0

After editing the file (with vi, of course), you apply it by restarting the network service: systemctl restart network. In the lab, NetworkManager is also stopped and disabled (systemctl stop NetworkManager and systemctl disable NetworkManager) so it doesn’t override the configuration in the files.

This article’s lab isn’t CentOS, so systemctl restart network wasn’t run: the file is shown as text. In the practice we write a script that does exactly what that service does with each ifcfg, and we really run it.

The other two files in the session:

  • /etc/resolv.conf: one nameserver line per DNS server, tried in order. These are the university’s.
  • /etc/hosts: names the machine resolves on its own, without asking any DNS. That’s why ping -c 2 router works: the system checks /etc/hosts first, finds 10.110.1.1 router and pings that IP (the output says PING router (10.110.1.1)).

ping: proof there’s a network

ping sends ICMP “echo” packets and waits for the reply. What to look at:

In the outputMeans
64 bytes from 10.110.7.1: icmp_seq=1 ttl=64 time=0.342 msit replied; ttl drops by 1 for every router crossed; time is the round trip
3 packets transmitted, 3 received, 0% packet lossthe summary: none were lost here
connect: Network is unreachableno route: the IP, the mask or the default gateway is missing
Destination Host Unreachablethere’s a route, but the machine the packet must be handed to on your local network doesn’t answer (or doesn’t exist)

On Linux, ping doesn’t stop by itself: use -c N to send N packets, or Ctrl-C to stop it.

Common mistakes

ip addr add 10.110.7.4 dev enp2s0 sets /32. Always write /24 (or whatever prefix applies).

The IP is set correctly but the card is still DOWN. First ip link set enp2s0 up.

The gateway has to be directly reachable. ip route add default via 10.110.1.1 from the workstation gives Error: Nexthop has invalid gateway.

What you do with ip vanishes on reboot. Once it works, move it to the ifcfg and set ONBOOT=yes.

Commands that change something give Operation not permitted. Looking, you can do as a normal user.

Try it in your terminal

These commands are safe: they only look, and you can run them on your own Linux without worry. This is how they came out on the workstation, as a normal user ($ prompt):

# @lab conf
# @sergio
ip -br addr                              # looking doesn't need root
ip route
ping -c 3 127.0.0.1                      # lo: the machine itself
ip addr add 10.110.7.9/24 dev enp2s0     # changing does

The real session:

$ ip -br addr
lo               UNKNOWN        127.0.0.1/8 
enp2s0@if69      UP             10.110.7.4/24 
$ ip route
default via 10.110.7.1 dev enp2s0 
10.110.7.0/24 dev enp2s0 proto kernel scope link src 10.110.7.4 
$ ping -c 3 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.233 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.043 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.050 ms

--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2044ms
rtt min/avg/max/mdev = 0.043/0.108/0.233/0.087 ms
$ ip addr add 10.110.7.9/24 dev enp2s0
RTNETLINK answers: Operation not permitted

What to watch for:

  1. ip -br addr and ip route work without root: querying the network needs no permissions. On your machine you’ll see your own cards (probably a wlp… one if you’re on wifi).
  2. In your ip route, the default via … line is your home or university router: your default gateway.
  3. ping -c 3 127.0.0.1 always works if the network stack is alive: it’s the machine itself, through lo. The times are tiny.
  4. The last command tries to change something and the kernel refuses: RTNETLINK answers: Operation not permitted. Don’t run it with sudo on your computer unless you want to really change your network.
  5. Also try cat /etc/resolv.conf: on many desktop Linux systems you’ll see nameserver 127.0.0.53, a local middleman (systemd-resolved) that forwards queries to the real DNS servers.

Summary

ConceptThe essentials
Namesenp2s0 = Ethernet, bus 2, slot 0; wl… wifi; lo the machine itself
Lookingip -br addr, ip link, ip route, ip route get IP
Configuring on the spotip link set X up, ip addr add IP/24 dev X, ip route add default via GW
Undoingip addr del, ip addr flush dev X, ip route del default, ip link set X down
Old onesifconfig, route -n (net-tools, obsolete)
Permanentifcfg-X (BOOTPROTO, ONBOOT, IPADDR, NETMASK, GATEWAY) + systemctl restart network; DNS in /etc/resolv.conf
Checkingping -c N: ttl, % packet loss, Network is unreachable

Three ideas to take away:

  1. Three steps to get a network: card up, IP with a mask, default gateway (on your network).
  2. ip changes the network instantly and in memory; the ifcfg with ONBOOT=yes makes it stick.
  3. When something fails, check in order: ip -br addr (UP? IP/prefix?), ip route (default?), ping the gateway and then further away.

In the network configuration practice we bring the workstation up step by step, fix a misconfigured one and turn the ifcfg into commands with a script. This topic closes the practical Linux part of IC2; next comes the networking theory behind all of this.

Next step: practiceNetwork configuration on Linux — practice with a workstation from scratch, a misconfigured one and a script that reads the ifcfg (and a ping that only got halfway)

Did this article help you? Here is how you can support SergioLearns →

Sigue aprendiendo

Leave a Reply

Your email address will not be published. Required fields are marked *