]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_damp.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgp_damp.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* BGP flap dampening
3 * Copyright (C) 2001 IP Infusion Inc.
4 */
5
6 #include <zebra.h>
7 #include <math.h>
8
9 #include "prefix.h"
10 #include "memory.h"
11 #include "command.h"
12 #include "log.h"
13 #include "thread.h"
14 #include "queue.h"
15 #include "filter.h"
16
17 #include "bgpd/bgpd.h"
18 #include "bgpd/bgp_damp.h"
19 #include "bgpd/bgp_table.h"
20 #include "bgpd/bgp_route.h"
21 #include "bgpd/bgp_attr.h"
22 #include "bgpd/bgp_advertise.h"
23 #include "bgpd/bgp_vty.h"
24
25 /* Global variable to access damping configuration */
26 static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
27
28 /* Utility macro to add and delete BGP dampening information to no
29 used list. */
30 #define BGP_DAMP_LIST_ADD(N, A) BGP_PATH_INFO_ADD(N, A, no_reuse_list)
31 #define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list)
32
33 /* Calculate reuse list index by penalty value. */
34 static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
35 {
36 unsigned int i;
37 int index;
38
39 /*
40 * reuse_limit can't be zero, this is for Coverity
41 * to bypass division by zero test.
42 */
43 assert(bdc->reuse_limit);
44
45 i = (int)(((double)penalty / bdc->reuse_limit - 1.0)
46 * bdc->scale_factor);
47
48 if (i >= bdc->reuse_index_size)
49 i = bdc->reuse_index_size - 1;
50
51 index = bdc->reuse_index[i] - bdc->reuse_index[0];
52
53 return (bdc->reuse_offset + index) % bdc->reuse_list_size;
54 }
55
56 /* Add BGP dampening information to reuse list. */
57 static void bgp_reuse_list_add(struct bgp_damp_info *bdi,
58 struct bgp_damp_config *bdc)
59 {
60 int index;
61
62 index = bdi->index = bgp_reuse_index(bdi->penalty, bdc);
63
64 bdi->prev = NULL;
65 bdi->next = bdc->reuse_list[index];
66 if (bdc->reuse_list[index])
67 bdc->reuse_list[index]->prev = bdi;
68 bdc->reuse_list[index] = bdi;
69 }
70
71 /* Delete BGP dampening information from reuse list. */
72 static void bgp_reuse_list_delete(struct bgp_damp_info *bdi,
73 struct bgp_damp_config *bdc)
74 {
75 if (bdi->next)
76 bdi->next->prev = bdi->prev;
77 if (bdi->prev)
78 bdi->prev->next = bdi->next;
79 else
80 bdc->reuse_list[bdi->index] = bdi->next;
81 }
82
83 /* Return decayed penalty value. */
84 int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc)
85 {
86 unsigned int i;
87
88 i = (int)((double)tdiff / DELTA_T);
89
90 if (i == 0)
91 return penalty;
92
93 if (i >= bdc->decay_array_size)
94 return 0;
95
96 return (int)(penalty * bdc->decay_array[i]);
97 }
98
99 /* Handler of reuse timer event. Each route in the current reuse-list
100 is evaluated. RFC2439 Section 4.8.7. */
101 static void bgp_reuse_timer(struct thread *t)
102 {
103 struct bgp_damp_info *bdi;
104 struct bgp_damp_info *next;
105 time_t t_now, t_diff;
106
107 struct bgp_damp_config *bdc = THREAD_ARG(t);
108
109 bdc->t_reuse = NULL;
110 thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
111 &bdc->t_reuse);
112
113 t_now = monotime(NULL);
114
115 /* 1. save a pointer to the current zeroth queue head and zero the
116 list head entry. */
117 bdi = bdc->reuse_list[bdc->reuse_offset];
118 bdc->reuse_list[bdc->reuse_offset] = NULL;
119
120 /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
121 rotating the circular queue of list-heads. */
122 bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size;
123
124 /* 3. if ( the saved list head pointer is non-empty ) */
125 for (; bdi; bdi = next) {
126 struct bgp *bgp = bdi->path->peer->bgp;
127
128 next = bdi->next;
129
130 /* Set t-diff = t-now - t-updated. */
131 t_diff = t_now - bdi->t_updated;
132
133 /* Set figure-of-merit = figure-of-merit * decay-array-ok
134 * [t-diff] */
135 bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
136
137 /* Set t-updated = t-now. */
138 bdi->t_updated = t_now;
139
140 /* if (figure-of-merit < reuse). */
141 if (bdi->penalty < bdc->reuse_limit) {
142 /* Reuse the route. */
143 bgp_path_info_unset_flag(bdi->dest, bdi->path,
144 BGP_PATH_DAMPED);
145 bdi->suppress_time = 0;
146
147 if (bdi->lastrecord == BGP_RECORD_UPDATE) {
148 bgp_path_info_unset_flag(bdi->dest, bdi->path,
149 BGP_PATH_HISTORY);
150 bgp_aggregate_increment(
151 bgp, bgp_dest_get_prefix(bdi->dest),
152 bdi->path, bdi->afi, bdi->safi);
153 bgp_process(bgp, bdi->dest, bdi->afi,
154 bdi->safi);
155 }
156
157 if (bdi->penalty <= bdc->reuse_limit / 2.0)
158 bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi);
159 else
160 BGP_DAMP_LIST_ADD(bdc, bdi);
161 } else
162 /* Re-insert into another list (See RFC2439 Section
163 * 4.8.6). */
164 bgp_reuse_list_add(bdi, bdc);
165 }
166 }
167
168 /* A route becomes unreachable (RFC2439 Section 4.8.2). */
169 int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
170 afi_t afi, safi_t safi, int attr_change)
171 {
172 time_t t_now;
173 struct bgp_damp_info *bdi = NULL;
174 unsigned int last_penalty = 0;
175 struct bgp_damp_config *bdc = &damp[afi][safi];
176
177 t_now = monotime(NULL);
178
179 /* Processing Unreachable Messages. */
180 if (path->extra)
181 bdi = path->extra->damp_info;
182
183 if (bdi == NULL) {
184 /* If there is no previous stability history. */
185
186 /* RFC2439 said:
187 1. allocate a damping structure.
188 2. set figure-of-merit = 1.
189 3. withdraw the route. */
190
191 bdi = XCALLOC(MTYPE_BGP_DAMP_INFO,
192 sizeof(struct bgp_damp_info));
193 bdi->path = path;
194 bdi->dest = dest;
195 bdi->penalty =
196 (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
197 bdi->flap = 1;
198 bdi->start_time = t_now;
199 bdi->suppress_time = 0;
200 bdi->index = -1;
201 bdi->afi = afi;
202 bdi->safi = safi;
203 (bgp_path_info_extra_get(path))->damp_info = bdi;
204 BGP_DAMP_LIST_ADD(bdc, bdi);
205 } else {
206 last_penalty = bdi->penalty;
207
208 /* 1. Set t-diff = t-now - t-updated. */
209 bdi->penalty = (bgp_damp_decay(t_now - bdi->t_updated,
210 bdi->penalty, bdc)
211 + (attr_change ? DEFAULT_PENALTY / 2
212 : DEFAULT_PENALTY));
213
214 if (bdi->penalty > bdc->ceiling)
215 bdi->penalty = bdc->ceiling;
216
217 bdi->flap++;
218 }
219
220 assert((dest == bdi->dest) && (path == bdi->path));
221
222 bdi->lastrecord = BGP_RECORD_WITHDRAW;
223 bdi->t_updated = t_now;
224
225 /* Make this route as historical status. */
226 bgp_path_info_set_flag(dest, path, BGP_PATH_HISTORY);
227
228 /* Remove the route from a reuse list if it is on one. */
229 if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) {
230 /* If decay rate isn't equal to 0, reinsert brn. */
231 if (bdi->penalty != last_penalty && bdi->index >= 0) {
232 bgp_reuse_list_delete(bdi, bdc);
233 bgp_reuse_list_add(bdi, bdc);
234 }
235 return BGP_DAMP_SUPPRESSED;
236 }
237
238 /* If not suppressed before, do annonunce this withdraw and
239 insert into reuse_list. */
240 if (bdi->penalty >= bdc->suppress_value) {
241 bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED);
242 bdi->suppress_time = t_now;
243 BGP_DAMP_LIST_DEL(bdc, bdi);
244 bgp_reuse_list_add(bdi, bdc);
245 }
246
247 return BGP_DAMP_USED;
248 }
249
250 int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
251 afi_t afi, safi_t safi)
252 {
253 time_t t_now;
254 struct bgp_damp_info *bdi;
255 int status;
256 struct bgp_damp_config *bdc = &damp[afi][safi];
257
258 if (!path->extra || !((bdi = path->extra->damp_info)))
259 return BGP_DAMP_USED;
260
261 t_now = monotime(NULL);
262 bgp_path_info_unset_flag(dest, path, BGP_PATH_HISTORY);
263
264 bdi->lastrecord = BGP_RECORD_UPDATE;
265 bdi->penalty =
266 bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty, bdc);
267
268 if (!CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
269 && (bdi->penalty < bdc->suppress_value))
270 status = BGP_DAMP_USED;
271 else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
272 && (bdi->penalty < bdc->reuse_limit)) {
273 bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED);
274 bgp_reuse_list_delete(bdi, bdc);
275 BGP_DAMP_LIST_ADD(bdc, bdi);
276 bdi->suppress_time = 0;
277 status = BGP_DAMP_USED;
278 } else
279 status = BGP_DAMP_SUPPRESSED;
280
281 if (bdi->penalty > bdc->reuse_limit / 2.0)
282 bdi->t_updated = t_now;
283 else
284 bgp_damp_info_free(bdi, 0, afi, safi);
285
286 return status;
287 }
288
289 void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi,
290 safi_t safi)
291 {
292 struct bgp_path_info *path;
293 struct bgp_damp_config *bdc = &damp[afi][safi];
294
295 if (!bdi)
296 return;
297
298 path = bdi->path;
299 path->extra->damp_info = NULL;
300
301 if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED))
302 bgp_reuse_list_delete(bdi, bdc);
303 else
304 BGP_DAMP_LIST_DEL(bdc, bdi);
305
306 bgp_path_info_unset_flag(bdi->dest, path,
307 BGP_PATH_HISTORY | BGP_PATH_DAMPED);
308
309 if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
310 bgp_path_info_delete(bdi->dest, path);
311
312 XFREE(MTYPE_BGP_DAMP_INFO, bdi);
313 }
314
315 static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse,
316 unsigned int sup, time_t maxsup,
317 struct bgp_damp_config *bdc)
318 {
319 double reuse_max_ratio;
320 unsigned int i;
321 double j;
322
323 bdc->suppress_value = sup;
324 bdc->half_life = hlife;
325 bdc->reuse_limit = reuse;
326 bdc->max_suppress_time = maxsup;
327
328 /* Initialize params per bgp_damp_config. */
329 bdc->reuse_index_size = REUSE_ARRAY_SIZE;
330
331 bdc->ceiling = (int)(bdc->reuse_limit
332 * (pow(2, (double)bdc->max_suppress_time
333 / bdc->half_life)));
334
335 /* Decay-array computations */
336 bdc->decay_array_size = ceil((double)bdc->max_suppress_time / DELTA_T);
337 bdc->decay_array = XMALLOC(MTYPE_BGP_DAMP_ARRAY,
338 sizeof(double) * (bdc->decay_array_size));
339 bdc->decay_array[0] = 1.0;
340 bdc->decay_array[1] =
341 exp((1.0 / ((double)bdc->half_life / DELTA_T)) * log(0.5));
342
343 /* Calculate decay values for all possible times */
344 for (i = 2; i < bdc->decay_array_size; i++)
345 bdc->decay_array[i] =
346 bdc->decay_array[i - 1] * bdc->decay_array[1];
347
348 /* Reuse-list computations */
349 i = ceil((double)bdc->max_suppress_time / DELTA_REUSE) + 1;
350 if (i > REUSE_LIST_SIZE || i == 0)
351 i = REUSE_LIST_SIZE;
352 bdc->reuse_list_size = i;
353
354 bdc->reuse_list =
355 XCALLOC(MTYPE_BGP_DAMP_ARRAY,
356 bdc->reuse_list_size * sizeof(struct bgp_reuse_node *));
357
358 /* Reuse-array computations */
359 bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
360 sizeof(int) * bdc->reuse_index_size);
361
362 reuse_max_ratio = (double)bdc->ceiling / bdc->reuse_limit;
363 j = (exp((double)bdc->max_suppress_time / bdc->half_life) * log10(2.0));
364 if (reuse_max_ratio > j && j != 0)
365 reuse_max_ratio = j;
366
367 bdc->scale_factor =
368 (double)bdc->reuse_index_size / (reuse_max_ratio - 1);
369
370 for (i = 0; i < bdc->reuse_index_size; i++) {
371 bdc->reuse_index[i] =
372 (int)(((double)bdc->half_life / DELTA_REUSE)
373 * log10(1.0
374 / (bdc->reuse_limit
375 * (1.0
376 + ((double)i / bdc->scale_factor))))
377 / log10(0.5));
378 }
379 }
380
381 int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
382 unsigned int reuse, unsigned int suppress, time_t max)
383 {
384 struct bgp_damp_config *bdc = &damp[afi][safi];
385
386 if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
387 if (bdc->half_life == half && bdc->reuse_limit == reuse
388 && bdc->suppress_value == suppress
389 && bdc->max_suppress_time == max)
390 return 0;
391 bgp_damp_disable(bgp, afi, safi);
392 }
393
394 SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
395 bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
396
397 /* Register reuse timer. */
398 thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
399 &bdc->t_reuse);
400
401 return 0;
402 }
403
404 static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
405 {
406 /* Free decay array */
407 XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
408 bdc->decay_array_size = 0;
409
410 /* Free reuse index array */
411 XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index);
412 bdc->reuse_index_size = 0;
413
414 /* Free reuse list array. */
415 XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
416 bdc->reuse_list_size = 0;
417 }
418
419 /* Clean all the bgp_damp_info stored in reuse_list. */
420 void bgp_damp_info_clean(afi_t afi, safi_t safi)
421 {
422 unsigned int i;
423 struct bgp_damp_info *bdi, *next;
424 struct bgp_damp_config *bdc = &damp[afi][safi];
425
426 bdc->reuse_offset = 0;
427
428 for (i = 0; i < bdc->reuse_list_size; i++) {
429 if (!bdc->reuse_list[i])
430 continue;
431
432 for (bdi = bdc->reuse_list[i]; bdi; bdi = next) {
433 next = bdi->next;
434 bgp_damp_info_free(bdi, 1, afi, safi);
435 }
436 bdc->reuse_list[i] = NULL;
437 }
438
439 for (bdi = bdc->no_reuse_list; bdi; bdi = next) {
440 next = bdi->next;
441 bgp_damp_info_free(bdi, 1, afi, safi);
442 }
443 bdc->no_reuse_list = NULL;
444 }
445
446 int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
447 {
448 struct bgp_damp_config *bdc = &damp[afi][safi];
449 /* If it wasn't enabled, there's nothing to do. */
450 if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
451 return 0;
452
453 /* Cancel reuse event. */
454 THREAD_OFF(bdc->t_reuse);
455
456 /* Clean BGP dampening information. */
457 bgp_damp_info_clean(afi, safi);
458
459 /* Clear configuration */
460 bgp_damp_config_clean(bdc);
461
462 UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
463 return 0;
464 }
465
466 void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi)
467 {
468 if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60
469 && damp[afi][safi].reuse_limit == DEFAULT_REUSE
470 && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
471 && damp[afi][safi].max_suppress_time
472 == damp[afi][safi].half_life * 4)
473 vty_out(vty, " bgp dampening\n");
474 else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60
475 && damp[afi][safi].reuse_limit == DEFAULT_REUSE
476 && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
477 && damp[afi][safi].max_suppress_time
478 == damp[afi][safi].half_life * 4)
479 vty_out(vty, " bgp dampening %lld\n",
480 damp[afi][safi].half_life / 60LL);
481 else
482 vty_out(vty, " bgp dampening %lld %d %d %lld\n",
483 damp[afi][safi].half_life / 60LL,
484 damp[afi][safi].reuse_limit,
485 damp[afi][safi].suppress_value,
486 damp[afi][safi].max_suppress_time / 60LL);
487 }
488
489 static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
490 size_t len, afi_t afi, safi_t safi,
491 bool use_json, json_object *json)
492 {
493 time_t reuse_time = 0;
494 struct tm tm;
495 int time_store = 0;
496
497 if (penalty > damp[afi][safi].reuse_limit) {
498 reuse_time = (int)(DELTA_T
499 * ((log((double)damp[afi][safi].reuse_limit
500 / penalty))
501 / (log(damp[afi][safi].decay_array[1]))));
502
503 if (reuse_time > damp[afi][safi].max_suppress_time)
504 reuse_time = damp[afi][safi].max_suppress_time;
505
506 gmtime_r(&reuse_time, &tm);
507 } else
508 reuse_time = 0;
509
510 /* Making formatted timer strings. */
511 if (reuse_time == 0) {
512 if (use_json)
513 json_object_int_add(json, "reuseTimerMsecs", 0);
514 else
515 snprintf(buf, len, "00:00:00");
516 } else if (reuse_time < ONE_DAY_SECOND) {
517 if (use_json) {
518 time_store = (3600000 * tm.tm_hour)
519 + (60000 * tm.tm_min)
520 + (1000 * tm.tm_sec);
521 json_object_int_add(json, "reuseTimerMsecs",
522 time_store);
523 } else
524 snprintf(buf, len, "%02d:%02d:%02d", tm.tm_hour,
525 tm.tm_min, tm.tm_sec);
526 } else if (reuse_time < ONE_WEEK_SECOND) {
527 if (use_json) {
528 time_store = (86400000 * tm.tm_yday)
529 + (3600000 * tm.tm_hour)
530 + (60000 * tm.tm_min)
531 + (1000 * tm.tm_sec);
532 json_object_int_add(json, "reuseTimerMsecs",
533 time_store);
534 } else
535 snprintf(buf, len, "%dd%02dh%02dm", tm.tm_yday,
536 tm.tm_hour, tm.tm_min);
537 } else {
538 if (use_json) {
539 time_store =
540 (604800000 * tm.tm_yday / 7)
541 + (86400000
542 * (tm.tm_yday - ((tm.tm_yday / 7) * 7)))
543 + (3600000 * tm.tm_hour) + (60000 * tm.tm_min)
544 + (1000 * tm.tm_sec);
545 json_object_int_add(json, "reuseTimerMsecs",
546 time_store);
547 } else
548 snprintf(buf, len, "%02dw%dd%02dh", tm.tm_yday / 7,
549 tm.tm_yday - ((tm.tm_yday / 7) * 7),
550 tm.tm_hour);
551 }
552
553 return buf;
554 }
555
556 void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
557 safi_t safi, json_object *json_path)
558 {
559 struct bgp_damp_info *bdi;
560 time_t t_now, t_diff;
561 char timebuf[BGP_UPTIME_LEN];
562 int penalty;
563 struct bgp_damp_config *bdc = &damp[afi][safi];
564
565 if (!path->extra)
566 return;
567
568 /* BGP dampening information. */
569 bdi = path->extra->damp_info;
570
571 /* If dampening is not enabled or there is no dampening information,
572 return immediately. */
573 if (!bdc || !bdi)
574 return;
575
576 /* Calculate new penalty. */
577 t_now = monotime(NULL);
578 t_diff = t_now - bdi->t_updated;
579 penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
580
581 if (json_path) {
582 json_object_int_add(json_path, "dampeningPenalty", penalty);
583 json_object_int_add(json_path, "dampeningFlapCount", bdi->flap);
584 peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 1,
585 json_path);
586
587 if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
588 && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
589 bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN,
590 afi, safi, 1, json_path);
591 } else {
592 vty_out(vty,
593 " Dampinfo: penalty %d, flapped %d times in %s",
594 penalty, bdi->flap,
595 peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 0,
596 json_path));
597
598 if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
599 && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
600 vty_out(vty, ", reuse in %s",
601 bgp_get_reuse_time(penalty, timebuf,
602 BGP_UPTIME_LEN, afi, safi, 0,
603 json_path));
604
605 vty_out(vty, "\n");
606 }
607 }
608
609 const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
610 char *timebuf, size_t len, afi_t afi,
611 safi_t safi, bool use_json,
612 json_object *json)
613 {
614 struct bgp_damp_info *bdi;
615 time_t t_now, t_diff;
616 int penalty;
617 struct bgp_damp_config *bdc = &damp[afi][safi];
618
619 if (!path->extra)
620 return NULL;
621
622 /* BGP dampening information. */
623 bdi = path->extra->damp_info;
624
625 /* If dampening is not enabled or there is no dampening information,
626 return immediately. */
627 if (!bdc || !bdi)
628 return NULL;
629
630 /* Calculate new penalty. */
631 t_now = monotime(NULL);
632 t_diff = t_now - bdi->t_updated;
633 penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
634
635 return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json,
636 json);
637 }
638
639 static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
640 afi_t afi, safi_t safi, bool use_json)
641 {
642 if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
643 struct bgp_damp_config *bdc = &damp[afi][safi];
644
645 if (use_json) {
646 json_object *json = json_object_new_object();
647
648 json_object_int_add(json, "halfLifeSecs",
649 bdc->half_life);
650 json_object_int_add(json, "reusePenalty",
651 bdc->reuse_limit);
652 json_object_int_add(json, "suppressPenalty",
653 bdc->suppress_value);
654 json_object_int_add(json, "maxSuppressTimeSecs",
655 bdc->max_suppress_time);
656 json_object_int_add(json, "maxSuppressPenalty",
657 bdc->ceiling);
658
659 vty_json(vty, json);
660 } else {
661 vty_out(vty, "Half-life time: %lld min\n",
662 (long long)bdc->half_life / 60);
663 vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit);
664 vty_out(vty, "Suppress penalty: %d\n",
665 bdc->suppress_value);
666 vty_out(vty, "Max suppress time: %lld min\n",
667 (long long)bdc->max_suppress_time / 60);
668 vty_out(vty, "Max suppress penalty: %u\n",
669 bdc->ceiling);
670 vty_out(vty, "\n");
671 }
672 } else if (!use_json)
673 vty_out(vty, "dampening not enabled for %s\n",
674 get_afi_safi_str(afi, safi, false));
675
676 return CMD_SUCCESS;
677 }
678
679 int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
680 uint16_t show_flags)
681 {
682 struct bgp *bgp;
683 bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
684
685 bgp = bgp_get_default();
686
687 if (bgp == NULL) {
688 vty_out(vty, "No BGP process is configured\n");
689 return CMD_WARNING;
690 }
691
692 if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL))
693 return bgp_print_dampening_parameters(bgp, vty, afi, safi,
694 use_json);
695
696 if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP)
697 || CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6)) {
698 afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) ? AFI_IP
699 : AFI_IP6;
700 FOREACH_SAFI (safi) {
701 if (strmatch(get_afi_safi_str(afi, safi, true),
702 "Unknown"))
703 continue;
704
705 if (!use_json)
706 vty_out(vty, "\nFor address family: %s\n\n",
707 get_afi_safi_str(afi, safi, false));
708
709 bgp_print_dampening_parameters(bgp, vty, afi, safi,
710 use_json);
711 }
712 } else {
713 FOREACH_AFI_SAFI (afi, safi) {
714 if (strmatch(get_afi_safi_str(afi, safi, true),
715 "Unknown"))
716 continue;
717
718 if (!use_json)
719 vty_out(vty, "\nFor address family: %s\n",
720 get_afi_safi_str(afi, safi, false));
721
722 bgp_print_dampening_parameters(bgp, vty, afi, safi,
723 use_json);
724 }
725 }
726 return CMD_SUCCESS;
727 }