이 페이지의 내용
gNOI 진단(Diag) 서비스
요약 gNOI 진단(Diag
) 서비스를 사용하여 두 디바이스 간 링크의 신뢰성을 테스트합니다.
개요
서비스 RPC를 사용하여 연결된 포트 쌍에서 비트 오류율 테스트(BERT)를 Diag
수행합니다. Diag
서비스 프로토 정의 파일은 https://github.com/openconfig/gnoi/blob/master/diag/diag.proto 에 있습니다.
PRBS(Pseudo-Random Binary Sequence) 테스트라고도 하는 BERT는 링크의 신뢰성을 테스트합니다. gNOI RPC는 StartBERT()
한 쌍의 연결된 물리적 인터페이스에서 양방향 BERT를 시작합니다. 디바이스는 링크 전체에서 1과 0의 설정된 패턴을 교환합니다. 디바이스는 수신된 메시지를 전송된 메시지와 비교하여 오류 수를 계산합니다. 오류 수가 적을수록 링크 품질이 높아집니다.
디바이스가 결과를 비교할 수 있도록 링크의 양쪽에서 gNOI BERT를 실행해야 합니다. 테스트 중인 링크는 BERT 중에 다운되고 BERT가 종료된 후 다시 작동합니다. 그러나 BERT를 실행 중인 디바이스 중 하나가 재부팅되면 다른 디바이스에서 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는 작업 ID로 각 BERT를 식별하므로 동일한 ID로 서로 다른 인터페이스에서 여러 BERT를 실행할 수 있습니다.
디바이스는 마지막 5개의 BERT 작업 결과를 유지합니다. 그러나 저장된 BERT 결과는 지속되지 않습니다. 시스템이 재부팅되면 손실됩니다.
저장된 특정 BERT 작업의 결과를 보려면 원하는 BERT 작업 ID에 대한 메시지를 보내고 GetBERTResultRequest
필드를 로 False
설정합니다result_from_all_ports
. 다른 ID에 대한 모든 요청 결과를 보려면 메시지의 필드를 GetBERTResultRequest
로 True
설정합니다result_from_all_ports
.
디바이스에서 RPC를 GetBERTResult()
실행하면 RPC는 BERT 중에 특정 디바이스가 감지한 일치하지 않는 비트의 수를 표시합니다. RPC에는 통과 또는 불합격 기준이 구성되어 있지 않으므로 결과를 평가하는 것은 사용자의 몫입니다. 다음과 같은 여러 가지 이유로 많은 수의 오류가 표시될 수 있습니다.
- 링크의 품질이 좋지 않습니다.
- 디바이스 중 하나가 BERT 중에 오프라인 상태가 되었습니다.
- BERT는 하나의 디바이스에서만 실행되었습니다.
- BERT는 두 디바이스에서 동시에 시작 및 중지되지 않았습니다.
마지막 오류를 방지하려면 RPC를 StartBERT()
두 디바이스에 동시에 보내는 것이 좋습니다. 한 디바이스에서 다른 디바이스보다 먼저 BERT를 시작하면 다른 디바이스에서 BERT가 시작될 때까지 첫 번째 디바이스가 응답을 수신하지 않습니다. 첫 번째 디바이스는 응답 부족을 불일치 비트로 기록합니다. 첫 번째 디바이스는 두 번째 디바이스에서 BERT가 시작될 때까지 오류를 계속 보고합니다. BERT를 동시에 시작할 수 없는 경우 BERT를 마지막으로 시작한 디바이스에서 RPC를 GetBERTResult()
실행하는 것이 좋습니다. BERT가 이미 첫 번째 디바이스에서 실행 중이었기 때문에 두 번째 디바이스는 잘못된 누락 비트를 보고하지 않아야 합니다.
지원되는 RPC
릴리스에 도입된 | RPC | 설명 |
---|---|---|
StartBERT() |
포트 세트에서 BERT를 시작합니다. Junos 디바이스는 gNOI BERT에 대해 다음과 같은 PRBS 패턴을 지원합니다.
|
진화한 Junos OS 22.2R1 |
StopBert() |
포트 집합에서 이미 진행 중인 BERT를 중지합니다. |
진화한 Junos OS 22.2R1 |
GetBERTResult() |
BERT 도중 또는 완료 후에 BERT 결과를 가져옵니다. |
진화한 Junos OS 22.2R1 |
네트워크 디바이스 구성
- gRPC 서비스 구성에 설명된 대로 네트워크 디바이스에서 gRPC 서비스를 구성합니다.
- gNOI 서비스 구성에 설명된 대로 gNOI 작업을 지원하도록 네트워크 관리 시스템을 구성합니다.
- BERT를 실행하려는 링크의 경우 서버 및 피어 인터페이스 속도를 일치하도록 구성합니다. BERT는 인터페이스 속도가 일치하는 경우에만 실행됩니다.
예: BERT 실행
인터페이스에서 BERT가 진행되는 동안 해당 인터페이스의 물리적 링크가 끊어집니다.
gNOI 클라이언트 및 서버를 구성한 후에는 응용 프로그램을 작성하고 실행하여 BERT를 실행할 수 있습니다. 이 예제에서 클라이언트는 Python 애플리케이션을 실행하여 gnoi_bert_client.py
서버와 피어 디바이스 간의 링크를 테스트합니다. gnoi_bert_client.py
애플리케이션은 인수에 따라 BERT를 시작하거나, BERT를 중지하거나, BERT 결과를 가져올 수 있습니다.
먼저 클라이언트는 서버와 피어에서 BERT를 시작하기 위해 RPC를 보내는 StartBERT()
데 사용합니다gnoi_bert_client.py
. BERT가 실행되는 동안 서버와 피어는 et-1/0/2 및 et-1/0/3 인터페이스 간의 링크를 통해 BERT 테스트 패킷을 교환합니다.

설정된 시간이 만료되면 BERT가 종료됩니다. 그런 다음 클라이언트는 RPC를 사용하여 GetBERTResult()
애플리케이션을 두 번째로 실행하여 서버에서 BERT 결과를 가져옵니다.
메시지에 대한 StartBERTRequest
매개 변수는 input_bert_start.json JSON 파일에 저장됩니다. 이 파일은 PRBS 패턴 31을 사용하여 BERT가 60초 동안 실행되어야 함을 지정합니다. 메시지에 대한 GetBERTResultRequest
매개 변수는 input_bert_get.json JSON 파일에 저장됩니다. result_from_all_ports
필드는 로 설정 False
되므로 RPC는 GetBERTResult()
이 포트에서 이 특정 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=50051, help='The server port. Default is 50051') 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
input_bert_start.json 파일 경로로StartBERTRequest
설정합니다input_file
. 각 장치에 대해 입력 파일은 해당 장치에서 테스트된 인터페이스를 지정해야 합니다. 상태는 BERTBERT_STATUS_OK
가 성공적으로 시작되었음을 나타냅니다.lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_bert_client.py --server 10.0.2.1 --port 50051 --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가 완료되면 다음을
GetBERTResultRequest
input_file
설정하고message
input_bert_get.json 파일 경로로 설정하여 애플리케이션을 다시 실행하여gnoi_bert_client.py
테스트 결과를 가져옵니다. 이 예에서 BERT는 1분 테스트 동안 0개의 오류를 발견했습니다.lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_bert_client.py --server 10.0.2.1 --port 50051 --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가 성공적으로 완료되었으며 링크 품질이 양호함을 보여줍니다.