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