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