😺

systemd-networkd入門

2020/09/28に公開

概要

systemd-networkdや関連ツールおよびサービスの基礎的なところから、設定ファイルの書き方、各設定項目の意味などをなるべく具体例を含めつつ書いていきます。

目次

はじめに

まだ書き始めたばかりですが公開してしまいます。随時更新していきます。

自己紹介とか

Yu Watanabeと申します。systemdを開発しているエンジニアの一人です。最近は特にsystemd-networkdやsystemd-udevdの開発をメインに行っています。

Zennへの最初の投稿としてsystemd-networkdについて書いてみます。Zennどころか技術系の記事を投稿したこと自体が初めてですので、暖かく見守っていただければと思います。

もしも内容が充実してきたら無料の本に転換するかもしれません(そういうことしてもいいのかな?)。後半はmanページの日本語訳になる予定ですので、今のところ、有料化はする予定はありません。てか、そういうことってしていいの?サポートはもちろん大歓迎です。

この文章の目的等

この文章は一人でも多くの方にsystemd-networkdを使っていただきたい、という目的で書いています。systemd-networkdの基本的な使い方から設定ファイル(.networkや.netdev)の書き方まで説明してみます。また、systemd-networkdではなくsystemd-udevdが用いるものですが、.linkファイルについても説明できればいいなと思っています。一朝一夕に書ききれる内容では無いので、公開後もちょくちょく更新していきたいと思っています。

また、本書後半のmanページの翻訳をするにあたって、manページの間違いを正したり不足している説明をupstreamにbackportしていくことも目的の一つです。

最後に、systemd-networkdの開発をしているにも関わらず私はネットワークの知識が豊富かと問われれば全くそんなことはありません。私にとってこの文章を書くもう一つの目的は、私自身のネットワーク関連の知識を充実させるためにあります。

間違いの指摘やバグ報告など

この文章の間違いを指摘して下さるのは大歓迎です。日本語の修正やtypoの指摘,Markdownの書き方のアドバイスなどもwelcomeです。しかし、本ページの内容に関してsystemdのメーリングリストに投稿したりGitHubのissueを作成するのはやめてください。このページのコメント欄やtwitterなどで私宛にご連絡下さい。

systemd-networkdそのもののバグを見つけた場合は、最新の2リリース(2020-09-27現在だとv246およびv245)を使用している場合についてはupstreamにてissueを作成していただけると助かります。それより古いものを使用している場合は、使用しているディストリビューションのバグトラッカー(Red Hat Bugzillaなど)にご連絡下さい。また、バグかどうか自信がない場合や英語にバリアを感じる場合などは、本ページのコメント欄やtwitterなどでまず私に相談していただいても構いません。

著作権とか

本書はYu Watanabeの著作物ですが、コピーしたり他のWikiなどに転載したり自由にしていただいて構いません。売れるもんだったら勝手に売って儲けてくれたって構わないです。その際に私の名前をmentionしてくれたり、私に連絡をいただけるととても嬉しいです。
本書はgithub連携機能を用いて書いています。gitのレポジトリの方からcloneするなりして使っていただいても結構です。

必要となるバックグラウンドや環境について

ネットワークの超基礎的なところを理解していれば大丈夫なように書くつもりです。とは言え、どこまでが'超基礎的'なのかは主観によると思いますので、ご容赦を。

必要となる環境は比較的新しいsystemdを採用しているLinuxです。systemd-networkdはsystemdを前提としているため、systemdを使用していないディストリビューションでは使用できません。
タイムラグは必然的に生じてしまいますが、現在のmasterブランチのsystemdを対象として書き、随時更新していく予定です。

なお、私がこの原稿を書いているシステムは、Fedora 32 (with systemd-245.8-2.fc32.x86_64)にsystemd-networkdとsystemd-udevdだけ現在のgitのmasterブランチのソースからコンパイルしたものになっています。

systemd-networkdを使うにあたって

本章ではsystemd-networkdを使うための準備や、関連コマンドおよびサービスについて説明していきたいと思います。

systemd-networkd.serviceを有効化する

まず、systemd-networkdが有効化されているかどうか調べてみましょう。

$ systemctl status systemd-networkd.service

このとき、

