- はじめに
- gNMIってなに?
- Sample Labの構成
- 実際にgNMIで設定してみる
- gNMIで状態を確認してみる
- おわりに
はじめに
この記事はシスコの同志による Advent Calendar2020 一枚目の一部として投稿しています
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
今年はIOS-XRのProgrammabilityについて少し書いてみようかと思います。
gNMIってなに?
gNMIはぐぐるとすでに結構な数の記事がヒットしますので、そちらを参照頂いたほうが詳細が記載されていると思いますが、gNMI (gRPC Network Management Interface)は、gRPCをベースとした、ネットワーク機器を管理/操作するためのプロトコルとして定義されています。
gRPCについてはさらに大量の記事がヒットするので、ここでは説明を割愛します。
個人的には今までModel Drivenという文脈ではNetconfと連呼してきましたが、今回はgNMIを紹介させていただきます。
gNMIのInstallはopenconfigでもcisco gNMIでも他のものでもお好みで良い気がします。(多少差分があってSampleが動かなかったりするかもしれませんが。。。)
YANGはGithubにNative/Open configともに上がっていますが、今回は横着してSample Labを利用して試してみたいと思います。
Sample Labの構成
Sample Labの構成を確認すると、gNMIだけではなくAnsibleやNetconf、Model-Driven SDKなどたくさんのシナリオが用意してあって遊びがいがありますが、このうち今回はgNMIだけについて触ります。
admin@controller:xr-pl2$ tree -d -L 5
.
├── ansible
│ └── ip_destination_reachable
│ └── library
├── gnmi
├── md-sdk
├── md-sdk+telemetry
├── netconf
└── yang
└── modules
└── cisco-ios-xr
└── 711
11 directories
gNMIのDirectoryには以下のようにXR Native Yang modelとOpenconfig Yang modelが用意してあり、IFやISISの設定をするためのJSONが用意されています。
ちょっと遊ぶだけならこれを使い回すだけで十分ですね。
admin@controller:gnmi$ ls -al
total 72
drwxrwxr-x 2 admin admin 4096 Feb 5 2020 .
drwxrwxr-x 9 admin admin 4096 Feb 5 2020 ..
lrwxrwxrwx 1 admin admin 65 Feb 5 2020 Cisco-IOS-XR-clns-isis-oper.yang -> ../yang/modules/cisco-ios-xr/711/Cisco-IOS-XR-clns-isis-oper.yang
lrwxrwxrwx 1 admin admin 67 Feb 5 2020 Cisco-IOS-XR-ip-rib-ipv4-oper.yang -> ../yang/modules/cisco-ios-xr/711/Cisco-IOS-XR-ip-rib-ipv4-oper.yang
lrwxrwxrwx 1 admin admin 71 Feb 5 2020 Cisco-IOS-XR-um-if-ip-address-cfg.yang -> ../yang/modules/cisco-ios-xr/711/Cisco-IOS-XR-um-if-ip-address-cfg.yang
lrwxrwxrwx 1 admin admin 67 Feb 5 2020 Cisco-IOS-XR-um-interface-cfg.yang -> ../yang/modules/cisco-ios-xr/711/Cisco-IOS-XR-um-interface-cfg.yang
lrwxrwxrwx 1 admin admin 69 Feb 5 2020 Cisco-IOS-XR-um-router-isis-cfg.yang -> ../yang/modules/cisco-ios-xr/711/Cisco-IOS-XR-um-router-isis-cfg.yang
-rw-rw-r-- 1 admin admin 830 Feb 5 2020 oc-interfaces-gi1-cfg.json
-rw-rw-r-- 1 admin admin 158 Feb 5 2020 oc-interfaces-gi1-enabled-cfg.json
lrwxrwxrwx 1 admin admin 54 Feb 5 2020 openconfig-if-ip.yang -> ../yang/modules/cisco-ios-xr/711/openconfig-if-ip.yang
lrwxrwxrwx 1 admin admin 59 Feb 5 2020 openconfig-interfaces.yang -> ../yang/modules/cisco-ios-xr/711/openconfig-interfaces.yang
-rw-rw-r-- 1 admin admin 81 Feb 5 2020 xr-interfaces-briefs-oper-filter.json
-rw-rw-r-- 1 admin admin 209 Feb 5 2020 xr-interfaces-gi0-shutdown-cfg.json
-rw-rw-r-- 1 admin admin 160 Feb 5 2020 xr-isis-neighbors-oper-filter.json
-rw-rw-r-- 1 admin admin 742 Feb 5 2020 xr-rib-172016255002-oper-filter.json
-rw-rw-r-- 1 admin admin 423 Feb 5 2020 xr-um-interfaces-gi0-cfg.json
-rw-rw-r-- 1 admin admin 173 Feb 5 2020 xr-um-interfaces-gi0-shutdown-cfg.json
-rw-rw-r-- 1 admin admin 410 Feb 5 2020 xr-um-interfaces-lo0-cfg.json
-rw-rw-r-- 1 admin admin 1454 Feb 5 2020 xr-um-interfaces-lo100-vrf-cfg.json
-rw-rw-r-- 1 admin admin 1962 Feb 5 2020 xr-um-isis-cfg.json
実際にgNMIで設定してみる
XR Native/OpenconfigのIF YANGをpyangで見てみると以下のように見えます。
admin@controller:gnmi$ pyang --format tree --tree-depth 3 Cisco-IOS-XR-um-interface-cfg.yang
module: Cisco-IOS-XR-um-interface-cfg
+--rw interfaces
+--rw interface* [interface-name]
| +--rw interface-name xr:Interface-name
| +--rw sub-interface-type
| | ...
| +--rw ipv4
| +--rw ipv6
| +--rw dampening!
| | ...
| +--rw encapsulation
| | ...
| +--rw shutdown!
| +--rw mtu? uint32
| +--rw logging
| | ...
| +--rw bandwidth? uint32
| +--rw description? string
+--rw interface-preconfigure* [interface-name]
+--rw interface-name xr:Interface-name
+--rw sub-interface-type
| ...
+--rw ipv4
+--rw ipv6
+--rw dampening!
| ...
+--rw encapsulation
| ...
+--rw shutdown!
+--rw mtu? uint32
+--rw logging
| ...
+--rw bandwidth? uint32
+--rw description? string
一方Openconfigは以下のように定義されています。
admin@controller:gnmi$ pyang --format tree --tree-depth 4 openconfig-interfaces.yang
module: openconfig-interfaces
+--rw interfaces
+--rw interface* [name]
+--rw name -> ../config/name
+--rw config
| +--rw type identityref
| +--rw mtu? uint16
| +--rw name? string
| +--rw description? string
| +--rw enabled? boolean
+--ro state
| +--ro type identityref
| +--ro mtu? uint16
| +--ro name? string
| +--ro description? string
| +--ro enabled? boolean
| +--ro ifindex? uint32
| +--ro admin-status enumeration
| +--ro oper-status enumeration
| +--ro last-change? yang:timeticks
| +--ro counters
| ...
+--rw hold-time
| +--rw config
| | ...
| +--ro state
| ...
+--rw subinterfaces
+--rw subinterface* [index]
...
まずはNative Modelを用いてLooopback 0の設定を入れてみます。
admin@controller:gnmi$ more xr-um-interfaces-lo0-cfg.json
{
"Cisco-IOS-XR-um-interface-cfg:interfaces": {
"interface": [
{
"interface-name": "Loopback0",
"description": "LOCAL TERMINATION ADDRESS",
"ipv4": {
"Cisco-IOS-XR-um-if-ip-address-cfg:addresses": {
"address": {
"address": "172.16.255.1",
"netmask": "255.255.255.255"
}
}
}
}
]
}
}
admin@controller:gnmi$ gnmi set --verbose --operation update --config xr-um-interfaces-lo0-cfg.json cisco:cisco@198.18.1.11
2020-12-22 04:20:44,000 - gnmi_client.gnmi_client.commands.rpc - INFO - Decoded rpc
2020-12-22 04:20:44,001 - ydk - INFO -
=============== Set Request Sent ================
update {
path {
origin: "Cisco-IOS-XR-um-interface-cfg"
elem {
name: "interfaces"
}
}
val {
json_ietf_val: "{\"interface\":[{\"interface-name\":\"Loopback0\",\"description\":\"LOCAL TERMINATION ADDRESS\",\"ipv4\":{\"Cisco-IOS-XR-um-if-ip-address-cfg:addresses\":{\"address\":{\"address\":\"172.16.255.1\",\"netmask\":\"255.255.255.255\"}}}}]}"
}
}
2020-12-22 04:20:45,275 - ydk - INFO -
============= Set Response Received =============
response {
path {
origin: "Cisco-IOS-XR-um-interface-cfg"
elem {
name: "interfaces"
}
}
message {
}
op: UPDATE
}
message {
}
timestamp: 1579200650765690987
2020-12-22 04:20:45,276 - ydk - INFO - Set Operation Succeeded
Router側で見るとちゃんとLo0にDescritption付きでIP addressが設定されています。
RP/0/RP0/CPU0:R1#show run int lo 0
Thu Jan 16 18:53:48.583 UTC
interface Loopback0
description LOCAL TERMINATION ADDRESS
ipv4 address 172.16.255.1 255.255.255.255
!
次にOpenconfigでGi0/0/0/1を設定するためのJSONが用意されているのでOpenconfigも試してみます。
admin@controller:gnmi$ more oc-interfaces-gi1-cfg.json
{
"openconfig-interfaces:interfaces": {
"interface": [
{
"name": "GigabitEthernet0/0/0/1",
"config": {
"name": "GigabitEthernet0/0/0/1",
"type": "iana-if-type:ethernetCsmacd",
"description": "CONNECTS TO LSR2 (g0/0/0/1)"
},
"subinterfaces": {
"subinterface": [
{
"index": 0,
"openconfig-if-ip:ipv4": {
"addresses": {
"address": [
{
"ip": "172.16.1.2",
"config": {
"ip": "172.16.1.2",
"prefix-length": 31
}
}
]
}
}
}
]
}
}
]
}
}
admin@controller:gnmi$ gnmi set --verbose --operation update --config oc-interfaces-gi1-cfg.json cisco:cisco@198.18.1.11
2020-12-22 04:30:17,299 - gnmi_client.gnmi_client.commands.rpc - INFO - Decoded rpc
2020-12-22 04:30:17,301 - ydk - INFO -
=============== Set Request Sent ================
update {
path {
origin: "openconfig-interfaces"
elem {
name: "interfaces"
}
}
val {
json_ietf_val: "{\"interface\":[{\"name\":\"GigabitEthernet0/0/0/1\",\"config\":{\"name\":\"GigabitEthernet0/0/0/1\",\"type\":\"iana-if-type:ethernetCsmacd\",\"description\":\"CONNECTS TO LSR2 (g0/0/0/1)\"},\"subinterfaces\":{\"subinterface\":[{\"index\":0,\"openconfig-if-ip:ipv4\":{\"addresses\":{\"address\":[{\"ip\":\"172.16.1.2\",\"config\":{\"ip\":\"172.16.1.2\",\"prefix-length\":31}}]}}}]}}]}"
}
}
2020-12-22 04:30:19,281 - ydk - INFO -
============= Set Response Received =============
response {
path {
origin: "openconfig-interfaces"
elem {
name: "interfaces"
}
}
message {
}
op: UPDATE
}
message {
}
timestamp: 1579201224755628859
2020-12-22 04:30:19,283 - ydk - INFO - Set Operation Succeeded
Router側で見るとちゃんとGi0/0/0/1にもDescritption付きでIP addressが設定されています。
RP/0/RP0/CPU0:R1#sh run int gigabitEthernet 0/0/0/1
Thu Jan 16 19:01:15.796 UTC
interface GigabitEthernet0/0/0/1
description CONNECTS TO LSR2 (g0/0/0/1)
ipv4 address 172.16.1.2 255.255.255.254
!
gNMIで状態を確認してみる
gNMIのRPCではsetだけではなくgetもありますので、gNMIで状態確認もしてみようと思います。
Routing tableを取得するJSONなどこのSampleでは色々用意されていますが、その中でInterfadceを設定したのでinterface briefを取得してみます。
admin@controller:gnmi$ more xr-interfaces-briefs-oper-filter.json
{
"Cisco-IOS-XR-pfi-im-cmd-oper:interfaces": {
"interface-briefs": {
}
}
}
admin@controller:gnmi$ gnmi get --type operational --filter xr-interfaces-briefs-oper-filter.json cisco:cisco@198.18.1.11
{
"Cisco-IOS-XR-pfi-im-cmd-oper:interfaces": {
"interface-briefs": {
"interface-brief": [
{
"interface-name": "GigabitEthernet0/0/0/0",
"interface": "GigabitEthernet0/0/0/0",
"type": "IFT_GETHERNET",
"state": "im-state-up",
"actual-state": "im-state-up",
"line-state": "im-state-up",
"actual-line-state": "im-state-up",
"encapsulation": "ether",
"encapsulation-type-string": "ARPA",
"mtu": 1514,
"sub-interface-mtu-overhead": 0,
"l2-transport": false,
"bandwidth": 1000000,
"bandwidth64-bit": "1000000"
},
{
"interface-name": "GigabitEthernet0/0/0/1",
"interface": "GigabitEthernet0/0/0/1",
"type": "IFT_GETHERNET",
"state": "im-state-up",
"actual-state": "im-state-up",
"line-state": "im-state-up",
"actual-line-state": "im-state-up",
"encapsulation": "ether",
"encapsulation-type-string": "ARPA",
"mtu": 1514,
"sub-interface-mtu-overhead": 0,
"l2-transport": false,
"bandwidth": 1000000,
"bandwidth64-bit": "1000000"
},
{
"interface-name": "Loopback0",
"interface": "Loopback0",
"type": "IFT_LOOPBACK",
"state": "im-state-up",
"actual-state": "im-state-up",
"line-state": "im-state-up",
"actual-line-state": "im-state-up",
"encapsulation": "loopback",
"encapsulation-type-string": "Loopback",
"mtu": 1500,
"sub-interface-mtu-overhead": 0,
"l2-transport": false,
"bandwidth": 0,
"bandwidth64-bit": "0"
},
{
"interface-name": "MgmtEth0/RP0/CPU0/0",
"interface": "MgmtEth0/RP0/CPU0/0",
"type": "IFT_ETHERNET",
"state": "im-state-up",
"actual-state": "im-state-up",
"line-state": "im-state-up",
"actual-line-state": "im-state-up",
"encapsulation": "ether",
"encapsulation-type-string": "ARPA",
"mtu": 1514,
"sub-interface-mtu-overhead": 0,
"l2-transport": false,
"bandwidth": 0,
"bandwidth64-bit": "0"
},
{
"interface-name": "Null0",
"interface": "Null0",
"type": "IFT_NULL",
"state": "im-state-up",
"actual-state": "im-state-up",
"line-state": "im-state-up",
"actual-line-state": "im-state-up",
"encapsulation": "null",
"encapsulation-type-string": "Null",
"mtu": 1500,
"sub-interface-mtu-overhead": 0,
"l2-transport": false,
"bandwidth": 0,
"bandwidth64-bit": "0"
}
]
}
}
}
IOS-XRのCLIからshow interface briefを取得するのと同じ情報が無事取得できました。
終わりに
今回はXR自体のProgrammabilityについて、gNMIを試してみました。
gRPCはTelemetryでよく使われると思いますが、gNMIを使えば状態の取得だけじゃなくて設定にも使えるのでできることの幅も広がりますね。
個人的にはXMLよりJSONのほうが見やすくてうれしいなあと思ったりします。
このSampleにはgNMI以外にも色々面白いシナリオが揃っているので興味を持った方がいましたらお試しいただければ幸いです。