読者です 読者をやめる 読者になる 読者になる

雑木林

頭の中の整理と忘れないための確認メモ

CentOS7におけるNIC命名ルール

前回、CentOS6におけるNICの命名ルールを記載しましたが、CentOS7では少し(?)変更されています。ということで今回はCentOS7のNIC命名規則ならびに固定に必要な手続きについて記載します。

前回同様に、簡単にまとめると以下の流れでデバイスが作成されます。

  1. ifcfg-XXXに記載されているMACアドレスと実アドレスを比較して、マッチすればファイルに記載されているデバイス名を設定する。
  2. 71-biosdevname.rulesからbioddevnameコマンドが実行され、SMBIOS(System Management BIOS)から読み取った情報を用いて、デバイス名を設定(変更)する。
  3. 75-net-description.rulesからNICの属性情報(実装位置やMACアドレスなど)を取得する。
  4. 80-net-name-slot.rulesからNICの実装位置に基づいてデバイス名を設定(変更)する。
  5. 99-systemd.rulesから最終的なデバイス名を設定する。

Predictable Network Interface Names

CentOS5.xや6.xではNICデバイス名はethXという名称が使われるのが一般的でしたが、udevのバージョン197より予測可能なネットワークインタフェース名に設定されるようになり、enoXやenpXが使われるようになりました。デバイス名は接頭語ならびにデバイス種別によって決まります。

接頭語の例

接頭語
Ethernet en
Wireless LAN wl
Wireless WAN ww

デバイス種別の例(上のものが優先される)

デバイス種別
オンボード o<index>
ホットプラグ s<slot>[f<function>][d<dev_id>]
PCIデバイス p<bus>s<slot>[f<function>][d<dev_id>]
USBデバイス p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
MACアドレス x<MAC>

詳しい内容はfreedesktop.orgPredictableNetworkInterfaceNamesRed Hat8.3. Understanding the Predictable Network Interface Device Namesに記載されてます。

CentOS7におけるNIC命名規則

CentOS7.xのNICのデバイス命名付与規則は以下のようになっています。

(1) /usr/lib/udev/rules.d/60-net.rules

ACTION=="add", SUBSYSTEM=="net", DRIVERS=="?*", ATTR{type}=="1", PROGRAM="/lib/udev/rename_device", RESULT=="?*", NAME="$result"

Cent6.xとの違いはローカルループバック(lo)やホットプラグに関する挙動が異なっていますが、/lib/udev/rename_deviceが実行され、/etc/sysconfig/network-scripts/ifcfg-XXXに記載されているMACアドレス(HWADDR)を比較し、マッチすれば該当するデバイス名(DEVICE)を付与するという挙動は同じです。


(2) /lib/udev/rules.d/71-biosdevname.rules

SUBSYSTEM!="net", GOTO="netdevicename_end"
ACTION!="add",    GOTO="netdevicename_end"
NAME=="?*",       GOTO="netdevicename_end"
ATTR{type}!="1",  GOTO="netdevicename_end"
ENV{DEVTYPE}=="?*", GOTO="netdevicename_end"

# whitelist all Dell systems
ATTR{[dmi/id]sys_vendor}=="Dell*", ENV{UDEV_BIOSDEVNAME}="1"

# kernel command line "biosdevname={0|1}" can turn off/on biosdevname
IMPORT{cmdline}="biosdevname"
ENV{biosdevname}=="?*", ENV{UDEV_BIOSDEVNAME}="$env{biosdevname}"
# ENV{UDEV_BIOSDEVNAME} can be used for blacklist/whitelist
# but will be overwritten by the kernel command line argument
ENV{UDEV_BIOSDEVNAME}=="0", GOTO="netdevicename_end"
ENV{UDEV_BIOSDEVNAME}=="1", GOTO="netdevicename_start"

# off by default
GOTO="netdevicename_end"

LABEL="netdevicename_start"

# using NAME= instead of setting INTERFACE_NAME, so that persistent
# names aren't generated for these devices, they are "named" on each boot.
SUBSYSTEMS=="pci", PROGRAM="/sbin/biosdevname --smbios 2.6 --nopirq --policy physical -i %k", NAME="%c"  OPTIONS+="string_escape=replace"

LABEL="netdevicename_end"