$ systemctl status systemd-networkd.service
● systemd-networkd.service - Network Service
     Loaded: loaded (/usr/lib/systemd/system/systemd-networkd.service; enabled; vendor preset: disabled)
     Active: active (running) since Sun 2020-09-27 22:56:09 JST; 2h 19min ago
       Docs: man:systemd-networkd.service(8)
   Main PID: 556 (systemd-network)
     Status: "Processing requests..."
      Tasks: 1 (limit: 9383)
     Memory: 62.2M
        CPU: 4.941s
     CGroup: /system.slice/systemd-networkd.service
             └─556 /usr/lib/systemd/systemd-networkd
(以下略)

のように表示されていれば、既にsystemd-networkd.serviceが有効化されていて(Loaded欄のユニットファイル名直後がenabledになっている。presetはここではどうでもよい)、また、起動しています(Active欄がactiveになっている)。

もしも、

$ systemctl status systemd-networkd.service
Unit systemd-networkd.service could not be found.

と表示された場合は、そもそもsystemd-networkdがインストールされていません。systemd-networkdをインストールして下さい。ちなみに、Fedora 32ではsystemdのメインrpmにsystemd-networkdが含まれているので、別途インストールする必要はありません。Fedora 34からはsystemd-networkdは別パッケージで提供されることになりそうです(より正確にはsystemd-246.6-2.fc34以降。See also)。RHEL8ではsystemd-networkdは提供されていないらしいです(未確認)。次節を参考にするなどしてソースからコンパイルして下さい。

もしも、systemd-networkd.serviceが無効化されている(Loaded欄がdisabledになっている)場合は、

$ sudo systemctl enable systemd-networkd.service

として有効化しましょう。また、systemd-networkd.serviceが無効化されている場合、ほとんどの場合において、NetworkManager.serviceやifupdownなど、別のネットワーク管理のためのserviceが起動・有効化されているはずです。それらを停止・無効化しておきましょう。例えば以下のような感じで。

$ sudo systemctl disable NetworkManager.service
$ sudo systemctl stop NetworkManager.service NetworkManager-dispatcher.service

その後、

$ sudo systemctl start systemd-networkd.service

としてserviceを起動しましょう。

最新のsystemd-networkdをビルドして試すには

使用しているディストリビューションが提供しているsystemdのバージョンが古く、最新のsystemd-networkdを試したい場合や、そもそもディストリビューションがsystemd-networkdを提供していない場合などは以下の方法が参考になるかもしれません。
また、この方法は、自分の使用しているsystemd-networkdにバグが有り、最新のコードで修正されているかどうか確認したい場合にも役に立つかもしれません。
なお、以下はsystemd-networkdなどのserviceだけを最新にする方法です。systemd自体(PID 1)も最新にしたい場合は、最新のコードからrpmを作成することをオススメします。

まず、適宜systemdのビルドに必要な環境を構築して下さい。例えばFedoraだと、

$ sudo dnf install dnf-plugins-core
$ sudo dnf builddep systemd

とすることで必要なものがインストールされます。

適当な場所にgithubからコードをダウンロードしてきます。以降では~/systemdにダウンロードしたとします。

$ cd
$ git clone https://github.com/systemd/systemd.git

ホームディレクトリでは 無い 場所にビルドディレクトリを作成し、所有権を変更します。以降では/var/build, ユーザはyuwataとします。

$ sudo mkdir /var/build
$ sudo chown yuwata:yuwata /var/build

ビルドします。

$ cd /var/build
$ meson ~/systemd .
$ ninja

ディストリビューションがsystemd-networkdを提供していない場合は、ユニットファイルをコピーします。

$ sudo cp /var/build/units/systemd-networkd.service /etc/systemd/system/.
$ sudo cp ~/systemd/units/systemd-networkd.socket /etc/systemd/system/.

systemd-networkd-wait-online.serviceなども必要に応じてコピーします。

ユニットファイルを編集します。

$ sudo systemctl edit systemd-networkd.service

適当なエディタが起動するので、以下のように記載してExecStart=を書き換えます。

[Service]
ExecStart=
ExecStart=/var/build/systemd-networkd

このとき、必ず空のExecStart=行が要ります。必要に応じてsystemd-networkd-wait-online.serviceなども編集して下さい。

networkctlによる状態確認

systemd-networkdと対になるコマンドラインツールがnetworkctlです。

まずは、networkctl単体で走らせてみましょう。(前節でビルドしたものを使用する場合は/var/build/networkctlとフルパスを指定して下さい。)
.networkファイルを何も作成していない状況だと、

