1 #include <vppinfra/time.h>
2 #include <vppinfra/hash.h>
3 #include <vppinfra/pool.h>
4 #include <vpp/stats/stat_segment.h>
5 #include <vpp-api/client/stat_client.h>
6 #include <vppinfra/vec.h>
7 #include <mactime/mactime_device.h>
8 #include <vlibapi/api_common.h>
9 #include <vlibmemory/memory_client.h>
10 #include <vlibmemory/api.h>
11 #include <vnet/api_errno.h>
12 #include <svm/queue.h>
14 /* define message IDs */
15 #include <mactime/mactime.api_enum.h>
16 #include <mactime/mactime.api_types.h>
21 uword *device_by_device_name;
22 mactime_device_t *devices;
25 /* Stat segment variables */
26 stat_client_main_t *stat_client_main;
27 u8 **pattern1, **pattern2;
28 u32 *ls_result1, *ls_result2;
29 vlib_counter_t *allow_counters;
30 vlib_counter_t *drop_counters;
33 clib_time_t clib_time;
34 clib_timebase_t timebase;
38 /* API message-handling */
39 svm_queue_t *vl_input_queue;
42 volatile u32 result_ready;
48 /* Indispensable for debugging in gdb... */
56 #define foreach_mactime_api_msg \
57 _(MACTIME_DUMP_REPLY, mactime_dump_reply) \
58 _(MACTIME_DETAILS, mactime_details)
60 static void vl_api_mactime_dump_reply_t_handler
61 (vl_api_mactime_dump_reply_t * mp)
63 mt_main_t *mm = &mt_main;
64 i32 retval = clib_net_to_host_u32 (mp->retval);
71 vl_api_mactime_details_t_handler (vl_api_mactime_details_t * mp)
73 mt_main_t *mm = &mt_main;
74 mactime_device_t *dev;
76 clib_timebase_range_t *rp;
79 if (PREDICT_FALSE (mm->device_by_device_name == 0))
80 mm->device_by_device_name = hash_create_string (0, sizeof (uword));
82 p = hash_get_mem (mm->device_by_device_name, mp->device_name);
84 dev = pool_elt_at_index (mm->devices, p[0]);
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,
95 clib_memcpy_fast (dev->mac_address, mp->mac_address,
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++)
104 vec_add2 (dev->ranges, rp, 1);
105 rp->start = mp->ranges[i].start;
106 rp->end = mp->ranges[i].end;
110 #define vl_print(handle, ...) fformat(handle, __VA_ARGS__)
114 #define vl_api_version(n,v) static u32 api_version = v;
115 #include <mactime/mactime.api.h>
116 #undef vl_api_version
121 connect_to_vpp (char *name)
123 api_main_t *am = vlibapi_get_main ();
124 mt_main_t *mm = &mt_main;
125 u8 *msg_base_lookup_name;
127 if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
130 mm->vl_input_queue = am->shmem_hdr->vl_input_queue;
131 mm->my_client_index = am->my_client_index;
133 msg_base_lookup_name = format (0, "mactime_%08x%c", api_version, 0);
135 mm->msg_id_base = vl_client_get_first_plugin_msg_id
136 ((char *) msg_base_lookup_name);
138 vec_free (msg_base_lookup_name);
140 if (mm->msg_id_base == ~0)
144 vl_msg_api_set_handlers((VL_API_##N + mm->msg_id_base), \
146 vl_api_##n##_t_handler, \
148 vl_api_##n##_t_endian, \
149 vl_api_##n##_t_print, \
150 sizeof(vl_api_##n##_t), 1);
151 foreach_mactime_api_msg;
158 dump_mactime_table (mt_main_t * mm)
160 vl_api_mactime_dump_t *mp;
161 u32 deadman_counter = 1000;
163 /* Send the dump request */
164 mp = vl_msg_api_alloc (sizeof (*mp));
165 memset (mp, 0, sizeof (*mp));
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);
172 /* Wait up to 1 second for vpp to reply */
173 while (deadman_counter-- && mm->result_ready == 0)
176 if (mm->retval && (mm->retval != VNET_API_ERROR_NO_CHANGE))
177 clib_warning ("dump reply %d", mm->retval);
182 scrape_stats_segment (mt_main_t * mm)
184 vlib_counter_t **counters_by_thread;
185 vlib_counter_t *counters;
187 mactime_device_t *dev;
188 stat_segment_access_t sa;
189 stat_client_main_t *sm = mm->stat_client_main;
190 stat_segment_directory_entry_t *ep;
191 int need_update2 = 0;
192 static u32 *pool_indices;
195 vec_reset_length (pool_indices);
197 pool_foreach (dev, mm->devices,
199 vec_add1 (pool_indices, dev->pool_index);
203 /* Nothing to do... */
204 if (vec_len (pool_indices) == 0)
209 /* Has directory been updated? */
210 if (mm->ls_result1 == 0 || (sm->shared_header->epoch != sm->current_epoch))
213 vec_free (mm->ls_result1);
214 mm->ls_result1 = stat_segment_ls (mm->pattern1);
217 stat_segment_access_start (&sa, sm);
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);
223 for (i = 0; i < vec_len (pool_indices); i++)
225 u32 index = pool_indices[i];
227 vec_validate (mm->allow_counters, index);
228 mm->allow_counters[index].packets = 0;
229 mm->allow_counters[index].bytes = 0;
231 for (j = 0; j < vec_len (counters_by_thread); j++)
233 counters = stat_segment_pointer (sm->shared_header,
235 mm->allow_counters[index].packets += counters[index].packets;
236 mm->allow_counters[index].bytes += counters[index].bytes;
240 /* Ugh, segment changed during access. Try again */
241 if (stat_segment_access_end (&sa, sm))
244 /* Has directory been updated? */
245 if (mm->ls_result2 == 0 || need_update2)
247 vec_free (mm->ls_result2);
248 mm->ls_result2 = stat_segment_ls (mm->pattern2);
252 stat_segment_access_start (&sa, sm);
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);
258 for (i = 0; i < vec_len (pool_indices); i++)
260 u32 index = pool_indices[i];
262 vec_validate (mm->drop_counters, index);
263 mm->drop_counters[index].packets = 0;
264 mm->drop_counters[index].bytes = 0;
266 for (j = 0; j < vec_len (counters_by_thread); j++)
268 counters = stat_segment_pointer (sm->shared_header,
270 mm->drop_counters[index].packets += counters[index].packets;
271 mm->drop_counters[index].bytes += counters[index].bytes;
274 /* Ugh, segment changed during access. Try again */
275 if (stat_segment_access_end (&sa, sm))
280 format_mac_address (u8 * s, va_list * args)
282 u8 *a = va_arg (*args, u8 *);
284 return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
285 a[0], a[1], a[2], a[3], a[4], a[5]);
289 format_bytes_with_width (u8 * s, va_list * va)
291 uword nbytes = va_arg (*va, u64);
292 int width = va_arg (*va, int);
298 fmt = format (0, "%%%d.3f%%s%c", width, 0);
300 fmt = format (0, "%%.3f%%s%c", 0);
302 if (nbytes > (1024ULL * 1024ULL * 1024ULL))
304 nbytes_f64 = ((f64) nbytes) / (1024.0 * 1024.0 * 1024.0);
307 else if (nbytes > (1024ULL * 1024ULL))
309 nbytes_f64 = ((f64) nbytes) / (1024.0 * 1024.0);
312 else if (nbytes > 1024ULL)
314 nbytes_f64 = ((f64) nbytes) / (1024.0);
319 nbytes_f64 = (f64) nbytes;
323 s = format (s, (char *) fmt, nbytes_f64, suffix);
329 format_device (u8 * s, va_list * args)
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;
342 s = format (s, "%-15s %5s %18s %14s %10s %11s %13s",
343 "Device Name", "Index", "Addresses", "Status",
344 "AllowPkt", "AllowByte", "DropPkt");
349 now = clib_timebase_now (&mm->timebase);
351 if (PREDICT_FALSE ((now - mm->sunday_midnight) > 86400.0 * 7.0))
352 mm->sunday_midnight = clib_timebase_find_sunday_midnight (now);
354 /* Check dynamic ranges */
355 for (j = 0; j < vec_len (dp->ranges); j++)
357 clib_timebase_range_t *r = dp->ranges + j;
360 start0 = r->start + mm->sunday_midnight;
361 end0 = r->end + mm->sunday_midnight;
363 s = format (s, " Range %d: %U - %U\n", j,
364 format_clib_timebase_time, start0,
365 format_clib_timebase_time, end0);
367 if (now >= start0 && now <= end0)
369 if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW)
371 else if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW_QUOTA)
377 s = format (s, " Time in range %d:", j);
378 s = format (s, " %U - %U\n",
379 format_clib_timebase_time, start0,
380 format_clib_timebase_time, end0);
386 s = format (s, " No range match.\n");
387 if (dp->flags & MACTIME_DEVICE_FLAG_STATIC_DROP)
389 if (dp->flags & MACTIME_DEVICE_FLAG_STATIC_ALLOW)
391 if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW)
393 if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_DROP)
395 if (dp->flags & MACTIME_DEVICE_FLAG_DYNAMIC_ALLOW_QUOTA)
399 macstring = format (0, "%U", format_mac_address, dp->mac_address);
400 switch (current_status)
403 status_string = "static drop";
406 status_string = "static allow";
409 status_string = "dynamic drop";
412 status_string = "dynamic allow";
415 status_string = "d-quota inact";
418 status_string = "d-quota activ";
421 status_string = "code bug!";
425 s = format (s, "%-15s %5d %18s %14s %10lld %U %13lld\n",
426 dp->device_name, dp->pool_index, macstring, status_string,
427 mm->allow_counters[dp->pool_index].packets,
428 format_bytes_with_width,
429 mm->allow_counters[dp->pool_index].bytes, 10,
430 mm->drop_counters[dp->pool_index].packets);
431 vec_free (macstring);
433 if (dp->data_quota > 0)
435 s = format (s, "%-59s %s%U %s%U", " ", "Quota ",
436 format_bytes_with_width, dp->data_quota, 10,
437 "Use ", format_bytes_with_width, dp->data_used_in_range, 8);
444 print_device_table (mt_main_t * mm)
446 mactime_device_t *dev;
448 fformat (stdout, "%U", format_device, 0 /* header */ , 0 /* verbose */ );
450 pool_foreach (dev, mm->devices,
452 fformat (stdout, "%U", format_device, dev, 0 /* verbose */);
458 main (int argc, char **argv)
460 mt_main_t *mm = &mt_main;
461 extern stat_client_main_t stat_client_main;
463 clib_mem_init (0, 64 << 20);
465 if (connect_to_vpp ("mactime_top") < 0)
467 fformat (stderr, "vpp api client connect error\n");
471 if (stat_segment_connect (argv[1]) < 0)
473 fformat (stderr, "stat segment connect error");
477 mm->stat_client_main = (stat_client_main_t *) & stat_client_main;
479 /* US EDT - $$$ FIXME */
480 clib_time_init (&mm->clib_time);
481 mm->timezone_offset = -5.0;
482 clib_timebase_init (&mm->timebase, mm->timezone_offset,
483 CLIB_TIMEBASE_DAYLIGHT_USA);
485 vec_add1 (mm->pattern1, (u8 *) "^/mactime/allow");
486 vec_add1 (mm->pattern2, (u8 *) "^/mactime/drop");
490 dump_mactime_table (mm);
491 scrape_stats_segment (mm);
492 print_device_table (mm);
500 * fd.io coding-style-patch-verification: ON
503 * eval: (c-set-style "gnu")