]>
git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_damp.c
2 * Copyright (C) 2001 IP Infusion Inc.
4 * This file is part of GNU Zebra.
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
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.
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
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"
40 /* Global variable to access damping configuration */
41 static struct bgp_damp_config damp
[AFI_MAX
][SAFI_MAX
];
43 /* Utility macro to add and delete BGP dampening information to no
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)
48 /* Calculate reuse list index by penalty value. */
49 static int bgp_reuse_index(int penalty
, struct bgp_damp_config
*bdc
)
55 * reuse_limit can't be zero, this is for Coverity
56 * to bypass division by zero test.
58 assert(bdc
->reuse_limit
);
60 i
= (int)(((double)penalty
/ bdc
->reuse_limit
- 1.0)
63 if (i
>= bdc
->reuse_index_size
)
64 i
= bdc
->reuse_index_size
- 1;
66 index
= bdc
->reuse_index
[i
] - bdc
->reuse_index
[0];
68 return (bdc
->reuse_offset
+ index
) % bdc
->reuse_list_size
;
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
)
77 index
= bdi
->index
= bgp_reuse_index(bdi
->penalty
, bdc
);
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
;
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
)
91 bdi
->next
->prev
= bdi
->prev
;
93 bdi
->prev
->next
= bdi
->next
;
95 bdc
->reuse_list
[bdi
->index
] = bdi
->next
;
98 /* Return decayed penalty value. */
99 int bgp_damp_decay(time_t tdiff
, int penalty
, struct bgp_damp_config
*bdc
)
103 i
= (int)((double)tdiff
/ DELTA_T
);
108 if (i
>= bdc
->decay_array_size
)
111 return (int)(penalty
* bdc
->decay_array
[i
]);
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
)
118 struct bgp_damp_info
*bdi
;
119 struct bgp_damp_info
*next
;
120 time_t t_now
, t_diff
;
122 struct bgp_damp_config
*bdc
= THREAD_ARG(t
);
125 thread_add_timer(bm
->master
, bgp_reuse_timer
, bdc
, DELTA_REUSE
,
130 /* 1. save a pointer to the current zeroth queue head and zero the
132 bdi
= bdc
->reuse_list
[bdc
->reuse_offset
];
133 bdc
->reuse_list
[bdc
->reuse_offset
] = NULL
;
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
;
139 /* 3. if ( the saved list head pointer is non-empty ) */
140 for (; bdi
; bdi
= next
) {
141 struct bgp
*bgp
= bdi
->path
->peer
->bgp
;
145 /* Set t-diff = t-now - t-updated. */
146 t_diff
= t_now
- bdi
->t_updated
;
148 /* Set figure-of-merit = figure-of-merit * decay-array-ok
150 bdi
->penalty
= bgp_damp_decay(t_diff
, bdi
->penalty
, bdc
);
152 /* Set t-updated = t-now. */
153 bdi
->t_updated
= t_now
;
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
,
160 bdi
->suppress_time
= 0;
162 if (bdi
->lastrecord
== BGP_RECORD_UPDATE
) {
163 bgp_path_info_unset_flag(bdi
->dest
, bdi
->path
,
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
,
172 if (bdi
->penalty
<= bdc
->reuse_limit
/ 2.0)
173 bgp_damp_info_free(bdi
, 1, bdc
->afi
, bdc
->safi
);
175 BGP_DAMP_LIST_ADD(bdc
, bdi
);
177 /* Re-insert into another list (See RFC2439 Section
179 bgp_reuse_list_add(bdi
, bdc
);
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
)
190 struct bgp_damp_info
*bdi
= NULL
;
191 unsigned int last_penalty
= 0;
192 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
196 /* Processing Unreachable Messages. */
198 bdi
= path
->extra
->damp_info
;
201 /* If there is no previous stability history. */
204 1. allocate a damping structure.
205 2. set figure-of-merit = 1.
206 3. withdraw the route. */
208 bdi
= XCALLOC(MTYPE_BGP_DAMP_INFO
,
209 sizeof(struct bgp_damp_info
));
213 (attr_change
? DEFAULT_PENALTY
/ 2 : DEFAULT_PENALTY
);
215 bdi
->start_time
= t_now
;
216 bdi
->suppress_time
= 0;
220 (bgp_path_info_extra_get(path
))->damp_info
= bdi
;
221 BGP_DAMP_LIST_ADD(bdc
, bdi
);
223 last_penalty
= bdi
->penalty
;
225 /* 1. Set t-diff = t-now - t-updated. */
226 bdi
->penalty
= (bgp_damp_decay(t_now
- bdi
->t_updated
,
228 + (attr_change
? DEFAULT_PENALTY
/ 2
231 if (bdi
->penalty
> bdc
->ceiling
)
232 bdi
->penalty
= bdc
->ceiling
;
237 assert((dest
== bdi
->dest
) && (path
== bdi
->path
));
239 bdi
->lastrecord
= BGP_RECORD_WITHDRAW
;
240 bdi
->t_updated
= t_now
;
242 /* Make this route as historical status. */
243 bgp_path_info_set_flag(dest
, path
, BGP_PATH_HISTORY
);
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
);
252 return BGP_DAMP_SUPPRESSED
;
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
);
264 return BGP_DAMP_USED
;
267 int bgp_damp_update(struct bgp_path_info
*path
, struct bgp_dest
*dest
,
268 afi_t afi
, safi_t safi
)
271 struct bgp_damp_info
*bdi
;
273 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
275 if (!path
->extra
|| !((bdi
= path
->extra
->damp_info
)))
276 return BGP_DAMP_USED
;
279 bgp_path_info_unset_flag(dest
, path
, BGP_PATH_HISTORY
);
281 bdi
->lastrecord
= BGP_RECORD_UPDATE
;
283 bgp_damp_decay(t_now
- bdi
->t_updated
, bdi
->penalty
, bdc
);
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
;
296 status
= BGP_DAMP_SUPPRESSED
;
298 if (bdi
->penalty
> bdc
->reuse_limit
/ 2.0)
299 bdi
->t_updated
= t_now
;
301 bgp_damp_info_free(bdi
, 0, afi
, safi
);
306 void bgp_damp_info_free(struct bgp_damp_info
*bdi
, int withdraw
, afi_t afi
,
309 struct bgp_path_info
*path
;
310 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
316 path
->extra
->damp_info
= NULL
;
318 if (CHECK_FLAG(path
->flags
, BGP_PATH_DAMPED
))
319 bgp_reuse_list_delete(bdi
, bdc
);
321 BGP_DAMP_LIST_DEL(bdc
, bdi
);
323 bgp_path_info_unset_flag(bdi
->dest
, path
,
324 BGP_PATH_HISTORY
| BGP_PATH_DAMPED
);
326 if (bdi
->lastrecord
== BGP_RECORD_WITHDRAW
&& withdraw
)
327 bgp_path_info_delete(bdi
->dest
, path
);
329 XFREE(MTYPE_BGP_DAMP_INFO
, bdi
);
332 static void bgp_damp_parameter_set(int hlife
, int reuse
, int sup
, int maxsup
,
333 struct bgp_damp_config
*bdc
)
335 double reuse_max_ratio
;
339 bdc
->suppress_value
= sup
;
340 bdc
->half_life
= hlife
;
341 bdc
->reuse_limit
= reuse
;
342 bdc
->max_suppress_time
= maxsup
;
344 /* Initialize params per bgp_damp_config. */
345 bdc
->reuse_index_size
= REUSE_ARRAY_SIZE
;
347 bdc
->ceiling
= (int)(bdc
->reuse_limit
348 * (pow(2, (double)bdc
->max_suppress_time
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));
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];
364 /* Reuse-list computations */
365 i
= ceil((double)bdc
->max_suppress_time
/ DELTA_REUSE
) + 1;
366 if (i
> REUSE_LIST_SIZE
|| i
== 0)
368 bdc
->reuse_list_size
= i
;
371 XCALLOC(MTYPE_BGP_DAMP_ARRAY
,
372 bdc
->reuse_list_size
* sizeof(struct bgp_reuse_node
*));
374 /* Reuse-array computations */
375 bdc
->reuse_index
= XCALLOC(MTYPE_BGP_DAMP_ARRAY
,
376 sizeof(int) * bdc
->reuse_index_size
);
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)
384 (double)bdc
->reuse_index_size
/ (reuse_max_ratio
- 1);
386 for (i
= 0; i
< bdc
->reuse_index_size
; i
++) {
387 bdc
->reuse_index
[i
] =
388 (int)(((double)bdc
->half_life
/ DELTA_REUSE
)
392 + ((double)i
/ bdc
->scale_factor
))))
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
)
400 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
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
)
407 bgp_damp_disable(bgp
, afi
, safi
);
410 SET_FLAG(bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
);
411 bgp_damp_parameter_set(half
, reuse
, suppress
, max
, bdc
);
413 /* Register reuse timer. */
414 thread_add_timer(bm
->master
, bgp_reuse_timer
, bdc
, DELTA_REUSE
,
420 static void bgp_damp_config_clean(struct bgp_damp_config
*bdc
)
422 /* Free decay array */
423 XFREE(MTYPE_BGP_DAMP_ARRAY
, bdc
->decay_array
);
424 bdc
->decay_array_size
= 0;
426 /* Free reuse index array */
427 XFREE(MTYPE_BGP_DAMP_ARRAY
, bdc
->reuse_index
);
428 bdc
->reuse_index_size
= 0;
430 /* Free reuse list array. */
431 XFREE(MTYPE_BGP_DAMP_ARRAY
, bdc
->reuse_list
);
432 bdc
->reuse_list_size
= 0;
435 /* Clean all the bgp_damp_info stored in reuse_list. */
436 void bgp_damp_info_clean(afi_t afi
, safi_t safi
)
439 struct bgp_damp_info
*bdi
, *next
;
440 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
442 bdc
->reuse_offset
= 0;
444 for (i
= 0; i
< bdc
->reuse_list_size
; i
++) {
445 if (!bdc
->reuse_list
[i
])
448 for (bdi
= bdc
->reuse_list
[i
]; bdi
; bdi
= next
) {
450 bgp_damp_info_free(bdi
, 1, afi
, safi
);
452 bdc
->reuse_list
[i
] = NULL
;
455 for (bdi
= bdc
->no_reuse_list
; bdi
; bdi
= next
) {
457 bgp_damp_info_free(bdi
, 1, afi
, safi
);
459 bdc
->no_reuse_list
= NULL
;
462 int bgp_damp_disable(struct bgp
*bgp
, afi_t afi
, safi_t safi
)
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
))
469 /* Cancel reuse event. */
470 thread_cancel(&(bdc
->t_reuse
));
472 /* Clean BGP dampening information. */
473 bgp_damp_info_clean(afi
, safi
);
475 /* Clear configuration */
476 bgp_damp_config_clean(bdc
);
478 UNSET_FLAG(bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
);
482 void bgp_config_write_damp(struct vty
*vty
, afi_t afi
, safi_t safi
)
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);
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);
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
)
509 time_t reuse_time
= 0;
513 if (penalty
> damp
[afi
][safi
].reuse_limit
) {
514 reuse_time
= (int)(DELTA_T
515 * ((log((double)damp
[afi
][safi
].reuse_limit
517 / (log(damp
[afi
][safi
].decay_array
[1]))));
519 if (reuse_time
> damp
[afi
][safi
].max_suppress_time
)
520 reuse_time
= damp
[afi
][safi
].max_suppress_time
;
522 gmtime_r(&reuse_time
, &tm
);
526 /* Making formatted timer strings. */
527 if (reuse_time
== 0) {
529 json_object_int_add(json
, "reuseTimerMsecs", 0);
531 snprintf(buf
, len
, "00:00:00");
532 } else if (reuse_time
< ONE_DAY_SECOND
) {
534 time_store
= (3600000 * tm
.tm_hour
)
535 + (60000 * tm
.tm_min
)
536 + (1000 * tm
.tm_sec
);
537 json_object_int_add(json
, "reuseTimerMsecs",
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
) {
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",
551 snprintf(buf
, len
, "%dd%02dh%02dm", tm
.tm_yday
,
552 tm
.tm_hour
, tm
.tm_min
);
556 (604800000 * tm
.tm_yday
/ 7)
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",
564 snprintf(buf
, len
, "%02dw%dd%02dh", tm
.tm_yday
/ 7,
565 tm
.tm_yday
- ((tm
.tm_yday
/ 7) * 7),
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
)
575 struct bgp_damp_info
*bdi
;
576 time_t t_now
, t_diff
;
577 char timebuf
[BGP_UPTIME_LEN
];
579 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
584 /* BGP dampening information. */
585 bdi
= path
->extra
->damp_info
;
587 /* If dampening is not enabled or there is no dampening information,
588 return immediately. */
592 /* Calculate new penalty. */
594 t_diff
= t_now
- bdi
->t_updated
;
595 penalty
= bgp_damp_decay(t_diff
, bdi
->penalty
, bdc
);
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,
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
);
609 " Dampinfo: penalty %d, flapped %d times in %s",
611 peer_uptime(bdi
->start_time
, timebuf
, BGP_UPTIME_LEN
, 0,
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,
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
,
630 struct bgp_damp_info
*bdi
;
631 time_t t_now
, t_diff
;
633 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
638 /* BGP dampening information. */
639 bdi
= path
->extra
->damp_info
;
641 /* If dampening is not enabled or there is no dampening information,
642 return immediately. */
646 /* Calculate new penalty. */
648 t_diff
= t_now
- bdi
->t_updated
;
649 penalty
= bgp_damp_decay(t_diff
, bdi
->penalty
, bdc
);
651 return bgp_get_reuse_time(penalty
, timebuf
, len
, afi
, safi
, use_json
,
655 static int bgp_print_dampening_parameters(struct bgp
*bgp
, struct vty
*vty
,
656 afi_t afi
, safi_t safi
, bool use_json
)
658 if (CHECK_FLAG(bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
)) {
659 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
662 json_object
*json
= json_object_new_object();
664 json_object_int_add(json
, "halfLifeSecs",
666 json_object_int_add(json
, "reusePenalty",
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",
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",
688 } else if (!use_json
)
689 vty_out(vty
, "dampening not enabled for %s\n",
690 get_afi_safi_str(afi
, safi
, false));
695 int bgp_show_dampening_parameters(struct vty
*vty
, afi_t afi
, safi_t safi
,
699 bool use_json
= CHECK_FLAG(show_flags
, BGP_SHOW_OPT_JSON
);
701 bgp
= bgp_get_default();
704 vty_out(vty
, "No BGP process is configured\n");
708 if (!CHECK_FLAG(show_flags
, BGP_SHOW_OPT_AFI_ALL
))
709 return bgp_print_dampening_parameters(bgp
, vty
, afi
, safi
,
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
716 FOREACH_SAFI (safi
) {
717 if (strmatch(get_afi_safi_str(afi
, safi
, true),
722 vty_out(vty
, "\nFor address family: %s\n\n",
723 get_afi_safi_str(afi
, safi
, false));
725 bgp_print_dampening_parameters(bgp
, vty
, afi
, safi
,
729 FOREACH_AFI_SAFI (afi
, safi
) {
730 if (strmatch(get_afi_safi_str(afi
, safi
, true),
735 vty_out(vty
, "\nFor address family: %s\n",
736 get_afi_safi_str(afi
, safi
, false));
738 bgp_print_dampening_parameters(bgp
, vty
, afi
, safi
,