$ networkctl
IDX LINK      TYPE     OPERATIONAL SETUP
  1 lo        loopback carrier     unmanaged
  2 enp0s31f6 ether    no-carrier  unmanaged
  3 wlp59s0   wlan     degraded    unmanaged

3 links listed.

のような出力になるはずです。上記の例では有線のポートenp0s31f6と無線LANポートwlp59s0の2つのネットワークインターフェイスが存在することを示しています。unmanagedというのはsystemd-networkdが管理していないインターフェイス、ということを意味しています。詳しくは次の節で。

詳細な.networkファイルの書き方は後の章で述べるとして、例えば、以下のような.networkファイルを作成してみましょう。

  • /etc/systemd/network/50-wired.network
[Match]
Name=enp0s31f6

[Network]
DHCP=yes
  • /etc/systemd/network/50-wireless.network
[Match]
Name=wlp59s0

[Network]
DHCP=yes

.networkファイルを再読込(v244以上)もしくはsystemd-networkd.serviceを再起動します。

$ sudo networkctl reload

or

$ sudo systemctl restart systemd-networkd.service

再度networkctlで状態を表示してみましょう。

$ networkctl
IDX LINK      TYPE     OPERATIONAL SETUP
  1 lo        loopback carrier     unmanaged
  2 enp0s31f6 ether    no-carrier  configuring
  3 wlp59s0   wlan     routable    configured

3 links listed.

SETUP欄がunmanagedからconfiguringもしくはconfiguredに変わっていると思います。上記の例では有線のケーブルが刺さってないため、enp0s31f6configuringになっています。

無線LANポートwlp59s0の詳細な情報を表示してみましょう。

$ networkctl status wlp59s0
● 3: wlp59s0
             Link File: /usr/lib/systemd/network/99-default.link
          Network File: /etc/systemd/network/50-wireless.network
                  Type: wlan
                 State: routable (configured)
     Alternative Names: wlxXXXXXXXXXXXX
                  Path: pci-0000:3b:00.0
                Driver: iwlwifi
                Vendor: Intel Corporation
                 Model: Wireless 8265 / 8275 (Dual Band Wireless-AC 8265)
            HW Address: XX:XX:XX:XX:XX:XX (Intel Corporate)
                   MTU: 1500 (min: 256, max: 2304)
     WiFi access point: WIFI_SSID (YY:YY:YY:YY:YY:YY)
  Queue Length (Tx/Rx): 1/1
               Address: 192.168.86.250
                        fe80::xxxx:xxxx:xxxx:xxxx
               Gateway: 192.168.86.1 (COMPANY_NAME)
                   DNS: 192.168.86.1
        Search Domains: lan

(ログは省略)

systemdやkernelのバージョンやネットワーク環境によって表示される項目や内容は変わりますが、概ね上記のような感じになるはずです。なお、networkctl -s status wlp59s0のように-sオプションを追加することでそのインターフェイスの統計情報を表示することも出来ます。

インターフェイス名を指定せずにstatusコマンドを実行するとシステムに割り当てられている全てのIPアドレスの情報などが表示されます。ただし、下記の例ではenp0s31f6にケーブルが刺さっていないので、wlp59s0がDHCPで取得した情報のみが表示されています。

$ networkctl status
●          State: routable
         Address: 192.168.86.250 on wlp59s0
                  fe80::xxxx:xxxx:xxxx:xxxx on wlp59s0
         Gateway: 192.168.86.1 (COMPANY_NAME) on wlp59s0
             DNS: 192.168.86.1
  Search Domains: lan

(ログは省略)

operational stateとsetup stateについて

networkctlで表示されるOPERATIONAL欄とSETUP欄の意味について説明したいと思います。基本的にはnetworkctl(1)の部分的な翻訳プラスアルファです。

まずはoperational stateから。

  • missing
    デバイスが存在しない。(基本的にはお目にかかれないはずです。デバイスを削除しつつ同時にnetworkctlを叩くようなracyな状況では原理的には可能か?)
  • off
    デバイスの電源がオフ。
  • no-carrier
    デバイスの電源はオンだが、キャリアが存在しない。例えば、有線LANポートの場合はケーブルが刺さっていない、無線LANポートの場合はアクセスポイントに接続していない、など。
  • dormant
    キャリアは存在するが、通常のトラフィックを流す準備が出来ていない。例えば、802.1X認証が完了していない、など。kernelのoperstateについてのドキュメントのIF_OPER_DORMANTの説明を参照。
  • degraded-carrier
    bridgeもしくはbondのmasterインターフェイスにおいて、1つ以上のslaveインターフェイスがoff, no-carrier, dormantのどれかの状態にある。
  • carrier
    キャリアが存在する。bridgeもしくはbondのmasterインターフェイスにおいては、全てのslaveインターフェイスがcarrierもしくはそれ以上の状態にある。
  • degraded
    キャリアが存在し、ローカル接続において有効なアドレスが割当てられている。
  • enslaved
    キャリアが存在し、bridgeもしくはbondのmasterインターフェイスのslaveインターフェイスとして割当てられている。
  • routable
    キャリアが存在し、ルート可能なアドレスが割当てられている。

