1#! /usr/bin/env python3 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright(c) 2018 Intel Corporation 4 5import socket 6import os 7import time 8import argparse 9 10BUFFER_SIZE = 200000 11 12METRICS_REQ = "{\"action\":0,\"command\":\"ports_all_stat_values\",\"data\":null}" 13API_REG = "{\"action\":1,\"command\":\"clients\",\"data\":{\"client_path\":\"" 14API_UNREG = "{\"action\":2,\"command\":\"clients\",\"data\":{\"client_path\":\"" 15GLOBAL_METRICS_REQ = "{\"action\":0,\"command\":\"global_stat_values\",\"data\":null}" 16DEFAULT_FP = "/var/run/dpdk/default_client" 17DEFAULT_PREFIX = 'rte' 18RUNTIME_SOCKET_NAME = 'telemetry' 19 20 21class Socket: 22 23 def __init__(self): 24 self.send_fd = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) 25 self.recv_fd = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) 26 self.client_fd = None 27 28 def __del__(self): 29 try: 30 self.send_fd.close() 31 self.recv_fd.close() 32 self.client_fd.close() 33 except: 34 print("Error - Sockets could not be closed") 35 36 37class Client: 38 39 def __init__(self): 40 # Creates a client instance 41 self.socket = Socket() 42 self.file_path = None 43 self.run_path = None 44 self.choice = None 45 self.unregistered = 0 46 47 def __del__(self): 48 try: 49 if self.unregistered == 0: 50 self.unregister() 51 except: 52 print("Error - Client could not be destroyed") 53 54 def getFilepath(self, file_path): 55 # Gets arguments from Command-Line and assigns to instance of client 56 self.file_path = file_path 57 58 def setRunpath(self, file_prefix): 59 self.run_path = os.path.join(get_dpdk_runtime_dir(file_prefix), 60 RUNTIME_SOCKET_NAME) 61 62 def register(self): 63 # Connects a client to DPDK-instance 64 if os.path.exists(self.file_path): 65 os.unlink(self.file_path) 66 try: 67 self.socket.recv_fd.bind(self.file_path) 68 except socket.error as msg: 69 print("Error - Socket binding error: " + str(msg) + "\n") 70 self.socket.recv_fd.settimeout(2) 71 self.socket.send_fd.connect(self.run_path) 72 JSON = (API_REG + self.file_path + "\"}}") 73 self.socket.send_fd.sendall(JSON.encode()) 74 75 self.socket.recv_fd.listen(1) 76 self.socket.client_fd = self.socket.recv_fd.accept()[0] 77 78 def unregister(self): 79 # Unregister a given client 80 self.socket.client_fd.send((API_UNREG + self.file_path + "\"}}").encode()) 81 self.socket.client_fd.close() 82 83 def requestMetrics(self): 84 # Requests metrics for given client 85 self.socket.client_fd.send(METRICS_REQ.encode()) 86 data = self.socket.client_fd.recv(BUFFER_SIZE).decode() 87 print("\nResponse: \n", data) 88 89 def repeatedlyRequestMetrics(self, sleep_time): 90 # Recursively requests metrics for given client 91 print("\nPlease enter the number of times you'd like to continuously request Metrics:") 92 n_requests = int(input("\n:")) 93 # Removes the user input from screen, cleans it up 94 print("\033[F") 95 print("\033[K") 96 for i in range(n_requests): 97 self.requestMetrics() 98 time.sleep(sleep_time) 99 100 def requestGlobalMetrics(self): 101 # Requests global metrics for given client 102 self.socket.client_fd.send(GLOBAL_METRICS_REQ.encode()) 103 data = self.socket.client_fd.recv(BUFFER_SIZE).decode() 104 print("\nResponse: \n", data) 105 106 def interactiveMenu(self, sleep_time): 107 # Creates Interactive menu within the script 108 while self.choice != 4: 109 print("\nOptions Menu") 110 print("[1] Send for Metrics for all ports") 111 print("[2] Send for Metrics for all ports recursively") 112 print("[3] Send for global Metrics") 113 print("[4] Unregister client") 114 115 try: 116 self.choice = int(input("\n:")) 117 # Removes the user input for screen, cleans it up 118 print("\033[F") 119 print("\033[K") 120 if self.choice == 1: 121 self.requestMetrics() 122 elif self.choice == 2: 123 self.repeatedlyRequestMetrics(sleep_time) 124 elif self.choice == 3: 125 self.requestGlobalMetrics() 126 elif self.choice == 4: 127 self.unregister() 128 self.unregistered = 1 129 else: 130 print("Error - Invalid request choice") 131 except: 132 pass 133 134 135def get_dpdk_runtime_dir(fp): 136 """ Using the same logic as in DPDK's EAL, get the DPDK runtime directory 137 based on the file-prefix and user """ 138 run_dir = os.environ.get('RUNTIME_DIRECTORY') 139 if not run_dir: 140 if (os.getuid() == 0): 141 run_dir = '/var/run' 142 else: 143 run_dir = os.environ.get('XDG_RUNTIME_DIR', '/tmp') 144 return os.path.join(run_dir, 'dpdk', fp) 145 146 147if __name__ == "__main__": 148 149 sleep_time = 1 150 parser = argparse.ArgumentParser() 151 parser.add_argument('-f', '--file-prefix', default=DEFAULT_PREFIX, 152 help='Provide file-prefix for DPDK runtime directory') 153 parser.add_argument('sock_path', nargs='?', default=DEFAULT_FP, 154 help='Provide socket file path connected by legacy client') 155 args = parser.parse_args() 156 157 client = Client() 158 client.getFilepath(args.sock_path) 159 client.setRunpath(args.file_prefix) 160 client.register() 161 client.interactiveMenu(sleep_time) 162