🐙

Ubuntu Server 20.04 で VXLAN を構成する

2022/10/16に公開

cloud-init で自動化した

ので見てみてください。

https://zenn.dev/skmkzyk/articles/vxlan-cloud-init

VXLAN の設定が再起動すると消える

以下のような script を実行すると VXLAN interface が生えるんですが、再起動すると消えてしまいます。

ip link add vxlan0 type vxlan id 77 remote 10.0.0.4 dstport 4789 dev eth0
ip link set up vxlan0
ip address add 169.254.0.2/24 dev vxlan0

interface に関する話で、昔は /etc/network/interfacespost-upip コマンドをたたくみたいな感じの対象方法がありましたが、Ubuntu Server 20.04 には適用できません。
また、/etc/network/if-up.d/ 配下にスクリプトを置いておけば動いたような気もしたんですが、試してみたところ実行されません。

Ubuntu Server の 20.04 あたりから post-up が動かない

といくつかの記事に書いてあります。
Ubuntu Server だとネットワーク系の設定は Netplan (/etc/netplan/*.yaml) を利用することになって、/etc/network/if-up.d/ 配下のファイルなどは扱われないようになったみたいです。

Netplan の FAQ に対処方法が書いてある

Example for an ifupdown legacy hook for post-up/post-down states に対処方法が書いてありました。
networkd-dispatcher と連携し、interface の up/down のタイミングで該当フォルダのスクリプトを /bin/run-parts で叩くようです。
permission は 755 以外は受け入れられず、ERROR:invalid permissions on /etc/networkd-dispatcher/routable.d/50-ifup-hooks. expected mode=0o755, uid=0, gid=0; got mode=0o644, uid=0, gid=0 というメッセージが出ます。

  • /etc/networkd-dispatcher/routable.d/50-ifup-hooks を書く & chmod 755
cat << EOF > /etc/networkd-dispatcher/routable.d/50-ifup-hooks
#!/bin/sh

for d in up post-up; do
    hookdir=/etc/network/if-\${d}.d
    [ -e \$hookdir ] && /bin/run-parts \$hookdir
done
exit 0
EOF
chmod +x /etc/networkd-dispatcher/routable.d/50-ifup-hooks
  • /etc/networkd-dispatcher/off.d/50-ifdown-hooks を書く & chmod 755
cat << EOF > /etc/networkd-dispatcher/off.d/50-ifdown-hooks
#!/bin/sh

for d in down post-down; do
    hookdir=/etc/network/if-\${d}.d
    [ -e \$hookdir ] && /bin/run-parts \$hookdir
done
exit 0
EOF
chmod +x /etc/networkd-dispatcher/off.d/50-ifdown-hooks
  • ll (ls -lalias です) で permission の確認
# ll /etc/networkd-dispatcher/routable.d/50-ifup-hooks
-rwxr-xr-x 1 root root 129 Aug 18 13:46 /etc/networkd-dispatcher/routable.d/50-ifup-hooks*
# ll /etc/networkd-dispatcher/off.d/50-ifdown-hooks
-rwxr-xr-x 1 root root 133 Aug 18 13:47 /etc/networkd-dispatcher/off.d/50-ifdown-hooks*

VXLAN 追加用のスクリプトを書く

/etc/network/if-post-up.d/vxlan にスクリプト本体を置きます。
一応 eth0 と紐づけて vxlan0up させたいため if をはさんでいます。

mkdir -p /etc/network/if-post-up.d
cat << EOF > /etc/network/if-post-up.d/vxlan
#!/bin/sh

if [ "\$IFACE" = "eth0" ]; then
  ip link add vxlan0 type vxlan id 77 remote 10.10.0.4 dstport 4789 dev eth0
  ip link set up vxlan0
  ip address add 169.254.0.1/24 dev vxlan0
fi
EOF
chmod u+x /etc/network/if-post-up.d/vxlan

こちらは 755 じゃなくて 744 でも動きます。

# ll /etc/network/if-post-up.d/vxlan
-rwxr--r-- 1 root root 165 Aug 18 13:23 /etc/network/if-post-up.d/vxlan*

動作確認

この状態でいったん再起動したのちに以下のようなコマンドで動作を確認します。

$ ip -d link show vxlan0
3: vxlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 5a:4c:7c:3e:0a:e5 brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535
    vxlan id 77 remote 10.10.0.4 dev eth0 srcport 0 0 dstport 4789 ttl auto ageing 300 udpcsum noudp6zerocsumtx noudp6zerocsumrx addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 62780 gso_max_segs 65535
$ ip addr show vxlan0
3: vxlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ether 5a:4c:7c:3e:0a:e5 brd ff:ff:ff:ff:ff:ff
    inet 169.254.0.1/24 scope global vxlan0
       valid_lft forever preferred_lft forever
    inet6 fe80::584c:7cff:fe3e:ae5/64 scope link
       valid_lft forever preferred_lft forever

ping も実行してみます。
こちらのホストが 169.254.0.1 を持っており、対向は 169.254.0.2 です。

$ ping -c 4 169.254.0.2
PING 169.254.0.2 (169.254.0.2) 56(84) bytes of data.
64 bytes from 169.254.0.2: icmp_seq=1 ttl=64 time=1.93 ms
64 bytes from 169.254.0.2: icmp_seq=2 ttl=64 time=1.14 ms
64 bytes from 169.254.0.2: icmp_seq=3 ttl=64 time=1.09 ms
64 bytes from 169.254.0.2: icmp_seq=4 ttl=64 time=1.73 ms

--- 169.254.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 1.089/1.472/1.931/0.363 ms

ちゃんとつながってます、よかった。

参考リンク

VXLAN のコマンド自体はこちらが大いに参考になりました、@tech_mmmm フォローしました、ありがとうございます。
https://tech-mmmm.blogspot.com/2017/10/vxlancentos-7vxlan.html

Netplan 自体が VXLAN に対応してくれないか、という話が書いてある。
https://bugs.launchpad.net/netplan/+bug/1764716

systemd service を作る、という方法も一応動いた
https://linuxconfig.org/how-to-run-script-on-startup-on-ubuntu-20-04-focal-fossa-server-desktop

Netplan の FAQ
https://netplan.io/faq/

man /bin/run-parts
https://manpages.ubuntu.com/manpages/focal/man8/run-parts.8.html

man /bin/run-parts の日本語
https://manpages.ubuntu.com/manpages/focal/ja/man8/run-parts.8.html

/bin/run-parts の文字種制限でハマった話
https://blog.ymgchi.com/posts/2020/05/run-parts/


network-dispatcher のマニュアルは /usr/share/doc/networkd-dispatcher/README.md.gz にあり、その中身をスナップショットがてらはりつけておきます。
環境変数のところに IFACE というのがあり、これを if [ "$IFACE" = "eth0" ]; then の箇所で使っているんだと思います、たぶん。

networkd-dispatcher

Networkd-dispatcher is a dispatcher daemon for systemd-networkd connection status changes. This daemon is similar to NetworkManager-dispatcher, but is much more limited in the types of events it supports due to the limited nature of systemd-networkd.

Desired actions (scripts) are placed into directories that reflect systemd-networkd operational states, and are executed when the daemon receives the relevant event from systemd-networkd.

The daemon listens for signals from systemd-networkd over dbus, so it should be very light on resources (e.g. no polling). It is meant to be run as a system-wide daemon (as root). This allows it to be used for tasks such as starting a VPN after a connection is established.

Usage

The daemon expects that scripts are 1) executable and 2) owned by root (gid = uid = 0), and will not execute scripts that are otherwise.

Scripts can be installed into these directories under /usr/lib/networkd-dispatcher for system packages, and /etc/networkd-dispatcher for local overrides:

routable.d/

dormant.d/

no-carrier.d/

off.d/

carrier.d/

degraded.d/

configuring.d/

configured.d/

networkd-dispatcher will execute any valid scripts in the directory that reflects the new state.

Scripts are executed in the alpha-numeric order in which they are named, starting with 0 and ending with z. For example, a script named 50runme would run before 99runmenext.

Scripts are executed with some environment variables set. Some of these variables may not be set or may be set to an empty value, dependent upon the type of event. These can be used by scripts to conditionally take action based on a specific interface, state, etc.

  • IFACE - interface that triggered the event

  • STATE - The destination state change for which a script is currently being invoked. May be any of the values listed as valid for AdministrativeState or OperationalState.

  • ESSID - for wlan connections, the ESSID the device is connected to

  • ADDR - the ipv4 address of the device

  • IP_ADDRS - space-delimited string of ipv4 address(es) assigned to the device (see note below)

  • IP6_ADDRS - space-delimited string of ipv6 address(es) assigned to the device (see note below)

  • AdministrativeState - One of pending, configuring, configured, unmanaged, failed or linger.

  • OperationalState - One of off, no-carrier, dormant, carrier, degraded, routable, configuring, or configured. For more information about the network operational states exposed by systemd, see the networkctl manpage (man networkctl`).

  • json - A JSON encoding of this program's interpretation of networkctl status "$IFACE", when the event is one for which such information is available; for debug logs or inspection with JSON-aware tools such as jq. Exact structure details are implementation-defined and liable to change.

*Note: For IP_ADDRS and IP6_ADDRS, the space-delimited string can be read into a BASH array like this:

read -r -a ip_addrs <<<"$IP_ADDRS"

Command-Line Options

usage: networkd-dispatcher [-h] [-S SCRIPT_DIR] [-T] [-v] [-q]

networkd dispatcher daemon

optional arguments:
  -h, --help            show this help message and exit
  -S SCRIPT_DIR, --script-dir SCRIPT_DIR
                        Location under which to look for scripts [default:
                        /etc/networkd-dispatcher:/usr/lib/networkd-dispatcher]
  -T, --run-startup-triggers
                        Generate events reflecting preexisting state and
                        behavior on startup [default: False]
  -v, --verbose         Increment verbosity level once per call
  -q, --quiet           Decrement verbosity level once per call

Some further notes:

  • The intended use case of --run-startup-triggers is race-condition avoidance: Ensuring that triggers are belatedly run even if networkd-dispatcher is invoked after systemd-networkd has already started an interface.
  • The default log level is WARNING. Each use of -v will increment the log level (towards INFO or DEBUG), and each use of -q will decrement it (towards ERROR or CRITICAL).

Systemd Service

There is an included systemd service file, networkd-dispatcher.service, which can be used to run networkd-dispatcher as a service. To specify command line options for the service, add them to a variable networkd_dispatcher_args in /etc/default/networkd-dispatcher. A template conf file is included.

Installation

Arch Linux

This package can be installed from AUR.

Other Linux Folks

Requirements:

  • >= python 3.4

  • python-gobject

  • python-dbus

  • Handling of wireless interfaces requires one of the following tools to be installed:

    • wireless_tools (providing iwconfig)
    • iw

Copy networkd-dispatcher to /usr/bin.

Create the appropriate directory structure:

$ sudo mkdir -p /etc/networkd-dispatcher/{routable,dormant,no-carrier,off,carrier,degraded,configuring,configured}.d

Install networkd-dispatcher.conf to /etc/default as 'networkd-dispatcher'.

Install networkd-dispatcher.service and start it. If networkd-dispatcher was not copied to /usr/bin, then edit service file to reflect the appropriate path.

Contributors

A large portion of the code was leveraged from networkd-notify, which was written by wavexx (Yuri D'Elia)

Microsoft (有志)

Discussion