kakkotetsu

Juniper vJunos-switchをKVM + GNS3で動かす

先日2023/04にJuniperがvJunos-switchというEX9214ベースの仮想(VM)版を公開したので、それをKVM + GNS3で動かします。
EXという名前の割にかなり機能が揃っているようですし、更に2023/05時点ではJuniperサイトのアカウントさえ持っていなくても誰でもダウンロードして使えるので、labや教育用途にピッタリでしょう。

最初に

本項でやること

  • Juniper EX9214の仮想版であるJuniper vJunos-switchをKVM + GNS3で動かして、ルーティングプロトコル(IS-IS)が動くのを簡易に確認するところまで
  • KVM や GNS3 の導入手順、Junos 操作の基礎は省略 (ある程度知っている人向け)

参考リンク集

環境情報

vJunos-switch自体がnested VMで動く(vJunos-switch Architecture 参照)ので、bare metalサーバにUbuntuとGNS3を入れてます。

なお、GNS3は以下を参考にWebインターフェース版を使っている(gns3-gui gns3-serverに加えてgns3-webclient-packもaptで入れただけ)ので、画面キャプチャなどはWeb Client版のものです。

vJunos-switchは2023/05時点で最新の23.1R1です。

# cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.2 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy


# gns3 --version
2.2.39


# grep -Eoc '(vmx|svm)' /proc/cpuinfo
96


# kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

デプロイ手順

qcow2イメージ入手

公式のダウンロードページで"vJunos-switch KVM image"をダウンロードするだけです。
なんと!ログイン不要で!!!入手できます!!!!!

$ sha256sum vjunos-switch-23.1R1.8.qcow2
d70eefa519f51d7d4cf2929862ed82b78a88512beb7da2ecade2bb19bf9ce505  vjunos-switch-23.1R1.8.qcow2

GNS3でQEMU VMテンプレート作成

ここがキモです。
"Preference"から"QEMU VM"のvjunos-switch用テンプレートを作ります。

以下に実際に正常に動作いるモノの設定を載せます。

  • General settings
    • RAMとvCPUは公式のRequirementsに沿っているだけ
      • 5GB, 4vCPU 以上
    • On closeはSend the Shutdown Signal(ACPI)
      • デフォルトのPower off the VMだと一旦停止して起動すると正常起動しなくなりました(エラー吐いてrebootを繰り返していた)

  • HDD
    • 先に公式サイトからダウンロードしたqcow2を1つ目のディスクとしてつけておく
    • 2つ目のディスクに初期設定ファイルをつけたりもできるらしいが未確認(ここでは何もつけておらず)

  • Network
    • 1つ目がマネージメント用のいわゆるfxp0
      • デフォルトでは起動時にここからDHCPリクエストを吐くので、適宜GNS3サーバの外界に繋げてDHCPサーバと通信させたり
    • 2つ目以降が"ge-0/0/[0-]"のデータポート
      • 公式によると96インターフェースまで可能?みたい

  • Advanced
    • "Additional settings"の"options"にqemu-system-x86_64の引数をベタ追記する
      • -smbios type=1,product="VM-VEX" は公式ドキュメントでも入れろとなっているのでそのまま入れておく
      • -cpu hostはvJunos-switch自体がnested VMで動くため

上記QEMU VMテンプレートを使って起動

GNS3のプロジェクトで先に作ったテンプレートを使ってデプロイ。
インターフェース1つ目がfxp0で、2つ目以降が"ge-0/0/[0-]"なので、それに合わせて適宜結線。
で、起動。

実際に起動しているものの引数など。

# ps aux | grep [J]unos
root       36635 94.8  1.8 7177172 3619800 pts/2 Sl+  15:19   0:48 /usr/bin/qemu-system-x86_64 -name vJunos-switch-23.1R1-1 -m 6144M -smp cpus=4,sockets=1 -enable-kvm -machine smm=off -boot order=c -drive file=/root/GNS3/projects/1710614b-c055-4427-8e15-abd4a9f2e9fe/project-files/qemu/3796adf7-8dbe-4dd1-acfa-586e78b9c1b9/hda_disk.qcow2,if=ide,index=0,media=disk,id=drive0 -uuid 3796adf7-8dbe-4dd1-acfa-586e78b9c1b9 -serial telnet:127.0.0.1:5002,server,nowait -monitor tcp:127.0.0.1:45513,server,nowait -net none -device virtio-net-pci,mac=0c:96:ad:f7:00:00,netdev=gns3-0 -netdev socket,id=gns3-0,udp=127.0.0.1:20005,localaddr=127.0.0.1:20004 -device virtio-net-pci,mac=0c:96:ad:f7:00:01,netdev=gns3-1 -netdev socket,id=gns3-1,udp=127.0.0.1:20007,localaddr=127.0.0.1:20006 -device virtio-net-pci,mac=0c:96:ad:f7:00:02,netdev=gns3-2 -netdev socket,id=gns3-2,udp=127.0.0.1:20009,localaddr=127.0.0.1:20008 -device virtio-net-pci,mac=0c:96:ad:f7:00:03,netdev=gns3-3 -netdev socket,id=gns3-3,udp=127.0.0.1:20011,localaddr=127.0.0.1:20010 -device virtio-net-pci,mac=0c:96:ad:f7:00:04,netdev=gns3-4 -netdev socket,id=gns3-4,udp=127.0.0.1:20013,localaddr=127.0.0.1:20012 -device virtio-net-pci,mac=0c:96:ad:f7:00:05,netdev=gns3-5 -netdev socket,id=gns3-5,udp=127.0.0.1:20015,localaddr=127.0.0.1:20014 -device virtio-net-pci,mac=0c:96:ad:f7:00:06,netdev=gns3-6 -netdev socket,id=gns3-6,udp=127.0.0.1:20017,localaddr=127.0.0.1:20016 -device virtio-net-pci,mac=0c:96:ad:f7:00:07,netdev=gns3-7 -netdev socket,id=gns3-7,udp=127.0.0.1:20019,localaddr=127.0.0.1:20018 -nographic -smbios type=1,product=VM-VEX -cpu host

で、コンソールを見守っていてFreeBSDのログインプロンプトが表示され、rootパスワードなしでログインできればOKです。

FreeBSD/amd64 (Amnesiac) (ttyu0)

login: root
Last login: Sun Mar 19 08:08:06 on ttyu0

--- JUNOS 23.1R1.8 Kernel 64-bit  JNPR-12.1-20230307.3e7c4b6_buil
root@:~ #


root@:~ # uname -a
FreeBSD  JNPR-12.1-20230307.3e7c4b6_buil FreeBSD JNPR-12.1-20230307.3e7c4b6_builder_stable_12_231 #0 r356482+3e7c4b6f6d3(stable/12_231): Wed Mar  8 11:06:07 PST 2023     builder@feyrith.juniper.net:/volume/build/junos/occam/llvm-10.0/sandbox-231-20230307-3e7c4b6/freebsd/stable_12_231/20230307.173653_builder_stable_12_231.3e7c4b6/obj/amd64/juniper/kernels/JNPR-AMD64-PRD/kernel  amd64

root@:~ # cli
root>

ZTP的なやつが動こうとしているっぽいので、適宜無効化するなり。

root>
Auto Image Upgrade: DHCP client(s) with NO VALID CONFIG, reset all enabled DHCP
 clients

Auto Image Upgrade: DHCP INET6 Client State Reset : fxp0.0

Auto Image Upgrade: DHCP INET6 Client State Reset : fxp0.0

Auto Image Upgrade: DHCP OFFER Client fxp0.0: Invalid config.
No File Server Information. OFFER REJECTED.

デフォルト設定とかバージョン情報とか。

root> show version brief
Model: ex9214
Junos: 23.1R1.8
JUNOS OS Kernel 64-bit  [20230307.3e7c4b6_builder_stable_12_231]
JUNOS OS libs [20230307.3e7c4b6_builder_stable_12_231]
JUNOS OS runtime [20230307.3e7c4b6_builder_stable_12_231]
JUNOS OS time zone information [20230307.3e7c4b6_builder_stable_12_231]
JUNOS network stack and utilities [20230319.041703_builder_junos_231_r1]
JUNOS libs [20230319.041703_builder_junos_231_r1]
JUNOS OS libs compat32 [20230307.3e7c4b6_builder_stable_12_231]
JUNOS OS 32-bit compatibility [20230307.3e7c4b6_builder_stable_12_231]
JUNOS libs compat32 [20230319.041703_builder_junos_231_r1]
JUNOS runtime [20230319.041703_builder_junos_231_r1]
JUNOS Packet Forwarding Engine Simulation Package [20230319.041703_builder_junos_231_r1]
JUNOS sflow mx [20230319.041703_builder_junos_231_r1]
JUNOS py extensions [20230319.041703_builder_junos_231_r1]
JUNOS py base [20230319.041703_builder_junos_231_r1]
JUNOS OS vmguest [20230307.3e7c4b6_builder_stable_12_231]
JUNOS OS package [20230301.012437_builder_stable_12]
JUNOS OS network modules [20230307.3e7c4b6_builder_stable_12_231]
JUNOS OS crypto [20230307.3e7c4b6_builder_stable_12_231]
JUNOS OS boot-ve files [20230307.3e7c4b6_builder_stable_12_231]
JUNOS na telemetry [23.1R1.8]
...


root> show chassis hardware
Hardware inventory:
Item             Version  Part number  Serial number     Description
Chassis                                VM646DAD0156      EX9214
Midplane
Routing Engine 0                                         RE-VMX
CB 0                                                     VMX SCB
FPC 0                     BUILTIN      BUILTIN           Virtual FPC
  CPU            Rev. 1.0 RIOT-LITE    BUILTIN
  MIC 0                                                  Virtual
    PIC 0                 BUILTIN      BUILTIN           Virtual



root> show interfaces terse
Interface               Admin Link Proto    Local                 Remote
ge-0/0/0                up    down
ge-0/0/0.16386          up    down
lc-0/0/0                up    up
lc-0/0/0.32769          up    up   vpls
pfe-0/0/0               up    up
pfe-0/0/0.16383         up    up   inet
                                   inet6
pfh-0/0/0               up    up
pfh-0/0/0.16383         up    up   inet
pfh-0/0/0.16384         up    up   inet
ge-0/0/1                up    down
ge-0/0/1.16386          up    down
ge-0/0/2                up    down
ge-0/0/2.16386          up    down
ge-0/0/3                up    down
ge-0/0/3.16386          up    down
ge-0/0/4                up    down
ge-0/0/4.16386          up    down
ge-0/0/5                up    down
ge-0/0/5.16386          up    down
ge-0/0/6                up    down
ge-0/0/6.16386          up    down
ge-0/0/7                up    down
ge-0/0/7.16386          up    down
ge-0/0/8                up    down
ge-0/0/8.16386          up    down
ge-0/0/9                up    down
ge-0/0/9.16386          up    down
cbp0                    up    up
demux0                  up    up
dsc                     up    up
em1                     up    up
em1.0                   up    up   inet     10.0.0.4/8
                                            128.0.0.1/2
                                            128.0.0.4/2
                                   inet6    fe80::5254:ff:fe12:bdfe/64
                                            fec0::a:0:0:4/64
                                   tnp      0x4
esi                     up    up
fxp0                    up    up
fxp0.0                  up    up   inet     10.138.126.103/25
                                   inet6    fe80::e96:adff:fef7:0/64
gre                     up    up
ipip                    up    up
irb                     up    up
jsrv                    up    up
jsrv.1                  up    up   inet     128.0.0.127/2
lo0                     up    up
lo0.16384               up    up   inet     127.0.0.1           --> 0/0
lo0.16385               up    up   inet
lsi                     up    up
mif                     up    up
mtun                    up    up
pimd                    up    up
pime                    up    up
pip0                    up    up
pp0                     up    up
rbeb                    up    up
tap                     up    up
vtep                    up    up



