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