]>
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 void 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
,
128 t_now
= monotime(NULL
);
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
);
183 /* A route becomes unreachable (RFC2439 Section 4.8.2). */
184 int bgp_damp_withdraw(struct bgp_path_info
*path
, struct bgp_dest
*dest
,
185 afi_t afi
, safi_t safi
, int attr_change
)
188 struct bgp_damp_info
*bdi
= NULL
;
189 unsigned int last_penalty
= 0;
190 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
192 t_now
= monotime(NULL
);
194 /* Processing Unreachable Messages. */
196 bdi
= path
->extra
->damp_info
;
199 /* If there is no previous stability history. */
202 1. allocate a damping structure.
203 2. set figure-of-merit = 1.
204 3. withdraw the route. */
206 bdi
= XCALLOC(MTYPE_BGP_DAMP_INFO
,
207 sizeof(struct bgp_damp_info
));
211 (attr_change
? DEFAULT_PENALTY
/ 2 : DEFAULT_PENALTY
);
213 bdi
->start_time
= t_now
;
214 bdi
->suppress_time
= 0;
218 (bgp_path_info_extra_get(path
))->damp_info
= bdi
;
219 BGP_DAMP_LIST_ADD(bdc
, bdi
);
221 last_penalty
= bdi
->penalty
;
223 /* 1. Set t-diff = t-now - t-updated. */
224 bdi
->penalty
= (bgp_damp_decay(t_now
- bdi
->t_updated
,
226 + (attr_change
? DEFAULT_PENALTY
/ 2
229 if (bdi
->penalty
> bdc
->ceiling
)
230 bdi
->penalty
= bdc
->ceiling
;
235 assert((dest
== bdi
->dest
) && (path
== bdi
->path
));
237 bdi
->lastrecord
= BGP_RECORD_WITHDRAW
;
238 bdi
->t_updated
= t_now
;
240 /* Make this route as historical status. */
241 bgp_path_info_set_flag(dest
, path
, BGP_PATH_HISTORY
);
243 /* Remove the route from a reuse list if it is on one. */
244 if (CHECK_FLAG(bdi
->path
->flags
, BGP_PATH_DAMPED
)) {
245 /* If decay rate isn't equal to 0, reinsert brn. */
246 if (bdi
->penalty
!= last_penalty
&& bdi
->index
>= 0) {
247 bgp_reuse_list_delete(bdi
, bdc
);
248 bgp_reuse_list_add(bdi
, bdc
);
250 return BGP_DAMP_SUPPRESSED
;
253 /* If not suppressed before, do annonunce this withdraw and
254 insert into reuse_list. */
255 if (bdi
->penalty
>= bdc
->suppress_value
) {
256 bgp_path_info_set_flag(dest
, path
, BGP_PATH_DAMPED
);
257 bdi
->suppress_time
= t_now
;
258 BGP_DAMP_LIST_DEL(bdc
, bdi
);
259 bgp_reuse_list_add(bdi
, bdc
);
262 return BGP_DAMP_USED
;
265 int bgp_damp_update(struct bgp_path_info
*path
, struct bgp_dest
*dest
,
266 afi_t afi
, safi_t safi
)
269 struct bgp_damp_info
*bdi
;
271 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
273 if (!path
->extra
|| !((bdi
= path
->extra
->damp_info
)))
274 return BGP_DAMP_USED
;
276 t_now
= monotime(NULL
);
277 bgp_path_info_unset_flag(dest
, path
, BGP_PATH_HISTORY
);
279 bdi
->lastrecord
= BGP_RECORD_UPDATE
;
281 bgp_damp_decay(t_now
- bdi
->t_updated
, bdi
->penalty
, bdc
);
283 if (!CHECK_FLAG(bdi
->path
->flags
, BGP_PATH_DAMPED
)
284 && (bdi
->penalty
< bdc
->suppress_value
))
285 status
= BGP_DAMP_USED
;
286 else if (CHECK_FLAG(bdi
->path
->flags
, BGP_PATH_DAMPED
)
287 && (bdi
->penalty
< bdc
->reuse_limit
)) {
288 bgp_path_info_unset_flag(dest
, path
, BGP_PATH_DAMPED
);
289 bgp_reuse_list_delete(bdi
, bdc
);
290 BGP_DAMP_LIST_ADD(bdc
, bdi
);
291 bdi
->suppress_time
= 0;
292 status
= BGP_DAMP_USED
;
294 status
= BGP_DAMP_SUPPRESSED
;
296 if (bdi
->penalty
> bdc
->reuse_limit
/ 2.0)
297 bdi
->t_updated
= t_now
;
299 bgp_damp_info_free(bdi
, 0, afi
, safi
);
304 void bgp_damp_info_free(struct bgp_damp_info
*bdi
, int withdraw
, afi_t afi
,
307 struct bgp_path_info
*path
;
308 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
314 path
->extra
->damp_info
= NULL
;
316 if (CHECK_FLAG(path
->flags
, BGP_PATH_DAMPED
))
317 bgp_reuse_list_delete(bdi
, bdc
);
319 BGP_DAMP_LIST_DEL(bdc
, bdi
);
321 bgp_path_info_unset_flag(bdi
->dest
, path
,
322 BGP_PATH_HISTORY
| BGP_PATH_DAMPED
);
324 if (bdi
->lastrecord
== BGP_RECORD_WITHDRAW
&& withdraw
)
325 bgp_path_info_delete(bdi
->dest
, path
);
327 XFREE(MTYPE_BGP_DAMP_INFO
, bdi
);
330 static void bgp_damp_parameter_set(int hlife
, int reuse
, int sup
, int maxsup
,
331 struct bgp_damp_config
*bdc
)
333 double reuse_max_ratio
;
337 bdc
->suppress_value
= sup
;
338 bdc
->half_life
= hlife
;
339 bdc
->reuse_limit
= reuse
;
340 bdc
->max_suppress_time
= maxsup
;
342 /* Initialize params per bgp_damp_config. */
343 bdc
->reuse_index_size
= REUSE_ARRAY_SIZE
;
345 bdc
->ceiling
= (int)(bdc
->reuse_limit
346 * (pow(2, (double)bdc
->max_suppress_time
349 /* Decay-array computations */
350 bdc
->decay_array_size
= ceil((double)bdc
->max_suppress_time
/ DELTA_T
);
351 bdc
->decay_array
= XMALLOC(MTYPE_BGP_DAMP_ARRAY
,
352 sizeof(double) * (bdc
->decay_array_size
));
353 bdc
->decay_array
[0] = 1.0;
354 bdc
->decay_array
[1] =
355 exp((1.0 / ((double)bdc
->half_life
/ DELTA_T
)) * log(0.5));
357 /* Calculate decay values for all possible times */
358 for (i
= 2; i
< bdc
->decay_array_size
; i
++)
359 bdc
->decay_array
[i
] =
360 bdc
->decay_array
[i
- 1] * bdc
->decay_array
[1];
362 /* Reuse-list computations */
363 i
= ceil((double)bdc
->max_suppress_time
/ DELTA_REUSE
) + 1;
364 if (i
> REUSE_LIST_SIZE
|| i
== 0)
366 bdc
->reuse_list_size
= i
;
369 XCALLOC(MTYPE_BGP_DAMP_ARRAY
,
370 bdc
->reuse_list_size
* sizeof(struct bgp_reuse_node
*));
372 /* Reuse-array computations */
373 bdc
->reuse_index
= XCALLOC(MTYPE_BGP_DAMP_ARRAY
,
374 sizeof(int) * bdc
->reuse_index_size
);
376 reuse_max_ratio
= (double)bdc
->ceiling
/ bdc
->reuse_limit
;
377 j
= (exp((double)bdc
->max_suppress_time
/ bdc
->half_life
) * log10(2.0));
378 if (reuse_max_ratio
> j
&& j
!= 0)
382 (double)bdc
->reuse_index_size
/ (reuse_max_ratio
- 1);
384 for (i
= 0; i
< bdc
->reuse_index_size
; i
++) {
385 bdc
->reuse_index
[i
] =
386 (int)(((double)bdc
->half_life
/ DELTA_REUSE
)
390 + ((double)i
/ bdc
->scale_factor
))))
395 int bgp_damp_enable(struct bgp
*bgp
, afi_t afi
, safi_t safi
, time_t half
,
396 unsigned int reuse
, unsigned int suppress
, time_t max
)
398 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
400 if (CHECK_FLAG(bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
)) {
401 if (bdc
->half_life
== half
&& bdc
->reuse_limit
== reuse
402 && bdc
->suppress_value
== suppress
403 && bdc
->max_suppress_time
== max
)
405 bgp_damp_disable(bgp
, afi
, safi
);
408 SET_FLAG(bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
);
409 bgp_damp_parameter_set(half
, reuse
, suppress
, max
, bdc
);
411 /* Register reuse timer. */
412 thread_add_timer(bm
->master
, bgp_reuse_timer
, bdc
, DELTA_REUSE
,
418 static void bgp_damp_config_clean(struct bgp_damp_config
*bdc
)
420 /* Free decay array */
421 XFREE(MTYPE_BGP_DAMP_ARRAY
, bdc
->decay_array
);
422 bdc
->decay_array_size
= 0;
424 /* Free reuse index array */
425 XFREE(MTYPE_BGP_DAMP_ARRAY
, bdc
->reuse_index
);
426 bdc
->reuse_index_size
= 0;
428 /* Free reuse list array. */
429 XFREE(MTYPE_BGP_DAMP_ARRAY
, bdc
->reuse_list
);
430 bdc
->reuse_list_size
= 0;
433 /* Clean all the bgp_damp_info stored in reuse_list. */
434 void bgp_damp_info_clean(afi_t afi
, safi_t safi
)
437 struct bgp_damp_info
*bdi
, *next
;
438 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
440 bdc
->reuse_offset
= 0;
442 for (i
= 0; i
< bdc
->reuse_list_size
; i
++) {
443 if (!bdc
->reuse_list
[i
])
446 for (bdi
= bdc
->reuse_list
[i
]; bdi
; bdi
= next
) {
448 bgp_damp_info_free(bdi
, 1, afi
, safi
);
450 bdc
->reuse_list
[i
] = NULL
;
453 for (bdi
= bdc
->no_reuse_list
; bdi
; bdi
= next
) {
455 bgp_damp_info_free(bdi
, 1, afi
, safi
);
457 bdc
->no_reuse_list
= NULL
;
460 int bgp_damp_disable(struct bgp
*bgp
, afi_t afi
, safi_t safi
)
462 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
463 /* If it wasn't enabled, there's nothing to do. */
464 if (!CHECK_FLAG(bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
))
467 /* Cancel reuse event. */
468 THREAD_OFF(bdc
->t_reuse
);
470 /* Clean BGP dampening information. */
471 bgp_damp_info_clean(afi
, safi
);
473 /* Clear configuration */
474 bgp_damp_config_clean(bdc
);
476 UNSET_FLAG(bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
);
480 void bgp_config_write_damp(struct vty
*vty
, afi_t afi
, safi_t safi
)
482 if (damp
[afi
][safi
].half_life
== DEFAULT_HALF_LIFE
* 60
483 && damp
[afi
][safi
].reuse_limit
== DEFAULT_REUSE
484 && damp
[afi
][safi
].suppress_value
== DEFAULT_SUPPRESS
485 && damp
[afi
][safi
].max_suppress_time
486 == damp
[afi
][safi
].half_life
* 4)
487 vty_out(vty
, " bgp dampening\n");
488 else if (damp
[afi
][safi
].half_life
!= DEFAULT_HALF_LIFE
* 60
489 && damp
[afi
][safi
].reuse_limit
== DEFAULT_REUSE
490 && damp
[afi
][safi
].suppress_value
== DEFAULT_SUPPRESS
491 && damp
[afi
][safi
].max_suppress_time
492 == damp
[afi
][safi
].half_life
* 4)
493 vty_out(vty
, " bgp dampening %lld\n",
494 damp
[afi
][safi
].half_life
/ 60LL);
496 vty_out(vty
, " bgp dampening %lld %d %d %lld\n",
497 damp
[afi
][safi
].half_life
/ 60LL,
498 damp
[afi
][safi
].reuse_limit
,
499 damp
[afi
][safi
].suppress_value
,
500 damp
[afi
][safi
].max_suppress_time
/ 60LL);
503 static const char *bgp_get_reuse_time(unsigned int penalty
, char *buf
,
504 size_t len
, afi_t afi
, safi_t safi
,
505 bool use_json
, json_object
*json
)
507 time_t reuse_time
= 0;
511 if (penalty
> damp
[afi
][safi
].reuse_limit
) {
512 reuse_time
= (int)(DELTA_T
513 * ((log((double)damp
[afi
][safi
].reuse_limit
515 / (log(damp
[afi
][safi
].decay_array
[1]))));
517 if (reuse_time
> damp
[afi
][safi
].max_suppress_time
)
518 reuse_time
= damp
[afi
][safi
].max_suppress_time
;
520 gmtime_r(&reuse_time
, &tm
);
524 /* Making formatted timer strings. */
525 if (reuse_time
== 0) {
527 json_object_int_add(json
, "reuseTimerMsecs", 0);
529 snprintf(buf
, len
, "00:00:00");
530 } else if (reuse_time
< ONE_DAY_SECOND
) {
532 time_store
= (3600000 * tm
.tm_hour
)
533 + (60000 * tm
.tm_min
)
534 + (1000 * tm
.tm_sec
);
535 json_object_int_add(json
, "reuseTimerMsecs",
538 snprintf(buf
, len
, "%02d:%02d:%02d", tm
.tm_hour
,
539 tm
.tm_min
, tm
.tm_sec
);
540 } else if (reuse_time
< ONE_WEEK_SECOND
) {
542 time_store
= (86400000 * tm
.tm_yday
)
543 + (3600000 * tm
.tm_hour
)
544 + (60000 * tm
.tm_min
)
545 + (1000 * tm
.tm_sec
);
546 json_object_int_add(json
, "reuseTimerMsecs",
549 snprintf(buf
, len
, "%dd%02dh%02dm", tm
.tm_yday
,
550 tm
.tm_hour
, tm
.tm_min
);
554 (604800000 * tm
.tm_yday
/ 7)
556 * (tm
.tm_yday
- ((tm
.tm_yday
/ 7) * 7)))
557 + (3600000 * tm
.tm_hour
) + (60000 * tm
.tm_min
)
558 + (1000 * tm
.tm_sec
);
559 json_object_int_add(json
, "reuseTimerMsecs",
562 snprintf(buf
, len
, "%02dw%dd%02dh", tm
.tm_yday
/ 7,
563 tm
.tm_yday
- ((tm
.tm_yday
/ 7) * 7),
570 void bgp_damp_info_vty(struct vty
*vty
, struct bgp_path_info
*path
, afi_t afi
,
571 safi_t safi
, json_object
*json_path
)
573 struct bgp_damp_info
*bdi
;
574 time_t t_now
, t_diff
;
575 char timebuf
[BGP_UPTIME_LEN
];
577 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
582 /* BGP dampening information. */
583 bdi
= path
->extra
->damp_info
;
585 /* If dampening is not enabled or there is no dampening information,
586 return immediately. */
590 /* Calculate new penalty. */
591 t_now
= monotime(NULL
);
592 t_diff
= t_now
- bdi
->t_updated
;
593 penalty
= bgp_damp_decay(t_diff
, bdi
->penalty
, bdc
);
596 json_object_int_add(json_path
, "dampeningPenalty", penalty
);
597 json_object_int_add(json_path
, "dampeningFlapCount", bdi
->flap
);
598 peer_uptime(bdi
->start_time
, timebuf
, BGP_UPTIME_LEN
, 1,
601 if (CHECK_FLAG(path
->flags
, BGP_PATH_DAMPED
)
602 && !CHECK_FLAG(path
->flags
, BGP_PATH_HISTORY
))
603 bgp_get_reuse_time(penalty
, timebuf
, BGP_UPTIME_LEN
,
604 afi
, safi
, 1, json_path
);
607 " Dampinfo: penalty %d, flapped %d times in %s",
609 peer_uptime(bdi
->start_time
, timebuf
, BGP_UPTIME_LEN
, 0,
612 if (CHECK_FLAG(path
->flags
, BGP_PATH_DAMPED
)
613 && !CHECK_FLAG(path
->flags
, BGP_PATH_HISTORY
))
614 vty_out(vty
, ", reuse in %s",
615 bgp_get_reuse_time(penalty
, timebuf
,
616 BGP_UPTIME_LEN
, afi
, safi
, 0,
623 const char *bgp_damp_reuse_time_vty(struct vty
*vty
, struct bgp_path_info
*path
,
624 char *timebuf
, size_t len
, afi_t afi
,
625 safi_t safi
, bool use_json
,
628 struct bgp_damp_info
*bdi
;
629 time_t t_now
, t_diff
;
631 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
636 /* BGP dampening information. */
637 bdi
= path
->extra
->damp_info
;
639 /* If dampening is not enabled or there is no dampening information,
640 return immediately. */
644 /* Calculate new penalty. */
645 t_now
= monotime(NULL
);
646 t_diff
= t_now
- bdi
->t_updated
;
647 penalty
= bgp_damp_decay(t_diff
, bdi
->penalty
, bdc
);
649 return bgp_get_reuse_time(penalty
, timebuf
, len
, afi
, safi
, use_json
,
653 static int bgp_print_dampening_parameters(struct bgp
*bgp
, struct vty
*vty
,
654 afi_t afi
, safi_t safi
, bool use_json
)
656 if (CHECK_FLAG(bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
)) {
657 struct bgp_damp_config
*bdc
= &damp
[afi
][safi
];
660 json_object
*json
= json_object_new_object();
662 json_object_int_add(json
, "halfLifeSecs",
664 json_object_int_add(json
, "reusePenalty",
666 json_object_int_add(json
, "suppressPenalty",
667 bdc
->suppress_value
);
668 json_object_int_add(json
, "maxSuppressTimeSecs",
669 bdc
->max_suppress_time
);
670 json_object_int_add(json
, "maxSuppressPenalty",
675 vty_out(vty
, "Half-life time: %lld min\n",
676 (long long)bdc
->half_life
/ 60);
677 vty_out(vty
, "Reuse penalty: %d\n", bdc
->reuse_limit
);
678 vty_out(vty
, "Suppress penalty: %d\n",
679 bdc
->suppress_value
);
680 vty_out(vty
, "Max suppress time: %lld min\n",
681 (long long)bdc
->max_suppress_time
/ 60);
682 vty_out(vty
, "Max suppress penalty: %u\n",
686 } else if (!use_json
)
687 vty_out(vty
, "dampening not enabled for %s\n",
688 get_afi_safi_str(afi
, safi
, false));
693 int bgp_show_dampening_parameters(struct vty
*vty
, afi_t afi
, safi_t safi
,
697 bool use_json
= CHECK_FLAG(show_flags
, BGP_SHOW_OPT_JSON
);
699 bgp
= bgp_get_default();
702 vty_out(vty
, "No BGP process is configured\n");
706 if (!CHECK_FLAG(show_flags
, BGP_SHOW_OPT_AFI_ALL
))
707 return bgp_print_dampening_parameters(bgp
, vty
, afi
, safi
,
710 if (CHECK_FLAG(show_flags
, BGP_SHOW_OPT_AFI_IP
)
711 || CHECK_FLAG(show_flags
, BGP_SHOW_OPT_AFI_IP6
)) {
712 afi
= CHECK_FLAG(show_flags
, BGP_SHOW_OPT_AFI_IP
) ? AFI_IP
714 FOREACH_SAFI (safi
) {
715 if (strmatch(get_afi_safi_str(afi
, safi
, true),
720 vty_out(vty
, "\nFor address family: %s\n\n",
721 get_afi_safi_str(afi
, safi
, false));
723 bgp_print_dampening_parameters(bgp
, vty
, afi
, safi
,
727 FOREACH_AFI_SAFI (afi
, safi
) {
728 if (strmatch(get_afi_safi_str(afi
, safi
, true),
733 vty_out(vty
, "\nFor address family: %s\n",
734 get_afi_safi_str(afi
, safi
, false));
736 bgp_print_dampening_parameters(bgp
, vty
, afi
, safi
,