3 from __future__ import print_function
9 typedef uint64_t counter_t;
16 STAT_DIR_TYPE_ILLEGAL = 0,
17 STAT_DIR_TYPE_SCALAR_INDEX,
18 STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE,
19 STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED,
20 STAT_DIR_TYPE_ERROR_INDEX,
21 } stat_directory_type_t;
25 stat_directory_type_t type;
31 uint64_t offset_vector;
32 char name[128]; // TODO change this to pointer to "somewhere"
33 } stat_segment_directory_entry_t;
38 stat_directory_type_t type;
43 counter_t **simple_counter_vec;
44 vlib_counter_t **combined_counter_vec;
46 } stat_segment_data_t;
52 uint64_t directory_offset;
53 uint64_t error_offset;
54 uint64_t stats_offset;
55 } stat_segment_shared_header_t;
59 uint64_t current_epoch;
60 stat_segment_shared_header_t *shared_header;
61 stat_segment_directory_entry_t *directory_vector;
65 stat_client_main_t * stat_client_get(void);
66 void stat_client_free(stat_client_main_t * sm);
67 int stat_segment_connect_r (char *socket_name, stat_client_main_t * sm);
68 int stat_segment_connect (char *socket_name);
69 void stat_segment_disconnect_r (stat_client_main_t * sm);
70 void stat_segment_disconnect (void);
72 uint32_t *stat_segment_ls_r (uint8_t ** patterns, stat_client_main_t * sm);
73 uint32_t *stat_segment_ls (uint8_t ** pattern);
74 stat_segment_data_t *stat_segment_dump_r (uint32_t * stats, stat_client_main_t * sm);
75 stat_segment_data_t *stat_segment_dump (uint32_t * counter_vec);
76 void stat_segment_data_free (stat_segment_data_t * res);
78 double stat_segment_heartbeat_r (stat_client_main_t * sm);
79 double stat_segment_heartbeat (void);
80 int stat_segment_vec_len(void *vec);
81 uint8_t **stat_segment_string_vector(uint8_t **string_vector, char *string);
86 def make_string_vector(api, strings):
88 if type(strings) is not list:
91 vec = api.stat_segment_string_vector(vec, ffi.new("char []",
96 def make_string_list(api, vec):
97 vec_len = api.stat_segment_vec_len(vec)
98 return [ffi.string(vec[i]) for i in range(vec_len)]
101 # 2-dimensonal array of thread, index
102 def simple_counter_vec_list(api, e):
104 for thread in range(api.stat_segment_vec_len(e)):
105 len_interfaces = api.stat_segment_vec_len(e[thread])
106 if_per_thread = [e[thread][interfaces]
107 for interfaces in range(len_interfaces)]
108 vec.append(if_per_thread)
112 def vlib_counter_dict(c):
113 return {'packets': c.packets,
117 def combined_counter_vec_list(api, e):
119 for thread in range(api.stat_segment_vec_len(e)):
120 len_interfaces = api.stat_segment_vec_len(e[thread])
121 if_per_thread = [vlib_counter_dict(e[thread][interfaces])
122 for interfaces in range(len_interfaces)]
123 vec.append(if_per_thread)
127 def stat_entry_to_python(api, e):
130 return e.scalar_value
133 return simple_counter_vec_list(api, e.simple_counter_vec)
135 return combined_counter_vec_list(api, e.combined_counter_vec)
141 class VPPStatsIOError(IOError):
145 class VPPStatsClientLoadError(RuntimeError):
149 class VPPStats(object):
150 VPPStatsIOError = VPPStatsIOError
152 default_socketname = '/var/run/stats.sock'
153 sharedlib_name = 'libvppapiclient.so'
155 def __init__(self, socketname=default_socketname, timeout=10):
157 self.api = ffi.dlopen(VPPStats.sharedlib_name)
159 raise VPPStatsClientLoadError("Could not open: %s" %
160 VPPStats.sharedlib_name)
161 self.client = self.api.stat_client_get()
163 poll_end_time = time.time() + timeout
164 while time.time() < poll_end_time:
165 rv = self.api.stat_segment_connect_r(socketname.encode(),
171 raise VPPStatsIOError()
174 return self.api.stat_segment_heartbeat_r(self.client)
176 def ls(self, patterns):
177 return self.api.stat_segment_ls_r(make_string_vector(self.api,
181 def dump(self, counters):
183 rv = self.api.stat_segment_dump_r(counters, self.client)
184 # Raise exception and retry
186 raise VPPStatsIOError()
187 rv_len = self.api.stat_segment_vec_len(rv)
188 for i in range(rv_len):
189 n = ffi.string(rv[i].name).decode()
190 e = stat_entry_to_python(self.api, rv[i])
195 def get_counter(self, name):
202 raise AttributeError('Matches multiple counters {}'
206 except VPPStatsIOError as e:
211 def disconnect(self):
212 self.api.stat_segment_disconnect_r(self.client)
213 self.api.stat_client_free(self.client)
215 def set_errors(self):
216 '''Return all errors counters > 0'''
220 error_names = self.ls(['/err/'])
221 error_counters = self.dump(error_names)
223 except VPPStatsIOError as e:
228 return {k: error_counters[k]
229 for k in error_counters.keys() if error_counters[k]}
231 def set_errors_str(self):
232 '''Return all errors counters > 0 pretty printed'''
234 error_counters = self.set_errors()
235 for k in sorted(error_counters):
236 s += '{:<60}{:>10}\n'.format(k, error_counters[k])