はじめに
前回に続き、Stratum on BMv2 を触っていきます。 前回は、P4 で定義したテーブルを P4Runtime 経由で操作しました。今回は、gNMI 経由でデバイスの状態取得や設定変更等を実施します。前回同様、ONF Connect ’19 にて開催されていたチュートリアル(EXERCISE 2)をベースに進めていきます。
構成
前回と同様に、Stratum スイッチ 1 台、クライアント 2 台を接続して、お互い通信可能なように P4Runtime 経由でテーブルを登録した状態にします。
gNMI に関して
gNMI (gRPC Network Management Interface)は、名前の通り gRPC をベースにした、ネットワークを管理/操作するためのプロトコルです。ネットワーク装置の状態取得や、設定変更等が可能です。Stratum では、OpenConfig で定義されたモデルの一部を利用しており、チュートリアル用に用意された Docker コンテナ(
bocon/yang-tools:latest)内部で以下のコマンドにより Tree 形式で表示させることが出来ます。bash-4.4# pyang -f tree \
    -p ietf \
    -p openconfig \
    -p hercules \
    openconfig/interfaces/openconfig-interfaces.yang \
    openconfig/interfaces/openconfig-if-ethernet.yang  \
    openconfig/platform/* \
    openconfig/qos/* \
    openconfig/system/openconfig-system.yang \
    hercules/openconfig-hercules-*.yang  | less
gNMI 送信
チュートリアルで用意されている gNMI client を使って装置に接続してみます。以下のコマンドで Get リクエストを送信できます。Path は
/を指定しているため config tree の root を取得する命令となります。util/gnmi-cli --grpc-addr 192.168.122.51:50001 get /
成功すると、以下のような結果が返ってきます。***************************
REQUEST
path {
}
type: CONFIG
encoding: PROTO
***************************
***************************
RESPONSE
notification {
  update {
    path {
    }
    val {
      any_val {
        type_url: "type.googleapis.com/openconfig.Device"
        value: "\252\221\231\304\001&\n\022... // 省略
1 番目のパートは送信したリクエストに関する情報であり、2 番目のパートはレスポンスの情報となっています。
gNMI の生の情報は、Protobuf でバイナリエンコーディングされているため、デコーダーも準備されています。以下のようにパイプでリクエストとつなげることでデコードされた情報を確認できます。
util/gnmi-cli --grpc-addr 192.168.122.51:50001 get / | util/oc-pb-decoder | less
成功すると、以下のような結果が返ってきます。今度は人間が読める形式で Device の情報(インタフェースの情報)が取得出来ていることが分かります。
***************************
REQUEST
path {
}
type: CONFIG
encoding: PROTO
***************************
***************************
RESPONSE
notification {
  update {
    path {
    }
    val {
      any_val {
        type_url: "type.googleapis.com/openconfig.Device"
        value:
component {
  name: "bmv2-simple_switch"
  component {
    chassis {
      platform: OPENCONFIGHERCULESPLATFORMPLATFORMTYPE_GENERIC
    }
  }
}
component {
  name: ":lc-1"
  component {
    linecard {
      slot_id {
        value: "1"
      }
    }
    id {
      value: "1"
    }
  }
}
component {
  name: "eth1"
  component {
    linecard {
      slot_id {
        value: "1"
      }
    }
    transceiver {
      channel {
        index: 1
      }
    }
    integrated_circuit {
      node_id {
        value: 1
      }
    }
    subcomponent {
      name: "eth1"
    }
    port {
      port_id {
        value: 1
      }
    }
  }
}
// 省略
Interface の情報取得
パケットカウンタの情報を取得するために、以下の gNMI リクエストを送信します。util/gnmi-cli --grpc-addr 192.168.122.51:50001 \
    --interval 1000 sub-sample \
    /interfaces/interface[name=eth3]/state/counters/in-unicast-pkts
/interfaces/interface[name=eth3]/state/counters/in-unicast-pktsは、受信ユニキャストのパケット数を示すリソースへの Path を指定しています。Path は、先述した YANG ツリーを辿っていくと確認できます。
sub-sampleは gNMI の STREAM Subscriptions における SAMPLE モードの要求であり、interval 時間毎(今回は 1 秒)にレスポンスを返すモードとなっています。成功すると、以下のような結果が返ってきて、1 秒毎に結果が更新されていることが確認できます。
***************************
REQUEST
subscribe {
  subscription {
    path {
      elem {
        name: "interfaces"
      }
      elem {
        name: "interface"
        key {
          key: "name"
          value: "eth3"
        }
      }
      elem {
        name: "state"
      }
      elem {
        name: "counters"
      }
      elem {
        name: "in-unicast-pkts"
      }
    }
    mode: SAMPLE
    sample_interval: 1000
  }
  updates_only: true
}
***************************
***************************
RESPONSE
update {
  timestamp: 1571898597675982684
  update {
    path {
      elem {
        name: "interfaces"
      }
      elem {
        name: "interface"
        key {
          key: "name"
          value: "eth3"
        }
      }
      elem {
        name: "state"
      }
      elem {
        name: "counters"
      }
      elem {
        name: "in-unicast-pkts"
      }
    }
    val {
      uint_val: 44
    }
  }
}
***************************
Interface の状態制御
次は、Interface の状態を制御して、gNMI でどのように確認できるかを見ていきます。以下のコマンドを発行することで、Interface の運用状態(oper-status)が確認できます。
sub-onchangeを用いて、ON_CHANGE モードの Subscription リクエストを発行しています。util/gnmi-cli --grpc-addr 192.168.122.51:50001 sub-onchange     /interfaces/interface[name=eth3]/state/oper-status
成功すると、以下のような結果が返ってきて、変更待ち受け状態となります。現在は、インタフェースはアップ状態のため、
string_val: "UP"と表示されていることを確認してください。***************************
REQUEST
subscribe {
  subscription {
    path {
      elem {
        name: "interfaces"
      }
      elem {
        name: "interface"
        key {
          key: "name"
          value: "eth3"
        }
      }
      elem {
        name: "state"
      }
      elem {
        name: "oper-status"
      }
    }
    mode: ON_CHANGE
  }
  updates_only: true
}
***************************
***************************
RESPONSE
update {
  timestamp: 1571901432581865924
  update {
    path {
      elem {
        name: "interfaces"
      }
      elem {
        name: "interface"
        key {
          key: "name"
          value: "eth3"
        }
      }
      elem {
        name: "state"
      }
      elem {
        name: "oper-status"
      }
    }
    val {
      string_val: "UP"
    }
  }
}
***************************
***************************
RESPONSE
sync_response: true
***************************
スイッチにコンソール接続し、以下のコマンドを発行して、インタフェースをダウンさせてみます。ifconfig eth3 down
変更するとすぐに、string_val: "DOWN"となることが確認できます。ON_CHANGE のモードで Subscription 発行しているため、変更検知で即時通知されます。また、以下のコマンドでアップ状態に戻すと、状態が即時更新されます。
ifconfig eth3 up
続いて、インタフェースのアップ/ダウンも gNMI 経由で制御してみます。別ターミナルを開いて、以下のように Set リクエストを発行してみます。
util/gnmi-cli --grpc-addr 192.168.122.51:50001 set \
    /interfaces/interface[name=eth3]/config/enabled \
    --bool-val false
コンソールからインタフェースダウンさせた場合と同様に、gNMI で状態が即時更新されていることが確認できます。



