Przewidywalne nazwy interfejsów sieciowych

Spis treści

Podczas jednej z aktualizacji systemu został mi zwrócony pewien komunikat. Oświadczał on bowiem, że od jakiegoś czasu nazewnictwo interfejsów sieciowych w systemie uległo zmianie, oraz, że w wersji 10 debiana, ten obecny system nazw nie będzie już wspierany. Rozchodzi się o coś co nazywa się Predictable Network Interface Names, czyli przewidywalne nazwy interfejsów sieciowych. Jako, że aktualne wydanie stabilnego debiana ma numerek 8 i w niedalekiej przyszłości zostanie wydana 9, to przydałoby się już zacząć migrować na ten nowy system nazw. W tym wpisie dokonamy takiej migracji i zobaczymy jakie zmiany musimy poczynić, by nie doświadczyć problemów związanych z tą migracją nazw.

Nazwy interfejsów sieciowych i problemy z nimi związane

Wszystkie narzędzia sieciowe, począwszy od ifconfig czy ip skończywszy na zaporach sieciowych, np. iptables , operują na interfejsach sieciowych. Zwykle mamy eth* dla połączeń przewodowych i wlan* dla bezprzewodowych. Są oczywiście i inne ale problem dotyczy głównie tych wymienionych wyżej.

Co się dzieje w przypadku gdy podłączamy do komputera nową kartę sieciową? Po jej wykryciu system nada jej odpowiedni numerek interfejsu. Jaki numerek zapytacie? No i to jest właśnie dobre pytanie i nikt na dobrą sprawę nie zna na nie odpowiedzi. Może się zatem zdarzyć tak, że mając dwie karty sieciowe, ich interfejsy się zamienią. By przeciwdziałać takim niepożądanym zmianom nazw, został obmyślony mechanizm przepisywania ich przy pomocy udev . Jeśli zajrzymy do katalogu /etc/udev/rules.d/ , to mamy w nim min. plik 70-persistent-net.rules . W nim jest kilka regułek, które zależą od tego jaki sprzęt podpinaliśmy do naszego komputera. Poniżej przykład takiej reguły:

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:e0:4c:75:13:09", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

W skrócie, karcie sieciowej mającej adres MAC 00:e0:4c:75:13:09 zostanie przypisany interfejs eth0 . Jeśli byśmy podłączyli drugą kartę sieciową, to będzie ona miła inny numerek niż ma eth0 , prawdopodobnie będzie to eth1 , itd. W taki sposób, mamy mniej więcej pewność, że każda karta ma stały interfejs.

Co zatem jest złego w tym sposobie przepisywania nazw, przecież mamy przewidywalne nazwy interfejsów? Co jest nie tak z tym mechanizmem, że trzeba go zastąpić nowym? Odpowiedź możemy znaleźć czytając plik /usr/share/doc/udev/README.Debian.gz , w którym mamy informację, że w pewnych sytuacjach mogą wystąpić kolizje nazw interfejsów, w wyniku których mogą się pojawić nazwy takie jak rename1 . By temu przeciwdziałać, trzeba zapisywać pewne informacje w katalogu /etc/ , co nie jest możliwe gdy partycja / jest w trybie tylko do odczytu. Poza tym ten mechanizm nie działa w ogóle w środowiskach wirtualnych. W pliku README.Debian.gz mamy także instrukcję dotyczącą przeprowadzenia migracji nazw interfejsów sieciowych, zatem do dzieła.

Migracja na nowy system nazw

Może i zostało nam jeszcze trochę czasu do momentu, gdy debian przestanie wspierać stare nazwy interfejsów sieciowych ale po co czekać do samego końca? Przeprowadzając migrację nazw w tym momencie oszczędzimy sobie sporo nerw związanych z robieniem wszystkiego na ostatnią chwilę.

Na początek musimy ustalić jakie interfejsy mamy w swoim systemie. Możemy tego dokonać na kilka sposobów. Najprościej jest zwyczajnie zajrzeć do pliku /etc/udev/rules.d/70-persistent-net.rules , no bo przecie są tam reguły dotyczące wszystkich kart sieciowych, które kiedykolwiek podpięliśmy do naszej maszyny. Możemy także zajrzeć do katalogu /sys/class/net/ lub zwyczajnie podejrzeć aktualne interfejsy via ip link czy ifconfig .

Teraz musimy ustalić w jakich plikach konfiguracyjnych w katalogu /etc/ mamy odwołania do tych poszczególnych interfejsów. Na pewno jest to konfiguracja sieciowa ale oprócz tego, mogą to być także skrypty startowe, czy też reguły iptables. Nie bez znaczenia może być także zwykła konfiguracja poszczególnych aplikacji. By ustalić, które pliki wymagają zmian, logujemy się na konto root i wydajemy w terminalu to poniższe polecenie dostosowując je pod kątem nazwy interfejsu:

# grep -r eth0 /etc/

Wszystkie te pliki, które zostaną wypisane, trzeba będzie odpowiednio przerobić. Oczywiście zwracajmy uwagę na komentarze. Jest tylko jeden problem, mianowicie nie wiemy jakie będą nowe nazwy interfejsów. By to ustalić musimy usunąć plik z regułami udev'a ( /etc/udev/rules.d/70-persistent-net.rules ). Dodatkowo na wszystkich maszynach wirtualnych musimy także usunąć plik /etc/udev/rules.d/80-net-setup-link.rules . Regenerujemy teraz initramfs przy pomocy tego poniższego polecenia:

