Konfiguracja interfejsów sieciowych

Współczesne komputery rzadko kiedy pracują w całkowitej izolacji od innych urządzeń tego typu. Nadzorujące ich pracę systemy operacyjne są przygotowane do zapewnienia komunikacji sieciowej między tymi urządzeniami, jeśli tylko zostały one wyposażone w modemy, adaptery sieciowe typu Ethernet, Wi-Fi, Bluetooth, itp., a jądro dysponuje odpowiednimi modułami obsługi tych urządzeń.

Od wielu już lat jądro systemu Linux wspiera komunikację sieciową w ramach protokołów IPv4 i IPv6, ale od kilku lat obsługa IPv6 jest domyślnie włączona, co – dzięki dostępnej w ramach tego protokołu autokonfiguracji – pozwala na natychmiastową komunikację hostów w ramach lokalnej sieci komputerowej (wykorzystywane są do tego specjalne adresy łącza lokalnego).

W ostatnich latach nastąpiło także ujednolicenie sposobu konfiguracji interfejsów, niezależnie od używanej dystrybucji Linuksa. Stało się to dzięki zastosowaniu do tego celu NetworkManagera, który nie tylko pozwala na łatwą konfigurację interfejsów ethernetowych, ale także dobrze radzi sobie z konfiguracją interfejsów innych sieci (DSL, Wi-Fi, szerokopasmowych sieci bezprzewodowych, InfiniBand). Ogromnym ułatwieniem w konfiguracji sieci są dostępne w większości dystrybucji graficzne interfejsy do programu NetworkManager, ale administrator systemu komputerowego nie może na nich polegać i z nich korzystać, bo zwykle serwery nie pracują w trybie graficznym. Dlatego poniżej konfigurowanie interfejsów i sieci jest realizowane przy wykorzystaniu komend nmcli oraz ip (zamiast ip można korzystać z ifconfig, ale ta komenda jest uznawana za przestarzałą; jesteśmy na nią skazani konfigurując sieć w starszych wersjach systemu operacyjnego). We wcześniejszych wersjach dystrybucji, takich jak Red Hat, CentOS, Fedora i podobnych, do zarządzania interfejsami był używany skrypt /etc/rc.d/init/network.

Zob. Podstawowe informacje o protokołach IPv4 i IPv6 można znaleźć w notatkach do wykładu: Sieci komputerowe.

Nazwy interfejsów

systemd używa domyślnie następującego schematu przydzielania nazw interfejsom sieciowym (przy założeniu, że obsługa podsystemu biosdevname jest wyłączona, tj. biosdevname=0; biosdevname jest pomocniczym programem użytkowym dla udev, opracowanym przez firmę Dell (na licencji GPL), który dostarcza spójnego mechanizmu nadawania nazw urządzeniom sieciowym na podstawie ich fizycznego położenia udostępnianego przez BIOS):

  1. nazwy urobione wg informacji pozyskanych z oprogramowania firmowego lub BIOS-u (np. eno1); w przeciwnym razie nazwy wg schematu 2

  2. nazwy urobione wg informacji pozyskanych z oprogramowania firmowego lub BIOS-u o położeniu urządzenia na szynie PCI (np. ens1); w przeciwnym razie nazwy wg schematu 3

  3. nazwy urobione wg informacji o fizycznym położeniu NIC na płycie głównej (np. enp2s0); w przeciwnym razie nazwy wg schematu 5

  4. nazwy urobione wg adresu MAC (np. enx78e7d1ea46da) nie sa stosowane, ale są dostępne na życzenie użytkownika

  5. tradycyjny, nieprzewidywalny schemat nazewniczy, jeśli inne zawiodły (np. eth0)

Nazwy interfejsów sieciowych są zależne od ich typu i poprzedzone prefiksami:

  • en – Ethernet

  • wl – wireless LAN (WLAN)

  • ww – wireless wide area network (WWAN)

Pozostała część nazwy zależy od typu urządzenia:

Format