biosdevnameコマンドの実行結果をデバイス名の変数に設定します。このとき、/proc/cmdlineからbiosdevnameの値を読み取ってます。従って、biosdevnameによる命名を無効化するには以下の値をgrub2のconfigに追記することで可能です。

  • biosdevname=0 (0は無効、1は有効を指します)

(3) /udev/rules.d/75-net-description.rules

# do not edit this file, it will be overwritten on update

ACTION=="remove", GOTO="net_end"
SUBSYSTEM!="net", GOTO="net_end"

IMPORT{builtin}="net_id"

SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
SUBSYSTEMS=="usb", GOTO="net_end"

SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci"

LABEL="net_end"

デバイスのサブシステムの種類(USBデバイス or PCIデバイス)から必要な情報を読み取っています。
この情報を基に80-net-name-slot.rulesによってデバイス名が変更されます。


(4) /lib/udev/rules.d/80-net-name-slot.rules

# do not edit this file, it will be overwritten on update

ACTION!="add", GOTO="net_name_slot_end"
SUBSYSTEM!="net", GOTO="net_name_slot_end"
NAME!="", GOTO="net_name_slot_end"

IMPORT{cmdline}="net.ifnames"
ENV{net.ifnames}=="0", GOTO="net_name_slot_end"

NAME=="", ENV{ID_NET_NAME_ONBOARD}!="", NAME="$env{ID_NET_NAME_ONBOARD}"
NAME=="", ENV{ID_NET_NAME_SLOT}!="", NAME="$env{ID_NET_NAME_SLOT}"
NAME=="", ENV{ID_NET_NAME_PATH}!="", NAME="$env{ID_NET_NAME_PATH}"

LABEL="net_name_slot_end"

71-biosdevname.rulesで実行したbiosdevnameの実行結果が空の場合、オンボード、スロット、パスの順(優先)でデバイス名の変数に値が設定されます。このとき、/proc/cmdlineからnet.ifnamesの値を読み取ってます。従って、このルールによる命名を無効化するには以下の値をgrub2のconfigに追記することで可能です。

  • net.ifnames=0 (0は無効、1は有効を指します)

(5) /lib/udev/rules.d/99-systemd.rules

#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

ACTION=="remove", GOTO="systemd_end"

SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*|ttysclp*|sclp_line*|3270/tty[0-9]*", TAG+="systemd"

KERNEL=="vport*", TAG+="systemd"

SUBSYSTEM=="block", KERNEL!="ram*", TAG+="systemd"
SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"

# Ignore encrypted devices with no identified superblock on it, since
# we are probably still calling mke2fs or mkswap on it.
SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"

# Ignore raid devices that are not yet assembled and started
SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", TEST!="md/array_state", ENV{SYSTEMD_READY}="0"
SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", ATTR{md/array_state}=="|clear|inactive", ENV{SYSTEMD_READY}="0"

# Ignore nbd devices in the "add" event, with "change" the nbd is ready
ACTION=="add", SUBSYSTEM=="block", KERNEL=="nbd*", ENV{SYSTEMD_READY}="0"

# Ignore loop devices that don't have any file attached
ACTION=="add|change", KERNEL=="loop[0-9]*", TEST!="loop/backing_file", ENV{SYSTEMD_READY}="0"

# We need a hardware independent way to identify network devices. We
# use the /sys/subsystem path for this. Current vanilla kernels don't
# actually support that hierarchy right now, however upcoming kernels
# will. HAL and udev internally support /sys/subsystem already, hence
# it should be safe to use this here, too. This is mostly just an
# identification string for systemd, so whether the path actually is
# accessible or not does not matter as long as it is unique and in the
# filesystem namespace.
#
# http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev/libudev-enumerate.c#n922

SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/$name"
SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k"

SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_WANTS}+="bluetooth.target"
ENV{ID_SMARTCARD_READER}=="*?", TAG+="systemd", ENV{SYSTEMD_WANTS}+="smartcard.target"
SUBSYSTEM=="sound", KERNEL=="card*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sound.target"

SUBSYSTEM=="printer", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target"
SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target"

