blob: 76e1e5435f0458b9bb3a314a21979a8f1624efa6 [file] [log] [blame]
Ole Troan73202102018-08-31 00:29:48 +02001#!/usr/bin/env python
2
3from __future__ import print_function
4from cffi import FFI
5
6ffi = FFI()
7ffi.cdef("""
8typedef uint64_t counter_t;
9typedef struct {
10 counter_t packets;
11 counter_t bytes;
12} vlib_counter_t;
13
14typedef enum {
15 STAT_DIR_TYPE_ILLEGAL = 0,
Ole Troan58492a82018-09-04 13:19:12 +020016 STAT_DIR_TYPE_SCALAR_INDEX,
Ole Troan73202102018-08-31 00:29:48 +020017 STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE,
18 STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED,
19 STAT_DIR_TYPE_ERROR_INDEX,
Ole Troan73202102018-08-31 00:29:48 +020020} stat_directory_type_t;
21
Ole Troan58492a82018-09-04 13:19:12 +020022typedef struct
23{
Ole Troan73202102018-08-31 00:29:48 +020024 stat_directory_type_t type;
25 union {
Ole Troan58492a82018-09-04 13:19:12 +020026 uint64_t offset;
27 uint64_t index;
28 uint64_t value;
29 };
30 uint64_t offset_vector;
31 char name[128]; // TODO change this to pointer to "somewhere"
32} stat_segment_directory_entry_t;
33
34typedef struct
35{
36 char *name;
37 stat_directory_type_t type;
38 union
39 {
Ole Troan73202102018-08-31 00:29:48 +020040 double scalar_value;
41 uint64_t error_value;
Ole Troan73202102018-08-31 00:29:48 +020042 counter_t **simple_counter_vec;
43 vlib_counter_t **combined_counter_vec;
44 };
45} stat_segment_data_t;
46
Ole Troan73202102018-08-31 00:29:48 +020047int stat_segment_connect (char *socket_name);
48void stat_segment_disconnect (void);
49
Ole Troan58492a82018-09-04 13:19:12 +020050uint32_t *stat_segment_ls (uint8_t ** pattern);
51stat_segment_data_t *stat_segment_dump (uint32_t * counter_vec);
Ole Troan73202102018-08-31 00:29:48 +020052void stat_segment_data_free (stat_segment_data_t * res);
53double stat_segment_heartbeat (void);
54int stat_segment_vec_len(void *vec);
55uint8_t **stat_segment_string_vector(uint8_t **string_vector, char *string);
56""")
57
58
59# Utility functions
60def make_string_vector(api, strings):
61 vec = ffi.NULL
62 if type(strings) is not list:
63 strings = [strings]
64 for s in strings:
Ole Troan31555a32018-10-22 09:30:26 +020065 vec = api.stat_segment_string_vector(vec, ffi.new("char []",
66 s.encode()))
Ole Troan73202102018-08-31 00:29:48 +020067 return vec
68
69
70def make_string_list(api, vec):
71 vec_len = api.stat_segment_vec_len(vec)
72 return [ffi.string(vec[i]) for i in range(vec_len)]
73
74
75# 2-dimensonal array of thread, index
76def simple_counter_vec_list(api, e):
77 vec = []
78 for thread in range(api.stat_segment_vec_len(e)):
79 len_interfaces = api.stat_segment_vec_len(e[thread])
80 if_per_thread = [e[thread][interfaces]
81 for interfaces in range(len_interfaces)]
82 vec.append(if_per_thread)
83 return vec
84
85
86def vlib_counter_dict(c):
87 return {'packets': c.packets,
88 'bytes': c.bytes}
89
90
91def combined_counter_vec_list(api, e):
92 vec = []
93 for thread in range(api.stat_segment_vec_len(e)):
94 len_interfaces = api.stat_segment_vec_len(e[thread])
95 if_per_thread = [vlib_counter_dict(e[thread][interfaces])
96 for interfaces in range(len_interfaces)]
97 vec.append(if_per_thread)
98 return vec
99
100
101def stat_entry_to_python(api, e):
Ole Troan58492a82018-09-04 13:19:12 +0200102 # Scalar index
103 if e.type == 1:
104 return e.scalar_value
105 return None
106 if e.type == 2:
107 return simple_counter_vec_list(api, e.simple_counter_vec)
Ole Troan73202102018-08-31 00:29:48 +0200108 if e.type == 3:
Ole Troan73202102018-08-31 00:29:48 +0200109 return combined_counter_vec_list(api, e.combined_counter_vec)
Ole Troan58492a82018-09-04 13:19:12 +0200110 if e.type == 4:
Ole Troan73202102018-08-31 00:29:48 +0200111 return e.error_value
112 return None
113
114
115class VPPStats:
116 def __init__(self, socketname='/var/run/stats.sock'):
117 self.api = ffi.dlopen('libvppapiclient.so')
Ole Troan45d5c872018-09-18 10:23:01 +0200118 rv = self.api.stat_segment_connect(socketname.encode())
Ole Troan73202102018-08-31 00:29:48 +0200119 if rv != 0:
120 raise IOError()
121
122 def heartbeat(self):
123 return self.api.stat_segment_heartbeat()
124
125 def ls(self, patterns):
126 return self.api.stat_segment_ls(make_string_vector(self.api, patterns))
127
128 def dump(self, counters):
129 stats = {}
130 rv = self.api.stat_segment_dump(counters)
Ole Troanb4603a72018-09-18 11:06:33 +0200131 # Raise exception and retry
132 if rv == ffi.NULL:
133 raise IOError()
Ole Troan73202102018-08-31 00:29:48 +0200134 rv_len = self.api.stat_segment_vec_len(rv)
135 for i in range(rv_len):
Ole Troan45d5c872018-09-18 10:23:01 +0200136 n = ffi.string(rv[i].name).decode()
Ole Troan73202102018-08-31 00:29:48 +0200137 e = stat_entry_to_python(self.api, rv[i])
Ole Troan31555a32018-10-22 09:30:26 +0200138 if e is not None:
Ole Troan282093f2018-09-19 12:38:51 +0200139 stats[n] = e
Ole Troan73202102018-08-31 00:29:48 +0200140 return stats
141
Ole Troan58492a82018-09-04 13:19:12 +0200142 def get_counter(self, name):
Ole Troanb4603a72018-09-18 11:06:33 +0200143 retries = 0
144 while True:
145 try:
146 dir = self.ls(name)
147 return self.dump(dir).values()[0]
Ole Troan31555a32018-10-22 09:30:26 +0200148 except Exception as e:
Ole Troanb4603a72018-09-18 11:06:33 +0200149 if retries > 10:
150 return None
151 retries += 1
152 pass
Ole Troan73202102018-08-31 00:29:48 +0200153
154 def disconnect(self):
155 self.api.stat_segment_disconnect()
156
157 def set_errors(self):
158 '''Return all errors counters > 0'''
Ole Troanb4603a72018-09-18 11:06:33 +0200159 retries = 0
160 while True:
161 try:
162 error_names = self.ls(['/err/'])
163 error_counters = self.dump(error_names)
164 break
Ole Troan31555a32018-10-22 09:30:26 +0200165 except Exception as e:
Ole Troanb4603a72018-09-18 11:06:33 +0200166 if retries > 10:
167 return None
168 retries += 1
169 pass
Ole Troan73202102018-08-31 00:29:48 +0200170 return {k: error_counters[k]
171 for k in error_counters.keys() if error_counters[k]}
172
173 def set_errors_str(self):
174 '''Return all errors counters > 0 pretty printed'''
175 s = 'ERRORS:\n'
176 error_counters = self.set_errors()
177 for k in sorted(error_counters):
178 s += '{:<60}{:>10}\n'.format(k, error_counters[k])
179 return s