root> show configuration | display set
set version 23.1R1.8
set system commit factory-settings
set system arp aging-timer 5
set system syslog file interactive-commands interactive-commands any
set system syslog file messages any notice
set system syslog file messages authorization info
set system processes dhcp-service traceoptions file dhcp_logfile
set system processes dhcp-service traceoptions file size 10m
set system processes dhcp-service traceoptions level all
set system processes dhcp-service traceoptions flag packet
set chassis auto-image-upgrade
set interfaces fxp0 unit 0 family inet dhcp vendor-id Juniper-ex9214-VM646DAD0156
set interfaces fxp0 unit 0 family inet6 dhcpv6-client client-type stateful
set interfaces fxp0 unit 0 family inet6 dhcpv6-client client-ia-type ia-na
set interfaces fxp0 unit 0 family inet6 dhcpv6-client client-identifier duid-type duid-ll
set interfaces fxp0 unit 0 family inet6 dhcpv6-client vendor-id Juniper:ex9214:VM646DAD0156
set multi-chassis mc-lag consistency-check
set protocols router-advertisement interface fxp0.0 managed-configuration
set protocols lldp interface all
set protocols lldp-med interface all

ルーティングプロトコル(IS-IS)簡易動作確認

適当にIS-ISを四角形トポロジで動かしました。
1台分の設定でいうとこんなので。

set interfaces ge-0/0/0 description "R2 ge-0/0/0"
set interfaces ge-0/0/0 mtu 9192
set interfaces ge-0/0/0 unit 0 family inet address 192.168.0.0/31
set interfaces ge-0/0/0 unit 0 family iso
set interfaces ge-0/0/0 unit 0 family inet6 address fd00::192:168:0:0/127

set interfaces ge-0/0/1 description "R3 ge-0/0/0"
set interfaces ge-0/0/1 mtu 9192
set interfaces ge-0/0/1 unit 0 family inet address 192.168.0.7/31
set interfaces ge-0/0/1 unit 0 family iso
set interfaces ge-0/0/1 unit 0 family inet6 address fd00::192:168:0:7/127

set interfaces lo0 unit 0 family inet address 192.168.255.1/32
set interfaces lo0 unit 0 family iso address 49.0000.0000.0000.0001.00
set interfaces lo0 unit 0 family inet6 address fd00::192:168:255:1/128

set protocols isis interface ge-0/0/0.0
set protocols isis interface ge-0/0/1.0
set protocols isis interface lo0.0 passive

licenseのwarningは出るけどcommitはできます。
syslogにも1分おきとかにlicense warningが出続けますが。

[edit]
root@R1# commit
[edit protocols]
  'isis'
    warning: requires 'isis' license
commit complete

adjacency確立して経路学習しており、pingで他の3台のlo addressにも到達可能。

root@R1> show isis adjacency

Warning: License key missing; requires 'isis' license

Interface             System         L State         Hold (secs) SNPA
ge-0/0/0.0            R2             1  Up                    22  c:29:76:2a:0:1
ge-0/0/0.0            R2             2  Up                    23  c:29:76:2a:0:1
ge-0/0/1.0            R3             1  Up                    26  c:8a:58:1a:0:1
ge-0/0/1.0            R3             2  Up                    19  c:8a:58:1a:0:1


root@R1> show route protocol isis

Warning: License key missing; requires 'isis' license


inet.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden)
Limit/Threshold: 1048576/1048576 destinations
+ = Active Route, - = Last Active, * = Both

192.168.0.2/31     *[IS-IS/15] 00:01:23, metric 20
                    >  to 192.168.0.1 via ge-0/0/0.0
192.168.0.4/31     *[IS-IS/15] 00:00:55, metric 20
                    >  to 192.168.0.6 via ge-0/0/1.0
192.168.255.2/32   *[IS-IS/15] 00:01:23, metric 10
                    >  to 192.168.0.1 via ge-0/0/0.0
192.168.255.3/32   *[IS-IS/15] 00:00:55, metric 10
                    >  to 192.168.0.6 via ge-0/0/1.0
192.168.255.4/32   *[IS-IS/15] 00:00:55, metric 20
                    >  to 192.168.0.1 via ge-0/0/0.0
                       to 192.168.0.6 via ge-0/0/1.0

iso.0: 1 destinations, 1 routes (1 active, 0 holddown, 0 hidden)

inet6.0: 14 destinations, 14 routes (14 active, 0 holddown, 0 hidden)
Limit/Threshold: 1048576/1048576 destinations
+ = Active Route, - = Last Active, * = Both

fd00::192:168:0:2/127
                   *[IS-IS/15] 00:01:23, metric 20
                    >  to fe80::e29:76ff:fe2a:1 via ge-0/0/0.0
fd00::192:168:0:4/127
                   *[IS-IS/15] 00:00:55, metric 20
                    >  to fe80::e8a:58ff:fe1a:1 via ge-0/0/1.0
fd00::192:168:255:2/128
                   *[IS-IS/15] 00:01:23, metric 10
                    >  to fe80::e29:76ff:fe2a:1 via ge-0/0/0.0
fd00::192:168:255:3/128
                   *[IS-IS/15] 00:00:55, metric 10
                    >  to fe80::e8a:58ff:fe1a:1 via ge-0/0/1.0
fd00::192:168:255:4/128
                   *[IS-IS/15] 00:00:55, metric 20
                    >  to fe80::e29:76ff:fe2a:1 via ge-0/0/0.0
                       to fe80::e8a:58ff:fe1a:1 via ge-0/0/1.0

何となくルーティングプロトコルも動きそうだと分かりました。

所感

  • EX9214のFeatureをみているとEXという名前の割にかなりMX寄りな良いモノのようで、vJunos-switchもかなり使い出がありそうな予感です。
  • いつの間にか(自分は)vMX Evaluationがダウンロードできなくなっているのもあり、vQFXも重いし...というところで期待の新星登場!という思いです。
  • nested VMを使っているとはいえ、VCP/VFPがシングルVMで動くのもノードを配置する際にはありがたいです。
  • それにしてもこれがアカウント不要で誰でもダウンロード可能なのは、大変にありがたいことでございます。Juniper様様。

RFC8910でDHCP option code 114がURLからDHCP Captive-Portalに変わっていた

Summary

タイトルの通りなんですが

2020/09にRFC化した"RFC8910 Captive-Portal Identification in DHCP and Router Advertisements (RAs)"で

  • "DHCP Captive-Portal"のDFCP option codeがかつては160だったが114に変わった
  • なのでDHCP option code 114が"URL"から"DHCP Captive-Portal"に変わった
    • DHCPサーバの実装としてISC dhcpdやKeaではdefault-urlとして知られていたもの

以下はRFC8910のAbstractから抜粋

   This document replaces RFC 7710, which used DHCP code point 160.  Due
   to a conflict, this document specifies 114.  Consequently, this
   document also updates RFC 3679.

DHCPサーバ実装の一つとしてISC Keaの場合はversion 2.1.2から設定名が変わってはいるものの、フォーマットとしては変わらずstringでURIを書けば良く、設定ファイルのdefault-urlv4-captive-portalに書き換えれば良いとのことです。
以下はKeaのドキュメントからの抜粋。

The default-url option was replaced with v4-captive-portal in Kea 2.1.2, as introduced by RFC 8910. The new option has exactly the same format as the old one. The general perception is that default-url was seldom used. If you used it and migrating, please replace default-url with v4-captive-portal and your configuration will continue to work as before.

リンク集

本件に関する参考リンク集です。

おまけ ~ Kea Upgrade from 1.6.3 to 2.2.0 ~

今回Keaを1.6.3から2.2.0にupgradeした際に設定ファイルの設定名の問題でisc-kea-dhcp4-server.serviceの起動に失敗したことでこの件を知りました。
そんなわけでUpgradeした時の記録をおまけとしてつけておきます。
公式ドキュメントは Upgrading to a Newer Version of Kea この辺。

事前の環境情報など
Ubuntu 22.04にKea 1.6.3が入っています。

$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy


$ apt show isc-kea-common
Package: isc-kea-common
Version: 1.6.3-isc0044120200730112858
Status: install ok installed
Priority: optional
Section: libs
Source: isc-kea
Maintainer: Kea <isc-kea@packages.debian.org>
Installed-Size: 12.1 MB
Depends: adduser, libboost-system1.65.1, libc6 (>= 2.15), libgcc1 (>= 1:3.0), liblog4cplus-1.1-9, libmysqlclient20 (>= 5.7.11), libpq5 (>= 9.1~), libssl1.1 (>= 1.1.0), libstdc++6 (>= 5.2)
Conflicts: kea-common
Homepage: http://kea.isc.org/
Download-Size: unknown
APT-Manual-Installed: no
APT-Sources: /var/lib/dpkg/status
Description: Common libraries for the ISC Kea DHCP server
 Kea is an IPv4 and IPv6 DHCP server developed by Internet Systems Consortium.
 .
 This package provides common libraries used by ISC Kea servers and utilities.


$ apt show isc-kea-dhcp4-server
Package: isc-kea-dhcp4-server
Version: 1.6.3-isc0044120200730112858
Status: install ok installed
Priority: optional
Section: net
Source: isc-kea
Maintainer: Kea <isc-kea@packages.debian.org>
Installed-Size: 1097 kB
Depends: isc-kea-common (= 1.6.3-isc0044120200730112858), lsb-base, libboost-system1.65.1, libc6 (>= 2.14), libgcc1 (>= 1:3.0), libstdc++6 (>= 5.2)
Recommends: libcap2-bin
Suggests: isc-kea-doc
Conflicts: kea-dhcp4-server
Homepage: http://kea.isc.org/
Download-Size: unknown
APT-Manual-Installed: yes
APT-Sources: /var/lib/dpkg/status
Description: ISC Kea IPv4 DHCP server
 Kea is an IPv4 and IPv6 DHCP server developed by Internet Systems Consortium
 providing a very high-performance with PostgreSQL, MySQL and memfile backends.
 .
 This package provides the IPv4 DHCP server.



$ more /etc/apt/sources.list.d/isc-kea-1-6.list*
::::::::::::::
/etc/apt/sources.list.d/isc-kea-1-6.list
::::::::::::::
# Source: Cloudsmith (support@cloudsmith.io)
# Repository: ISC - Internet Systems Consortium / kea-1.6
# Description: Kea 1.6. This is the current STABLE version of the Kea DHCPv4/DHCPv6/DDNS server.

# deb https://dl.cloudsmith.io/public/isc/kea-1-6/deb/ubuntu focal main # disabled on upgrade to focal

# deb-src https://dl.cloudsmith.io/public/isc/kea-1-6/deb/ubuntu bionic main
::::::::::::::
/etc/apt/sources.list.d/isc-kea-1-6.list.distUpgrade
::::::::::::::
# Source: Cloudsmith (support@cloudsmith.io)
# Repository: ISC - Internet Systems Consortium / kea-1.6
# Description: Kea 1.6. This is the current STABLE version of the Kea DHCPv4/DHCPv6/DDNS server.

# deb https://dl.cloudsmith.io/public/isc/kea-1-6/deb/ubuntu focal main # disabled on upgrade to focal

# deb-src https://dl.cloudsmith.io/public/isc/kea-1-6/deb/ubuntu bionic main

これらはUbuntu 18.04の時にCloudsmithのリポジトリを使って入れたものです。OSのパッケージとCloudsmithのパッケージに関しては以下を参照下さい。

2022/10時点のstable版である2.2系のCloudsmithリポジトリを使うことに。

$ curl -1sLf \
  'https://dl.cloudsmith.io/public/isc/kea-2-2/setup.deb.sh' \
  | sudo -E bash
Executing the  setup script for the 'isc/kea-2-2' repository ...

   OK: Checking for required executable 'curl' ...
   OK: Checking for required executable 'apt-get' ...
   OK: Detecting your OS distribution and release using system methods ...
 ^^^^: ... Detected/provided for your OS/distribution, version and architecture:
 >>>>:
 >>>>: ... distro=ubuntu  version=22.04  codename=jammy  arch=x86_64
 >>>>:
   OK: Checking for apt dependency 'apt-transport-https' ...
   OK: Checking for apt dependency 'ca-certificates' ...
   OK: Checking for apt dependency 'gnupg' ...
  RUN: Importing 'isc/kea-2-2' repository GPG key ...gpg: WARNING: unsafe ownership on homedir '/home/kotetsu/.gnupg'
   OK: Checking for apt signed-by key support ...
   OK: Importing 'isc/kea-2-2' repository GPG key ...
   OK: Checking if upstream install config is OK ...
   OK: Installing 'isc/kea-2-2' repository via apt ...
   OK: Updating apt repository metadata cache ...
   OK: The repository has been installed successfully - You're ready to rock!