Description

o<index>

on-board device index number

s<slot>[f<function>][d<dev_id>]

hotplug slot index number

x<MAC>

MAC address

p<bus>s<slot>[f<function>][d<dev_id>]

PCI geographical location

p<bus>s<slot>[f<function>][u<port>] [..][c<config>][i<interface>]

USB port number chain


Kilka przykładów wyznaczania nazw:

System

device

biosdevname -i device

lspci

Dell

em1

em1

Dell

p2p1

p2p1

Supermicro

eno1

em1

SunFire X4200

enp134s1f0

em1

86:01.0 … Gigabit …

SunFire X4200

enp134s1f1

em2

86:01.1 … Gigabit …

SunFire X4200

enp132s0

p1p1

84:00.0 … 10-Gigabit …

SunFire X4440

enp3s0

p1p1

03:00.0 … 10-Gigabit …


Nazwy wg biosdevname (schemat stosowany domyślnie dla systemów firmy Dell oraz gdy biosdevname został explicite włączony):

Urządzenie

Stara nazwa

Nowa nazwa

Przykład

Embedded NIC

eth[0123…]

em[1234…]

PCI NIC

eth[0123…]

p<slot>p<ethernet port>

p2p1, p2p2

Jeśli nie chcemy modyfikować konfiguracji udev w celu zmiany nazwy interfejsu sieciowego, to można tę nazwę zmienić korzystając z komendy ip, np.:

# ip link set eth1 down
# ip link set eth1 name em2
# ip link set em2 up

Tę samą zmianę nazwy interfejsu sieciowego, ale w sposób trwały można uzyskać poprzez zastosowanie następujących komend:

# echo 'ACTION=="add", SUBSYSTEM=="net", DRIVERS=="?*", ATTR{address}=="54:52:00:10:00:02", NAME="em2"' \
                                                                 > /etc/udev/rules.d/70-persistent-net.rules

# (modprobe -r virtio_net; modprobe virtio_net)&

Oczywiście w powyższym przykładzie adres MAC trzeba zastąpić adresem właściwym dla interfejsu, którego nazwę zmieniamy. Także nazwę modułu do obsługi danego rodzaju interfesju, który trzeba wyładować i ponownie załadować, należy dostosować do systemu komputerowego (np. interfejsy gigabitowe firmy Intel będą obsługiwane przez moduł e1000).

Konfiguracja interfejsów w IPv4

Każda z maszyn wirtualnych dysponuje dwoma adapterami ethernetowymi; zob. lspci. Przy pomocy komendy lspci można także określić moduł używany przez jądro do obsługi konkretnego urządzenia:

[root@centos7-2 ~]# lspci -v -s 00:03.0
00:03.0 Ethernet controller: Red Hat, Inc Virtio network device
        Subsystem: Red Hat, Inc Device 0001
        Physical Slot: 3
        Flags: bus master, fast devsel, latency 0, IRQ 10
        I/O ports at c0a0 [size=32]
        Memory at febf1000 (32-bit, non-prefetchable) [size=4K]
        Expansion ROM at febd0000 [disabled] [size=64K]
        Capabilities: [40] MSI-X: Enable+ Count=3 Masked-
        Kernel driver in use: virtio-pci
        Kernel modules: virtio_pci

Komenda lsmod | grep virtio_pci potwierdza obecność wskazanego modułu w jądrze.

Komendy ifconfig (w nowszych wersjach systemu już jej nie ma) oraz ip pokazują dostępne w systemie interfejsy sieciowe i ich konfigurację:

# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.142.2  netmask 255.255.255.0  broadcast 192.168.142.255
        inet6 fe80::5652:ff:fe01:2  prefixlen 64  scopeid 0x20<link>
        ether 54:52:00:01:00:02  txqueuelen 1000  (Ethernet)
        RX packets 74615  bytes 26271654 (25.0 MiB)
        RX errors 0  dropped 9  overruns 0  frame 0
        TX packets 6380  bytes 642702 (627.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 54:52:00:10:00:02  txqueuelen 1000  (Ethernet)
        RX packets 66956  bytes 3481944 (3.3 MiB)
        RX errors 0  dropped 41857  overruns 0  frame 0
        TX packets 14321  bytes 2540790 (2.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

 lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        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
# ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    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
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 54:52:00:01:00:02 brd ff:ff:ff:ff:ff:ff
    inet 192.168.142.2/24 brd 192.168.142.255 scope global dynamic eth0
       valid_lft 2369sec preferred_lft 2369sec
    inet6 fe80::5652:ff:fe01:2/64 scope link
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
       link/ether 54:52:00:10:00:02 brd ff:ff:ff:ff:ff:ff

Wykorzystując interfejs eth1 można połączyć ze sobą maszyny wirtualne w odrębną, wydzieloną sieć (sieci). W tym celu trzeba wykonać następujące czynności:

  • sprawdzić, czy interfejs eth1 jest prawidłowo podłączony do urządzenia sieciowego (przełącznika)

    # ethtool eth1
    Settings for eth1:
            Link detected: yes
    
  • przypisać interfejsowi statyczny adres z puli 10.0.0.0/24:

    # ip address add 10.0.0.1/24 dev eth1
    

    Przypisanie adresu do interfejsu wg powyższego przepisu jest równoznaczne z wykonaniem komendy ip link set dev eth1 up. Jak wygląda stan interfejsu i tablica routing po wykonaniu komendy ip link set dev eth1 down?

  • sprawdzić, czy host widzi bramę sieci oraz inne hosty w tej samej sieci

    # ping -c 1 10.0.0.254
    PING 10.0.0.254 (10.0.0.254) 56(84) bytes of data.
    64 bytes from 10.0.0.254: icmp_seq=1 ttl=64 time=0.103 ms
    
    --- 10.0.0.254 ping statistics ---
    1 packets transmitted, 1 received, 0% packet loss, time 0ms
    rtt min/avg/max/mdev = 0.103/0.103/0.103/0.000 ms
    
  • sprawdzić tablicę routingu

    # ip route [show]
    default via 192.168.142.254 dev eth0  proto static  metric 100
    10.0.0.0/24 dev eth1  proto kernel  scope link  src 10.0.0.1
    192.168.142.0/24 dev eth0  proto kernel  scope link  src 192.168.142.1  metric 100
    

Zob. Przykłady użycia komendy ip.

W jaki sposób trwale przypisać adres do interfejsu?

W najnowszych wersjach systemu operacyjnego Linux (niezależnie od używanej dystrybucji) za obsługę sieci jest odpowiedzialna oddzielna usługa systemowa o nazwie NetworkManager. Do zarządzania tą usługą służy komenda nmcli:

# nmcli con show [--active]
NAME                UUID                                  TYPE            DEVICE
System eth0         5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03  802-3-ethernet  eth0
Wired connection 1  bc674f80-f9b7-3850-bb79-df4207e13099  802-3-ethernet  eth1

Przy jej pomocy można skonfigurować interfejs eth1 w następujący sposób:

# nmcli con delete [UUID] bc674f80-f9b7-3850-bb79-df4207e13099
Connection 'Wired connection 1' (bc674f80-f9b7-3850-bb79-df4207e13099) successfully deleted.

# cd /etc/sysconfig/network-scripts
# cat <<EOF > ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.111.0.1
PREFIX=24
DEFROUTE=no
DOMAIN="fizyka.umk.pl"
EOF

# nmcli con load /etc/sysconfig/network-scripts/ifcfg-eth1

Interfejs może być wyłączany/włączany przy pomocy komendy ifdown|ifup eth1, ale lepiej użyć komendy nmcli con down|up id 'System eth1' lub nmcli con down|up UUID, gdzie UUID jest identyfikatorem połączenia, które wyświetla komenda nmcli con.

Prosta modyfikacja pliku ifcfg-eth1 pozwala na przypisanie do interfejsu więcej niż jednego adresu, np.

# cat <<EOF > ifcfg-eth1
DEVICE=eth1
BOOTPROTO=static
ONBOOT=yes
IPADDR1=10.111.0.1
PREFIX1=24
IPADDR2=192.168.242.1
PREFIX2=24
DEFROUTE=no
EOF

# nmcli con load /etc/sysconfig/network-scripts/ifcfg-eth1

Opis wszystkich możliwych zmiennych, które mogą pojawić się w plikach konfigurujących interfejsy znajduje się w pliku /usr/share/doc/initscripts-9.49.37/sysconfig.txt.

Jeśli w sieci działa serwer DHCP, to interfejs eth1 można skonfigurować przy pomocy komendy:

# nmcli connection add type ethernet con-name 'System eth1 via dhcp' ifname eth1

W wyniku działania tej komendy powstaje plik ifcfg-System_eth1_via_dhcp o następującej zawartości:

# cat ifcfg-System_eth1_via_dhcp
TYPE=Ethernet
BOOTPROTO=dhcp
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME="System eth1 via dhcp"
UUID=e46f6d9f-b6dd-4ccc-af0f-b267e6b4b57e
DEVICE=eth1
ONBOOT=yes

Zob. Przykłady użycia komendy nmcli.

Instalacja i konfiguracja serwera DHCP

Zob. Instalacja i konfiguracja serwera DHCP.

Konfiguracja interfejsów w IPv6

Zob. Konfiguracja interfejsów w IPv6.

Testowanie IPv6 – tunel Hurricane Electric

Firma Hurricane Electric (https://he.net/) pozwala na utworzenie (bez opłat) do pięciu tuneli pozwalających na dostęp do sieci IPv6.

Załóżmy, że został utworzony następujacy tunel:

IPv6 Tunnel Endpoints
   Server IPv4 Address:216.66.80.162
   Server IPv6 Address:2001:470:70:130::1/64
   Client IPv4 Address:158.75.5.233
   Client IPv6 Address:2001:470:70:130::2/64
Routed IPv6 Prefixes
   Routed /64:2001:470:71:130::/64
   Routed /48:2001:470:60be::/48

W celu skorzystania z tego tunelu należy na serwerze (158.75.5.233) wykonać następujące komendy:

ip tunnel add he-ipv6 mode sit remote $remoteIP local $localIP

ip link set he-ipv6 up
ip addr add $localIPv6 dev he-ipv6
ip route add ::/0 dev he-ipv6

sysctl net.ipv4.conf.he-ipv6.route_localnet=1
sysctl net.ipv6.conf.all.forwarding=1

gdzie $remoteIP (216.66.80.162) wskazuje na koniec tunelu po stronie HE, a $localIP (158.75.5.233) - po stronie klienta.

Pierwsza z komend tworzy tunel, druga go aktywuje, a trzecia przypisuje adres IPv6 po stronie klienta, tj. $localIPv6 (2001:470:70:130::2/64). Trzeba także powiadomić jądro, żeby serwer mógł działać jako router IPv6.

W tym celu trzeba dodatkowo przygotować plik konfiguracyjny dla usługi radvd.service:

interface $device
{
   AdvSendAdvert on;
   MinRtrAdvInterval 30;
   MaxRtrAdvInterval 100;
   prefix 2001:470:71:130::/64
   {
        AdvOnLink on;
        AdvAutonomous on;
        AdvRouterAddr off;
        AdvValidLifetime 300;
        AdvPreferredLifetime 30;
    };
 };

A następnie uruchomić usługę radvd rozgłaszającą zdefiniowane prefiksy sieci IPv6 (router advertisement daemon for IPv6): systemct start radvd.

Komunikację w ramach sieci IPv6 można sprawdzić przy pomocy komendy ping6:

# ping6 -c5 www.ipv6tf.org
# ping6 -c5 e2867.dsca.akamaiedge.net
# ping6 -c5 ipv6.google.com