余談ですが、operational stateは、内部的にはcarrier stateとaddress stateの2つから決定されています。networkd-link.cより。

/* Mapping of address and carrier state vs operational state
 *                                                     carrier state
 *                          | off | no-carrier | dormant | degraded-carrier | carrier  | enslaved
 *                 ------------------------------------------------------------------------------
 *                 off      | off | no-carrier | dormant | degraded-carrier | carrier  | enslaved
 * address_state   degraded | off | no-carrier | dormant | degraded-carrier | degraded | enslaved
 *                 routable | off | no-carrier | dormant | degraded-carrier | routable | routable
 */

次に、setup stateについて。

  • pending
    systemd-udevdがまだデバイスの初期化を完了していない。systemd-networkdはまだこのデバイスを管理するかどうか決定していない。
  • failed
    systemd-networkdがデバイスを管理するのに失敗。基本的にはどこかがバグってる状態。
  • configuring
    デバイスの設定中。
  • configured
    デバイスの設定が完了。
  • unmanaged
    systemd-networkdはこのデバイスを管理していない。
  • linger
    既にこのデバイスは削除されているが、このデバイスの情報がsystemd-networkdのメモリ上に残っている。

systemd-networkd-wait-online.serviceの使用方法

systemd-network-generator.serviceについて

トラブルシューティング

まずはjournalログを確認してみましょう。例えば、

$ journalctl -b -u systemd-networkd.service

でsystemd-networkd.serviceについてのログが表示されます。システム全体のログを表示したければjournalctl -bだけでOKです。余談ですが、一番下までスクロールするのが面倒であれば、-rオプションもオススメ。また、バグ投稿時などにホスト名を隠したければ、--no-hostnameオプションも便利です。他には-f or --followオプションもいいかも。詳しくはjournalctl(1)を見て下さい。

もしも、それらしいエラーメッセージが見つからなかったり、エラー内容がよくわからない場合は、デバッグログを出力させるようにしてみましょう。systemdの提供するサービスおよびツールはSYSTEMD_LOG_LEVEL=環境変数でログレベルを変更できます。これをdebugに設定すればデバッグログを出力することが出来ます。

サービスに対して環境変数を設定するには、例えば、

$ sudo systemctl edit systemd-networkd.service

として、起動したエディタ上で、

[Service]
Environment=SYSTEMD_LOG_LEVEL=debug

と記載し、

$ sudo systemctl restart systemd-networkd.service

でサービスを再起動しましょう。この方法はsystemd-networkd-wait-online.serviceやsystemd-udevd.serviceなど他のサービスに対しても使えます。

なお、networkctludevadmなどのコマンドラインツールに対しては、

$ SYSTEMD_LOG_LEVEL=debug networkctl

とすることでデバッグログを表示できます。

デバッグログを出力させたら、再度journalctlでログを表示させてみましょう。なお、ネットワークインターフェイスやnetdevが大量にありログを追いかけにくい場合は、

$ networkctl status eth0

などとすることで特定のインターフェイスのログのみ表示することもできます(v245以上)。このとき、オプションで-n 1000などとすることで出力する行数を指定できます。

.networkファイルの基礎

systemd.network(5)の日本語訳プラスアルファ

.netdevファイルの基礎

systemd.netdev(5)の日本語訳プラスアルファ

systemd-udevdについて

.linkファイルの基礎

systemd.link(5)の日本語訳プラスアルファ

最後に

是非systemd-networkdを使ってみて下さい。

更新履歴

  • 2020-09-27 1章と2章の半分ぐらい。
    途中まで書いていて思ったけど、現状書けてる範囲って、たぶんArchとかGentooのWikiにあるんじゃないだろうか。。。悔しいから今日は見ない。
  • 2020-09-28 著作権について軽くコメント。

Discussion