$ cat /etc/apt/sources.list.d/isc-kea-2-2.list
# Source: ISC - Internet Systems Consortium
# Site: https://www.isc.org
# Repository: ISC - Internet Systems Consortium / kea-2-2
# Description: A certifiably-awesome public package repository curated by ISC - Internet Systems Consortium, hosted by Cloudsmith.


deb [signed-by=/usr/share/keyrings/isc-kea-2-2-archive-keyring.gpg] https://dl.cloudsmith.io/public/isc/kea-2-2/deb/ubuntu jammy main

deb-src [signed-by=/usr/share/keyrings/isc-kea-2-2-archive-keyring.gpg] https://dl.cloudsmith.io/public/isc/kea-2-2/deb/ubuntu jammy main

どうせコメントアウトされているけど古いのを除外しつつ

$ sudo mv /etc/apt/sources.list.d/isc-kea-1-6.list* ~/work/kea/

$ sudo apt-get clean

$ sudo apt update
Get:1 https://dl.cloudsmith.io/public/isc/kea-2-2/deb/ubuntu jammy InRelease [5104 B]
Hit:2 http://security.ubuntu.com/ubuntu jammy-security InRelease
Hit:3 http://archive.ubuntu.com/ubuntu jammy InRelease
Get:4 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [114 kB]
Get:5 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [99.8 kB]
Fetched 219 kB in 4s (60.8 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
4 packages can be upgraded. Run 'apt list --upgradable' to see them.


$ apt list --upgradable
Listing... Done
isc-kea-admin/jammy 2.2.0-isc20220726061131 amd64 [upgradable from: 1.6.3-isc0044120200730112858]
isc-kea-common/jammy 2.2.0-isc20220726061131 amd64 [upgradable from: 1.6.3-isc0044120200730112858]
isc-kea-ctrl-agent/jammy 2.2.0-isc20220726061131 amd64 [upgradable from: 1.6.3-isc0044120200730112858]
isc-kea-dhcp4-server/jammy 2.2.0-isc20220726061131 amd64 [upgradable from: 1.6.3-isc0044120200730112858]


$ sudo apt upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
  libboost-system1.65.1 liblog4cplus-1.1-9 libmysqlclient20
Use 'sudo apt autoremove' to remove them.
Try Ubuntu Pro beta with a free personal subscription on up to 5 machines.
Learn more at https://ubuntu.com/pro
The following NEW packages will be installed:
  liblog4cplus-2.0.5 libmysqlclient21 python3-isc-kea-connector
The following packages will be upgraded:
  isc-kea-admin isc-kea-common isc-kea-ctrl-agent isc-kea-dhcp4-server
4 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
Need to get 5533 kB of archives.
After this operation, 9501 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y

...

sudo apt upgrade中に確認が入りますが設定ファイルは現行のものを残すようにしました。

Configuration file '/etc/kea/kea-ctrl-agent.conf'
 ==> Modified (by you or by a script) since installation.
 ==> Package distributor has shipped an updated version.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer's version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a shell to examine the situation
 The default action is to keep your current version.
*** kea-ctrl-agent.conf (Y/I/N/O/D/Z) [default=N] ? N


...

Configuration file '/etc/kea/kea-dhcp4.conf'
 ==> Modified (by you or by a script) since installation.
 ==> Package distributor has shipped an updated version.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer's version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a shell to examine the situation
 The default action is to keep your current version.
*** kea-dhcp4.conf (Y/I/N/O/D/Z) [default=N] ? N

...

後処理して一応reboot

$ sudo apt autoclean -y
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done


$ sudo apt autoremove -y
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages will be REMOVED:
  libboost-system1.65.1 liblog4cplus-1.1-9 libmysqlclient20
0 upgraded, 0 newly installed, 3 to remove and 0 not upgraded.
After this operation, 4636 kB disk space will be freed.
(Reading database ... 110648 files and directories currently installed.)
Removing libboost-system1.65.1:amd64 (1.65.1+dfsg-0ubuntu5) ...
Removing liblog4cplus-1.1-9 (1.1.2-3.2build1) ...
Removing libmysqlclient20:amd64 (5.7.39-0ubuntu0.18.04.2) ...
Processing triggers for libc-bin (2.35-0ubuntu3.1) ...


$ sudo reboot

するとisc-kea-dhcp4-server.serviceがfailedになってしまい、この記事の問題を知りました。(先にリリースノートをちゃんと熟読しておらず...)

$ journalctl -u isc-kea-dhcp4-server.service | less
...
ERROR [kea-dhcp4.dhcp4/590] DHCP4_PARSER_FAIL failed to create or run parser for configuration element client-classes: definition for the option 'dhcp4.default-url' does not exist (/etc/kea/kea-dhcp4.conf:2>

で単純に設定ファイルのs/default-url/v4-captive-portal/gで対応

$ sudo sed -ie 's/default-url/v4-captive-portal/g' /etc/kea/kea-dhcp4.conf
$ sudo grep default-url /etc/kea/kea-dhcp4.conf
$ sudo grep v4-captive-portal /etc/kea/kea-dhcp4.conf
        //    "name": "v4-captive-portal",
                    "name": "v4-captive-portal",
                    "name": "v4-captive-portal",
                    "name": "v4-captive-portal",
                #    "name": "v4-captive-portal",


$ sudo systemctl restart isc-kea-dhcp4-server.service

今度は別のエラーで起動失敗
まあ書いてある通りKeaのバックエンドに使っているMySQLのschemaが古い模様

$ journalctl -u isc-kea-dhcp4-server.service | less
...
ERROR [kea-dhcp4.dhcp4/1219.140587984404096] DHCP4_INIT_FAIL failed to initialize Kea server: configuration error using file '/etc/kea/kea-dhcp4.conf': Unable to open database: MySQL schema version mismatc>

公式ドキュメント 4.3.2.2. Upgrading a MySQL Database From an Earlier Version of Kea に従いshemaのアップデートします。
が...何やらまたエラーが...。

$ kea-admin db-version mysql -u kea -p password -n kea
mysql: [Warning] Using a password on the command line interface can be insecure.
8.2


$ kea-admin db-upgrade mysql -u kea -p password -n kea
Database version reported before upgrade: mysql: [Warning] Using a password on the command line interface can be insecure.
8.2

Verifying upgrade permissions for kea
mysql: [Warning] Using a password on the command line interface can be insecure.
MySQL Version is: 8.0.30
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1419 (HY000) at line 1: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
ERROR/kea-admin: mysql_can_create cannot trigger, check user permissions, mysql status = 1
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR/kea-admin: Create failed, the user, kea, has insufficient privileges.

公式ドキュメント 4.3.2.1. First-Time Creation of the MySQL Database に対処方法が書いてある通りlog_bin_trust_function_creatorsを1に設定します。

# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 22
Server version: 8.0.30 MySQL Community Server - GPL

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set @@global.log_bin_trust_function_creators = 1;
Query OK, 0 rows affected (0.00 sec)

mysql> quit
Bye

#

これでschemaのアップデートができました。

$ kea-admin db-upgrade mysql -u kea -p password -n kea
Database version reported before upgrade: mysql: [Warning] Using a password on the command line interface can be insecure.
8.2

Verifying upgrade permissions for kea
mysql: [Warning] Using a password on the command line interface can be insecure.
MySQL Version is: 8.0.30
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql: [Warning] Using a password on the command line interface can be insecure.
Processing /usr/share/kea/scripts/mysql/upgrade_001.0_to_002.0.sh file...
mysql: [Warning] Using a password on the command line interface can be insecure.
This script upgrades 1.0 to 2.0. Reported version is 8.2. Skipping upgrade.

...

Database version reported after upgrade: mysql: [Warning] Using a password on the command line interface can be insecure.
14.0


$ kea-admin db-version mysql -u kea -p password -n kea
mysql: [Warning] Using a password on the command line interface can be insecure.
14.0

これで正常起動しました。

$ sudo systemctl restart isc-kea-dhcp4-server.service

事後バージョン

$ sudo apt show isc-kea-common
Package: isc-kea-common
Version: 2.2.0-isc20220726061131
Priority: optional
Section: libs
Source: isc-kea
Maintainer: Kea <isc-kea@packages.debian.org>
Installed-Size: 13.0 MB
Depends: adduser, libc6 (>= 2.34), libgcc-s1 (>= 3.3.1), liblog4cplus-2.0.5 (>= 2.0.5), libmysqlclient21 (>= 8.0.11), libpq5 (>= 9.1~), libssl3 (>= 3.0.0~~alpha1), libstdc++6 (>= 12)
Conflicts: kea-common
Homepage: http://kea.isc.org/
Download-Size: 3282 kB
APT-Manual-Installed: no
APT-Sources: https://dl.cloudsmith.io/public/isc/kea-2-2/deb/ubuntu jammy/main amd64 Packages
Description: Common libraries for the ISC Kea DHCP server
 Kea is an IPv4 and IPv6 DHCP server developed by Internet Systems Consortium.
 .
 This package provides common libraries used by ISC Kea servers and utilities.
 It also contains a base set of hook libraries: bootp, ha, flex_option,
 lease_cmds, mysql_cb, pgsql_cb, stat_cmds and run_script.


$ sudo apt show isc-kea-dhcp4-server
Package: isc-kea-dhcp4-server
Version: 2.2.0-isc20220726061131
Priority: optional
Section: net
Source: isc-kea
Maintainer: Kea <isc-kea@packages.debian.org>
Installed-Size: 1110 kB
Depends: isc-kea-common (= 2.2.0-isc20220726061131), lsb-base, libc6 (>= 2.34), libgcc-s1 (>= 3.3.1), libstdc++6 (>= 12)
Recommends: libcap2-bin
Suggests: isc-kea-doc
Conflicts: kea-dhcp4-server
Homepage: http://kea.isc.org/
Download-Size: 359 kB
APT-Manual-Installed: yes
APT-Sources: https://dl.cloudsmith.io/public/isc/kea-2-2/deb/ubuntu jammy/main amd64 Packages
Description: ISC Kea IPv4 DHCP server
 Kea is an IPv4 and IPv6 DHCP server developed by Internet Systems Consortium
 providing a very high-performance with PostgreSQL, MySQL and memfile backends.
 .
 This package provides the IPv4 DHCP server.

最後に

僕らがあんなに慣れ親しんだ"DHCP option code 114 = URL"という常識が2年も前に変わっていたこと、それに気付かなかったことに驚いたので記録として残しておきました。では。

Unbound の cache-max-ttl 設定

概要

Unbound には cache-max-ttl という設定があります。
unbound.conf(5)

       cache-max-ttl: <seconds>
              Time  to  live maximum for RRsets and messages in the cache. De-
              fault is 86400 seconds (1 day).  When the TTL expires, the cache
              item  has  expired.   Can  be set lower to force the resolver to
              query for data often, and not trust  (very  large)  TTL  values.
              Downstream clients also see the lower TTL.

少し古いバージョン(今回の例だと Ubuntu 18.04 に apt で降ってくる 1.6.7)だと、特定の構成では巧く働いてくれない...という話です。
解決策は Ubuntu を 20.04 にあげて Unbound も 1.9.4 にあげることです。

なお、本問題は cache-max-ttl というメールスレッド(パッチ付)を見ると簡潔に纏まっています。

発生した問題

構成は以下

  • クライアントは Ubuntu 18.04 で systemd-resolved が cache 有効で動いている
    • systemd-resolved で以下のDNSキャッシュサーバ(Unbound)を指定している (設定は netplan でやっている)
  • DNSキャッシュサーバは Ubuntu 18.04 + Unbound 1.6.7 で cache-max-ttl 設定は 1800s

クライアントから original ttl が 1800 以上のレコードを引いて ttl の様子を見てみると、最初は original ttl の 10800 だったのが cache-max-ttl 設定の 1800s 後に 9000 から 10800 に戻っています。10800 から始まるから分かりにくいものの 1800s で cache が切れてくれてはいます。

$ dig www5e.biglobe.ne.jp @<Unbound ip address>

; <<>> DiG 9.11.3-1ubuntu1.15-Ubuntu <<>> www5e.biglobe.ne.jp @<Unbound ip address>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2113
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www5e.biglobe.ne.jp.           IN      A

;; ANSWER SECTION:
www5e.biglobe.ne.jp.    10800    IN      A       133.208.182.75

;; Query time: 0 msec
;; SERVER: <Unbound ip address>#53(<Unbound ip address>)
;; WHEN: Fri Oct 01 12:34:16 JST 2021
;; MSG SIZE  rcvd: 64


$ dig www5e.biglobe.ne.jp @<Unbound ip address>

; <<>> DiG 9.11.3-1ubuntu1.15-Ubuntu <<>> www5e.biglobe.ne.jp @<Unbound ip address>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2113
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www5e.biglobe.ne.jp.           IN      A

;; ANSWER SECTION:
www5e.biglobe.ne.jp.    9000    IN      A       133.208.182.75

;; Query time: 0 msec
;; SERVER: <Unbound ip address>#53(<Unbound ip address>)
;; WHEN: Fri Oct 01 13:04:17 JST 2021
;; MSG SIZE  rcvd: 64



$ dig www5e.biglobe.ne.jp @<Unbound ip address>

; <<>> DiG 9.11.3-1ubuntu1.15-Ubuntu <<>> www5e.biglobe.ne.jp @<Unbound ip address>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2113
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www5e.biglobe.ne.jp.           IN      A

;; ANSWER SECTION:
www5e.biglobe.ne.jp.    10800    IN      A       133.208.182.75

;; Query time: 0 msec
;; SERVER: <Unbound ip address>#53(<Unbound ip address>)
;; WHEN: Fri Oct 01 13:04:19 JST 2021
;; MSG SIZE  rcvd: 64

ここで cache 有効な systemd-resolved が噛む形にすると original ttl の値が使われてしまい、Unbound で設定している cache-max-ttl 設定が想定通りに働かなくなってしまいます。1800sを超えても cache が残り続けます...。

$ dig www5e.biglobe.ne.jp

; <<>> DiG 9.11.3-1ubuntu1.15-Ubuntu <<>> www5e.biglobe.ne.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64774
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;www5e.biglobe.ne.jp.           IN      A

;; ANSWER SECTION:
www5e.biglobe.ne.jp.    10800   IN      A       133.208.182.75

;; Query time: 179 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Fri Oct 01 13:24:34 JST 2021
;; MSG SIZE  rcvd: 64



$ dig www5e.biglobe.ne.jp

; <<>> DiG 9.11.3-1ubuntu1.15-Ubuntu <<>> www5e.biglobe.ne.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64774
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;www5e.biglobe.ne.jp.           IN      A

;; ANSWER SECTION:
www5e.biglobe.ne.jp.    8400   IN      A       133.208.182.75

;; Query time: 179 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Fri Oct 01 14:04:35 JST 2021
;; MSG SIZE  rcvd: 64

対処

というわけで調査したところ、まんま本問題を示している前述の cache-max-ttl というメールスレッドを見つけました。
この改修パッチは unbound/doc/Changelog の通り 2018/12 には取り込まれているようです。

Ubuntu 18.04 に apt で入れた Unbound 1.6.7 (2017/10 release) では踏むけれど、Ubuntu 20.04 なら Unbound 1.9.4 (2019/10 release)で踏まない筈... ということで Unbound を動かしている Ubuntu を 18.04 から 20.04 に upgarade して Unbound も 1.9.4 にあげたところ、問題は解決しました。

Unbound からは cache-max-ttl より大きな original ttl ではなく cache-max-ttl 設定値が返ってくるようになり、

$ dig www5e.biglobe.ne.jp @<Unbound ip address>

; <<>> DiG 9.11.3-1ubuntu1.15-Ubuntu <<>> www5e.biglobe.ne.jp @<Unbound ip address>
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3042
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www5e.biglobe.ne.jp.           IN      A

;; ANSWER SECTION:
www5e.biglobe.ne.jp.    1800    IN      A       133.208.182.75

;; Query time: 20 msec
;; SERVER: <Unbound ip address>#53(<Unbound ip address>)
;; WHEN: Fri Oct 01 18:48:24 JST 2021
;; MSG SIZE  rcvd: 64

cache 有効な systemd-resolved が噛む形にしても Unbound で設定している cache-max-ttl 設定が効いてくれるようになりました。

$ dig www5e.biglobe.ne.jp

; <<>> DiG 9.11.3-1ubuntu1.15-Ubuntu <<>> www5e.biglobe.ne.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63263
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;www5e.biglobe.ne.jp.           IN      A

;; ANSWER SECTION:
www5e.biglobe.ne.jp.    1756    IN      A       133.208.182.75

;; Query time: 1 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Fri Oct 01 18:49:31 JST 2021
;; MSG SIZE  rcvd: 64

余談

前述のメールスレッドを追うと「必ずしもクライアントからの問い合わせに上流の resolver が override した ttl 値を返すのが良い挙動ではない (元の挙動が望ましいこともある)」という意見が出ています。
現状の実装を見ると serve-original-ttl という設定で挙動を切り替えられるようにしているようです。デフォルトは no なので override する挙動です。

       serve-original-ttl: <yes or no>
              If  enabled,  unbound will always return the original TTL as re-
              ceived from the upstream name server rather than the  decrement-
              ing  TTL  as stored in the cache.  This feature may be useful if
              unbound serves as a front-end to  a  hidden  authoritative  name
              server.  Enabling  this feature does not impact cache expiry, it
              only changes the TTL unbound embeds  in  responses  to  queries.
              Note  that enabling this feature implicitly disables enforcement
              of the configured minimum and maximum  TTL,  as  it  is  assumed
              users  who enable this feature do not want unbound to change the
              TTL obtained from an upstream server.  Thus, the values set  us-
              ing  cache-min-ttl  and  cache-max-ttl  are ignored.  Default is
              "no".
 if(!SERVE_ORIGINAL_TTL && (*rr_ttl > MAX_TTL))
        *rr_ttl = MAX_TTL;

InMon sFlow-RT + Prometheus / Grafana でお手軽 sFlow collector 環境

はじめに

やること

「お手軽に無償で sFlow collector を立てて実験をしたい!」...そんな時の候補になりうる構成を例示します。
タイトル通り「InMon sFlow-RT (sFlow collector & Prometheus の scrape 受け & リアルタイムデータ可視化) + Prometheus (metrics 収集 & 過去データ蓄積) + Grafana (過去データ可視化)」という構成です。

これまではそんな時に

などを動かしていましたが、Prometheus + Grafana が既に動いている環境では今回紹介する構成も良いと思います。
ただし本構成の場合には sFlow agent 側で sampling rate / interval をキリキリ突き詰めても、過去データ保存はあくまで Prometheus 側の scrape interval 設定に依存して丸まってしまう点は要注意かもです。今回はお手軽環境の話で、そんなシビアな話はしませんが。

注意事項 (InMon sFlow-RT ライセンス周り)

InMon sFlow-RT License Agreement によると

  1. Only use for research purposes and evaluation purposes is permitted. All use in production networks, including production networks in academic; research; and non-profit institutions, is prohibited.

とのことですので、ラボ環境のみで使うようにしましょう。

なお inMon sFlow-RT / Download and install の "Production use" のところには「Production ライセンス利用するには InMon の営業に相談して下さい」的な文言もあります。

参考資料

  • inMon / sFlow-RT 公式
    • sFlow collector + REST API + リアルタイム可視化インタフェース + Prometheus exporter などのアプリケーションがある
    • 今回はこれの Docker コンテナ版を使う
      • Dockerhub / sflow/prometheus
        • "sflow-rt/prometheus is an sFlow-RT application that receives a continuous stream of telemetry from standard sFlow agents embedded in network devices, hosts and applications and exports metrics so that the Prometheus time series database can scrape them."
    • ↑は sFlow-RT 専用サイトで inMon Corp. 公式サイト内の sFlow-RT のページは こちら sFlow-RT
      • ほぼ↑のサイトへのリンクのみ
  • blog.sflow.com / Prometheus exporter
    • 本項の元ネタ記事 その1
    • sFlow-RT を sFlow collector として動かしつつ Prometheus から scrape も受ける構成
    • 収集する metrics として sFlow Host Structures に着目
  • blog.sflow.com / Flow metrics with Prometheus and Grafana
    • 本項の元ネタ記事 その2
    • sFlow-RT を sFlow collector として動かしつつ Prometheus から scrape も受ける構成
    • 収集する metrics として Flow Sample に着目
  • Grafana / Published Dashboards / sflow
    • InMon が公開している sFlow-RT と組み合わせて使える Grafana ダッシュボード
    • そのままインポートして好みでカスタマイズするなり、定義を参考にするなり

動かす

今回は sFlow-RT に焦点をあてており、Prometheus や Grafana のデプロイ手順や sFlow agent 側の話はしません。

環境情報

sflow-rt/prometheus の Docker イメージを動かす仮想サーバは以下

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

$ docker --version
Docker version 20.10.6, build 370c289

$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c

仮想マシンスペックは 4vCPU, 8GB Memory, 32GB disk 程度
作り(ローカルにデータを溜め込む機能がない)的にディスクは食わないので適当で良いですが、受ける flow の多寡に合わせて CPU, Memory はカスタマイズするのが良いでしょう

sflow-rt/prometheus Docker

rpm , deb パッケージやソースから入れることも出来るようですが、今回は Docker コンテナで立てます。
InMon sFlow-RT / Download / Applications に Application と提供 Docker Image の一覧があります。今回使いたい機能的に "sflow/prometheus" を。

docker-conpose.yml は以下のように作りました。
コメントにも書いていますが InMon sFlow-RT / Reference / System Propertiescommand で指定可能な各種パラメータの説明があります。

version: '3'

services:
  # see.
  #  https://hub.docker.com/r/sflow/prometheus
  #  https://sflow-rt.com/reference.php#properties
  sflow-prometheus:
    image: sflow/prometheus:latest
    ports:
      - "8008:8008"
      - "6343:6343/udp"
    command:
      - '-Dsnmp.ifname=yes'
      - '-Dsnmp.version=2c'
      - '-Dsnmp.community=COM-KOTETSU'
    environment:
      - TZ=Asia/Tokyo
      - RTMEM=4G
    restart: always

以下パラメータの補足

  • ports
    • "8008:8008"API,Webインターフェース,Prometheus scrape 受け用
    • "6343:6343/udp" は sFlow 受け用
  • command
    • '-Dsnmp.ifname=yes'
      • yes にすると sFlow を送ってきた agent に SNMP Get を仕掛けて ifIndexifNameマッピングsysName を取得してくれる
    • -Dsnmp.version=2c -Dsnmp.community=COM-KOTETSU
      • 上記の SNMP Get で使う version, community のデフォルト値パラメータ
      • 何も設定しないと 2c community がデフォルトになる
  • environment
    • RTMEM=4G はコンテナ内で動く Java アプリケーションの Max Heap size など
      • 指定すると java -Xms4G -Xmx4G で動く
      • デフォルト値は 1GB

docker-compose up -d でコンテナ起動

ちなみに SNMP Get を有効化した時にどういうタイミングで Get するのか見ようとしたのですが、全然 SNMP Get パケットが観測されませんでした。
これに関しては sFlow-RT google group / SNMP with sflowtrend and sflow-rt にて開発者が以下のようにコメントしていました。

sFlow-RT makes very few SNMP requests. It will only make a request for the sysName and ifName associated with an interface that it sees in an sFlow counter sample. If the SNMP request fails, it will be retried 10 minutes later. If the request succeeds, the result is retained for 24 hours before being refreshed.

sFlow-RT のWebインターフェースを眺める

コンテナが起動したらブラウザで http://<docker-composeを動かしている母艦のIPアドレス>:8008 にアクセスすれば sFlow-RT の Status 画面が出てくるはずです。

f:id:kakkotetsu:20210528180056p:plain
sFlow-RT Status

HTTPS アクセスや認証などのためにリバースプロキシ配下で動かす時には InMon sFlow-RT / Download / Download and install にある例示のように設定すれば良いです。質素な画面なのもあって特段リバプロ設定でハマることもなく。

画面上部のメニューで Apps を選択すると本コンテナ版で提供している Application 4 つが表示されます。

f:id:kakkotetsu:20210528180210p:plain
sFlow-RT Apps

リアルタイムで Flow 情報を参照できる Flow Browser

f:id:kakkotetsu:20210528180235p:plain
sFlow-RT FlowBrowser

リアルタイムで metrics (Counters Sample で得たインターフェースカウンタや OS の情報) を参照できる Metric Browser

f:id:kakkotetsu:20210528180303p:plain
sFlow-RT MetricBrowser

なお sFlow-RT でサポートしている Metrics の一覧は InMon sFlow-RT / Reference / Metrics にあります。Broadcom ASIC の各種リソース(Broadcom ASIC Table Utilization Metrics)なんていうマニアックなものにまで対応済!

これらでリアルタイムな Flow Sample, Counters Sample 情報を確認することができます。
なお -Dsnmp.ifname=yes 設定で sysName や ifName の情報をとるようにしていても、これらのアプリケーションでは使われませんでした。

ここから Prometheus 設定することで過去の情報を蓄積して確認したり、得た SysName や ifName の情報を有効活用できるようになります。

Prometheus の設定

sFlow-RT Webインターフェースの Apps の中で Prometheus を選択することで Swagger で動作確認ができるので、特に Flows に関してはこれで色々と素振りをしてみるのが良いでしょう。

f:id:kakkotetsu:20210528180340p:plain
sFlow-RT Prometheus Swagger

と言っても、Analyzer(sFlow-RT 自体の performance metrics) と Metrics(Counter Sample) はほとんどパラメータもないので Docker Hub にある sflow/prometheus の例示 のままで

scrape_configs:

  - job_name: 'sflow-rt-analyzer'
    metrics_path: /prometheus/analyzer/txt
    static_configs:
      - targets: ['<docker-composeを動かしている母艦のIPアドレス>:8008']

  - job_name: 'sflow-rt-metrics'
    metrics_path: /prometheus/metrics/ALL/ALL/txt
    static_configs:
      - targets: ['<docker-composeを動かしている母艦のIPアドレス>:8008']
    metric_relabel_configs:
      - source_labels: ['agent', 'datasource']
        separator: ':'
        target_label: instance

一方 Flow Sample の方は色々とパラメータがあります。
先の Swagger で色々と試しつつ、使える Key などを解説した公式ドキュメント InMon sFlow-RT / Reference / Defining Flows を見つつ、設定を作るのが良いでしょう。

いくつかポイントを書くと

  • sFlow agent の識別
    • URI に agent を定義する部分がある(/export.js/flows/{agent}/txt)が、ALL にしないと agent ごとの metrics 設定をつくる必要がある(ので事実上 ALL 一択かと)
    • これを ALL にした場合は全ての agent の flow データが同一 metrics 名で集まるので、何とか label に agent を識別する情報を入れたい
    • そのためには sflow-rt/prometheusSNMP 系設定で得た SNMPsysName が使える
    • 具体的には node:inputifindex と key を指定するととれる
  • 収集対象 Key の指定
    • 収集対象の Key で指定した情報を持つ flow データのみを得られる、あらゆる flow を得るような指定の仕方はできない
      • 例えば key の中で udpsourceport と指定すると TCP フローは収集対象にならない
    • 本来はこの手の絞り込みは可視化画面の Filter などで実現したいもので、Prometheus で収集する時点では絞り込みをしたくない筈
    • null:<flowkey>:<val> の Key Function を使って null 値を許容することができるようになる
      • 例えば null:udpsourceport:unknow と指定すれば TCP フローも収集対象になり、この label が unknow 値になる
      • ただしこれをやると label 名が null_udpsourceport_unknown のように鬱陶しくなってしまうので、label 設定をすることで udpsourceport のような label 名に上書きできる
    • 中長期的に必要そうな Key をなるべく網羅しつつ nullor を巧く使って定義する、のが現実解か
  • ifName の取得(Flow Sample の ifIndex とのマッピング)
    • sflow-rt/prometheusSNMP 系設定で得た SNMP ifName を得ることができる
    • ifname:inputifindex のように指定すると ifIndex と対応する ifName を得られる
  • FQDN を得る
    • DNS 逆引きができるならば ipsourceipdestination の PTR を引いて得ることができる
    • dns:ipsource のように指定すれば良い
  • 重複した flow と扱い
    • 重複した flow データをどう扱うかは aggMode で設定可能
    • sum max などが使えますが合計する sum にしておくのが良いかと
  • 1回の scrape で取得する flow 数
    • maxFlows で設定可能
    • 何も設定しないとデフォルトで 20 flow しか取得してくれない(無制限にとる動作ではない)ので、増やすべき
    • どれだけ多くしてもエラーにはならないので、どこまで増やせるのかは不明

これらを踏まえて「ほぼ全フローの TCP/UDP Src/Dst port, IPv4 Src/Dst address , MAC Src/Dst address, IN/Out Interface と VLAN 情報を拾う」ように作った設定が以下

scrape_configs:

  - job_name: 'sflow-rt-flow-l4-bps'
    metrics_path: /app/prometheus/scripts/export.js/flows/ALL/txt
    static_configs:
      - targets:
        - <docker-composeを動かしている母艦のIPアドレス>:8008
    params:
      metric: ['sflow_l4_bps']
      key:
        - 'null:[node:inputifindex]:unknown'
        - 'direction'
        - 'inputifindex'
        - 'outputifindex'
        - 'null:[ifname:inputifindex]:unknown'
        - 'null:[ifname:outputifindex]:unknown'
        - 'macsource'
        - 'macdestination'
        - 'null:vlansource:unknown'
        - 'null:vlandestination:unknown'
        - 'null:ethernetprotocol:unknown'
        - 'null:ipsource:unknown'
        - 'null:ipdestination:unknown'
        - 'null:[dns:ipsource]:unknown'
        - 'null:[dns:ipdestination]:unknown'
        - 'null:ipprotocol:unknown'
        - 'null:tcpsourceport:unknown'
        - 'null:tcpdestinationport:unknown'
        - 'null:udpsourceport:unknown'
        - 'null:udpdestinationport:unknown'
      label:
        - 'agent'
        - 'direction'
        - 'inputifindex'
        - 'outputifindex'
        - 'ifname_inputifindex'
        - 'ifname_outputifindex'
        - 'macsource'
        - 'macdestination'
        - 'vlansource'
        - 'vlandestination'
        - 'ethernetprotocol'
        - 'ipsource'
        - 'ipdestination'
        - 'dns_ipsource'
        - 'dns_ipdestination'
        - 'ipprotocol'
        - 'tcpsourceport'
        - 'tcpdestinationport'
        - 'udpsourceport'
        - 'udpdestinationport'
      value: ['bytes']
      scale: ['8']
      aggMode: ['sum']
      maxFlows: ['100000']

これで Prometheus の設定を反映して、定義した Flow Sample 用の metics sflow_l4_bps を取得すると、以下のように Flow の metrics が取得できます
1つ目は TCP フローで src や dst IP address の逆引きが出来るもの、2つ目は UDP フローで src や dst IP address の逆引きができなかったもの

sflow_l4_bps{agent="agent00.example.com",direction="ingress",dns_ipdestination="sv002.example.com.",dns_ipsource="sv000.example.com.",ethernetprotocol="2048",ifname_inputifindex="Ethernet1",ifname_outputifindex="Ethernet3",inputifindex="1",instance="flow000:8008",ipdestination="10.1.0.12",ipprotocol="6",ipsource="10.1.0.10",job="sflow-rt-flow-l4-bps",macdestination="866238CF8AB7",macsource="22169AAD4179",outputifindex="3",tcpdestinationport="6802",tcpsourceport="35530",udpdestinationport="unknown",udpsourceport="unknown",vlandestination="20",vlansource="20"}    6051757.673760984


sflow_l4_bps{agent="agent01",direction="ingress",dns_ipdestination="unknown",dns_ipsource="unknown",ethernetprotocol="2048",ifname_inputifindex="swp31",ifname_outputifindex="swp32",inputifindex="1031",instance="flow000:8008",ipdestination="2.0.0.199",ipprotocol="17",ipsource="1.0.0.199",job="sflow-rt-flow-l4-bps",macdestination="B4A9FCD77F45",macsource="001101000001",outputifindex="1032",tcpdestinationport="unknown",tcpsourceport="unknown",udpdestinationport="34199",udpsourceport="14219",vlandestination="unknown",vlansource="unknown"}    2417374.4902792345

Grafana ダッシュボード作成

前述の Prometheus (もしくはそこから remote_write している VictoriaMetrics) を Data Sources としている Grafana にて用途に合わせたダッシュボードを作ります。

インターフェースの Counters Sample 用のダッシュボードsFlow-RT 自体のキャパシティのダッシュボードは InMon が完成品をあげているので、これをそのまま Import して必要に応じてカスタマイズして使うと良いでしょう。

Flow Sample に関しては sFlow-RT Countries and Networks が参考にはなりますが、自分が欲しいと思う情報のダッシュボードをゼロから作ってやる方が良いかと思います。
ただ、どうしてもよく出来た既製品のように直感的にグリグリと Filter などの絞り込みができる UI を作るのは難しいですね...。

おしまい

冒頭にも書きましたが、Pull 型の Prometheus scrape を挟む都合上、対象 Flow の Key/label を網羅しづらかったり rate の精度が落ちてしまうのは仕方ないかと思います。(他の方式に比べて)
ただその辺のデメリットを知った上で、ちょっと手元で動かす分には良い選択肢かと。
その場のリアルタイムデータさえ見られれば良いならば、Prometheus や Grafana 側は考えずに sflow-rt/prometheus 単体の WebUI でも動きますし。

あと細かい話でいうと ifIndexifNameマッピングやら agent の hostname やら Src/Dst の FQDN やら、この手のものを作る時に少し悩みがちな部分をサクッと設定ひとつで解決してくれるのはナイスです。ちまたでは「SNMP は死んだ」とかよく言われますが、まだ生きてますってば。

そして本当に必要な/欲しい情報を参照できるダッシュボードを作るのは難しい...そこはお手軽じゃーないですね。
あと Flow pps が増えた時にどの程度リソースが必要になるのか、トラシューがお手軽じゃないのでは...って部分は未知数で懸念点ですかね。

DHCP Vendor-specific Information Option の Code, Length フィールド長 実装 (Kea, ISC DHCP)

前置き~やること

DHCP には Vendor-specific Information Option というベンダ固有のデータをやり取りするための Option があります。(IPv4 なら Option code 43, IPv6 なら Option code 17)
この中身は基本構造が RFC で定められており、その範囲内で各ベンダが好きに Code と使い道を定義して使うことが出来ます。
利用者は DHCP サーバでベンダが定義した内容を設定して使うことになります。

IPv4 の場合は RFC2132 で外枠と

   Code   Len   Vendor-specific information
   +-----+-----+-----+-----+---
   |  43 |  n  |  i1 |  i2 | ...
   +-----+-----+-----+-----+---

Encapsulated された Vendor-specific information 内の構造が定められています。

    Code   Len   Data item        Code   Len   Data item       Code
   +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
   |  T1 |  n  |  d1 |  d2 | ... |  T2 |  n  |  D1 |  D2 | ... | ... |
   +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+

本記事では DHCP Vendor-specific Information Option の Encapsulated vendor-specific options field の Code, Length フィールドの長さに関する Kea と ISC DHCP の実装を調査します。
2021 現在 ISC 的には Kea の開発に注力しており、そちらを使うことを推奨しております。

参考資料

調査のきっかけ

IPv4 の Option 43 で実行スクリプトを取得する際に、ISC DHCP の場合は以下のように定義せよ」というモノがありました。

option space test_opt code width 2 length width 2 hash size 17;
option test_opt.script-url code 36 = text;

subnet 192.0.2.128 netmask 255.255.255.128 {
  option routers 192.0.2.129;
  option subnet-mask 255.255.255.128;
  range dynamic-bootp 192.0.2.220 192.0.2.254;
  vendor-option-space test_opt;
  option test_opt.script-url = "http://192.0.2.130/test_script.py";
}

ここで code width 2 length width 2 と定義しているのが曲者です。
ISC DHCP でそのように設定すると DHCP client から Parameter Request List(Option 53) で Option 43 を求めてきた時に、以下のように Option 43 を返します。

0x00.0x24.0x00.0x21....
  • 0x00.0x24code width 2 の設定通り 2byte 分で Code 36 を示しており
  • 0x00.0x21length width 2 の設定通り 2bytes 分で Length 33 を示しており
  • その後に http://192.0.2.130/test_script.py という 33bits の Data が続く

一方 Kea で以下のように設定すると

"Dhcp4": {
    "option-def": [
        {
            "name": "test_opt_script-url",
            "code": 36,
            "space": "vendor-encapsulated-options-space",
            "type": "string"
        }
    ],

    "subnet4": [

        {
            "subnet": "192.0.2.128/25",
            "pools": [ { "pool": "192.0.2.220 - 192.0.2.254" } ],
            "option-data": [
                {
                    "name": "routers",
                    "data": "192.0.2.129"
                },
                {
                    "name": "test_opt_script-url",
                    "space": "vendor-encapsulated-options-space",
                    "data": "http://192.0.2.130/test_script.py"
                },
                {
                    "name": "vendor-encapsulated-options"
                }
            ]
        }
    ]
}

DHCP client から Parameter Request List(Option 53) で Option 43 を求めてきた時に、以下のように Option 43 を返します

0x24.0x21....
  • 0x24 は 1byte 分で Code 36 を示しており
  • 0x21 は 1byte 分で Length 33 を示しており
  • その後に http://192.0.2.130/test_script.py という 33bits の Data が続く

DHCP client 側は Code と Length を 2bytes ずつで来ることに期待しているようで、解釈してくれず。

調査

RFC

参考資料にあげた RFC に目を通すと

Encapsulated された Vendor-specific information 内の Code, Length は IPv6 の場合には 2bytes ずつ固定、IPv4 の場合には 1byte ずつ固定で良さそうです。

ISC DHCP の実装

前述の「調査のきっかけ」で見たとおり、Encapsulated された Vendor-specific information 内の Codes と Length のフィールド長を設定で変えることが出来ます。
IPv4 であっても 2bytes にしたり。

参考資料にあげたドキュメントにもそう書かれています、option space 設定の文法は IPv4IPv6 も共通なのでそうなるのでしょう。

option space name [ [ code width number ] [ length width number ] [ hash size number ] ] ;

Where the numbers following code width, length width, and hash size respectively identify the number of bytes used to describe option codes, option lengths, and the size in buckets of the hash tables to hold options in this space (most DHCPv4 option spaces use 1 byte codes and lengths, which is the default, whereas most DHCPv6 option spaces use 2 byte codes and lengths).

The code and length widths are used in DHCP protocol - you must configure these numbers to match the applicable option space you are configuring. They each default to 1. Valid values for code widths are 1, 2 or 4. Valid values for length widths are 0, 1 or 2. Most DHCPv4 option spaces use 1 byte codes and lengths, which is the default, whereas most DHCPv6 option spaces use 2 byte codes and lengths. A zero-byte length produces options similar to the DHCPv6 Vendor-specific Information Option - but not their contents!

Kea の実装

ドキュメント

これを見ても Encapsulated された Vendor-specific information 内の Codes と Length のフィールド長については明記されていないようです。

ISC DHCP の設定を Kea に convert (KEA Migration Assistant (aka keama))

KEA Migration Assistant (aka keama) という ISC DHCP の設定ファイルを Kea の設定ファイルに convert するツールが ISC 公式であります。

試しにこれを使って option space test_opt code width 2 length width 2 hash size 17; 設定を含む ISC DHCP 設定ファイルを convert してみます。

$ curl -1sLf \
>   'https://dl.cloudsmith.io/public/isc/keama/setup.deb.sh' \
>   | sudo -E bash

$ apt search isc-dhcp-keama
Sorting... Done
Full Text Search... Done
isc-dhcp-keama/focal 4.4.2 amd64
  ISC DHCP Kea Migration Assistant

$ sudo apt install -y isc-dhcp-keama

$ keama -h
Unknown command: -h
Usage: keama [-4|-6] [-D] [-N] [-r {perform|fatal|pass}\n [-l hook-library-path] [-i input-file] [-o output-file]


$ keama -4 -i /etc/dhcp/dhcpd.conf -o /tmp/keama_output

生成されたファイルを見ると

$ more /tmp/keama_output
{
  # dhcpd.conf
  #
  # Sample configuration file for ISC dhcpd
  #
  # Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as
  # configuration file instead of this file.
  #
  # option definitions common to all supported networks...
  /// This configuration declares some subnets but has no interfaces-config
  /// Reference Kea #245
  "Dhcp4": {
//  "option-space": {
//    "name": "test_opt",
//    /// Only code width 1 is supported
//    "code-width": 2,
//    /// Only length width 1 is supported
//    "length-width": 2
//  },
    "option-def": [
      {
        "space": "test_opt",
        "name": "script-url",
        "code": 36,
        "type": "string"
      }
    ],
    "subnet4": [
      {
        "id": 2,
        "subnet": "192.0.2.128/25",
        "option-data": [
          {
            "space": "dhcp4",
            "name": "routers",
            "code": 3,
            "data": "192.0.2.129"
          },
          {
            "space": "dhcp4",
            "name": "subnet-mask",
            "code": 1,
            "data": "255.255.255.128"
          },
          {
            "name": "vendor-encapsulated-options",
            "code": 43
          },
          {
            "space": "test_opt",
            "name": "script-url",
            "code": 36,
            "csv-format": false,
//          "original-data": "http://192.0.2.130/test_script.py",
            "data": "687474703a2f2f3139322e302e322e3133302f746573745f7363726970742e7079"
          }
        ],
        "pools": [
          {
            "pool": "192.0.2.220 - 192.0.2.254"
          }
        ],
        "option-def": [
          {
            "name": "vendor-encapsulated-options",
            "code": 43,
            "type": "empty",
            "encapsulate": "test_opt"
          }
        ]
      }
    ]
  }
}

思いっきり Only code width 1 is supported と書かれています

 //  "option-space": {
 //    "name": "test_opt",
 //    /// Only code width 1 is supported
 //    "code-width": 2,
 //    /// Only length width 1 is supported
 //    "length-width": 2
 //  },

Kea メーリングリストより

Kea のメーリングリストで 2021/04/23 に ISC 開発者の方からの以下メールがありました。

[Kea-users] How to define "code width" / "length width" on Vendor-Specific Information option (code 43)

You can't: Kea wires these widths to the DHCP version (one octet for v4 and two for v6). You have to use the binary format or to write a hook converting the option content.

BTW if the RFC 2132 loosely specifies the option 43 there is a SHOULD about the suboption format which clearly does not allow 2x2 widths. Now I saw enough options 43 with not compliant contents I am not surprised...

Regards

Encapsulated された Vendor-specific information 内の Codes と Length のフィールド長は IPv4 なら 1byte 固定で IPv6 なら 2bytes 固定 (hook を書いて無理矢理どうにかしない限り)、という実装のようです。

おしまい

DHCP の Vendor-specific Information Option を用いる場合、ベンダは通常「Encapsulated された Vendor-specific information 内の Codes と Length のフィールド長は、IPv4 ならば 1byte を使い IPv6 なら 2bytes を使う」ことを示してそう実装するのが良いでしょう。
というか普通はそうなっていると思います。今回私が出会った実装がイマイチだったので突っ込んでおきましょう...。

それにしても ISC が Kea を推奨して何年か経ちますが、世間の設定例ではまだまだ ISC DHCP の例示が多いですね。Kea での例示に変わっていくと良いのですが。
まあ 2021 年に DHCP サーバを自前で立てて運用している層がどれだけいるんだって話もありますが...。

Ansible AWX の upgrade が楽になっていた (v14.1.0 -> v16.0.0)

小ネタです
Ansible AWX の upgrade というと、かつては「新バージョンで作り直してデータを export import で migrate すれば(一部のデータを除いて)出来るっぽい」「それは商用版であるところの Tower を買えば出来る」といった状況で正直面倒でした
が、いつのまにか大変楽に「新しいコンテナイメージをとってくるだけ」に近い手順で upgrade できるようになっていました

事前情報

参考ドキュメント

環境情報

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.1 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal


$ docker --version
Docker version 20.10.2, build 2291f61


$ docker-compose --version
docker-compose version 1.26.2, build unknown

upgrade (v14.1.0 -> v16.0.0)

upgrade 前は v14.1.0 の環境です

  • v14.1.0 新規 install には docker-compose 利用
  • PostgreDB は外部(ホスト的には AWX と同居)のものを利用
    • デフォルトは AWX がコンテナを用意する
 ______________ 
<  AWX 14.1.0  >
 -------------- 
        \   ^__^
         \  (oo)\_______
            (__)      A )\/\
                ||----w |
                ||     ||

Ansible 2.9.11
Copyright © 2019 Red Hat, Inc.
Visit Ansible.com for more information.

事前バックアップ

AWX / PostgreDB が乗っている仮想マシンのスナップショットをとっただけ
本来的には PostgreDB のバックアップなど丁寧にやると良いのでしょうが

upgrade

最新バージョンのリポジトリを clone してきて

$ mkdir ~/work/awx_16.0.0
$ cd ~/work/awx_16.0.0/

$ git clone https://github.com/ansible/awx.git -b 16.0.0
Cloning into 'awx'...
remote: Enumerating objects: 15, done.
remote: Counting objects: 100% (15/15), done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 262009 (delta 6), reused 1 (delta 0), pack-reused 261994
Receiving objects: 100% (262009/262009), 233.40 MiB | 13.33 MiB/s, done.
Resolving deltas: 100% (202532/202532), done.
Note: switching to '9bf721665d9ec3a29aa24f209c1b6cfc5554daea'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false


$ cd awx/
$ git show
commit 9bf721665d9ec3a29aa24f209c1b6cfc5554daea (HEAD, tag: 16.0.0)
Merge: 871b86273 5f6a383eb
Author: softwarefactory-project-zuul[bot] <33884098+softwarefactory-project-zuul[bot]@users.noreply.github.com>
Date:   Thu Dec 10 17:39:28 2020 +0000

    Merge pull request #8723 from ryanpetrello/bump-16

    Bump version to 16.0.0

    Reviewed-by: https://github.com/apps/softwarefactory-project-zuul

各種インストールパラメータが書いてある inventory ファイルだけは新規インストールに使ったものを流用しています
(公式では password 系だけを新規 vars.yml に用意する手順)
以下の ~/work/awx/installer/inventory が前のバージョンを新規インストールした時に作った設定ファイルです

$ cd installer/
$ cp ~/work/awx/installer/inventory .
$ git diff
diff --git a/installer/inventory b/installer/inventory
index 89d0684a7..7d0e9dfa8 100644
--- a/installer/inventory
+++ b/installer/inventory
@@ -62,13 +62,13 @@ dockerhub_base=ansible
 # Common Docker parameters
 awx_task_hostname=awx
 awx_web_hostname=awxweb
-postgres_data_dir="~/.awx/pgdocker"
+#postgres_data_dir="~/.awx/pgdocker"
 host_port=80
 host_port_ssl=443
 #ssl_certificate=
 # Optional key file
 #ssl_certificate_key=
-docker_compose_dir="~/.awx/awxcompose"
+docker_compose_dir="/opt/awx/awxcompose"

 # Required for Openshift when building the image on your own
 # Optional for Openshift if using Dockerhub or another prebuilt registry
@@ -82,21 +82,15 @@ docker_compose_dir="~/.awx/awxcompose"

 # Set pg_hostname if you have an external postgres server, otherwise
 # a new postgres service will be created
-# pg_hostname=postgresql
+pg_hostname=10.3.12.53
 pg_username=awx
 # pg_password should be random 10 character alphanumeric string, when postgresql is running on kubernetes
 # NB: it's a limitation of the "official" postgres helm chart
-pg_password=awxpass
+pg_password=password
 pg_database=awx
 pg_port=5432
 #pg_sslmode=require

-# If requiring SSL communication (e.g. pg_sslmode='verify-full') with Postgres
-# and using a self-signed certificate or a certificate signed by a custom CA
-# set pg_root_ca_file to a file containing the self-signed certificate or the
-# root CA certificate chain.
-# pg_root_ca_file='example_root_ca.crt'
-
 # The following variable is only required when using the provided
 # containerized postgres deployment on OpenShift
 # pg_admin_password=postgrespass
@@ -115,7 +109,7 @@ pg_port=5432
 # This will create or update a default admin (superuser) account in AWX, if not provided
 # then these default values are used
 admin_user=admin
-admin_password=password
+admin_password=admin

 # Whether or not to create preload data for demonstration purposes
 create_preload_data=True
@@ -136,9 +130,9 @@ secret_key=awxsecret
 # awx_official=false

 # Container networking configuration
 # Set the awx_task and awx_web containers' search domain(s)
@@ -151,7 +145,7 @@ secret_key=awxsecret
 #project_data_dir=/var/lib/awx/projects

 # AWX custom virtual environment folder. Only usable for local install.
-#custom_venv_dir=/opt/my-envs/
+custom_venv_dir=/opt/awx/my-envs/

 # CA Trust directory. If you need to provide custom CA certificates, supplying
 # this variable causes this directory on the host to be bind mounted over
@@ -178,6 +172,6 @@ secret_key=awxsecret
 #

 # Add extra hosts to docker compose file. This might be necessary to
-# sneak in servernames. For example for DMZ self-signed CA certificates.
+# sneak in servernames. For exmaple for DMZ self-signed CA certificates.
 # Equivialent to using the --add-host parameter with "docker run".
 #docker_compose_extra_hosts="otherserver.local:192.168.0.1,ldap-server.local:192.168.0.2"

あとは新規インストールの時と同様に playbook を流すだけ

$ ansible-playbook -i inventory install.yml

...<snip>

TASK [local_docker : Create Docker Compose Configuration] *******************************************************************************************************************************************************************************
ok: [localhost] => (item={'file': 'environment.sh', 'mode': '0600'})
changed: [localhost] => (item={'file': 'credentials.py', 'mode': '0600'})
ok: [localhost] => (item={'file': 'docker-compose.yml', 'mode': '0600'})
changed: [localhost] => (item={'file': 'nginx.conf', 'mode': '0600'})
ok: [localhost] => (item={'file': 'redis.conf', 'mode': '0664'})

TASK [local_docker : Render SECRET_KEY file] ********************************************************************************************************************************************************************************************
ok: [localhost]

TASK [local_docker : Start the containers] **********************************************************************************************************************************************************************************************
changed: [localhost]

TASK [local_docker : Update CA trust in awx_web container] ******************************************************************************************************************************************************************************
changed: [localhost]

TASK [local_docker : Update CA trust in awx_task container] *****************************************************************************************************************************************************************************
changed: [localhost]

TASK [local_docker : Create Preload data] ***********************************************************************************************************************************************************************************************
ok: [localhost]

PLAY RECAP ******************************************************************************************************************************************************************************************************************************
localhost                  : ok=12   changed=4    unreachable=0    failed=0    skipped=95   rescued=0    ignored=0

状態確認

$ docker ps --no-trunc
CONTAINER ID                                                       IMAGE                COMMAND                                                  CREATED       STATUS         PORTS                  NAMES
ccddcc82e0de1d3c0755c6acb5e7b5ffe22a80539d6ef542ba3236494886e66d   ansible/awx:16.0.0   "/usr/bin/tini -- /usr/bin/launch_awx_task.sh"           2 hours ago   Up 3 minutes   8052/tcp               awx_task
9f3370c7b6f956efded176b4ce48710db2dda15e068e3b76325cea27e27c6fc9   ansible/awx:16.0.0   "/usr/bin/tini -- /bin/sh -c /usr/bin/launch_awx.sh"     2 hours ago   Up 3 minutes   0.0.0.0:80->8052/tcp   awx_web
5e375b9f22fb8c83fc507ee1398390258b34b1e5fda24a185bb25a43bcb8f98a   redis                "docker-entrypoint.sh /usr/local/etc/redis/redis.conf"   2 hours ago   Up 3 minutes   6379/tcp               awx_redis
$ cd /opt/awx/awxcompose/

$ docker-compose images
Container   Repository     Tag       Image Id       Size
----------------------------------------------------------
awx_redis   redis         latest   41de2cc0b30e   104.2 MB
awx_task    ansible/awx   16.0.0   125dda56af33   1.535 GB
awx_web     ansible/awx   16.0.0   125dda56af33   1.535 GB


$ docker-compose logs --tail=30

GUI アクセスも良さげ

f:id:kakkotetsu:20210113134623p:plain

認証情報や template などなど一通り前のバージョンで作っていたものが残っていることを確認

余談ですが、今回は install に使う playbook 内の roll なども最新で使いたいのでマルっとリポジトリを pull してきて使いましたが、単にリポジトリ直下の VERSION をあげたいバージョンに書き換えて install.yml を流すだけでも動くといえば動きます

upgrade 後に発生するかも知れない問題

割とバージョン固有な話が多いですが、自分がブチ当たった問題をいくつか紹介しておきます

upgrade 後 GUI で Settings ページにアクセスできなくなっていた

自分はこの問題に遭遇したのですが、upgrade 後に GUI で Settings ページが正しく表示されない問題が起きました

$ docker-compose logs --tail=30

...<snip>

awx_web  | 2021/01/13 02:35:21 [crit] 90#0: *253 open() "/var/lib/nginx/tmp/uwsgi/9/00/0000000009" failed (13: Permission denied) while reading upstream, client: 10.3.12.13, server: _, request: "OPTIONS /api/v2/settings/all/ HTTP/1.1", upstream: "uwsgi://127.0.0.1:8050", host: "10.3.12.53", referrer: "http://10.3.12.53/"

Can't go to Settings page. Nothing happens の issue を見ると、前々からバージョンアップ時に発生することがある問題のようで、以下のように権限設定修正してやれば直りました

$ docker exec -it awx_web bash -c "chown -R nginx:nginx /var/lib/nginx"

upgrade 後 HTTP しか使っていないのに WebSocket 通信が wss でされる (v16.0.0 固有問題)

upgrade 後に WebUI で WebSocket 周りがちゃんと動いていないように見えたのですが、こんな Issue がありました
試していないけど HTTPS 環境では元々 wss で動くので問題が顕在化しないかもです

Websockets defaults to wss when connecting unsecurely

upgrade 後 ジョブ実行時の output が auto refresh されない (v16.0.0 固有問題)

upgrade 後に ジョブ実行した時に完了するまで output が出力されない問題が起きました
以下のような Issue がありました

AWX 16.0.0 UI not auto refreshing job output

upgrade 後 dynamic inventory スクリプトを指定する入力が出来なくなっていた (v16.0.0 固有問題?)

upgrade 後に inventories > Sources で Sourced from a Project を使って Inventory File 欄に Dynamic Inventory のスクリプトを指定しようとしたら、入力できませんでした
探すと以下の Issue がありました

inventory file field should be typable

おしまい

大した手順ではないのですが「大した手順でなくなって良かったね」という話です
何年か前に「AWX?コンテナなら upgrade なんて latest 取ってくるだけっしょ?」と言われて泣いたことがあるのですが、今なら「そんな感じっすね」と言えそうです

ARISTA cEOS-lab で NETCONF を動かす (小ネタ)

小ネタです
twitter で「A社のnetconf動作確認失敗」「マニュアルでは記載あるのに使えない」「たぶん、旧バージョンでは使えていたけど新バージョンで廃止。でドキュメントはメンテしてないのパターンだろう」という噂を見かけたので、実際にどうなのか動かしてみます

結果から先に書くと、2020/03/23 時点でダウンロードできた最新の cEOS-lab 4.23.2F で最低限の動作(<get-config>)は動きました

事前情報

環境情報

ARISTA 公式の Software Download ページ からとってきた 2020/03/23 時点で最新版 の cEOS-lab

localhost>show ver
 cEOSLab
Hardware version:
Serial number:
System MAC address:  0242.ac11.3eb8

Software image version: 4.23.2F
Architecture:           i686
Internal build version: 4.23.2F-15405360.4232F
Internal build ID:      4cde5c53-3642-4934-8bcc-05691ffd79b3

cEOS tools version: 1.1

Uptime:                 7 weeks, 3 days, 4 hours and 33 minutes
Total memory:           2040924 kB
Free memory:            1282940 kB

上記の docker image を動かす母艦

$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic


$ uname -a
Linux testvm 4.15.0-76-generic #86-Ubuntu SMP Fri Jan 17 17:24:28 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux


$ docker --version
Docker version 19.03.8, build afacb8b7f0

動作確認

環境準備 (cEOS-lab deploy)

前述の cEOS-lab image ダウンロードページに手順のテキストも置いてあるので、その通りにやっただけです
後ほど、この母艦の外から NETCONF 接続をするので docker create 時に NETCONF のデフォルトTCPポートを突けるように -p 830:830 しておくのが今回の固有ポイント

$ ll
total 391128
drwxrwxr-x 2 kotetsu kotetsu      4096 Mar 23 07:11 ./
drwxrwxr-x 3 kotetsu kotetsu      4096 Mar 23 07:10 ../
-rw-rw-r-- 1 kotetsu kotetsu 400501512 Mar 23 07:11 cEOS-lab-4.23.2F.tar.xz
-rw-rw-r-- 1 kotetsu kotetsu       153 Mar 23 07:11 cEOS-lab-4.23.2F.tar.xz.sha512sum

$ sha512sum cEOS-lab-4.23.2F.tar.xz
40af1a1fa456bb0eb3b99aabddc1905614d032f84fb947070d1818e4cb48b9f655723effbdc03ed782b44461789d01a8935f775684086b28f32bfed65df9b94d  cEOS-lab-4.23.2F.tar.xz


$ docker import cEOS-lab-4.23.2F.tar.xz ceosimage:4.23.2F
sha256:3228be9a009f6931cd07f3867f3f2f5be288f440158412f980d1197fd699dac5

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
ceosimage           4.23.2F             3228be9a009f        About a minute ago   1.74GB


$ docker create --name=ceos1 --privileged -p 830:830 -e INTFTYPE=eth -e ETBA=1 -e SKIP_ZEROTOUCH_BARRIER_IN_SYSDBINIT=1 -e CEOS=1 -e EOS_PLATFORM=ceoslab -e container=docker -i -t ceosimage:4.23.2F /sbin/init systemd.setenv=INTFTYPE=eth systemd.setenv=ETBA=1 systemd.setenv=SKIP_ZEROTOUCH_BARRIER_IN_SYSDBINIT=1 systemd.setenv=CEOS=1 systemd.setenv=EOS_PLATFORM=ceoslab systemd.setenv=container=docker


$ docker network create net1
fb0cef09267bc7da25ef4394cd80f6333a8433942f8380568b57d15d041b08bf

$ docker network connect net1 ceos1

$ docker start ceos1
ceos1

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
28b52fc3fbde        ceosimage:4.23.2F   "/sbin/init systemd.窶ヲ"   2 minutes ago       Up 9 seconds        0.0.0.0:830->830/tcp   ceos1


$ docker exec -it ceos1 Cli
localhost>

NETCONF 有効化設定 at cEOS-lab

NETCONF で外部から突くために ユーザ作成して NETCONF 有効化

ARISTA EOS Central / OpenConfig 4.20.2.1F Release Notes / NETCONF Transport を参考に
(なお、このリリースノートが twitter 上では「マニュアルでは記載あるのに使えない」として画面キャプされてました)

localhost#conf t
localhost(config)#username kotetsu role network-admin secret kotetsu
localhost(config)#
localhost(config)#management api ?
  external-services  Configure the external(customer specific) web services on HTTP server
  gnmi               Configure GNMI
  gribi              Configure gRIBI
  http-commands      Configure the HTTP Commands API
  netconf            Configure NETCONF
  openconfig         Configure OpenConfig
  restconf           Configure RESTCONF

localhost(config)#management api netconf ?
  <cr>

localhost(config)#management api netconf
localhost(config-mgmt-api-netconf)#transport ?
  ssh  Configure SSH transport for NETCONF

localhost(config-mgmt-api-netconf)#transport ssh ?
  WORD  Transport name

localhost(config-mgmt-api-netconf)#transport ssh TEST-NETCONF ?
  WORD  Transport name
  <cr>

localhost(config-mgmt-api-netconf)#transport ssh TEST-NETCONF
localhost(config-netconf-transport-TEST-NETCONF)#end
localhost#
localhost#show management api netconf
Enabled:            Yes
Server:             running on port 830, in default VRF
localhost#show run
! Command: show running-config
! device: localhost (cEOSLab, EOS-4.23.2F)
!
transceiver qsfp default-mode 4x10G
!
agent Bfd shutdown
agent PowerManager shutdown
agent LedPolicy shutdown
agent Thermostat shutdown
agent PowerFuse shutdown
agent StandbyCpld shutdown
agent LicenseManager shutdown
!
spanning-tree mode mstp
!
no aaa root
!
username kotetsu role network-admin secret sha512 $6$Esck1TwFdZfKszo6$K54/xPLQguinpmY2q4S9IxOg1TZASNdnJYZzhs3FkUujs6uccGJbiYR6w.yOW/ML.G2CowJrFFoU7EtpCpmJe/
!
interface Ethernet1
!
no ip routing
!
management api netconf
   transport ssh TEST-NETCONF
!
end

動作確認 (via remote ssh)

とりあえず外部から ssh で突いてみると、hello メッセージで capability リストを教えてくれてきています
長いので途中で切ってますが...
ちな、ここで <rpc>...</rpc> とか貼っていけばやりとりできます

$ ssh -l kotetsu <docker母艦のIPアドレス> -p 830 -s netconf
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability><capability>urn:ietf:params:netconf:base:1.1</capability><capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability><capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring</capability><capability>urn:ietf:params:netconf:capability:writable-running:1.0</capability><capability>urn:ietf:params:netconf:capability:candidate:1.0</capability><capability>http://arista.com/yang/openconfig/policy/augments?module=arista-rpol-augments&amp;revision=2018-04-12</capability><capability>http://arista.com/yang/openconfig/isis/deviations?module=arista-isis-deviations&amp;revision=2019-05-14</capability><capability>http://openconfig.net/yang/hercules/qos?module=openconfig-hercules-qos&amp;revision=2018-06-01</capability><capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&amp;revision=2013-07-15</capability><capability>http://openconfig.net/yang/openconfig-types?module=openconfig-types&amp;revision=2019-04-16</capability><capability>http://openconfig.net/yang/lacp?module=openconfig-lacp&amp;revision=2018-11-21</capability><capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04</capability><capability>http://openconfig.net/yang/aft?module=openconfig-aft&amp;revision=2019-08-01</capability><capability>http://openconfig.net/yang/system/logging?module=openconfig-system-logging&amp;revision=2018-11-21</capability><capability>http://arista.com/yang/openconfig/acl/deviations?module=arista-acl-deviations&amp;revision=2019-06-17</capability><capability>http://openconfig.net/yang/ospf-types?module=openconfig-ospf-types&amp;revision=2018-11-21</capability><capability>http://openconfig.net/yang/interfaces/ip?module=openconfig-if-ip&amp;revision=2019-01-08</capability><capability>http://arista.com/yang/openconfig/relay-agent/deviations?module=arista-relay-agent-deviations&amp;revision=2016-11-21</capability><capability>http://openconfig.net/yang/platform/fan?module=openconfig-platform-fan&amp;revision=2018-11-21</capability><capability>urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&amp;revision=2011-06-01</capability><capability>http://openconfig.net/yang/routing-policy?module=openconfig-routing-policy&amp;revision=2018-11-21</capability><capability>http://openconfig.net/yang/network-instance-l3?module=openconfig-network-instance-l3&amp;revision=2018-11-21</capability><capability>http://openconfig.net/yang/vlan-types?module=openconfig-vlan-types&amp;revision=2019-01-31</capability><capability>http://arista.com/yang/openconfig/local-routing/deviations?module=arista-local-routing-deviations&amp;revision=2017-11-22</capability><capability>http://arista.com/yang/experimental/eos/eos-types?module=arista-eos-types&amp;revision=2016-10-14</capability><capability>http://openconfig.net/yang/system/terminal?module=openconfig-system-terminal&amp;revision=2018-11-21</capability>

...snip

動作確認 (via Python ncclient)

有名どころの NETCONF クライアントライブラリを使って <get-config> くらいまでは見ておきましょーか

以下のような NETCONF クライアント用の Python venv 環境を用意して

$ pip list --format=columns
Package       Version
------------- -------
bcrypt        3.1.7
cffi          1.14.0
cryptography  2.8
lxml          4.5.0
ncclient      0.6.7
paramiko      2.7.1
pip           9.0.1
pkg-resources 0.0.0
pycparser     2.20
PyNaCl        1.3.0
setuptools    39.0.1
six           1.14.0


$ python3 --version
Python 3.6.9

NETCONF で cEOS-lab に <get-config> して xml を標準出力するだけの簡易スクリプトを用意して

#!/usr/bin/env python3
from ncclient import manager
import xml.dom.minidom

with manager.connect(host='<docker母艦のIPアドレス>', port=830, username='kotetsu', password='kotetsu', hostkey_verify=False) as m:
    c = m.get_config(source='running').data_xml
    print(xml.dom.minidom.parseString(c).toprettyxml())
$ ./nc-test.py > result.log

Gist / ceos-lab_4.23.2F_netconf_get-config.xml にカットなしのモノは置きましたが、以下が出力の一部です

<?xml version="1.0" ?>
<data time-modified="2020-03-23T08:03:36.805590273Z" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
        <acl xmlns="http://openconfig.net/yang/acl"/>
        <arista xmlns="http://arista.com/yang/experimental/eos">
                <eos>
                        <bridging xmlns="http://arista.com/yang/experimental/igmpsnooping">
                                <igmpsnooping>
                                        <config/>
                                </igmpsnooping>
                        </bridging>
                        <mlag xmlns="urn:aristanetworks:yang:experimental:eos">
                                <config>
                                        <dual-primary-action>action-none</dual-primary-action>
                                        <enabled>true</enabled>
                                        <heartbeat-interval>4000</heartbeat-interval>
                                        <heartbeat-peer-address>
                                                <address>0.0.0.0</address>
                                                <vrf/>
                                        </heartbeat-peer-address>
                                        <lacp-standby>false</lacp-standby>
                                </config>
                        </mlag>
                        <qos xmlns="http://arista.com/yang/experimental/eos/qos">
                                <acl xmlns="http://arista.com/yang/experimental/eos/qos/acl">
                                        <input>
                                                <cli>


...snip


                                <input xmlns="http://arista.com/yang/experimental/eos/qos/config">
                                        <config>
                                                <cli>
                                                        <servicePolicyConfig>
                                                                <key-direction>input</key-direction>
                                                                <key-pmapName>copp-system-policy</key-pmapName>
                                                                <key-type>mapControlPlane</key-type>
                                                        </servicePolicyConfig>
                                                </cli>
                                        </config>
                                </input>
                        </qos>
                        <routing xmlns="http://arista.com/yang/experimental/multicast">
                                <multicast>
                                        <routeconfig>
                                                <static>
                                                        <vrfConfig>
                                                                <vrfName>default</vrfName>
                                                        </vrfConfig>
                                                </static>
                                        </routeconfig>
                                </multicast>
                        </routing>
                </eos>
        </arista>

...snip

        <interfaces xmlns="http://openconfig.net/yang/interfaces">
                <interface>
                        <name>Ethernet1</name>
                        <config>
                                <description/>
                                <enabled>true</enabled>
                                <load-interval xmlns="http://arista.com/yang/openconfig/interfaces/augments">300</load-interval>
                                <loopback-mode>false</loopback-mode>
                                <mtu>0</mtu>
                                <name>Ethernet1</name>
                                <tpid xmlns="http://openconfig.net/yang/vlan" xmlns:oc-vlan-types="http://openconfig.net/yang/vlan-types">oc-vlan-types:TPID_0X8100</tpid>
                                <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>
                        </config>
                        <ethernet xmlns="http://openconfig.net/yang/interfaces/ethernet">
                                <config>
                                        <fec-encoding xmlns="http://arista.com/yang/openconfig/interfaces/augments">
                                                <disabled>false</disabled>
                                                <fire-code>false</fire-code>
                                                <reed-solomon>false</reed-solomon>
                                                <reed-solomon544>false</reed-solomon544>
                                        </fec-encoding>
                                        <forwarding-viable xmlns="http://openconfig.net/yang/hercules/interfaces">true</forwarding-viable>
                                        <mac-address>00:00:00:00:00:00</mac-address>
                                        <port-speed>SPEED_UNKNOWN</port-speed>
                                        <sfp-1000base-t xmlns="http://arista.com/yang/openconfig/interfaces/augments">false</sfp-1000base-t>
                                </config>
                        </ethernet>
                        <hold-time>
                                <config>
                                        <down>0</down>
                                        <up>0</up>
                                </config>
                        </hold-time>
                        <subinterfaces>
                                <subinterface>
                                        <index>0</index>
                                        <config>
                                                <description/>
                                                <enabled>true</enabled>
                                                <index>0</index>
                                        </config>
                                        <ipv4 xmlns="http://openconfig.net/yang/interfaces/ip">
                                                <config>
                                                        <dhcp-client>false</dhcp-client>
                                                        <enabled>false</enabled>
                                                        <mtu>1500</mtu>
                                                </config>
                                        </ipv4>
                                        <ipv6 xmlns="http://openconfig.net/yang/interfaces/ip">
                                                <config>
                                                        <dhcp-client>false</dhcp-client>
                                                        <dup-addr-detect-transmits>1</dup-addr-detect-transmits>
                                                        <enabled>false</enabled>
                                                        <mtu>1500</mtu>
                                                </config>
                                        </ipv6>
                                </subinterface>
                        </subinterfaces>

...snip

                </interface>
        </interfaces>

...snip

        <lldp xmlns="http://openconfig.net/yang/lldp">
                <config>
                        <enabled>true</enabled>
                        <hello-timer>30</hello-timer>
                        <management-address xmlns="http://arista.com/yang/openconfig/lldp/augments">
                                <interface/>
                                <network-instance>default</network-instance>
                                <transmit-mode>BEST</transmit-mode>
                        </management-address>
                </config>
                <interfaces>
                        <interface>
                                <name>Ethernet1</name>
                                <config>
                                        <enabled>true</enabled>
                                </config>
                        </interface>
                </interfaces>
        </lldp>

        </system>
</data>

おしまい

最低限の動作を見ただけですが、以下まとめ/所感

  • cEOS-lab 4.23.2F で NETCONF <get-config> までは動くことを確認できた
  • 実際に生で NETCONF を使う人がいるかどうかは知らんけど(ARISTA の API としては古くから eAPI という結構良い感じのがあるし )、ARISTA のマニュアル構造的には YANG, OpenConfig のサポートのために動くようにしているのかな...
  • こういうちょっとしたコントロール系動作だけなら cEOS-lab は軽くて良さげ