FD.io VPP  v21.06
Vector Packet Processing
mactime_top.c
Go to the documentation of this file.
1 #include <vppinfra/time.h>
2 #include <vppinfra/hash.h>
3 #include <vppinfra/pool.h>
5 #include <vppinfra/vec.h>
7 #include <vlibapi/api_common.h>
9 #include <vlibmemory/api.h>
10 #include <vnet/api_errno.h>
11 #include <svm/queue.h>
12 
13 #include <vnet/format_fns.h>
14 #include <mactime/mactime.api_types.h>
15 #include <mactime/mactime.api_enum.h>
16 
17 typedef struct
18 {
19  /* device database */
23 
24  /* Stat segment variables */
26  u8 **pattern1, **pattern2;
27  u32 *ls_result1, *ls_result2;
30 
31  /* Timebase */
36 
37  /* API message-handling */
41  volatile u32 result_ready;
42  volatile i32 retval;
43 } mt_main_t;
44 
46 
47 /* Indispensable for debugging in gdb... */
48 
49 u32
50 vl (void *x)
51 {
52  return vec_len (x);
53 }
54 
55 #define foreach_mactime_api_msg \
56 _(MACTIME_DUMP_REPLY, mactime_dump_reply) \
57 _(MACTIME_DETAILS, mactime_details)
58 
61 {
62  mt_main_t *mm = &mt_main;
63  i32 retval = clib_net_to_host_u32 (mp->retval);
64 
65  mm->retval = retval;
66  mm->result_ready = 1;
67 }
68 
69 static void
71 {
72  mt_main_t *mm = &mt_main;
73  mactime_device_t *dev;
74  int i;
76  uword *p;
77 
78  if (PREDICT_FALSE (mm->device_by_device_name == 0))
80 
82  if (p)
83  dev = pool_elt_at_index (mm->devices, p[0]);
84  else
85  {
86  u8 *hash_name_copy = format (0, "%s%c", mp->device_name, 0);
87  pool_get (mm->devices, dev);
88  memset (dev, 0, sizeof (*dev));
89  dev->device_name = vec_dup (hash_name_copy);
90  hash_set_mem (mm->device_by_device_name, hash_name_copy,
91  dev - mm->devices);
92  }
93 
95  sizeof (dev->mac_address));
96  dev->data_quota = clib_net_to_host_u64 (mp->data_quota);
97  dev->data_used_in_range = clib_net_to_host_u64 (mp->data_used_in_range);
98  dev->flags = clib_net_to_host_u32 (mp->flags);
99  dev->pool_index = clib_net_to_host_u32 (mp->pool_index);
100  vec_reset_length (dev->ranges);
101  for (i = 0; i < clib_net_to_host_u32 (mp->nranges); i++)
102  {
103  vec_add2 (dev->ranges, rp, 1);
104  rp->start = mp->ranges[i].start;
105  rp->end = mp->ranges[i].end;
106  }
107 }
108 
109 #define vl_print(handle, ...) fformat(handle, __VA_ARGS__)
110 #define vl_endianfun /* define message structures */
111 #include <mactime/mactime.api.h>
112 #undef vl_endianfun
113 
114 /* instantiate all the print functions we know about */
115 #define vl_printfun
116 #include <mactime/mactime.api.h>
117 #undef vl_printfun
118 
119 #define vl_api_version(n,v) static u32 api_version = v;
120 #include <mactime/mactime.api.h>
121 #undef vl_api_version
122 
123 static int
125 {
127  mt_main_t *mm = &mt_main;
128  u8 *msg_base_lookup_name;
129 
130  if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
131  return -1;
132 
135 
136  msg_base_lookup_name = format (0, "mactime_%08x%c", api_version, 0);
137 
139  ((char *) msg_base_lookup_name);
140 
141  vec_free (msg_base_lookup_name);
142 
143  if (mm->msg_id_base == (u16) ~ 0)
144  return -1;
145 
146 #define _(N,n) \
147  vl_msg_api_set_handlers((VL_API_##N + mm->msg_id_base), \
148  #n, \
149  vl_api_##n##_t_handler, \
150  vl_noop_handler, \
151  vl_api_##n##_t_endian, \
152  vl_api_##n##_t_print, \
153  sizeof(vl_api_##n##_t), 1);
155 #undef _
156 
157  return 0;
158 }
159 
160 static void
162 {
164  u32 deadman_counter = 1000;
165 
166  /* Send the dump request */
167  mp = vl_msg_api_alloc (sizeof (*mp));
168  memset (mp, 0, sizeof (*mp));
169  mp->_vl_msg_id =
170  clib_host_to_net_u16 (VL_API_MACTIME_DUMP + mm->msg_id_base);
171  mp->client_index = mm->my_client_index;
172  mp->my_table_epoch = mm->my_table_epoch;
173  vl_msg_api_send_shmem (mm->vl_input_queue, (u8 *) & mp);
174 
175  /* Wait up to 1 second for vpp to reply */
176  while (deadman_counter-- && mm->result_ready == 0)
177  unix_sleep (1e-3);
178 
179  if (mm->retval && (mm->retval != VNET_API_ERROR_NO_CHANGE))
180  clib_warning ("dump reply %d", mm->retval);
181 
182 }
183 
184 static void
186 {
187  vlib_counter_t **counters_by_thread;
188  vlib_counter_t *counters;
189  mactime_device_t *dev;
193  int need_update2 = 0;
194  static u32 *pool_indices;
195  int i, j;
196 
197  vec_reset_length (pool_indices);
198  /* *INDENT-OFF* */
199  pool_foreach (dev, mm->devices)
200  {
201  vec_add1 (pool_indices, dev->pool_index);
202  }
203  /* *INDENT-ON* */
204 
205  /* Nothing to do... */
206  if (vec_len (pool_indices) == 0)
207  return;
208 
209 again1:
210 
211  /* Has directory been updated? */
212  if (mm->ls_result1 == 0 || (sm->shared_header->epoch != sm->current_epoch))
213  {
214  need_update2 = 1;
215  vec_free (mm->ls_result1);
216  mm->ls_result1 = stat_segment_ls (mm->pattern1);
217  }
218 
219  stat_segment_access_start (&sa, sm);
220 
221  ep = vec_elt_at_index (sm->directory_vector, mm->ls_result1[0]);
222  counters_by_thread = stat_segment_adjust (sm, ep->data);
223 
224  for (i = 0; i < vec_len (pool_indices); i++)
225  {
226  u32 index = pool_indices[i];
227 
228  vec_validate (mm->allow_counters, index);
229  mm->allow_counters[index].packets = 0;
230  mm->allow_counters[index].bytes = 0;
231 
232  for (j = 0; j < vec_len (counters_by_thread); j++)
233  {
234  counters = stat_segment_adjust (sm, counters_by_thread[j]);
235  mm->allow_counters[index].packets += counters[index].packets;
236  mm->allow_counters[index].bytes += counters[index].bytes;
237  }
238  }
239 
240  /* Ugh, segment changed during access. Try again */
241  if (stat_segment_access_end (&sa, sm))
242  goto again1;
243 
244  /* Has directory been updated? */
245  if (mm->ls_result2 == 0 || need_update2)
246  {
247  vec_free (mm->ls_result2);
248  mm->ls_result2 = stat_segment_ls (mm->pattern2);
249  }
250 
251 again2:
252  stat_segment_access_start (&sa, sm);
253 
254  ep = vec_elt_at_index (sm->directory_vector, mm->ls_result2[0]);
255  counters_by_thread = stat_segment_adjust (sm, ep->data);
256 
257  for (i = 0; i < vec_len (pool_indices); i++)
258  {
259  u32 index = pool_indices[i];
260 
261  vec_validate (mm->drop_counters, index);
262  mm->drop_counters[index].packets = 0;
263  mm->drop_counters[index].bytes = 0;
264 
265  for (j = 0; j < vec_len (counters_by_thread); j++)
266  {
267  counters = stat_segment_adjust (sm, counters_by_thread[j]);
268  mm->drop_counters[index].packets += counters[index].packets;
269  mm->drop_counters[index].bytes += counters[index].bytes;
270  }
271  }
272  /* Ugh, segment changed during access. Try again */
273  if (stat_segment_access_end (&sa, sm))
274  goto again2;
275 }
276 
277 static u8 *
278 format_mac_address (u8 * s, va_list * args)
279 {
280  u8 *a = va_arg (*args, u8 *);
281 
282  return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
283  a[0], a[1], a[2], a[3], a[4], a[5]);
284 }
285 
286 static u8 *
287 format_bytes_with_width (u8 * s, va_list * va)
288 {
289  uword nbytes = va_arg (*va, u64);
290  int width = va_arg (*va, int);
291  f64 nbytes_f64;
292  u8 *fmt;
293  char *suffix = "";
294 
295  if (width > 0)
296  fmt = format (0, "%%%d.3f%%s%c", width, 0);
297  else
298  fmt = format (0, "%%.3f%%s%c", 0);
299 
300  if (nbytes > (1024ULL * 1024ULL * 1024ULL))
301  {
302  nbytes_f64 = ((f64) nbytes) / (1024.0 * 1024.0 * 1024.0);
303  suffix = "G";
304  }
305  else if (nbytes > (1024ULL * 1024ULL))
306  {
307  nbytes_f64 = ((f64) nbytes) / (1024.0 * 1024.0);
308  suffix = "M";
309  }
310  else if (nbytes > 1024ULL)
311  {
312  nbytes_f64 = ((f64) nbytes) / (1024.0);
313  suffix = "K";
314  }
315  else
316  {
317  nbytes_f64 = (f64) nbytes;
318  suffix = "B";
319  }
320 
321  s = format (s, (char *) fmt, nbytes_f64, suffix);
322  vec_free (fmt);
323  return s;
324 }
325 
326 static u8 *
327 format_device (u8 * s, va_list * args)
328 {
329  mactime_device_t *dp = va_arg (*args, mactime_device_t *);
330  mt_main_t *mm = &mt_main;
331  int verbose = va_arg (*args, int);
332  int current_status = 99;
333  char *status_string;
334  u8 *macstring = 0;
335  f64 now;
336  int j;
337 
338  if (dp == 0)
339  {
340  s = format (s, "%-15s %5s %18s %14s %10s %11s %13s",
341  "Device Name", "Index", "Addresses", "Status",
342  "AllowPkt", "AllowByte", "DropPkt");
343  vec_add1 (s, '\n');
344  return s;
345  }
346 
347  now = clib_timebase_now (&mm->timebase);
348 
349  if (PREDICT_FALSE ((now - mm->sunday_midnight) > 86400.0 * 7.0))
351 
352  /* Check dynamic ranges */
353  for (j = 0; j < vec_len (dp->ranges); j++)
354  {
355  clib_timebase_range_t *r = dp->ranges + j;
356  f64 start0, end0;
357 
358  start0 = r->start + mm->sunday_midnight;
359  end0 = r->end + mm->sunday_midnight;
360  if (verbose)
361  s = format (s, " Range %d: %U - %U\n", j,
364 
365  if (now >= start0 && now <= end0)
366  {
368  current_status = 3;
370  current_status = 5;
371  else
372  current_status = 2;
373  if (verbose)
374  {
375  s = format (s, " Time in range %d:", j);
376  s = format (s, " %U - %U\n",
379  }
380  goto print;
381  }
382  }
383  if (verbose && j)
384  s = format (s, " No range match.\n");
386  current_status = 0;
388  current_status = 1;
390  current_status = 2;
392  current_status = 3;
394  current_status = 4;
395 
396 print:
397  macstring = format (0, "%U", format_mac_address, dp->mac_address);
398  switch (current_status)
399  {
400  case 0:
401  status_string = "static drop";
402  break;
403  case 1:
404  status_string = "static allow";
405  break;
406  case 2:
407  status_string = "dynamic drop";
408  break;
409  case 3:
410  status_string = "dynamic allow";
411  break;
412  case 4:
413  status_string = "d-quota inact";
414  break;
415  case 5:
416  status_string = "d-quota activ";
417  break;
418  default:
419  status_string = "code bug!";
420  break;
421  }
422 
423  s = format (s, "%-15s %5d %18s %14s %10lld %U %13lld\n",
424  dp->device_name, dp->pool_index, macstring, status_string,
427  mm->allow_counters[dp->pool_index].bytes, 10,
428  mm->drop_counters[dp->pool_index].packets);
429  vec_free (macstring);
430 
431  if (dp->data_quota > 0)
432  {
433  s = format (s, "%-59s %s%U %s%U", " ", "Quota ",
436  vec_add1 (s, '\n');
437  }
438  return s;
439 }
440 
441 static void
443 {
444  mactime_device_t *dev;
445 
446  fformat (stdout, "%U", format_device, 0 /* header */ , 0 /* verbose */ );
447  /* *INDENT-OFF* */
448  pool_foreach (dev, mm->devices)
449  {
450  fformat (stdout, "%U", format_device, dev, 0 /* verbose */);
451  }
452  /* *INDENT-ON* */
453 }
454 
455 int
456 main (int argc, char **argv)
457 {
458  mt_main_t *mm = &mt_main;
460 
461  clib_mem_init (0, 64 << 20);
462 
463  if (connect_to_vpp ("mactime_top") < 0)
464  {
465  fformat (stderr, "vpp api client connect error\n");
466  exit (1);
467  }
468 
469  if (stat_segment_connect (argv[1]) < 0)
470  {
471  fformat (stderr, "stat segment connect error");
472  exit (1);
473  }
474 
475  mm->stat_client_main = (stat_client_main_t *) & stat_client_main;
476 
477  /* US EDT - $$$ FIXME */
478  clib_time_init (&mm->clib_time);
479  mm->timezone_offset = -5.0;
482  0 /* allocate a clib_time_t */ );
483 
484  vec_add1 (mm->pattern1, (u8 *) "^/mactime/allow");
485  vec_add1 (mm->pattern2, (u8 *) "^/mactime/drop");
486 
487  while (1)
488  {
489  dump_mactime_table (mm);
491  print_device_table (mm);
492  unix_sleep (5.0);
493  }
494  return 0;
495 }
496 
497 
498 /*
499  * fd.io coding-style-patch-verification: ON
500  *
501  * Local Variables:
502  * eval: (c-set-style "gnu")
503  * End:
504  */
#define MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW_QUOTA
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:524
int vl_client_connect_to_vlib(const char *svm_name, const char *client_name, int rx_queue_size)
int stat_segment_connect(const char *socket_name)
Definition: stat_client.c:151
a
Definition: bitmap.h:544
vnet_hw_if_output_node_runtime_t * r
static void print_device_table(mt_main_t *mm)
Definition: mactime_top.c:442
stat_segment_directory_entry_t * directory_vector
Definition: stat_client.h:53
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:534
void * clib_mem_init(void *base, uword size)
Definition: mem_dlmalloc.c:266
unsigned long u64
Definition: types.h:89
Fixed length block allocator.
int my_client_index
All VLIB-side message handlers use my_client_index to identify the queue / client.
Definition: api_common.h:339
dump mactime table
Definition: mactime.api:115
stat_client_main_t stat_client_main
Definition: stat_client.c:35
#define MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:607
Combined counter to hold both packets and byte differences.
Definition: counter_types.h:26
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:645
mactime table entry details
Definition: mactime.api:125
#define hash_set_mem(h, key, value)
Definition: hash.h:275
string name[64]
Definition: fib.api:25
void * data
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:255
void * vl_msg_api_alloc(int nbytes)
unsigned char u8
Definition: types.h:56
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
unsigned int u32
Definition: types.h:88
svm_queue_t * vl_input_queue
Definition: mactime_top.c:38
__clib_export word fformat(FILE *f, char *fmt,...)
Definition: format.c:466
stat_segment_shared_header_t * shared_header
Definition: stat_client.h:52
static void unix_sleep(f64 dt)
Definition: time.h:304
static void scrape_stats_segment(mt_main_t *mm)
Definition: mactime_top.c:185
clib_timebase_range_t * ranges
volatile i32 retval
Definition: mactime_top.c:42
clib_timebase_t timebase
Definition: mactime_top.c:33
vlib_counter_t * drop_counters
Definition: mactime_top.c:29
uint64_t current_epoch
Definition: stat_client.h:51
f64 timezone_offset
Definition: mactime_top.c:34
static f64 clib_timebase_now(clib_timebase_t *tb)
Definition: time_range.h:88
description fragment has unexpected format
Definition: map.api:433
u32 my_client_index
Definition: mactime_top.c:39
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
static int connect_to_vpp(char *name)
Definition: mactime_top.c:124
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
Definition: api_common.h:294
void vl_msg_api_send_shmem(svm_queue_t *q, u8 *elem)
format_function_t format_clib_timebase_time
Definition: time_range.h:70
static void * stat_segment_adjust(stat_client_main_t *sm, void *data)
Definition: stat_client.h:102
#define MACTIME_DEVICE_FLAG_STATIC_ALLOW
#define hash_create_string(elts, value_bytes)
Definition: hash.h:690
mt_main_t mt_main
Definition: mactime_top.c:45
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:553
counter_t packets
packet counter
Definition: counter_types.h:28
u32 client_index
client index, from api_main
Definition: mactime.api:117
static u8 * format_mac_address(u8 *s, va_list *args)
Definition: mactime_top.c:278
int main(int argc, char **argv)
Definition: mactime_top.c:456
vl_api_mac_address_t mac_address
Definition: mactime.api:129
unsigned short u16
Definition: types.h:57
vl_api_mactime_time_range_t ranges[nranges]
Definition: mactime.api:135
u32 my_table_epoch
to suppress dump if no changes
Definition: mactime.api:119
#define MACTIME_DEVICE_FLAG_DYNAMIC_DROP
static u8 * format_bytes_with_width(u8 *s, va_list *va)
Definition: mactime_top.c:287
u16 vl_client_get_first_plugin_msg_id(const char *plugin_name)
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:444
f64 sunday_midnight
Definition: mactime_top.c:35
#define PREDICT_FALSE(x)
Definition: clib.h:124
stat_client_main_t * stat_client_main
Definition: mactime_top.c:25
#define foreach_mactime_api_msg
Definition: mactime_top.c:55
uword * device_by_device_name
Definition: mactime_top.c:20
int cJSON_bool fmt
Definition: cJSON.h:160
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:228
clib_time_t clib_time
Definition: mactime_top.c:32
__clib_export void clib_timebase_init(clib_timebase_t *tb, i32 timezone_offset_in_hours, clib_timebase_daylight_time_t daylight_type, clib_time_t *clib_time)
Definition: time_range.c:19
u8 ** pattern2
Definition: mactime_top.c:26
dump mactime table reply Includes the vpp table epoch, needed to optimize API traffic ...
Definition: mactime.api:141
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
u32 index
Definition: flow_types.api:221
#define clib_warning(format, args...)
Definition: error.h:59
u32 my_table_epoch
Definition: mactime_top.c:22
static u8 * format_device(u8 *s, va_list *args)
Definition: mactime_top.c:327
static void vl_api_mactime_details_t_handler(vl_api_mactime_details_t *mp)
Definition: mactime_top.c:70
svm_queue_t * vl_input_queue
Definition: memory_shared.h:84
vlib_counter_t * allow_counters
Definition: mactime_top.c:28
uint32_t * stat_segment_ls(uint8_t **patterns)
Definition: stat_client.c:405
signed int i32
Definition: types.h:77
__clib_export void clib_time_init(clib_time_t *c)
Definition: time.c:207
#define MACTIME_DEVICE_FLAG_STATIC_DROP
Always drop packets from this device.
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
static void dump_mactime_table(mt_main_t *mm)
Definition: mactime_top.c:161
counter_t bytes
byte counter
Definition: counter_types.h:29
static bool stat_segment_access_end(stat_segment_access_t *sa, stat_client_main_t *sm)
Definition: stat_client.h:165
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u16 msg_id_base
Definition: mactime_top.c:40
u64 uword
Definition: types.h:112
u32 * ls_result1
Definition: mactime_top.c:27
mactime_device_t * devices
Definition: mactime_top.c:21
struct _svm_queue svm_queue_t
#define hash_get_mem(h, key)
Definition: hash.h:269
static api_main_t * vlibapi_get_main(void)
Definition: api_common.h:390
API common definitions See api_doc.md for more info.
u32 * ls_result2
Definition: mactime_top.c:27
f64 now
volatile u32 result_ready
Definition: mactime_top.c:41
static void vl_api_mactime_dump_reply_t_handler(vl_api_mactime_dump_reply_t *mp)
Definition: mactime_top.c:60
static int stat_segment_access_start(stat_segment_access_t *sa, stat_client_main_t *sm)
Definition: stat_client.h:115
app_main_t * am
Definition: application.c:489
static unsigned char * print(const cJSON *const item, cJSON_bool format, const internal_hooks *const hooks)
Definition: cJSON.c:1183
__clib_export f64 clib_timebase_find_sunday_midnight(f64 start_time)
Definition: time_range.c:221
u8 ** pattern1
Definition: mactime_top.c:26
u32 vl(void *x)
Definition: mactime_top.c:50
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".