1 #! /usr/bin/env python3
2 # SPDX-License-Identifier: BSD-3-Clause
3 # Copyright(c) 2020 Intel Corporation
6 Script to be used with V2 Telemetry.
7 Allows the user input commands and read the Telemetry response.
20 TELEMETRY_VERSION = "v2"
21 SOCKET_NAME = 'dpdk_telemetry.{}'.format(TELEMETRY_VERSION)
22 DEFAULT_PREFIX = 'rte'
26 def read_socket(sock, buf_len, echo=True):
27 """ Read data from socket and return it in JSON format """
28 reply = sock.recv(buf_len).decode()
30 ret = json.loads(reply)
31 except json.JSONDecodeError:
32 print("Error in reply: ", reply)
36 print(json.dumps(ret))
40 def get_app_name(pid):
41 """ return the app name for a given PID, for printing """
42 proc_cmdline = os.path.join('/proc', str(pid), 'cmdline')
44 with open(proc_cmdline) as f:
45 argv0 = f.read(1024).split('\0')[0]
46 return os.path.basename(argv0)
48 # ignore file not found errors
49 if e.errno != errno.ENOENT:
54 def find_sockets(path):
55 """ Find any possible sockets to connect to and return them """
56 return glob.glob(os.path.join(path, SOCKET_NAME + '*'))
59 def print_socket_options(prefix, paths):
60 """ Given a set of socket paths, give the commands needed to connect """
62 if prefix != DEFAULT_PREFIX:
63 cmd += " -f " + prefix
64 for s in sorted(paths):
65 sock_name = os.path.basename(s)
66 if sock_name.endswith(TELEMETRY_VERSION):
67 print("- {} # Connect with '{}'".format(os.path.basename(s),
70 print("- {} # Connect with '{} -i {}'".format(os.path.basename(s),
75 def get_dpdk_runtime_dir(fp):
76 """ Using the same logic as in DPDK's EAL, get the DPDK runtime directory
77 based on the file-prefix and user """
78 if (os.getuid() == 0):
79 return os.path.join('/var/run/dpdk', fp)
80 return os.path.join(os.environ.get('XDG_RUNTIME_DIR', '/tmp'), 'dpdk', fp)
84 """ List all available file-prefixes to user """
85 path = get_dpdk_runtime_dir('')
86 sockets = glob.glob(os.path.join(path, "*", SOCKET_NAME + "*"))
89 print("No DPDK apps with telemetry enabled available")
91 print("Valid file-prefixes:\n")
93 prefixes.append(os.path.relpath(os.path.dirname(s), start=path))
94 for p in sorted(set(prefixes)):
96 print_socket_options(p, glob.glob(os.path.join(path, p,
100 def handle_socket(args, path):
101 """ Connect to socket and handle user input """
102 prompt = '' # this evaluates to false in conditions
103 sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
106 if os.isatty(sys.stdin.fileno()):
108 print("Connecting to " + path)
112 print("Error connecting to " + path)
114 # if socket exists but is bad, or if non-interactive just return
115 if os.path.exists(path) or not prompt:
117 # if user didn't give a valid socket path, but there are
118 # some sockets, help the user out by printing how to connect
119 socks = find_sockets(os.path.dirname(path))
121 print("\nOther DPDK telemetry sockets found:")
122 print_socket_options(args.file_prefix, socks)
126 json_reply = read_socket(sock, 1024, prompt)
127 output_buf_len = json_reply["max_output_len"]
128 app_name = get_app_name(json_reply["pid"])
129 if app_name and prompt:
130 print('Connected to application: "%s"' % app_name)
132 # get list of commands for readline completion
133 sock.send("/".encode())
134 CMDS = read_socket(sock, output_buf_len, False)["/"]
138 text = input(prompt).strip()
139 while text != "quit":
140 if text.startswith('/'):
141 sock.send(text.encode())
142 read_socket(sock, output_buf_len)
143 text = input(prompt).strip()
150 def readline_complete(text, state):
151 """ Find any matching commands from the list based on user input """
152 all_cmds = ['quit'] + CMDS
154 matches = [c for c in all_cmds if c.startswith(text)]
157 return matches[state]
160 readline.parse_and_bind('tab: complete')
161 readline.set_completer(readline_complete)
162 readline.set_completer_delims(readline.get_completer_delims().replace('/', ''))
164 parser = argparse.ArgumentParser()
165 parser.add_argument('-f', '--file-prefix', default=DEFAULT_PREFIX,
166 help='Provide file-prefix for DPDK runtime directory')
167 parser.add_argument('-i', '--instance', default='0', type=int,
168 help='Provide instance number for DPDK application')
169 parser.add_argument('-l', '--list', action="store_true", default=False,
170 help='List all possible file-prefixes and exit')
171 args = parser.parse_args()
175 sock_path = os.path.join(get_dpdk_runtime_dir(args.file_prefix), SOCKET_NAME)
176 if args.instance > 0:
177 sock_path += ":{}".format(args.instance)
178 handle_socket(args, sock_path)