# update-initramfs -u -k all

Po czym uruchamiamy ponowne komputer. Po załadowaniu się systemu, dostosowujemy całą konfigurację w oparciu o nowe nazwy interfejsów sieciowych. W moim przypadku pojawiły się enp2s0 (przewodowy) i wlp3s0b1 (bezprzewodowy). Jeśli mamy obecny w systemie pakiet ifrename , to możemy go bez problemu odinstalować.

Nowe nazwy interfejsów

W stosunku do starych nazw, tj. eth0 czy wlan1 , nazwy takie jak wlp3s0b1 mogą nieco przytłoczyć. Wyjaśnienie struktury tych nazw znajduje się tutaj. Jeśli komuś się nie chce zaglądać do przytoczonego linka, to warto nadmienić, że interfejsy przewodowe zawsze zaczynają się od en* , a bezprzewodowe od wl*. Pozostała część nazwy będzie stała dla konkretnej maszyny.

Warto też dodać, że jest kilka schematów nadawania nazw interfejsom sieciowym. Możemy wyróżnić nazwy w oparciu o fizyczne położenie ( path ). Są też nazwy interfejsów w oparciu o adres MAC ( mac ) czy też nazwy zwracane przez sterownik karty ( onboard ). Naturalnie jest jeszcze więcej polityk nadawania nazw ale zwykle z tymi powyższymi typami nazw będziemy mieli największą styczność.

Wszystkie aktualnie rozpoznane interfejsy w systemie są do wglądu w katalogu /sys/class/net/ . Weźmy sobie przykładowo interfejs wlan1 . Jego alternatywne nazwy są przechowywane w zmiennych udev'a i w zależności od wybranej polityki są one aplikowane. Poniżej znajdują się przykładowe nazwy dla tego interfejsu:

$  udevadm info /sys/class/net/wlan1
...
E: ID_NET_NAME=wlan1
E: ID_NET_NAME_MAC=wlxe8de271d4ca5
E: ID_NET_NAME_PATH=wlp0s29u1u3

Nazwy oparte o MAC i PATH nie są zbytnio przyjazne użytkownikowi ale to nie stanowi praktycznie żadnego problemu, bo nikt nas nie zmusza do korzystania z nich. Nazwę praktycznie każdego interfejsu jesteśmy w stanie bez problemu przepisać na dowolną. By tego dokonać, musimy stworzyć sobie plik /etc/systemd/network/05-wlan1.link i dodać w nim tę poniższą treść:

[Match]
MACAddress=e8:de:27:1d:4c:a5

[Link]
Description=Wireless interface configuration (wlan1)
Name=wlan1

W tym przypadku mamy do czynienia z kartą USB, dlatego lepiej nie korzystać ze ścieżki, bo ta może ulec zmianie. Można natomiast wykorzystać adres MAC tego urządzenia, bo ten zwykle jest niepowtarzalny i stały dla konkretnej karty.

Parametry net.ifnames= oraz biosdevname=

W nowszych wydaniach dystrybucji Debian lepszym rozwiązaniem zdaje się być skorzystanie z parametru net.ifnames= lub biosdevname= . Jaka jest różnica między tymi dwiema opcjami?

Parametr biosdevname= jest przeznaczony do wykorzystania wszędzie tam gdzie jest zainstalowane stosowne oprogramowanie od deweloperów DELL'a mające na celu wspomagać UDEV'a przy przepisywaniu nazw interfejsów sieciowych, tak by były one konsekwentne i niezmienne w czasie.

Niemniej jednak, w Debianie nie ma tego oprogramowania i na dobrą sprawę nie jest ono potrzebne, przynajmniej tam, gdzie mamy do czynienia z systemd. Systemd posiada własny mechanizm przepisywania nazw interfejsów sieciowych i do jego kontroli służy właśnie ten drugi z powyżej wymienionych parametrów, tj. net.ifnames= . Domyślnie mechanizm przepisywania tych nazw jest włączony i dlatego na świeżo postawionym systemie nie uświadczymy interfejsów typu wlan0 czy eth0 .

Jeśli nie podobają nam się nowe nazwy interfejsów sieciowych albo też zwyczajnie ich nie potrzebujemy, bo nasz system posiada tylko jeden interfejs przewodowy i bezprzewodowy, to dla uproszenia możemy ten mechanizm przepisywania nazw wyłączyć dopisując w konfiguracji bootloader'a (np. GRUB) net.ifnames=0 (ten drugi parametr można pominąć).

Mikhail Morfikov avatar
Mikhail Morfikov
Po ponad 10 latach spędzonych z różnej maści linux'ami (Debian/Ubuntu, OpenWRT, Android) mogę śmiało powiedzieć, że nie ma rzeczy niemożliwych i problemów, których nie da się rozwiązać. Jedną umiejętność, którą ludzki umysł musi posiąść, by wybrnąć nawet z tej najbardziej nieprzyjemniej sytuacji, to zdolność logicznego rozumowania.