このページの内容
gNOI診断(診断)サービス
gNOI診断(Diag)サービスを使用して、2つのデバイス間のリンクの信頼性をテストします。
概要
DiagサービスRPCを使用して、接続されたポートのペアでビットエラーレートテスト(BERT)を実行します。Diagサービスプロト定義ファイルは、https://github.com/openconfig/gnoi/blob/master/diag/diag.proto にあります。
BERTは、擬似ランダムバイナリシーケンス(PRBS)テストとも呼ばれ、リンクの信頼性をテストします。 StartBERT() gNOI RPCは、接続された物理インターフェイスのペアで双方向BERTを開始します。デバイスは、リンク全体で1と0の設定されたパターンを交換します。デバイスは受信したメッセージと送信したメッセージを比較し、エラーの数をカウントします。エラー数が少ないほど、リンクの品質は高くなります。
デバイスが結果を比較できるように、リンクの両側でgNOI BERTを実行する必要があります。テストしているリンクは、BERTの実行中にダウンし、BERTの終了後に再び立ち上がります。ただし、BERTを実行しているデバイスの1つが再起動すると、もう一方のデバイスでBERTを停止しない限り、リンクはダウンしたままになります。
テストパターンは、いくつかの所定のタイプから選択できます。BERTまたはPRBSテストパターンのタイトルは、PRBSxの形式で、xは数値です。Junosデバイスは、gNOI BERTの以下のテストパターンをサポートしています。
- PRBS7
- PRBS9
- PRBS15
- PRBS23
- PRBS31
各 gNOI BERT に固有の操作 ID を指定する必要があります。BERT の開始、BERT の停止、および BERT 結果の取得を行う RPC は、BERT 操作 ID によってリンクされます。新しいBERTを実行する場合は、操作IDを新しい文字列に変更する必要があります。RPCは各BERTをその操作IDで識別するため、同じIDを持つ異なるインターフェイスで複数のBERTを実行できます。
デバイスは、過去 5 回の BERT 操作の結果を保持します。ただし、保存されたBERT結果は永続的ではありません。システムが再起動すると、それらは失われます。
保存された特定のBERT操作の結果を表示するには、目的のBERT操作IDのGetBERTResultRequestメッセージを送信し、result_from_all_portsフィールドをFalseに設定します。異なるIDのすべてのリクエスト結果を表示するには、GetBERTResultRequestメッセージのresult_from_all_portsフィールドをTrueに設定します。
デバイス上で GetBERTResult() RPCを実行すると、RPCは、特定のデバイスがBERT中に検出した不一致ビットの数を表示します。RPCには合格または不合格の基準が設定されていないため、結果を評価するのはユーザー次第です。以下のような理由により、多数のエラーが発生することがあります。
- リンクの品質が悪い。
- BERT中にデバイスの1つがオフラインになりました。
- BERTは1台のデバイスでのみ実行されました。
- BERTは、両方のデバイスで同時に起動および停止しませんでした。
最後のエラーを回避するために、 StartBERT() RPCを両方のデバイスに同時に送信することをお勧めします。一方のデバイスで他方のデバイスよりも先にBERTを開始した場合、もう一方のデバイスでBERTが起動するまで、最初のデバイスは応答を受信しません。最初のデバイスは、応答の欠如を不一致ビットとして記録します。2番目のデバイスでBERTが起動するまで、最初のデバイスはエラーを報告し続けます。BERTを同時に起動できない場合は、最後にBERTを開始したデバイスで GetBERTResult() RPCを実行することをお勧めします。BERTはすでに最初のデバイスで実行されていたため、2番目のデバイスは誤った欠落ビットを報告しません。
サポートされているRPC
| RPC | 説明 | リリースで導入 |
|---|---|---|
StartBERT() |
一連のポートでBERTを開始します。Junosデバイスは、gNOI BERTに対して以下のPRBSパターンをサポートしています。
|
Junos OS Evolved 22.2R1 |
StopBert() |
一連のポートですでに進行中のBERTを停止します。 |
Junos OS Evolved 22.2R1 |
GetBERTResult() |
BERT中またはBERT完了後にBERT結果を取得します。 |
Junos OS Evolved 22.2R1 |
ネットワークデバイスの設定
始める前に:
- gRPCサービスを設定するの説明に従って、ネットワークデバイス上でgRPCサービスを設定します。
- gNOIサービスを設定するで説明されているように、gNOI操作をサポートするようにネットワーク管理システムを構成します。
- BERTを実行するリンクについて、サーバーとピアインターフェイスの速度を一致するように設定します。BERTは、インターフェイスの速度が一致する場合にのみ実行されます。
例:BERTを実行する
インターフェイス上でBERTが進行中は、そのインターフェイス上の物理リンクがダウンします。
gNOI クライアントとサーバーを設定したら、BERT を実行するためのアプリケーションを作成して実行する準備が整います。この例では、クライアントが gnoi_bert_client.py Pythonアプリケーションを実行して、サーバーとピアデバイス間のリンクをテストします。 gnoi_bert_client.py アプリケーションは、引数に応じて、BERTの開始、BERTの停止、またはBERT結果の取得を行うことができます。
まず、クライアントは gnoi_bert_client.py を使用して StartBERT() RPC を送信し、サーバーとピアで BERT を開始します。BERTの実行中、サーバーとピアは、et-1/0/2とet-1/0/3インターフェイス間のリンクを介してBERTテストパケットを交換します。
時のネットワークトポロジー
BERTは、設定された時間が終了すると終了します。次に、クライアントは GetBERTResult() RPC でアプリケーションを 2 回実行し、サーバーから BERT 結果を取得します。
StartBERTRequestメッセージのパラメーターは、input_bert_start.json JSONファイルに保存されます。このファイルは、PRBSパターン31を使用してBERTを60秒間実行することを指定します。GetBERTResultRequestメッセージのパラメーターは、input_bert_get.json JSONファイルに保存されます。result_from_all_portsフィールドはFalseに設定されているため、GetBERTResult() RPCはこの特定のBERTの結果のみをこのポートから取得します。BERT操作IDは、両方のJSONファイルでBERT-operation id 1されています。
アプリケーションは、チャネルを確立するための grpc_channel モジュールをインポートします。 grpc_channel モジュールについては、 gNOIサービスを設定するで説明しています。アプリケーションファイルとJSONファイルはこちらに示されています。
gnoi_bert_client.py
"""gRPC gNOI BERT utility.""" from __future__ import print_function import argparse import json import sys import logging from getpass import getpass import diag_pb2 import diag_pb2_grpc from grpc_channel import grpc_authenticate_channel_mutual from google.protobuf.json_format import MessageToJson from google.protobuf.json_format import ParseDict def get_args(parser): # Main arguments parser.add_argument('--server', dest='server', type=str, default='localhost', help='Server IP or name. Default is localhost') parser.add_argument('--port', dest='port', nargs='?', type=int, default=32767, help='The server port. Default is 32767') parser.add_argument('--client_key', dest='client_key', type=str, default='', help='Full path of the client private key. Default ""') parser.add_argument('--client_cert', dest='client_cert', type=str, default='', help='Full path of the client certificate. Default ""') parser.add_argument('--root_ca_cert', dest='root_ca_cert', required=True, type=str, help='Full path of the Root CA certificate.') parser.add_argument('--user_id', dest='user_id', required=True, type=str, help='User ID for RPC call credentials.') # BERT arguments parser.add_argument('--input_file', dest='input_file', type=str, default=None, help='Input JSON file to convert to a Message Object. Default NULL string') parser.add_argument('--output_file', dest='output_file', type=str, default=None, help='Output file. Default NULL string') parser.add_argument('--message', dest='message', type=str, default=None, help='The type of Message Object. Must correspond to input file JSON. Default NULL string') args = parser.parse_args() return args def check_inputs(args): # Check each of the default=None arguments if args.server is None: print('\nFAIL: --server is not passed in\n') return False if args.port is None: print('\nFAIL: server port (--port) is not passed in\n') return False if args.input_file is None: print('\nFAIL: --input_file is not passed in\n') return False if args.output_file is None: print('\nFAIL: --output_file is not passed in\n') return False if args.message is None: print('\nFAIL: --message is not passed in\n') return False return True # Create a dictionary where top-level keys match what is passed in via args.message # The values are pointers to the relevant classes and method names needed to build/send message objects MESSAGE_RELATED_OBJECTS = { 'StartBERTRequest': { 'msg_type': diag_pb2.StartBERTRequest, 'grpc': diag_pb2_grpc.DiagStub, 'method': 'StartBERT' }, 'StopBERTRequest': { 'msg_type': diag_pb2.StopBERTRequest, 'grpc': diag_pb2_grpc.DiagStub, 'method': 'StopBERT' }, 'GetBERTResultRequest': { 'msg_type': diag_pb2.GetBERTResultRequest, 'grpc': diag_pb2_grpc.DiagStub, 'method': 'GetBERTResult' } } def send_rpc(channel, metadata, args): if not check_inputs(args): print('\nFAIL: One of the inputs was not as expected.\n') return False print('\nMessage Type is {}'.format(args.message)) # Message objects to send msg_object_list = [] with open(args.input_file) as json_file: user_input = json.load(json_file) # Choose the Request Message Object type based on the --message type passed request_message = MESSAGE_RELATED_OBJECTS[args.message]['msg_type']() # Convert the dictionary to the type of message object specified by request_message try: msg_object_list.append(ParseDict(user_input, request_message)) except Exception as error: print('\n\nError:\n{}'.format(error), file=sys.stderr) raise # Assemble callable object to use for sending, e.g. diag_pb2_grpc.DiagStub(channel).StartBERT method = MESSAGE_RELATED_OBJECTS[args.message]['method'] send_message = getattr( MESSAGE_RELATED_OBJECTS[args.message]['grpc'](channel), method) # send the Request Object(s) for msg_object in msg_object_list: resp = send_message(msg_object, metadata=metadata) print('\n\nResponse:\n{}'.format(resp)) print('=================================') resp_json = MessageToJson(resp) print('\n\nResponse JSON:\n{}'.format(resp_json)) with open(args.output_file, 'w') as data: data.write(str(resp_json)) return True def main(): parser = argparse.ArgumentParser() args = get_args(parser) grpc_server_password = getpass("gRPC server password for executing RPCs: ") metadata = [('username', args.user_id), ('password', grpc_server_password)] try: # Establish grpc channel to network device channel = grpc_authenticate_channel_mutual( args.server, args.port, args.root_ca_cert, args.client_key, args.client_cert) response = send_rpc(channel, metadata, args) except Exception as e: logging.error('Received error: %s', e) print(e) if __name__ == '__main__': logging.basicConfig(filename='gnoi-testing.log', format='%(asctime)s %(levelname)-8s %(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S') main()
input_bert_start.json
{
"bert_operation_id": "BERT-operation id 1",
"per_port_requests": [
{
"interface": {
"origin": "origin",
"elem": [
{"name": "interfaces"},
{"name": "interface", "key": {"name": "et-1/0/2"}}
]
},
"prbs_polynomial": "PRBS_POLYNOMIAL_PRBS31",
"test_duration_in_secs": "60"
}
]
}
input_bert_get.json
{
"bert_operation_id": "BERT-operation id 1",
"result_from_all_ports": false,
"per_port_requests": [
{
"interface": {
"origin": "origin",
"elem": [
{"name": "interfaces"},
{"name": "interface", "key": {"name": "et-1/0/2"}}
]
}
}
]
}
アプリケーションの実行
-
クライアントから
gnoi_bert_client.pyアプリケーションを実行し、ピア(図示せず)でBERTを開始します。次に、gnoi_bert_client.pyアプリケーションを実行して、サーバー上で BERT を起動します (以下を参照)。BERTを開始するには、messageをStartBERTRequestに設定し、input_fileをinput_bert_start.jsonファイルパスに設定します。各デバイスについて、入力ファイルには、そのデバイスでテストされたインターフェイスを指定する必要があります。BERT_STATUS_OKステータスは、BERTが正常に開始されたことを示しています。lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_bert_client.py --server 10.0.2.1 --port 32767 --root_ca_cert /etc/pki/certs/serverRootCA.crt --client_key /home/lab/certs/client.key --client_cert /home/lab/certs/client.crt --user_id gnoi-user --message StartBERTRequest --input_file diag/input_bert_start.json --output_file diag/output/bert-start-resp1.json gRPC server password for executing RPCs: Message Type is StartBERTRequest Response: bert_operation_id: "BERT-operation id 1" per_port_responses { interface { origin: "origin" elem { name: "interfaces" } elem { name: "interface" key { key: "name" value: "et-1/0/2" } } } status: BERT_STATUS_OK } ================================= Response JSON: { "bertOperationId": "BERT-operation id 1", "perPortResponses": [ { "interface": { "origin": "origin", "elem": [ { "name": "interfaces" }, { "name": "interface", "key": { "name": "et-1/0/2" } } ] }, "status": "BERT_STATUS_OK" } ] } -
(オプション)BERTの実行中に、サーバーまたはピアデバイスで
show interfacesコマンドを使用して、進行中のBERT結果を表示します。BERTが実行されている場合、PRBSモードはEnabledです。この例の出力は、わかりやすくするために切り捨てられています。user@server> show interfaces et-1/0/2 Physical interface: et-1/0/2, Enabled, Physical link is Down Interface index: 1018, SNMP ifIndex: 534 [...] PRBS Mode : Enabled PRBS Pattern : 31 PRBS Statistics Lane 0 : Error Bits : 0 Total Bits : 200000000000 Monitored Seconds : 8 Lane 1 : Error Bits : 0 Total Bits : 200000000000 Monitored Seconds : 8 Lane 2 : Error Bits : 0 Total Bits : 200000000000 Monitored Seconds : 8 Lane 3 : Error Bits : 0 Total Bits : 200000000000 Monitored Seconds : 8 Interface transmit statistics: Disabled Link Degrade : Link Monitoring : Disable [...] -
BERTが終了したら、
messageをGetBERTResultRequestに設定し、input_fileをinput_bert_get.jsonファイルパスに設定して、gnoi_bert_client.pyアプリケーションを再度実行し、テストの結果を取得します。この例では、BERTは1分間のテスト中にエラーを検出しませんでした。lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_bert_client.py --server 10.0.2.1 --port 32767 --root_ca_cert /etc/pki/certs/serverRootCA.crt --client_key /home/lab/certs/client.key --client_cert /home/lab/certs/client.crt --user_id gnoi-user --message GetBERTResultRequest --input_file diag/input_bert_get.json --output_file diag/output/bert-get-resp1.json gRPC server password for executing RPCs: Message Type is GetBERTResultRequest Response: per_port_responses { interface { origin: "origin" elem { name: "interfaces" } elem { name: "interface" key { key: "name" value: "et-1/0/2" } } } status: BERT_STATUS_OK bert_operation_id: "BERT-operation id 1" prbs_polynomial: PRBS_POLYNOMIAL_PRBS31 last_bert_start_timestamp: 1652379568178 last_bert_get_result_timestamp: 1652379688037 peer_lock_established: true error_count_per_minute: 0 total_errors: 0 } ================================= Response JSON: { "perPortResponses": [ { "interface": { "origin": "origin", "elem": [ { "name": "interfaces" }, { "name": "interface", "key": { "name": "et-1/0/2" } } ] }, "status": "BERT_STATUS_OK", "bertOperationId": "BERT-operation id 1", "prbsPolynomial": "PRBS_POLYNOMIAL_PRBS31", "lastBertStartTimestamp": "1652379568178", "lastBertGetResultTimestamp": "1652379688037", "peerLockEstablished": true, "errorCountPerMinute": [ 0 ], "totalErrors": "0" } ] }BERTは正常に完了し、リンクの品質が良好であることを示しています。