blob: c570476d130fb6735d24213fa78cafa3c4aa1f86 [file] [log] [blame]
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <vnet/fib/fib_walk.h>
17#include <vnet/fib/fib_node_list.h>
18
19/**
20 * The flags on a walk
21 */
22typedef enum fib_walk_flags_t_
23{
24 /**
25 * A synchronous walk.
26 * This walk will run to completion, i.e. visit ALL the children.
27 * It is a depth first traversal of the graph.
28 */
29 FIB_WALK_FLAG_SYNC = (1 << 0),
30 /**
31 * An asynchronous walk.
32 * This walk will be scheduled to run in the background. It will thus visits
33 * the children at a later point in time.
34 * It is a depth first traversal of the graph.
35 */
36 FIB_WALK_FLAG_ASYNC = (1 << 1),
37 /**
38 * An indication that the walk is currently executing.
39 */
40 FIB_WALK_FLAG_EXECUTING = (1 << 2),
41} fib_walk_flags_t;
42
43/**
44 * A representation of a graph walk from a parent object to its children
45 */
46typedef struct fib_walk_t_
47{
48 /**
49 * FIB node linkage. This object is not in the FIB object graph,
50 * but it is present in other node's dependency lists, so it needs to
51 * be pointerable to.
52 */
53 fib_node_t fw_node;
54
55 /**
56 * the walk's flags
57 */
58 fib_walk_flags_t fw_flags;
59
60 /**
61 * Sibling index in the dependency list
62 */
63 u32 fw_dep_sibling;
64
65 /**
66 * Sibling index in the list of all walks
67 */
68 u32 fw_prio_sibling;
69
70 /**
71 * Pointer to the node whose dependants this walk is walking
72 */
73 fib_node_ptr_t fw_parent;
74
75 /**
76 * Number of nodes visited by this walk. saved for debugging purposes.
77 */
78 u32 fw_n_visits;
79
80 /**
Neale Ranns33a7dd52016-10-07 15:14:33 +010081 * Time the walk started
82 */
83 f64 fw_start_time;
84
85 /**
Neale Ranns0bfe5d82016-08-25 15:29:12 +010086 * The reasons this walk is occuring.
87 * This is a vector ordered in time. The reasons and the front were started
88 * first, and so should be acted first when a node is visisted.
89 */
90 fib_node_back_walk_ctx_t *fw_ctx;
91} fib_walk_t;
92
93/**
94 * @brief The pool of all walk objects
95 */
96static fib_walk_t *fib_walk_pool;
97
98/**
Neale Ranns0bfe5d82016-08-25 15:29:12 +010099 * Statistics maintained per-walk queue
100 */
101typedef enum fib_walk_queue_stats_t_
102{
103 FIB_WALK_SCHEDULED,
104 FIB_WALK_COMPLETED,
105} fib_walk_queue_stats_t;
Neale Ranns450cd302016-11-09 17:49:42 +0000106#define FIB_WALK_QUEUE_STATS_NUM ((fib_walk_queue_stats_t)(FIB_WALK_COMPLETED+1))
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100107
108#define FIB_WALK_QUEUE_STATS { \
109 [FIB_WALK_SCHEDULED] = "scheduled", \
110 [FIB_WALK_COMPLETED] = "completed", \
111}
112
113#define FOR_EACH_FIB_WALK_QUEUE_STATS(_wqs) \
114 for ((_wqs) = FIB_WALK_SCHEDULED; \
Neale Ranns33a7dd52016-10-07 15:14:33 +0100115 (_wqs) < FIB_WALK_QUEUE_STATS_NUM; \
116 (_wqs)++)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100117
118/**
119 * The names of the walk stats
120 */
121static const char * const fib_walk_queue_stats_names[] = FIB_WALK_QUEUE_STATS;
Neale Rannsad95b5d2016-11-10 20:35:14 +0000122/**
123 * The names of the walk reasons
124 */
125static const char * const fib_node_bw_reason_names[] = FIB_NODE_BW_REASONS;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100126
127/**
128 * A represenation of one queue of walk
129 */
130typedef struct fib_walk_queue_t_
131{
132 /**
133 * Qeuee stats
134 */
135 u64 fwq_stats[FIB_WALK_QUEUE_STATS_NUM];
136
137 /**
138 * The node list which acts as the queue
139 */
140 fib_node_list_t fwq_queue;
141} fib_walk_queue_t;
142
143/**
144 * A set of priority queues for outstanding walks
145 */
146typedef struct fib_walk_queues_t_
147{
148 fib_walk_queue_t fwqs_queues[FIB_WALK_PRIORITY_NUM];
149} fib_walk_queues_t;
150
151/**
152 * The global queues of outstanding walks
153 */
154static fib_walk_queues_t fib_walk_queues;
155
156/**
157 * The names of the walk priorities
158 */
159static const char * const fib_walk_priority_names[] = FIB_WALK_PRIORITIES;
160
Neale Ranns33a7dd52016-10-07 15:14:33 +0100161/**
162 * @brief Histogram stats on the lenths of each walk in elemenets visisted.
163 * Store upto 1<<23 elements in increments of 1<<10
164 */
165#define HISTOGRAM_VISITS_PER_WALK_MAX (1<<23)
166#define HISTOGRAM_VISITS_PER_WALK_INCR (1<<10)
167#define HISTOGRAM_VISITS_PER_WALK_N_BUCKETS \
168 (HISTOGRAM_VISITS_PER_WALK_MAX/HISTOGRAM_VISITS_PER_WALK_INCR)
169static u64 fib_walk_hist_vists_per_walk[HISTOGRAM_VISITS_PER_WALK_N_BUCKETS];
170
171/**
172 * @brief History of state for the last 128 walks
173 */
174#define HISTORY_N_WALKS 128
Neale Ranns19c68d22016-12-07 15:38:14 +0000175#define MAX_HISTORY_REASONS 16
Neale Ranns33a7dd52016-10-07 15:14:33 +0100176static u32 history_last_walk_pos;
177typedef struct fib_walk_history_t_ {
178 u32 fwh_n_visits;
179 f64 fwh_duration;
Neale Ranns8b37b872016-11-21 12:25:22 +0000180 f64 fwh_completed;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100181 fib_node_ptr_t fwh_parent;
Neale Rannsad95b5d2016-11-10 20:35:14 +0000182 fib_walk_flags_t fwh_flags;
Neale Ranns19c68d22016-12-07 15:38:14 +0000183 fib_node_bw_reason_flag_t fwh_reason[MAX_HISTORY_REASONS];
Neale Ranns33a7dd52016-10-07 15:14:33 +0100184} fib_walk_history_t;
185static fib_walk_history_t fib_walk_history[HISTORY_N_WALKS];
186
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100187u8*
188format_fib_walk_priority (u8 *s, va_list ap)
189{
190 fib_walk_priority_t prio = va_arg(ap, fib_walk_priority_t);
191
192 ASSERT(prio < FIB_WALK_PRIORITY_NUM);
193
194 return (format(s, "%s", fib_walk_priority_names[prio]));
195}
196static u8*
197format_fib_walk_queue_stats (u8 *s, va_list ap)
198{
199 fib_walk_queue_stats_t wqs = va_arg(ap, fib_walk_queue_stats_t);
200
201 ASSERT(wqs < FIB_WALK_QUEUE_STATS_NUM);
202
203 return (format(s, "%s", fib_walk_queue_stats_names[wqs]));
204}
205
206static index_t
207fib_walk_get_index (fib_walk_t *fwalk)
208{
209 return (fwalk - fib_walk_pool);
210}
211
212static fib_walk_t *
213fib_walk_get (index_t fwi)
214{
215 return (pool_elt_at_index(fib_walk_pool, fwi));
216}
217
218/*
219 * not static so it can be used in the unit tests
220 */
221u32
222fib_walk_queue_get_size (fib_walk_priority_t prio)
223{
224 return (fib_node_list_get_size(fib_walk_queues.fwqs_queues[prio].fwq_queue));
225}
226
227static fib_node_index_t
228fib_walk_queue_get_front (fib_walk_priority_t prio)
229{
230 fib_node_ptr_t wp;
231
232 fib_node_list_get_front(fib_walk_queues.fwqs_queues[prio].fwq_queue, &wp);
233
234 return (wp.fnp_index);
235}
236
237static void
Neale Rannsf12a83f2017-04-18 09:09:40 -0700238fib_walk_destroy (index_t fwi)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100239{
Neale Rannsf12a83f2017-04-18 09:09:40 -0700240 fib_walk_t *fwalk;
Neale Ranns19c68d22016-12-07 15:38:14 +0000241 u32 bucket, ii;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100242
Neale Rannsf12a83f2017-04-18 09:09:40 -0700243 fwalk = fib_walk_get(fwi);
244
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100245 if (FIB_NODE_INDEX_INVALID != fwalk->fw_prio_sibling)
246 {
Neale Ranns33a7dd52016-10-07 15:14:33 +0100247 fib_node_list_elt_remove(fwalk->fw_prio_sibling);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100248 }
249 fib_node_child_remove(fwalk->fw_parent.fnp_type,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100250 fwalk->fw_parent.fnp_index,
251 fwalk->fw_dep_sibling);
252
253 /*
Neale Rannsf12a83f2017-04-18 09:09:40 -0700254 * refetch the walk object. More walks could have been spawned as a result
255 * of releasing the lock on the parent.
256 */
257 fwalk = fib_walk_get(fwi);
258
259 /*
Neale Ranns33a7dd52016-10-07 15:14:33 +0100260 * add the stats to the continuous histogram collection.
261 */
262 bucket = (fwalk->fw_n_visits / HISTOGRAM_VISITS_PER_WALK_INCR);
Neale Ranns924d03a2016-10-19 08:25:46 +0100263 bucket = (bucket >= HISTOGRAM_VISITS_PER_WALK_N_BUCKETS ?
Neale Ranns5899fde2016-10-12 13:51:05 +0100264 HISTOGRAM_VISITS_PER_WALK_N_BUCKETS - 1 :
Neale Ranns33a7dd52016-10-07 15:14:33 +0100265 bucket);
266 fib_walk_hist_vists_per_walk[bucket]++;
267
268 /*
269 * save stats to the recent history
270 */
271
272 fib_walk_history[history_last_walk_pos].fwh_n_visits =
273 fwalk->fw_n_visits;
Neale Ranns8b37b872016-11-21 12:25:22 +0000274 fib_walk_history[history_last_walk_pos].fwh_completed =
275 vlib_time_now(vlib_get_main());
Neale Ranns33a7dd52016-10-07 15:14:33 +0100276 fib_walk_history[history_last_walk_pos].fwh_duration =
Neale Ranns8b37b872016-11-21 12:25:22 +0000277 fib_walk_history[history_last_walk_pos].fwh_completed -
278 fwalk->fw_start_time;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100279 fib_walk_history[history_last_walk_pos].fwh_parent =
280 fwalk->fw_parent;
Neale Rannsad95b5d2016-11-10 20:35:14 +0000281 fib_walk_history[history_last_walk_pos].fwh_flags =
282 fwalk->fw_flags;
283
Neale Ranns19c68d22016-12-07 15:38:14 +0000284 vec_foreach_index(ii, fwalk->fw_ctx)
Neale Rannsad95b5d2016-11-10 20:35:14 +0000285 {
Neale Ranns19c68d22016-12-07 15:38:14 +0000286 if (ii < MAX_HISTORY_REASONS)
287 {
288 fib_walk_history[history_last_walk_pos].fwh_reason[ii] =
289 fwalk->fw_ctx[ii].fnbw_reason;
290 }
Neale Rannsad95b5d2016-11-10 20:35:14 +0000291 }
Neale Ranns33a7dd52016-10-07 15:14:33 +0100292
293 history_last_walk_pos = (history_last_walk_pos + 1) % HISTORY_N_WALKS;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100294
295 fib_node_deinit(&fwalk->fw_node);
Neale Ranns19c68d22016-12-07 15:38:14 +0000296 vec_free(fwalk->fw_ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100297 pool_put(fib_walk_pool, fwalk);
298}
299
300/**
301 * return code when advancing a walk
302 */
303typedef enum fib_walk_advance_rc_t_
304{
305 /**
306 * The walk is complete
307 */
308 FIB_WALK_ADVANCE_DONE,
309 /**
310 * the walk has more work
311 */
312 FIB_WALK_ADVANCE_MORE,
313 /**
314 * The walk merged with the one in front
315 */
316 FIB_WALK_ADVANCE_MERGE,
317} fib_walk_advance_rc_t;
318
319/**
320 * @brief Advance the walk one element in its work list
321 */
322static fib_walk_advance_rc_t
323fib_walk_advance (fib_node_index_t fwi)
324{
Neale Ranns19c68d22016-12-07 15:38:14 +0000325 fib_node_back_walk_ctx_t *ctx, *old;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100326 fib_node_back_walk_rc_t wrc;
327 fib_node_ptr_t sibling;
328 fib_walk_t *fwalk;
329 int more_elts;
330
331 /*
332 * this walk function is re-entrant - walks acan spawn walks.
Neale Ranns33a7dd52016-10-07 15:14:33 +0100333 * fib_walk_t objects come from a pool, so they can realloc. we need
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100334 * to retch from said pool at the appropriate times.
335 */
336 fwalk = fib_walk_get(fwi);
337
338 more_elts = fib_node_list_elt_get_next(fwalk->fw_dep_sibling, &sibling);
339
340 if (more_elts)
341 {
Neale Ranns19c68d22016-12-07 15:38:14 +0000342 old = fwalk->fw_ctx;
343
Neale Ranns33a7dd52016-10-07 15:14:33 +0100344 vec_foreach(ctx, fwalk->fw_ctx)
345 {
346 wrc = fib_node_back_walk_one(&sibling, ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100347
Neale Ranns33a7dd52016-10-07 15:14:33 +0100348 fwalk = fib_walk_get(fwi);
349 fwalk->fw_n_visits++;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100350
Neale Ranns33a7dd52016-10-07 15:14:33 +0100351 if (FIB_NODE_BACK_WALK_MERGE == wrc)
352 {
353 /*
354 * this walk has merged with the one further along the node's
355 * dependecy list.
356 */
357 return (FIB_WALK_ADVANCE_MERGE);
358 }
Neale Ranns19c68d22016-12-07 15:38:14 +0000359 if (old != fwalk->fw_ctx)
360 {
361 /*
362 * nasty re-entrant addition of a walk has realloc'd the vector
363 * break out
364 */
365 return (FIB_WALK_ADVANCE_MERGE);
366 }
Neale Ranns33a7dd52016-10-07 15:14:33 +0100367 }
368 /*
369 * move foward to the next node to visit
370 */
371 more_elts = fib_node_list_advance(fwalk->fw_dep_sibling);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100372 }
373
374 if (more_elts)
375 {
Neale Ranns33a7dd52016-10-07 15:14:33 +0100376 return (FIB_WALK_ADVANCE_MORE);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100377 }
378
379 return (FIB_WALK_ADVANCE_DONE);
380}
381
382/**
Neale Ranns33a7dd52016-10-07 15:14:33 +0100383 * @breif Enurmerate the times of sleep between walks
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100384 */
Neale Ranns33a7dd52016-10-07 15:14:33 +0100385typedef enum fib_walk_sleep_type_t_
386{
387 FIB_WALK_SHORT_SLEEP,
388 FIB_WALK_LONG_SLEEP,
389} fib_walk_sleep_type_t;
390
391#define FIB_WALK_N_SLEEP (FIB_WALK_LONG_SLEEP+1)
392
393/**
394 * @brief Durations for the sleep types
395 */
396static f64 fib_walk_sleep_duration[] = {
397 [FIB_WALK_LONG_SLEEP] = 1e-3,
398 [FIB_WALK_SHORT_SLEEP] = 1e-8,
399};
400
401/**
402 * @brief The time quota for a walk. When more than this amount of time is
403 * spent, the walk process will yield.
404 */
405static f64 quota = 1e-4;
406
407/**
408 * Histogram on the amount of work done (in msecs) in each walk
409 */
410#define N_TIME_BUCKETS 128
411#define TIME_INCREMENTS (N_TIME_BUCKETS/2)
412static u64 fib_walk_work_time_taken[N_TIME_BUCKETS];
413
414/**
415 * Histogram on the number of nodes visted in each quota
416 */
417#define N_ELTS_BUCKETS 128
418static u32 fib_walk_work_nodes_visisted_incr = 2;
419static u64 fib_walk_work_nodes_visited[N_ELTS_BUCKETS];
420
421/**
422 * Histogram of the sleep lengths
423 */
424static u64 fib_walk_sleep_lengths[2];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100425
426/**
427 * @brief Service the queues
428 * This is not declared static so that it can be unit tested - i know i know...
429 */
430f64
431fib_walk_process_queues (vlib_main_t * vm,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100432 const f64 quota)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100433{
Neale Ranns33a7dd52016-10-07 15:14:33 +0100434 f64 start_time, consumed_time;
435 fib_walk_sleep_type_t sleep;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100436 fib_walk_priority_t prio;
437 fib_walk_advance_rc_t rc;
438 fib_node_index_t fwi;
439 fib_walk_t *fwalk;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100440 u32 n_elts;
441 i32 bucket;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100442
Neale Ranns33a7dd52016-10-07 15:14:33 +0100443 consumed_time = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100444 start_time = vlib_time_now(vm);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100445 n_elts = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100446
447 FOR_EACH_FIB_WALK_PRIORITY(prio)
448 {
Neale Ranns33a7dd52016-10-07 15:14:33 +0100449 while (0 != fib_walk_queue_get_size(prio))
450 {
451 fwi = fib_walk_queue_get_front(prio);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100452
Neale Ranns33a7dd52016-10-07 15:14:33 +0100453 /*
454 * set this walk as executing
455 */
456 fwalk = fib_walk_get(fwi);
457 fwalk->fw_flags |= FIB_WALK_FLAG_EXECUTING;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100458
Neale Ranns33a7dd52016-10-07 15:14:33 +0100459 do
460 {
461 rc = fib_walk_advance(fwi);
462 n_elts++;
463 consumed_time = (vlib_time_now(vm) - start_time);
464 } while ((consumed_time < quota) &&
465 (FIB_WALK_ADVANCE_MORE == rc));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100466
Neale Ranns33a7dd52016-10-07 15:14:33 +0100467 /*
468 * if this walk has no more work then pop it from the queue
469 * and move on to the next.
470 */
471 if (FIB_WALK_ADVANCE_MORE != rc)
472 {
Neale Rannsf12a83f2017-04-18 09:09:40 -0700473 fib_walk_destroy(fwi);
Neale Ranns33a7dd52016-10-07 15:14:33 +0100474 fib_walk_queues.fwqs_queues[prio].fwq_stats[FIB_WALK_COMPLETED]++;
475 }
476 else
477 {
478 /*
479 * passed our work quota. sleep time.
480 */
481 fwalk = fib_walk_get(fwi);
482 fwalk->fw_flags &= ~FIB_WALK_FLAG_EXECUTING;
483 sleep = FIB_WALK_SHORT_SLEEP;
484 goto that_will_do_for_now;
485 }
486 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100487 }
488 /*
489 * got to the end of all the work
490 */
Neale Ranns33a7dd52016-10-07 15:14:33 +0100491 sleep = FIB_WALK_LONG_SLEEP;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100492
493that_will_do_for_now:
Neale Ranns33a7dd52016-10-07 15:14:33 +0100494
495 /*
496 * collect the stats:
497 * - for the number of nodes visisted we store 128 increments
498 * - for the time consumed we store quota/TIME_INCREMENTS increments.
499 */
500 bucket = ((n_elts/fib_walk_work_nodes_visisted_incr) > N_ELTS_BUCKETS ?
501 N_ELTS_BUCKETS-1 :
502 n_elts/fib_walk_work_nodes_visisted_incr);
503 ++fib_walk_work_nodes_visited[bucket];
504
505 bucket = (consumed_time - quota) / (quota / TIME_INCREMENTS);
506 bucket += N_TIME_BUCKETS/2;
507 bucket = (bucket < 0 ? 0 : bucket);
508 bucket = (bucket > N_TIME_BUCKETS-1 ? N_TIME_BUCKETS-1 : bucket);
509 ++fib_walk_work_time_taken[bucket];
510
511 ++fib_walk_sleep_lengths[sleep];
512
513 return (fib_walk_sleep_duration[sleep]);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100514}
515
516/**
Neale Rannsf12a83f2017-04-18 09:09:40 -0700517 * Events sent to the FIB walk process
518 */
519typedef enum fib_walk_process_event_t_
520{
521 FIB_WALK_PROCESS_EVENT_DATA,
522 FIB_WALK_PROCESS_EVENT_ENABLE,
523 FIB_WALK_PROCESS_EVENT_DISABLE,
524} fib_walk_process_event;
525
526/**
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100527 * @brief The 'fib-walk' process's main loop.
528 */
529static uword
530fib_walk_process (vlib_main_t * vm,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100531 vlib_node_runtime_t * node,
532 vlib_frame_t * f)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100533{
Neale Rannsf12a83f2017-04-18 09:09:40 -0700534 uword event_type, *event_data = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100535 f64 sleep_time;
Neale Rannsf12a83f2017-04-18 09:09:40 -0700536 int enabled;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100537
Neale Rannsf12a83f2017-04-18 09:09:40 -0700538 enabled = 1;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100539 sleep_time = fib_walk_sleep_duration[FIB_WALK_SHORT_SLEEP];
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100540
541 while (1)
542 {
Neale Rannsf12a83f2017-04-18 09:09:40 -0700543 /*
544 * the feature to disable/enable this walk process is only
545 * for testing purposes
546 */
547 if (enabled)
548 {
549 vlib_process_wait_for_event_or_clock(vm, sleep_time);
550 }
551 else
552 {
553 vlib_process_wait_for_event(vm);
554 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100555
Neale Rannsf12a83f2017-04-18 09:09:40 -0700556 event_type = vlib_process_get_events(vm, &event_data);
557 vec_reset_length(event_data);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100558
Neale Rannsf12a83f2017-04-18 09:09:40 -0700559 switch (event_type)
560 {
561 case FIB_WALK_PROCESS_EVENT_ENABLE:
562 enabled = 1;
563 break;
564 case FIB_WALK_PROCESS_EVENT_DISABLE:
565 enabled = 0;
566 break;
567 default:
568 break;
569 }
570
571 if (enabled)
572 {
573 sleep_time = fib_walk_process_queues(vm, quota);
574 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100575 }
576
577 /*
578 * Unreached
579 */
580 ASSERT(!"WTF");
581 return 0;
582}
583
584/* *INDENT-OFF* */
585VLIB_REGISTER_NODE (fib_walk_process_node,static) = {
586 .function = fib_walk_process,
587 .type = VLIB_NODE_TYPE_PROCESS,
588 .name = "fib-walk",
589};
590/* *INDENT-ON* */
591
592/**
593 * @brief Allocate a new walk object
Neale Ranns33a7dd52016-10-07 15:14:33 +0100594 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100595static fib_walk_t *
596fib_walk_alloc (fib_node_type_t parent_type,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100597 fib_node_index_t parent_index,
598 fib_walk_flags_t flags,
599 fib_node_back_walk_ctx_t *ctx)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100600{
601 fib_walk_t *fwalk;
602
603 pool_get(fib_walk_pool, fwalk);
604
605 fib_node_init(&fwalk->fw_node, FIB_NODE_TYPE_WALK);
606
607 fwalk->fw_flags = flags;
608 fwalk->fw_dep_sibling = FIB_NODE_INDEX_INVALID;
609 fwalk->fw_prio_sibling = FIB_NODE_INDEX_INVALID;
610 fwalk->fw_parent.fnp_index = parent_index;
611 fwalk->fw_parent.fnp_type = parent_type;
612 fwalk->fw_ctx = NULL;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100613 fwalk->fw_start_time = vlib_time_now(vlib_get_main());
614 fwalk->fw_n_visits = 0;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100615
616 /*
617 * make a copy of the backwalk context so the depth count remains
618 * the same for each sibling visitsed. This is important in the case
Neale Ranns19c68d22016-12-07 15:38:14 +0000619 * where a parent has a loop via one child, but all the others are not.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100620 * if the looped child were visited first, the depth count would exceed, the
621 * max and the walk would terminate before it reached the other siblings.
622 */
623 vec_add1(fwalk->fw_ctx, *ctx);
624
625 return (fwalk);
626}
627
628/**
629 * @brief Enqueue a walk onto the appropriate priority queue. Then signal
630 * the background process there is work to do.
631 */
632static index_t
633fib_walk_prio_queue_enquue (fib_walk_priority_t prio,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100634 fib_walk_t *fwalk)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100635{
636 index_t sibling;
637
638 sibling = fib_node_list_push_front(fib_walk_queues.fwqs_queues[prio].fwq_queue,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100639 0,
640 FIB_NODE_TYPE_WALK,
641 fib_walk_get_index(fwalk));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100642 fib_walk_queues.fwqs_queues[prio].fwq_stats[FIB_WALK_SCHEDULED]++;
643
644 /*
645 * poke the fib-walk process to perform the async walk.
646 * we are not passing it specific data, hence the last two args,
647 * the process will drain the queues
648 */
649 vlib_process_signal_event(vlib_get_main(),
Neale Ranns33a7dd52016-10-07 15:14:33 +0100650 fib_walk_process_node.index,
Neale Rannsf12a83f2017-04-18 09:09:40 -0700651 FIB_WALK_PROCESS_EVENT_DATA,
652 0);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100653
654 return (sibling);
655}
656
657void
658fib_walk_async (fib_node_type_t parent_type,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100659 fib_node_index_t parent_index,
660 fib_walk_priority_t prio,
661 fib_node_back_walk_ctx_t *ctx)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100662{
663 fib_walk_t *fwalk;
664
665 if (FIB_NODE_GRAPH_MAX_DEPTH < ++ctx->fnbw_depth)
666 {
Neale Ranns33a7dd52016-10-07 15:14:33 +0100667 /*
668 * The walk has reached the maximum depth. there is a loop in the graph.
669 * bail.
670 */
671 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100672 }
Neale Rannsad422ed2016-11-02 14:20:04 +0000673 if (0 == fib_node_get_n_children(parent_type,
674 parent_index))
Neale Ranns8b37b872016-11-21 12:25:22 +0000675 {
676 /*
677 * no children to walk - quit now
678 */
679 return;
680 }
Neale Rannsad95b5d2016-11-10 20:35:14 +0000681 if (ctx->fnbw_flags & FIB_NODE_BW_FLAG_FORCE_SYNC)
682 {
683 /*
684 * the originator of the walk wanted it to be synchronous, but the
685 * parent object chose async - denied.
686 */
687 return (fib_walk_sync(parent_type, parent_index, ctx));
688 }
689
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100690
691 fwalk = fib_walk_alloc(parent_type,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100692 parent_index,
693 FIB_WALK_FLAG_ASYNC,
694 ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100695
696 fwalk->fw_dep_sibling = fib_node_child_add(parent_type,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100697 parent_index,
698 FIB_NODE_TYPE_WALK,
699 fib_walk_get_index(fwalk));
700
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100701 fwalk->fw_prio_sibling = fib_walk_prio_queue_enquue(prio, fwalk);
702}
703
704/**
705 * @brief Back walk all the children of a FIB node.
706 *
707 * note this is a synchronous depth first walk. Children visited may propagate
708 * the walk to thier children. Other children node types may not propagate,
709 * synchronously but instead queue the walk for later async completion.
710 */
711void
712fib_walk_sync (fib_node_type_t parent_type,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100713 fib_node_index_t parent_index,
714 fib_node_back_walk_ctx_t *ctx)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100715{
716 fib_walk_advance_rc_t rc;
717 fib_node_index_t fwi;
718 fib_walk_t *fwalk;
719
720 if (FIB_NODE_GRAPH_MAX_DEPTH < ++ctx->fnbw_depth)
721 {
Neale Ranns33a7dd52016-10-07 15:14:33 +0100722 /*
723 * The walk has reached the maximum depth. there is a loop in the graph.
724 * bail.
725 */
726 return;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100727 }
Neale Rannsad422ed2016-11-02 14:20:04 +0000728 if (0 == fib_node_get_n_children(parent_type,
729 parent_index))
Neale Ranns8b37b872016-11-21 12:25:22 +0000730 {
731 /*
732 * no children to walk - quit now
733 */
734 return;
735 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100736
737 fwalk = fib_walk_alloc(parent_type,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100738 parent_index,
739 FIB_WALK_FLAG_SYNC,
740 ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100741
742 fwalk->fw_dep_sibling = fib_node_child_add(parent_type,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100743 parent_index,
744 FIB_NODE_TYPE_WALK,
745 fib_walk_get_index(fwalk));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100746 fwi = fib_walk_get_index(fwalk);
747
748 while (1)
749 {
Neale Ranns33a7dd52016-10-07 15:14:33 +0100750 /*
751 * set this walk as executing
752 */
753 fwalk->fw_flags |= FIB_WALK_FLAG_EXECUTING;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100754
Neale Ranns33a7dd52016-10-07 15:14:33 +0100755 do
756 {
757 rc = fib_walk_advance(fwi);
758 } while (FIB_WALK_ADVANCE_MORE == rc);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100759
760
Neale Ranns33a7dd52016-10-07 15:14:33 +0100761 /*
762 * this walk function is re-entrant - walks can spawn walks.
763 * fib_walk_t objects come from a pool, so they can realloc. we need
764 * to re-fetch from said pool at the appropriate times.
765 */
766 fwalk = fib_walk_get(fwi);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100767
Neale Ranns33a7dd52016-10-07 15:14:33 +0100768 if (FIB_WALK_ADVANCE_MERGE == rc)
769 {
770 /*
771 * this sync walk merged with an walk in front.
772 * by reqeusting a sync walk the client wanted all children walked,
773 * so we ditch the walk object in hand and continue with the one
774 * we merged into
775 */
776 fib_node_ptr_t merged_walk;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100777
Neale Ranns33a7dd52016-10-07 15:14:33 +0100778 fib_node_list_elt_get_next(fwalk->fw_dep_sibling, &merged_walk);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100779
Neale Ranns33a7dd52016-10-07 15:14:33 +0100780 ASSERT(FIB_NODE_INDEX_INVALID != merged_walk.fnp_index);
781 ASSERT(FIB_NODE_TYPE_WALK == merged_walk.fnp_type);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100782
Neale Rannsf12a83f2017-04-18 09:09:40 -0700783 fib_walk_destroy(fwi);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100784
Neale Ranns33a7dd52016-10-07 15:14:33 +0100785 fwi = merged_walk.fnp_index;
786 fwalk = fib_walk_get(fwi);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100787
Neale Ranns33a7dd52016-10-07 15:14:33 +0100788 if (FIB_WALK_FLAG_EXECUTING & fwalk->fw_flags)
789 {
790 /*
791 * we are executing a sync walk, and we have met with another
792 * walk that is also executing. since only one walk executs at once
793 * (there is no multi-threading) this implies we have met ourselves
794 * and hence the is a loop in the graph.
795 * This function is re-entrant, so the walk object we met is being
796 * acted on in a stack frame below this one. We must therefore not
797 * continue with it now, but let the stack unwind and along the
798 * appropriate frame to read the depth count and bail.
799 */
800 fwalk = NULL;
801 break;
802 }
803 }
804 else
805 {
806 /*
807 * the walk reached the end of the depdency list.
808 */
809 break;
810 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100811 }
812
813 if (NULL != fwalk)
814 {
Neale Rannsf12a83f2017-04-18 09:09:40 -0700815 fib_walk_destroy(fwi);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100816 }
817}
818
819static fib_node_t *
820fib_walk_get_node (fib_node_index_t index)
821{
822 fib_walk_t *fwalk;
823
824 fwalk = fib_walk_get(index);
825
826 return (&(fwalk->fw_node));
827}
828
829/**
830 * Walk objects are not parents, nor are they locked.
831 * are no-ops
832 */
833static void
834fib_walk_last_lock_gone (fib_node_t *node)
835{
836 ASSERT(0);
837}
838
839static fib_walk_t*
840fib_walk_get_from_node (fib_node_t *node)
841{
842 return ((fib_walk_t*)(((char*)node) -
Neale Ranns33a7dd52016-10-07 15:14:33 +0100843 STRUCT_OFFSET_OF(fib_walk_t, fw_node)));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100844}
845
846/**
847 * @brief Another back walk has reach this walk.
848 * Megre them so there is only one left. It is this node being
849 * visited that will remain, so copy or merge the context onto it.
850 */
851static fib_node_back_walk_rc_t
852fib_walk_back_walk_notify (fib_node_t *node,
853 fib_node_back_walk_ctx_t *ctx)
854{
Neale Ranns19c68d22016-12-07 15:38:14 +0000855 fib_node_back_walk_ctx_t *last;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100856 fib_walk_t *fwalk;
857
858 fwalk = fib_walk_get_from_node(node);
859
860 /*
Neale Ranns19c68d22016-12-07 15:38:14 +0000861 * check whether the walk context can be merged with the most recent.
862 * the most recent was the one last added and is thus at the back of the vector.
863 * we can merge walks if the reason for the walk is the same.
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100864 */
Neale Ranns19c68d22016-12-07 15:38:14 +0000865 last = vec_end(fwalk->fw_ctx) - 1;
866
867 if (last->fnbw_reason == ctx->fnbw_reason)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100868 {
Neale Ranns19c68d22016-12-07 15:38:14 +0000869 /*
870 * copy the largest of the depth values. in the presence of a loop,
871 * the same walk will merge with itself. if we take the smaller depth
872 * then it will never end.
873 */
874 last->fnbw_depth = ((last->fnbw_depth >= ctx->fnbw_depth) ?
875 last->fnbw_depth :
876 ctx->fnbw_depth);
877 }
878 else
879 {
880 /*
881 * walks could not be merged, this means that the walk infront needs to
882 * perform different action to this one that has caught up. the one in
883 * front was scheduled first so append the new walk context to the back
884 * of the list.
885 */
886 vec_add1(fwalk->fw_ctx, *ctx);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100887 }
888
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100889 return (FIB_NODE_BACK_WALK_MERGE);
890}
891
892/**
893 * The FIB walk's graph node virtual function table
894 */
895static const fib_node_vft_t fib_walk_vft = {
896 .fnv_get = fib_walk_get_node,
897 .fnv_last_lock = fib_walk_last_lock_gone,
898 .fnv_back_walk = fib_walk_back_walk_notify,
899};
900
901void
902fib_walk_module_init (void)
903{
904 fib_walk_priority_t prio;
905
906 FOR_EACH_FIB_WALK_PRIORITY(prio)
907 {
Neale Ranns33a7dd52016-10-07 15:14:33 +0100908 fib_walk_queues.fwqs_queues[prio].fwq_queue = fib_node_list_create();
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100909 }
910
911 fib_node_register_type(FIB_NODE_TYPE_WALK, &fib_walk_vft);
912}
913
914static u8*
915format_fib_walk (u8* s, va_list ap)
916{
917 fib_node_index_t fwi = va_arg(ap, fib_node_index_t);
918 fib_walk_t *fwalk;
919
920 fwalk = fib_walk_get(fwi);
921
922 return (format(s, " parent:{%s:%d} visits:%d flags:%d",
Neale Ranns33a7dd52016-10-07 15:14:33 +0100923 fib_node_type_get_name(fwalk->fw_parent.fnp_type),
924 fwalk->fw_parent.fnp_index,
925 fwalk->fw_n_visits,
926 fwalk->fw_flags));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100927}
928
929static clib_error_t *
930fib_walk_show (vlib_main_t * vm,
Neale Ranns33a7dd52016-10-07 15:14:33 +0100931 unformat_input_t * input,
932 vlib_cli_command_t * cmd)
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100933{
934 fib_walk_queue_stats_t wqs;
935 fib_walk_priority_t prio;
936 fib_node_ptr_t sibling;
937 fib_node_index_t fwi;
938 fib_walk_t *fwalk;
Neale Ranns33a7dd52016-10-07 15:14:33 +0100939 int more_elts, ii;
940 u8 *s = NULL;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100941
Neale Ranns33a7dd52016-10-07 15:14:33 +0100942#define USEC 1000000
943 vlib_cli_output(vm, "FIB Walk Quota = %.2fusec:", quota * USEC);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100944 vlib_cli_output(vm, "FIB Walk queues:");
945
946 FOR_EACH_FIB_WALK_PRIORITY(prio)
947 {
Neale Ranns33a7dd52016-10-07 15:14:33 +0100948 vlib_cli_output(vm, " %U priority queue:",
949 format_fib_walk_priority, prio);
950 vlib_cli_output(vm, " Stats: ");
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100951
Neale Ranns33a7dd52016-10-07 15:14:33 +0100952 FOR_EACH_FIB_WALK_QUEUE_STATS(wqs)
953 {
954 vlib_cli_output(vm, " %U:%d",
955 format_fib_walk_queue_stats, wqs,
956 fib_walk_queues.fwqs_queues[prio].fwq_stats[wqs]);
957 }
958 vlib_cli_output(vm, " Occupancy:%d",
959 fib_node_list_get_size(
960 fib_walk_queues.fwqs_queues[prio].fwq_queue));
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100961
Neale Ranns33a7dd52016-10-07 15:14:33 +0100962 more_elts = fib_node_list_get_front(
963 fib_walk_queues.fwqs_queues[prio].fwq_queue,
964 &sibling);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100965
Neale Ranns33a7dd52016-10-07 15:14:33 +0100966 while (more_elts)
967 {
968 ASSERT(FIB_NODE_INDEX_INVALID != sibling.fnp_index);
969 ASSERT(FIB_NODE_TYPE_WALK == sibling.fnp_type);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100970
Neale Ranns33a7dd52016-10-07 15:14:33 +0100971 fwi = sibling.fnp_index;
972 fwalk = fib_walk_get(fwi);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100973
Neale Ranns33a7dd52016-10-07 15:14:33 +0100974 vlib_cli_output(vm, " %U", format_fib_walk, fwi);
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100975
Neale Ranns33a7dd52016-10-07 15:14:33 +0100976 more_elts = fib_node_list_elt_get_next(fwalk->fw_prio_sibling,
977 &sibling);
978 }
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100979 }
Neale Ranns33a7dd52016-10-07 15:14:33 +0100980
981 vlib_cli_output(vm, "Histogram Statistics:");
982 vlib_cli_output(vm, " Number of Elements visit per-quota:");
983 for (ii = 0; ii < N_ELTS_BUCKETS; ii++)
984 {
985 if (0 != fib_walk_work_nodes_visited[ii])
986 s = format(s, "%d:%d ",
987 (ii * fib_walk_work_nodes_visisted_incr),
988 fib_walk_work_nodes_visited[ii]);
989 }
990 vlib_cli_output(vm, " %v", s);
991 vec_free(s);
992
993 vlib_cli_output(vm, " Time consumed per-quota (Quota=%f usec):", quota*USEC);
994 s = format(s, "0:%d ", fib_walk_work_time_taken[0]);
995 for (ii = 1; ii < N_TIME_BUCKETS; ii++)
996 {
997 if (0 != fib_walk_work_time_taken[ii])
998 s = format(s, "%d:%d ", (u32)((((ii - N_TIME_BUCKETS/2) *
999 (quota / TIME_INCREMENTS)) + quota) *
1000 USEC),
1001 fib_walk_work_time_taken[ii]);
1002 }
1003 vlib_cli_output(vm, " %v", s);
1004 vec_free(s);
1005
1006 vlib_cli_output(vm, " Sleep Types:");
1007 vlib_cli_output(vm, " Short Long:");
1008 vlib_cli_output(vm, " %d %d:",
1009 fib_walk_sleep_lengths[FIB_WALK_SHORT_SLEEP],
1010 fib_walk_sleep_lengths[FIB_WALK_LONG_SLEEP]);
1011
1012 vlib_cli_output(vm, " Number of Elements visited per-walk:");
1013 for (ii = 0; ii < HISTOGRAM_VISITS_PER_WALK_N_BUCKETS; ii++)
1014 {
1015 if (0 != fib_walk_hist_vists_per_walk[ii])
1016 s = format(s, "%d:%d ",
1017 ii*HISTOGRAM_VISITS_PER_WALK_INCR,
1018 fib_walk_hist_vists_per_walk[ii]);
1019 }
1020 vlib_cli_output(vm, " %v", s);
1021 vec_free(s);
1022
1023
1024 vlib_cli_output(vm, "Brief History (last %d walks):", HISTORY_N_WALKS);
Neale Rannsad95b5d2016-11-10 20:35:14 +00001025 ii = history_last_walk_pos - 1;
1026 if (ii < 0)
1027 ii = HISTORY_N_WALKS - 1;
1028
1029 while (ii != history_last_walk_pos)
Neale Ranns33a7dd52016-10-07 15:14:33 +01001030 {
Neale Ranns19c68d22016-12-07 15:38:14 +00001031 if (0 != fib_walk_history[ii].fwh_reason[0])
Neale Ranns33a7dd52016-10-07 15:14:33 +01001032 {
Neale Rannsad95b5d2016-11-10 20:35:14 +00001033 fib_node_back_walk_reason_t reason;
1034 u8 *s = NULL;
Neale Ranns19c68d22016-12-07 15:38:14 +00001035 u32 jj;
Neale Rannsad95b5d2016-11-10 20:35:14 +00001036
Neale Ranns8b37b872016-11-21 12:25:22 +00001037 s = format(s, "[@%d]: %s:%d visits:%d duration:%.2f completed:%.2f ",
1038 ii, fib_node_type_get_name(fib_walk_history[ii].fwh_parent.fnp_type),
Neale Rannsad95b5d2016-11-10 20:35:14 +00001039 fib_walk_history[ii].fwh_parent.fnp_index,
1040 fib_walk_history[ii].fwh_n_visits,
Neale Ranns8b37b872016-11-21 12:25:22 +00001041 fib_walk_history[ii].fwh_duration,
1042 fib_walk_history[ii].fwh_completed);
Neale Rannsad95b5d2016-11-10 20:35:14 +00001043 if (FIB_WALK_FLAG_SYNC & fib_walk_history[ii].fwh_flags)
1044 s = format(s, "sync, ");
1045 if (FIB_WALK_FLAG_ASYNC & fib_walk_history[ii].fwh_flags)
1046 s = format(s, "async, ");
1047
1048 s = format(s, "reason:");
Neale Ranns19c68d22016-12-07 15:38:14 +00001049 jj = 0;
1050 while (0 != fib_walk_history[ii].fwh_reason[jj])
1051 {
1052 FOR_EACH_FIB_NODE_BW_REASON(reason) {
1053 if ((1<<reason) & fib_walk_history[ii].fwh_reason[jj]) {
1054 s = format (s, "%s,", fib_node_bw_reason_names[reason]);
1055 }
Neale Rannsad95b5d2016-11-10 20:35:14 +00001056 }
Neale Ranns19c68d22016-12-07 15:38:14 +00001057 jj++;
Neale Rannsad95b5d2016-11-10 20:35:14 +00001058 }
1059 vlib_cli_output(vm, "%v", s);
Neale Ranns33a7dd52016-10-07 15:14:33 +01001060 }
1061
Neale Rannsad95b5d2016-11-10 20:35:14 +00001062 ii--;
1063 if (ii < 0)
1064 ii = HISTORY_N_WALKS - 1;
1065 }
Neale Ranns33a7dd52016-10-07 15:14:33 +01001066
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001067 return (NULL);
1068}
1069
1070VLIB_CLI_COMMAND (fib_walk_show_command, static) = {
1071 .path = "show fib walk",
1072 .short_help = "show fib walk",
1073 .function = fib_walk_show,
1074};
Neale Ranns33a7dd52016-10-07 15:14:33 +01001075
1076static clib_error_t *
1077fib_walk_set_quota (vlib_main_t * vm,
1078 unformat_input_t * input,
1079 vlib_cli_command_t * cmd)
1080{
1081 clib_error_t * error = NULL;
1082 f64 new_quota;
1083
1084 if (unformat (input, "%f", &new_quota))
1085 {
1086 quota = new_quota;
1087 }
1088 else
1089 {
1090 error = clib_error_return(0 , "Pass a float value");
1091 }
1092
1093 return (error);
1094}
1095
1096VLIB_CLI_COMMAND (fib_walk_set_quota_command, static) = {
1097 .path = "set fib walk quota",
1098 .short_help = "set fib walk quota",
1099 .function = fib_walk_set_quota,
1100};
1101
1102static clib_error_t *
1103fib_walk_set_histogram_elements_size (vlib_main_t * vm,
1104 unformat_input_t * input,
1105 vlib_cli_command_t * cmd)
1106{
1107 clib_error_t * error = NULL;
1108 u32 new;
1109
1110 if (unformat (input, "%d", &new))
1111 {
1112 fib_walk_work_nodes_visisted_incr = new;
1113 }
1114 else
1115 {
1116 error = clib_error_return(0 , "Pass an int value");
1117 }
1118
1119 return (error);
1120}
1121
1122VLIB_CLI_COMMAND (fib_walk_set_histogram_elements_size_command, static) = {
1123 .path = "set fib walk histogram elements size",
1124 .short_help = "set fib walk histogram elements size",
1125 .function = fib_walk_set_histogram_elements_size,
1126};
1127
1128static clib_error_t *
1129fib_walk_clear (vlib_main_t * vm,
1130 unformat_input_t * input,
1131 vlib_cli_command_t * cmd)
1132{
1133 memset(fib_walk_hist_vists_per_walk, 0, sizeof(fib_walk_hist_vists_per_walk));
1134 memset(fib_walk_history, 0, sizeof(fib_walk_history));
1135 memset(fib_walk_work_time_taken, 0, sizeof(fib_walk_work_time_taken));
1136 memset(fib_walk_work_nodes_visited, 0, sizeof(fib_walk_work_nodes_visited));
1137 memset(fib_walk_sleep_lengths, 0, sizeof(fib_walk_sleep_lengths));
1138
1139 return (NULL);
1140}
1141
1142VLIB_CLI_COMMAND (fib_walk_clear_command, static) = {
1143 .path = "clear fib walk",
1144 .short_help = "clear fib walk",
1145 .function = fib_walk_clear,
1146};
Neale Rannsf12a83f2017-04-18 09:09:40 -07001147
1148void
1149fib_walk_process_enable (void)
1150{
1151 vlib_process_signal_event(vlib_get_main(),
1152 fib_walk_process_node.index,
1153 FIB_WALK_PROCESS_EVENT_ENABLE,
1154 0);
1155}
1156
1157void
1158fib_walk_process_disable (void)
1159{
1160 vlib_process_signal_event(vlib_get_main(),
1161 fib_walk_process_node.index,
1162 FIB_WALK_PROCESS_EVENT_DISABLE,
1163 0);
1164}
1165
1166static clib_error_t *
1167fib_walk_process_enable_disable (vlib_main_t * vm,
1168 unformat_input_t * input,
1169 vlib_cli_command_t * cmd)
1170{
1171 if (unformat (input, "enable"))
1172 {
1173 fib_walk_process_enable();
1174 }
1175 else if (unformat (input, "disable"))
1176 {
1177 fib_walk_process_disable();
1178 }
1179 else
1180 {
1181 return clib_error_return(0, "choose enable or disable");
1182 }
1183 return (NULL);
1184}
1185
1186VLIB_CLI_COMMAND (fib_walk_process_command, static) = {
1187 .path = "test fib-walk-process",
1188 .short_help = "test fib-walk-process [enable|disable]",
1189 .function = fib_walk_process_enable_disable,
1190};