見出し画像

SNMPに代わるネットワーク管理技術gNMIの実験:gNMIcからSNMPのTRAPをTWSNMP FCに送信できた

助手の猫さんは12時に起こしてきていましたが、ご飯をあげてから、まだ寝る時間だと説得して寝てもらいました。
今朝は3時15分に自力で起きました。猫さんは4時すぎに、私の部屋に呼びに来ました。

早起きして昨日のgNMIcからSNMPのTRAPを送信する実験の問題を解決できました。

のサンプルに従って設定したのですが、

2024/09/26 11:51:41.751284 [cache:oc] failed cache query:target "192.168.1.50:57400" not found in cache
2024/09/26 11:51:41.751310 [snmp_output:snmp_trap] failed to build PDU from binding index 0: failed to build PDU, corresponding value not found or too many values found

のようなエラーが多数記録されていて、TRAPにいくつかのMIBが抜けていました。
どうやらgNMIcのバグのようです。

targets:
  192.168.1.50:57400:

のようにtargetsの設定でポート番号を指定すると、このエラーがでるようです。

2024/09/26 11:51:36.750558 [cache:oc] target "192.168.1.50" added to local cache "sub1"

キャッシュに書き込む時は、"192.168.1.50"をターゲットだと思っているのに、読み出す時には、"192.168.1.50:57400"をターゲットに指定していて、ないと言っています。
とりあえず、

targets:
  192.168.1.50:

のように変更すればエラーはなくなりました。

TWSNMP FCでTARPを受信した時、TRAPの種別が空欄になっていました。

TRAPの種類をsnmpTrapOID.0で送るようにgNMIcの設定ファイルを変更しました。

username: admin
password: NokiaSrl1!
skip-verify: true
log: true

targets:
  192.168.1.50:

subscriptions:
  sub1:
    paths:
      - /interface/admin-state
      - /interface/oper-state
      - /interface/ifindex
      - /system/name/host-name
    stream-mode: on-change
    encoding: ascii

outputs:
  snmp_trap:
    type: snmp
    address: 192.168.1.250
    port: 162
    community: public
    cache: 
      type: oc
      # duration, default: 60s.
      # updates older than the expiration value will not be read from the cache.
      expiration: 60s
      # enable extra logging
      debug: true
    traps:
      - trigger:
          path: /interface/oper-state # static path
          oid: '".1.3.6.1.2.1.2.2.1.8"' # ifOperStatus
          type: int
          value: if (.values."/interface/oper-state" == "up") 
                  then 1 
                  else 2 
                  end
        bindings:         
          - path: '"/system/name/host-name"' # jq script
            oid: '".1.3.6.1.2.1.1.5"' # sysName
            type: octetString
            value: '.values."/system/name/host-name"'

          - path: '"/interface[name="+.tags.interface_name+"]/admin-state"' # jq script
            oid: '".1.3.6.1.2.1.2.2.1.7"' # ifAdminStatus
            type: int
            value: if (.values."/interface/admin-state" == "enable") 
                    then 1 
                    else 2 
                    end

          - path: '"/interface[name="+.tags.interface_name+"]/oper-state"' # jq script
            oid: '".1.3.6.1.6.3.1.1.4.1.0"' # sysTrapOID.0
            type: objectID
            value: if (.values."/interface/oper-state" == "up") 
                    then ".1.3.6.1.6.3.1.1.5.4"
                    else ".1.3.6.1.6.3.1.1.5.3"
                    end

          - path: '"/interface[name="+.tags.interface_name+"]/ifindex"' # jq script
            oid: '".1.3.6.1.2.1.2.2.1.1"' # ifIndex
            type: int
            value: '.values."/interface/ifindex" | tonumber' # jq script

これで送ると

いい感じのTRAPを受信できました。SR Linuxの接続先をup/downすれば、ちゃんとTRAPを受信します。

これでgNMIcとTWSNMP FCのSNMP TRAP連携ができることを確認できました。これはTWSNMP FC側を変更しなくても使えます。