# Apply sysctl variables to network devices (and only to those) as they appear.

ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo", RUN+="/usr/lib/systemd/systemd-sysctl --prefix=/proc/sys/net/ipv4/conf/$name --prefix=/proc/sys/net/ipv4/neigh/$name --prefix=/proc/sys/net/ipv6/conf/$name --prefix=/proc/sys/net/ipv6/neigh/$name"

# Pull in backlight save/restore for all firmware backlight devices

SUBSYSTEM=="backlight", ATTR{type}=="firmware", TAG+="systemd", ENV{SYSTEMD_WANTS}+="systemd-backlight@$name.service"

# Asynchronously mount file systems implemented by these modules as
# soon as they are loaded.

SUBSYSTEM=="module", KERNEL=="fuse", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-fs-fuse-connections.mount"
SUBSYSTEM=="module", KERNEL=="configfs", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-kernel-config.mount"

LABEL="systemd_end"

# Apply sysctl variables ~の箇所でデバイス名に基づいた設定がされています。71-biosdevname.rulesならびに80-net-name-slot.rulesからデバイス名が取得できない場合は、CentOS6.xなどでもおなじみのethXが振られることになります。


NICを固定するにはどうすれば...

Predictable Network Interface Namesによって、デバイスの実装位置によってデバイス名が設定されるため、物理実装位置を変えない限り不変となります。ただ、USBNICとかを用いる場合は、刺すポートによってデバイス名が変わることになってしまいますが…。


ethXが使いたいのだけど...

Predictable Network Interface Namesが導入されてから、ethXは上記の命名則が使えない場合に利用されます。ただし、biosdevnameならびにnet.ifnamesの値をあらかじめ設定することで、ethXを使うことができます。

grub2のデフォルト状態の設定ファイルを編集する。

CMDLINE_LINUXにbiosdevname=0 net.ifnames=0を追加します。

# 編集前
[root@localhost ~]# vi /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/swap rd.lvm.lv=centos/root rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

# 編集後
[root@localhost ~]# vi /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto biosdevname=0 net.ifnames=0 rd.lvm.lv=centos/swap rd.lvm.lv=centos/root rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

grub2設定ファイルの出力

コマンドを実行することで/boot/grub2/grub.cfgに先ほどの変更が反映されます。

[root@localhost ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-229.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-229.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-0df2ba0c301649e081ae8a621c3b9d04
Found initrd image: /boot/initramfs-0-rescue-0df2ba0c301649e081ae8a621c3b9d04.img
done

[root@localhost ~]# cat /boot/grub2/grub.cfg | grep "biosdevname=0 net.ifnames=0"
        linux16 /vmlinuz-3.10.0-229.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto biosdevname=0 net.ifnames=0 rd.lvm.lv=centos/swap rd.lvm.lv=centos/root rhgb quiet
        linux16 /vmlinuz-0-rescue-0df2ba0c301649e081ae8a621c3b9d04 root=/dev/mapper/centos-root ro crashkernel=auto biosdevname=0 net.ifnames=0 rd.lvm.lv=centos/swap rd.lvm.lv=centos/root rhgb quiet

NIC設定ファイル名の変更

設定ファイルはインストール時を除き、自動で生成されませんので、適宜リネームまたは作成します。

[root@localhost ~]# mv /etc/sysconfig/network-scripts/ifcfg-enp0s3 /etc/sysconfig/network-scripts/ifcfg-eth0

再起動

再起動することでデバイス名がethXに変更されます。

#変更前
[root@localhost ~]# ip addr
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: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:b6:5e:b2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.102/24 brd 192.168.56.255 scope global dynamic enp0s3
       valid_lft 995sec preferred_lft 995sec
    inet6 fe80::a00:27ff:feb6:5eb2/64 scope link
       valid_lft forever preferred_lft forever

# 変更後
[root@localhost ~]# ip addr
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 08:00:27:b6:5e:b2 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.102/24 brd 192.168.56.255 scope global dynamic eth0
       valid_lft 1161sec preferred_lft 1161sec
    inet6 fe80::a00:27ff:feb6:5eb2/64 scope link
       valid_lft forever preferred_lft forever

インストール時に反映する場合

そもそもインストール時に設定したい場合、インストーラ起動前にTabキーを押下し、biosdevname=0 net.ifnames=0を追加すればethXで認識します。
f:id:zokibayashi:20150405034056p:plain