IOS-XRのApplication hostingについて考えてみた

1. はじめに
2. IOS-XRとHost Linuxの関係
3. IOS-XR Application hosting
4. Application hostingの用途
5. おわりに

この記事はシスコの有志による Cisco Systems Japan Advent Calendar 2022 （一枚目） の 7日目として投稿しています。

2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco
2020年版: https://qiita.com/advent-calendar/2020/cisco
2020年版(2枚目): https://qiita.com/advent-calendar/2020/cisco2
2021年版: https://qiita.com/advent-calendar/2021/cisco
2021年版(2枚目): https://qiita.com/advent-calendar/2021/cisco2
2022年版(1,2): https://qiita.com/advent-calendar/2022/cisco

## はじめに
少し前の実装になりますが、IOS-XRの6.0以降ではIOS-XR上でThird partyのコンテナを動かすことができるようになりました。
このThird PartyコンテナにはLXCやDcokerを使用することができ、自由にアプリケーションをホストすることが可能です。
この記事ではIOS-XRとそのHost Linuxの関係を説明した上で、IOS-XRのApplication hostingに関わるNetworkについて確認してみようと思います
詳細については[xrdocs](https://xrdocs.io/application-hosting/tutorials/2017-02-26-running-docker-containers-on-ios-xr-6-1-2/)にも公開されていますので、ぜひこちらもご参照ください。

## IOS-XRとHost Linuxの関係
IOS-XRではハイパーバイザーやLXCなどの仮想化レイヤ上で IOS-XRを稼働しています。
IOS-XRのHost LinuxはWind River Linuxを利用しており、BashコマンドでShellに入ることができます。
今回NCS5504の上でコマンドを実施してみると以下のようにWRLのVersionも確認できます。

```
RP/0/RP1/CPU0:R1-NCS5504#bash
Wed Dec  7 15:48:47.171 JST
RP/0/RP1/CPU0:Dec  7 15:48:47.217 JST: bash_cmd[66639]: %INFRA-INFRA_MSG-5-RUN_LOGIN : User cisco logged into shell from vty3
[R1-NCS5504:~]$ cat /etc/*release
ID=ios_xr
ID_LIKE="cisco-wrlinux wrlinux"
NAME=IOS XR
VERSION="7.3.2"
VERSION_ID=7.3.2
PRETTY_NAME="Cisco IOS XR Software, Version 7.3.2"
HOME_URL=http://www.cisco.com
BUILD_ID="2021-10-14-04-13-49"
CISCO_RELEASE_INFO=/etc/cisco-release
ID=wrlinux
NAME=Wind River Linux
VERSION=7.0.0.2
VERSION_ID=7.0.0.2
PRETTY_NAME=Wind River Linux 7.0.0.2
CISCO_RELEASE_INFO=/etc/cisco-release
Hostname     : calcium-99.cisco.com
Workspace    : /nobackup/hetsoi/satori-r73x.release.20210804/target-n9000-gdb
Source Base  : ssh://wwwin-git-sjc-2/git/thinstack/satori.git
Devline      : satori-r73x
Devline Ver  : 7fd205e0ba04ce398bad95059bbf2e6e253bf6a6
Devline Type : GIT Repository
```

また、Host Linux上からもXRが持つIF情報や経路情報を確認することもできます。
いま私の環境ではXR上でIFを以下のように設定しています。

```
RP/0/RP1/CPU0:R1-NCS5504#show ipv4 int bri

Interface                      IP-Address      Status          Protocol Vrf-Name
(snip)
Loopback0                      10.0.255.1      Up              Up       default
MgmtEth0/RP1/CPU0/0            172.20.0.1      Up              Up       mgmt
HundredGigE0/0/0/0             10.0.12.1       Up              Up       default
(snip)
```

これをLinux shellから確認しても以下のように確認することができます。

```
RP/0/RP1/CPU0:R1-NCS5504#bash
Wed Dec  7 15:51:43.800 JST
RP/0/RP1/CPU0:Dec  7 15:51:43.849 JST: bash_cmd[67497]: %INFRA-INFRA_MSG-5-RUN_LOGIN : User cisco logged into shell from vty3
[R1-NCS5504:~]$ ifconfig
Fg0_0_0_30 Link encap:Ethernet  HWaddr 9c:e1:76:16:64:78
          inet6 addr: fe80::9ee1:76ff:fe16:6478/64 Scope:Link
          UP RUNNING NOARP MULTICAST  MTU:9168  Metric:1
          RX packets:241294338 errors:0 dropped:0 overruns:0 frame:0
          TX packets:283380799 errors:0 dropped:0 overruns:0 carrier:3
          collisions:0 txqueuelen:1000
          RX bytes:158447879948 (147.5 GiB)  TX bytes:135709596006 (126.3 GiB)
(snip)
Hg0_0_0_0 Link encap:Ethernet  HWaddr 9c:e1:76:16:64:00
          inet addr:10.0.12.1  Mask:255.255.255.0
          inet6 addr: fe80::9ee1:76ff:fe16:6400/64 Scope:Link
          UP RUNNING NOARP MULTICAST  MTU:9202  Metric:1
          RX packets:1019097259 errors:0 dropped:0 overruns:0 frame:0
          TX packets:856292201 errors:0 dropped:0 overruns:0 carrier:1
          collisions:0 txqueuelen:1000
          RX bytes:466551724222 (434.5 GiB)  TX bytes:479681169248 (446.7 GiB)
(snip)
fwd_ew    Link encap:Ethernet  HWaddr 00:00:00:00:00:0b
          inet6 addr: fe80::200:ff:fe00:b/64 Scope:Link
          UP RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:140 (140.0 B)

fwdintf   Link encap:Ethernet  HWaddr 00:00:00:00:00:0a
          inet6 addr: fe80::200:ff:fe00:a/64 Scope:Link
          UP RUNNING NOARP MULTICAST  MTU:1482  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:16236 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:1092058 (1.0 MiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          inet6 addr: 2001:db8:0:ffff::1/128 Scope:Global
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:4 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:336 (336.0 B)  TX bytes:336 (336.0 B)

lo:0      Link encap:Local Loopback
          inet addr:10.0.255.1  Mask:255.255.255.255
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
```

この出力をみると`Hg0/0/0/0`や`Lo0`などの状態はLinux Shellから確認できることがわかります。
`fwdintf`と`fwd_ew`については以下の図を見ていただくと理解できると思います。

![xr_docker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143031/710913d6-a262-f8e8-6307-0fa722fd9528.png)

この図にあるようにIOS-XR LinuxがIOS-XRのFIBを介してData plane通信を行う際のIFが`fwdintf`でControp planeとの通信を行う際のIFが`fwd_ew`となります。

```
[R1-NCS5504:~]$ ifconfig fwdintf
fwdintf   Link encap:Ethernet  HWaddr 00:00:00:00:00:0a
          inet6 addr: fe80::200:ff:fe00:a/64 Scope:Link
          UP RUNNING NOARP MULTICAST  MTU:1482  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:20787 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:1396304 (1.3 MiB)

[R1-NCS5504:~]$ ifconfig fwd_ew
fwd_ew    Link encap:Ethernet  HWaddr 00:00:00:00:00:0b
          inet6 addr: fe80::200:ff:fe00:b/64 Scope:Link
          UP RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:140 (140.0 B)

[R1-NCS5504:~]$ ip route
default dev fwdintf  scope link  src 10.0.255.1
```

この出力例を見てわかる通り、XR linux上ではDefault routeが`fwdintf`に向いています
つまり、XR linux上のアプリケーションは基本的にRoutingのためにはIOS-XRのFIBを利用しており、`fwdintf`経由でXRのFIBに送信されます。

また、`src 10.0.255.1`につきましてはXR LinuxからのトラフィックのSource IP addressが10.0.255.1であることを意味しています。
これはtpa(third-party-app)アドレスと呼ばれております。
デフォルトではTPAのアドレスはXRで最初に設定されたLoopbackのアドレスを用います。
今回の例ではLoopback0に設定した10.0.255.1を利用しています。

これを変更する場合はIOS-XR CLI上で以下のように設定することで変更する事ができます。

```
RP/0/RP1/CPU0:R1-NCS5504(config)#tpa
RP/0/RP1/CPU0:R1-NCS5504(config-tpa)#address-family ipv4
RP/0/RP1/CPU0:R1-NCS5504(config-tpa-vrf-afi)#update-source hundredGigE 0/0/0/0
RP/0/RP1/CPU0:R1-NCS5504(config-tpa-vrf-afi)#show configuration
Wed Dec  7 15:54:58.034 JST
Building configuration...
!! IOS XR Configuration 7.3.2
tpa
 vrf default
  address-family ipv4
   update-source dataports HundredGigE0/0/0/0
  !
 !
!
end

RP/0/RP1/CPU0:R1-NCS5504(config-tpa-vrf-afi)#commit
RP/0/RP1/CPU0:R1-NCS5504(config-tpa-vrf-afi)#end
RP/0/RP1/CPU0:R1-NCS5504#bash
[R1-NCS5504:~]$ ip route
default dev fwdintf  scope link  src 10.0.12.1
```

今回は10.0.255.1から他のNetworkに疎通できるのでTPAのアドレスは戻して進めます。

次にXRdocsにもありますが、Global VRF Namespaceに直接SSHログインする必要があるのでお作法をこなしておきます。

```

[R1-NCS5504:~]$ adduser tkamata
Login name for new user []:
Come on, man, you can't leave the login field empty...
[R1-NCS5504:~]$ adduser tkamata
Login name for new user []:tkamata

User id for tkamata [ defaults to next available]:

Initial group for tkamata [users]:

Additional groups for tkamata []:sudo

tkamata's home directory [/home/tkamata]:

tkamata's shell [/bin/bash]:

tkamata's account expiry date (MM/DD/YY) []:

OK, Im about to make a new account. Heres what you entered so far:
New login name: tkamata
New UID: [Next available]
Initial group: users
/usr/sbin/adduser: line 68: [: -G: binary operator expected
Additional groups: sudo
Home directory: /home/tkamata
Shell: /bin/bash
Expiry date: [no expiration]
This is it... if you want to bail out, you'd better do it now.

Making new account...
Changing the user information for tkamata
Enter the new value, or press ENTER for the default
        Full Name []:
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Done...
[R1-NCS5504:~]$ service sshd_operns start
SSH service for global-vrf has been created. You may use 'service sshd_operns_global-vrf <start|stop|reload|restart|status>'.
Service can be configured to run on reload using 'chkconfig --add sshd_operns_global-vrf'
Wed Dec 7 16:15:53 JST 2022 /etc/init.d/sshd_operns: Waiting for OPERNS interface creation...
Wed Dec 7 16:15:53 JST 2022 /etc/init.d/sshd_operns: Press ^C to stop if needed.
Wed Dec 7 16:15:53 JST 2022 /etc/init.d/sshd_operns: Found nic, Tg0_0_0_16
Wed Dec 7 16:15:53 JST 2022 /etc/init.d/sshd_operns: Waiting for OPERNS management interface creation...
Wed Dec 7 16:16:54 JST 2022 /etc/init.d/sshd_operns: Waiting for OPERNS management interface... timed out
Wed Dec 7 16:16:54 JST 2022 /etc/init.d/sshd_operns: OPERNS is ready
Wed Dec 7 16:16:54 JST 2022 /etc/init.d/sshd_operns: Start sshd_operns
Starting OpenBSD Secure Shell server: sshd
  generating ssh RSA key...
  generating ssh ECDSA key...
  generating ssh DSA key...
  generating ssh ED25519 key...
```

これで無事にSSHログインできるようになりました。

```
tkamata@jump-ubuntu18-01:~$ ssh 10.0.255.1 -p 57722
The authenticity of host '[10.0.255.1]:57722 ([10.0.255.1]:57722)' can't be established.
ECDSA key fingerprint is SHA256:yhiAWbnJjTSchP6TPnvJDSA1SclfvYZZbI1QA7BBQ0A.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[10.0.255.1]:57722' (ECDSA) to the list of known hosts.
tkamata@10.0.255.1's password:
-sh: /var/log/boot.log: Permission denied
-sh: /var/log/boot.log: Permission denied
-sh: /var/log/boot.log: Permission denied
R1-NCS5504:~$
R1-NCS5504:~$ sudo -i

We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:

    #1) Respect the privacy of others.
    #2) Think before you type.
    #3) With great power comes great responsibility.

Password:
[R1-NCS5504:~]$ whoami
root
```

## IOS-XR Application hosting

本当はここでIOS-XRのDocker版であるXRdをHostingしてみたかったのですが、残念ながらLinux kernelのVersionが合わず動作できませんでした。


```
[R1-NCS5504:~]$ uname -r
3.14.23-WR7.0.0.2_standard
[R1-NCS5504:~]$ ./launch-xrd ios-xr/xrd-control-plane:7.8.1
[ERROR  ] Kernel version of at least 4 is required
[ERROR  ] XRd hit a critical error during initialization and has aborted launch
```

Host linuxのKernel versionを上げるのはさすがに厳しいので、まずはUbuntuを動かしてみようと思います。
Labの中でもPrivate Networkを使っていてDocker pullするのが手間だったので、ちょっと横着してiproute2などを入れてBuildしたTarイメージをLoadしました。

```
[R1-NCS5504:~]$ docker load -i ubuntu.tar
f4462d5b2da2: Loading layer [==================================================>]  75.16MB/75.16MB
fbcf9170a75c: Loading layer [==================================================>]  220.8MB/220.8MB
5770d84ec64a: Loading layer [==================================================>]  352.8kB/352.8kB
d4fd5133c950: Loading layer [==================================================>]  7.168kB/7.168kB
6c3b188a6ce3: Loading layer [==================================================>]  7.168kB/7.168kB
64cd48a8310b: Loading layer [==================================================>]  3.584kB/3.584kB
5f70bf18a086: Loading layer [==================================================>]  1.024kB/1.024kB
Loaded image: ubuntu:20.04
[R1-NCS5504:~]$ docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
ubuntu                     20.04               904a72b97ead        27 minutes ago      285MB
ios-xr/xrd-control-plane   7.8.1               41793e0133d6        10 days ago         1.14GB
[R1-NCS5504:~]$ docker run -itd --name ubuntu -v /var/run/netns/global-vrf:/var/run/netns/global-vrf --cap-add=SYS_ADMIN ubuntu:20.04 bash
1e2cbbf8c2d5aa73ede8d0b32ff698724b73645230f10ad3381f5e94398a34ab
[R1-NCS5504:~]$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
1e2cbbf8c2d5        ubuntu:20.04        "bash"              5 seconds ago       Up 4 seconds                            ubuntu
[R1-NCS5504:~]$ docker exec -it ubuntu bash
root@1e2cbbf8c2d5:/# cat /etc/*-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.5 LTS"
NAME="Ubuntu"
VERSION="20.04.5 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.5 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
```

問題なく立ち上がっています。
が、いまいちDockerネットワークがどうなってるのかわからないので確認してみました。

```
[R1-NCS5504:~]$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5ef51af6cac2        host                host                local
c3b9c0649c06        none                null                local
```

Bridgeはデフォルトではないんですね。。。
手動で追加してDockerにアタッチして再度Dockerを立ち上げてみることにします

```
[R1-NCS5504:~]$ docker network create --subnet 192.168.0.0/24 network01
01386ba851b6cea6f407834a312ae2f4420f3f9a79f1c8ccefd1284758211db4
[R1-NCS5504:~]$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
5ef51af6cac2        host                host                local
01386ba851b6        network01           bridge              local
c3b9c0649c06        none                null                local
[R1-NCS5504:~]$ docker run -itd --net network01 --name ubuntu -v /var/run/netns/global-vrf:/var/run/netns/global-vrf --cap-add=SYS_ADMIN ubuntu:20.04 bash
a27f1580c6a8be9ca3487f9c0b43a3ff26dad45528728a7318d580d286e4b0fe
[R1-NCS5504:~]$ docker exec -it ubuntu bash
root@a27f1580c6a8:/home/cisco# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/16 scope host lo
       valid_lft forever preferred_lft forever
40: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:c0:a8:00:02 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.2/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever
root@a27f1580c6a8:/home/cisco# ping 10.0.255.1
PING 10.0.255.1 (10.0.255.1) 56(84) bytes of data.
64 bytes from 10.0.255.1: icmp_seq=1 ttl=64 time=0.025 ms
64 bytes from 10.0.255.1: icmp_seq=2 ttl=64 time=0.028 ms
64 bytes from 10.0.255.1: icmp_seq=3 ttl=64 time=0.048 ms
64 bytes from 10.0.255.1: icmp_seq=4 ttl=64 time=0.059 ms
^C
--- 10.0.255.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.025/0.040/0.059/0.014 ms
```

XRのLoopback0に無事疎通できるようになりました。

## Application hostingの用途
本当はここから作り込みに行きたかったのですが、XRdなど思うように動かなかったので、ユースケースを紹介してみます。
以下の表をご参照いただければと思いますが、機器のMonitoringや正常性確認などRouter上でApplicationを動かすことによるメリットは色々ありそうです。

![SS 144.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143031/2da4c9e4-a7a0-d85d-c5e1-200cead37ba3.png)

xrdocsにはOpen/Rを動かしつつIOS-XRのService layer APIを叩くことでIOS-XRが対応していないRouting protocolに対応するようなユースケースも紹介されています。
https://xrdocs.io/cisco-service-layer/blogs/2018-02-16-xr-s-journey-to-the-we-b-st-open-r-integration-with-ios-xr/

## 終わりに
今回はIOS-XRのApplication hostingについて紹介いたしました。
自由度が本当に高く色んな使い方ができると思いますので、他にもこんな使い方があるなど思いつく方いたら、ぜひご紹介ください。

おしまい

## 免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。