次に、gNMIcのTCPアウトプット

との連携テストです。
まず、受信するTCPサーバーを作りました。

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"os"
	"strings"

	"github.com/itchyny/gojq"
)

func main() {
	l, err := net.Listen("tcp", ":3333")
	if err != nil {
		fmt.Println("Error listening:", err.Error())
		os.Exit(1)
	}
	defer l.Close()
	fmt.Println("Listening on :3333")
	for {
		// Listen for an incoming connection.
		conn, err := l.Accept()
		if err != nil {
			fmt.Println("Error accepting: ", err.Error())
			os.Exit(1)
		}
		// Handle connections in a new goroutine.
		go handleRequest(conn)
	}
}

func handleRequest(conn net.Conn) {
	query, err := gojq.Parse(".timestamp")
	if err != nil {
		fmt.Println("Error: ", err)
	}
	buf := make([]byte, 1024*1024)
	for {
		n, err := conn.Read(buf)
		if err != nil {
			log.Println("Error reading:", err.Error())
			break
		}
		log.Printf("%+v", buf[:n])
		for _, l := range strings.Split(string(buf[:n]), "\n") {
			if len(l) < 2 {
				continue
			}
			log.Println(l)
			var data interface{}
			if err := json.Unmarshal([]byte(l), &data); err != nil {
				log.Println(err)
				continue
			}
			iter := query.Run(data)

			for {
				v, ok := iter.Next()
				if !ok {
					break
				}
				if err, ok := v.(error); ok {
					fmt.Println("Error: ", err)
					break
				}
				fmt.Printf("%#v\n", v)
			}
		}
	}
	conn.Close()
}

取得したデータからtimestampを数値取得するようになっています。
gNMIcの設定ファイルを

#TCP output
username: admin
password: NokiaSrl1!
skip-verify: true
encoding: json_ietf
log: true

targets:
  192.168.1.50:57400:

subscriptions:
  sub1:
    paths:
      - /interface/statistics
    stream-mode: sample
    sample-interval: 10s

outputs:
  tcp-output:
    type: tcp
    address: 192.168.1.250:3333
    format: json
    delimiter: "\n"
    

のようにすると、ちゃんと送信されました。

2024/09/27 06:13:40 {"source":"192.168.1.50:57400","subscription-name":"sub1","timestamp":1727385221015459535,"time":"2024-09-27T06:13:41.015459535+09:00","updates":[{"Path":"srl_nokia-interfaces:interface[name=ethernet-1/57]/statistics","values":{"srl_nokia-interfaces:interface/statistics":{}}},{"Path":"srl_nokia-interfaces:interface[name=ethernet-1/58]/statistics","values":{"srl_nokia-interfaces:interface/statistics":{}}},{"Path":"srl_nokia-interfaces:interface[name=mgmt0]/statistics","values":{"srl_nokia-interfaces:interface/statistics":{"carrier-transitions":"1","in-broadcast-packets":"0","in-discarded-packets":"47","in-error-packets":"0","in-fcs-error-packets":"0","in-multicast-packets":"0","in-octets":"2752137","in-packets":"36627","in-unicast-packets":"36580","out-broadcast-packets":"7","out-discarded-packets":"0","out-error-packets":"0","out-mirror-octets":"0","out-mirror-packets":"0","out-multicast-packets":"65","out-octets":"8353988","out-packets":"32035","out-unicast-packets":"31963"}}}]}
1.7273852210154596e+18

timestampも数値で取得できます。受信する機能をTWSNMP FCに組み込めば連携できそうです。暗号化したTLSの実験をしてから、組み込もうと思います。
かなり、TWSNMPシリーズをgNMIに対応する方向性が見えてきました。
早く起きすぎて眠くなってきたので、今朝は、ここまで

明日に続く

いいなと思ったら応援しよう!

twsnmp
開発のための諸経費(機材、Appleの開発者、サーバー運用)に利用します。 ソフトウェアのマニュアルをnoteの記事で提供しています。 サポートによりnoteの運営にも貢献できるのでよろしくお願います。