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