examples/l3fwd: add vector stubs for RISC-V
[dpdk.git] / usertools / dpdk-telemetry.py
1 #! /usr/bin/env python3
2 # SPDX-License-Identifier: BSD-3-Clause
3 # Copyright(c) 2020 Intel Corporation
4
5 """
6 Script to be used with V2 Telemetry.
7 Allows the user input commands and read the Telemetry response.
8 """
9
10 import socket
11 import os
12 import sys
13 import glob
14 import json
15 import errno
16 import readline
17 import argparse
18
19 # global vars
20 TELEMETRY_VERSION = "v2"
21 SOCKET_NAME = 'dpdk_telemetry.{}'.format(TELEMETRY_VERSION)
22 DEFAULT_PREFIX = 'rte'
23 CMDS = []
24
25
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()
29     try:
30         ret = json.loads(reply)
31     except json.JSONDecodeError:
32         print("Error in reply: ", reply)
33         sock.close()
34         raise
35     if echo:
36         print(json.dumps(ret))
37     return ret
38
39
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')
43     try:
44         with open(proc_cmdline) as f:
45             argv0 = f.read(1024).split('\0')[0]
46             return os.path.basename(argv0)
47     except IOError as e:
48         # ignore file not found errors
49         if e.errno != errno.ENOENT:
50             raise
51     return None
52
53
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 + '*'))
57
58
59 def print_socket_options(prefix, paths):
60     """ Given a set of socket paths, give the commands needed to connect """
61     cmd = sys.argv[0]
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),
68                                                      cmd))
69         else:
70             print("- {}  # Connect with '{} -i {}'".format(os.path.basename(s),
71                                                            cmd,
72                                                            s.split(':')[-1]))
73
74
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     run_dir = os.environ.get('RUNTIME_DIRECTORY')
79     if not run_dir:
80         if (os.getuid() == 0):
81             run_dir = '/var/run'
82         else:
83             run_dir = os.environ.get('XDG_RUNTIME_DIR', '/tmp')
84     return os.path.join(run_dir, 'dpdk', fp)
85
86
87 def list_fp():
88     """ List all available file-prefixes to user """
89     path = get_dpdk_runtime_dir('')
90     sockets = glob.glob(os.path.join(path, "*", SOCKET_NAME + "*"))
91     prefixes = []
92     if not sockets:
93         print("No DPDK apps with telemetry enabled available")
94     else:
95         print("Valid file-prefixes:\n")
96     for s in sockets:
97         prefixes.append(os.path.relpath(os.path.dirname(s), start=path))
98     for p in sorted(set(prefixes)):
99         print(p)
100         print_socket_options(p, glob.glob(os.path.join(path, p,
101                                                        SOCKET_NAME + "*")))
102
103
104 def handle_socket(args, path):
105     """ Connect to socket and handle user input """
106     prompt = ''  # this evaluates to false in conditions
107     sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
108     global CMDS
109
110     if os.isatty(sys.stdin.fileno()):
111         prompt = '--> '
112         print("Connecting to " + path)
113     try:
114         sock.connect(path)
115     except OSError:
116         print("Error connecting to " + path)
117         sock.close()
118         # if socket exists but is bad, or if non-interactive just return
119         if os.path.exists(path) or not prompt:
120             return
121         # if user didn't give a valid socket path, but there are
122         # some sockets, help the user out by printing how to connect
123         socks = find_sockets(os.path.dirname(path))
124         if socks:
125             print("\nOther DPDK telemetry sockets found:")
126             print_socket_options(args.file_prefix, socks)
127         else:
128             list_fp()
129         return
130     json_reply = read_socket(sock, 1024, prompt)
131     output_buf_len = json_reply["max_output_len"]
132     app_name = get_app_name(json_reply["pid"])
133     if app_name and prompt:
134         print('Connected to application: "%s"' % app_name)
135
136     # get list of commands for readline completion
137     sock.send("/".encode())
138     CMDS = read_socket(sock, output_buf_len, False)["/"]
139
140     # interactive prompt
141     try:
142         text = input(prompt).strip()
143         while text != "quit":
144             if text.startswith('/'):
145                 sock.send(text.encode())
146                 read_socket(sock, output_buf_len)
147             text = input(prompt).strip()
148     except EOFError:
149         pass
150     finally:
151         sock.close()
152
153
154 def readline_complete(text, state):
155     """ Find any matching commands from the list based on user input """
156     all_cmds = ['quit'] + CMDS
157     if text:
158         matches = [c for c in all_cmds if c.startswith(text)]
159     else:
160         matches = all_cmds
161     return matches[state]
162
163
164 readline.parse_and_bind('tab: complete')
165 readline.set_completer(readline_complete)
166 readline.set_completer_delims(readline.get_completer_delims().replace('/', ''))
167
168 parser = argparse.ArgumentParser()
169 parser.add_argument('-f', '--file-prefix', default=DEFAULT_PREFIX,
170                     help='Provide file-prefix for DPDK runtime directory')
171 parser.add_argument('-i', '--instance', default='0', type=int,
172                     help='Provide instance number for DPDK application')
173 parser.add_argument('-l', '--list', action="store_true", default=False,
174                     help='List all possible file-prefixes and exit')
175 args = parser.parse_args()
176 if args.list:
177     list_fp()
178     sys.exit(0)
179 sock_path = os.path.join(get_dpdk_runtime_dir(args.file_prefix), SOCKET_NAME)
180 if args.instance > 0:
181     sock_path += ":{}".format(args.instance)
182 handle_socket(args, sock_path)