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"
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
;
43 /* Utility macro to add and delete BGP dampening information to no
45 #define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list)
46 #define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list)
48 /* Calculate reuse list index by penalty value. */
50 bgp_reuse_index (int penalty
)
55 i
= (int)(((double) penalty
/ damp
->reuse_limit
- 1.0) * damp
->scale_factor
);
57 if ( i
>= damp
->reuse_index_size
)
58 i
= damp
->reuse_index_size
- 1;
60 index
= damp
->reuse_index
[i
] - damp
->reuse_index
[0];
62 return (damp
->reuse_offset
+ index
) % damp
->reuse_list_size
;
65 /* Add BGP dampening information to reuse list. */
67 bgp_reuse_list_add (struct bgp_damp_info
*bdi
)
71 index
= bdi
->index
= bgp_reuse_index (bdi
->penalty
);
74 bdi
->next
= damp
->reuse_list
[index
];
75 if (damp
->reuse_list
[index
])
76 damp
->reuse_list
[index
]->prev
= bdi
;
77 damp
->reuse_list
[index
] = bdi
;
80 /* Delete BGP dampening information from reuse list. */
82 bgp_reuse_list_delete (struct bgp_damp_info
*bdi
)
85 bdi
->next
->prev
= bdi
->prev
;
87 bdi
->prev
->next
= bdi
->next
;
89 damp
->reuse_list
[bdi
->index
] = bdi
->next
;
92 /* Return decayed penalty value. */
94 bgp_damp_decay (time_t tdiff
, int penalty
)
98 i
= (int) ((double) tdiff
/ DELTA_T
);
103 if (i
>= damp
->decay_array_size
)
106 return (int) (penalty
* damp
->decay_array
[i
]);
109 /* Handler of reuse timer event. Each route in the current reuse-list
110 is evaluated. RFC2439 Section 4.8.7. */
112 bgp_reuse_timer (struct thread
*t
)
114 struct bgp_damp_info
*bdi
;
115 struct bgp_damp_info
*next
;
116 time_t t_now
, t_diff
;
118 damp
->t_reuse
= NULL
;
119 thread_add_timer(bm
->master
, bgp_reuse_timer
, NULL
, DELTA_REUSE
,
122 t_now
= bgp_clock ();
124 /* 1. save a pointer to the current zeroth queue head and zero the
126 bdi
= damp
->reuse_list
[damp
->reuse_offset
];
127 damp
->reuse_list
[damp
->reuse_offset
] = NULL
;
129 /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
130 rotating the circular queue of list-heads. */
131 damp
->reuse_offset
= (damp
->reuse_offset
+ 1) % damp
->reuse_list_size
;
133 /* 3. if ( the saved list head pointer is non-empty ) */
134 for (; bdi
; bdi
= next
)
136 struct bgp
*bgp
= bdi
->binfo
->peer
->bgp
;
140 /* Set t-diff = t-now - t-updated. */
141 t_diff
= t_now
- bdi
->t_updated
;
143 /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */
144 bdi
->penalty
= bgp_damp_decay (t_diff
, bdi
->penalty
);
146 /* Set t-updated = t-now. */
147 bdi
->t_updated
= t_now
;
149 /* if (figure-of-merit < reuse). */
150 if (bdi
->penalty
< damp
->reuse_limit
)
152 /* Reuse the route. */
153 bgp_info_unset_flag (bdi
->rn
, bdi
->binfo
, BGP_INFO_DAMPED
);
154 bdi
->suppress_time
= 0;
156 if (bdi
->lastrecord
== BGP_RECORD_UPDATE
)
158 bgp_info_unset_flag (bdi
->rn
, bdi
->binfo
, BGP_INFO_HISTORY
);
159 bgp_aggregate_increment (bgp
, &bdi
->rn
->p
, bdi
->binfo
,
160 bdi
->afi
, bdi
->safi
);
161 bgp_process (bgp
, bdi
->rn
, bdi
->afi
, bdi
->safi
);
164 if (bdi
->penalty
<= damp
->reuse_limit
/ 2.0)
165 bgp_damp_info_free (bdi
, 1);
167 BGP_DAMP_LIST_ADD (damp
, bdi
);
170 /* Re-insert into another list (See RFC2439 Section 4.8.6). */
171 bgp_reuse_list_add (bdi
);
177 /* A route becomes unreachable (RFC2439 Section 4.8.2). */
179 bgp_damp_withdraw (struct bgp_info
*binfo
, struct bgp_node
*rn
,
180 afi_t afi
, safi_t safi
, int attr_change
)
183 struct bgp_damp_info
*bdi
= NULL
;
184 double last_penalty
= 0;
186 t_now
= bgp_clock ();
188 /* Processing Unreachable Messages. */
190 bdi
= binfo
->extra
->damp_info
;
194 /* If there is no previous stability history. */
197 1. allocate a damping structure.
198 2. set figure-of-merit = 1.
199 3. withdraw the route. */
201 bdi
= XCALLOC (MTYPE_BGP_DAMP_INFO
, sizeof (struct bgp_damp_info
));
204 bdi
->penalty
= (attr_change
? DEFAULT_PENALTY
/ 2 : DEFAULT_PENALTY
);
206 bdi
->start_time
= t_now
;
207 bdi
->suppress_time
= 0;
211 (bgp_info_extra_get (binfo
))->damp_info
= bdi
;
212 BGP_DAMP_LIST_ADD (damp
, bdi
);
216 last_penalty
= bdi
->penalty
;
218 /* 1. Set t-diff = t-now - t-updated. */
220 (bgp_damp_decay (t_now
- bdi
->t_updated
, bdi
->penalty
)
221 + (attr_change
? DEFAULT_PENALTY
/ 2 : DEFAULT_PENALTY
));
223 if (bdi
->penalty
> damp
->ceiling
)
224 bdi
->penalty
= damp
->ceiling
;
229 assert ((rn
== bdi
->rn
) && (binfo
== bdi
->binfo
));
231 bdi
->lastrecord
= BGP_RECORD_WITHDRAW
;
232 bdi
->t_updated
= t_now
;
234 /* Make this route as historical status. */
235 bgp_info_set_flag (rn
, binfo
, BGP_INFO_HISTORY
);
237 /* Remove the route from a reuse list if it is on one. */
238 if (CHECK_FLAG (bdi
->binfo
->flags
, BGP_INFO_DAMPED
))
240 /* If decay rate isn't equal to 0, reinsert brn. */
241 if (bdi
->penalty
!= last_penalty
)
243 bgp_reuse_list_delete (bdi
);
244 bgp_reuse_list_add (bdi
);
246 return BGP_DAMP_SUPPRESSED
;
249 /* If not suppressed before, do annonunce this withdraw and
250 insert into reuse_list. */
251 if (bdi
->penalty
>= damp
->suppress_value
)
253 bgp_info_set_flag (rn
, binfo
, BGP_INFO_DAMPED
);
254 bdi
->suppress_time
= t_now
;
255 BGP_DAMP_LIST_DEL (damp
, bdi
);
256 bgp_reuse_list_add (bdi
);
259 return BGP_DAMP_USED
;
263 bgp_damp_update (struct bgp_info
*binfo
, struct bgp_node
*rn
,
264 afi_t afi
, safi_t safi
)
267 struct bgp_damp_info
*bdi
;
270 if (!binfo
->extra
|| !((bdi
= binfo
->extra
->damp_info
)))
271 return BGP_DAMP_USED
;
273 t_now
= bgp_clock ();
274 bgp_info_unset_flag (rn
, binfo
, BGP_INFO_HISTORY
);
276 bdi
->lastrecord
= BGP_RECORD_UPDATE
;
277 bdi
->penalty
= bgp_damp_decay (t_now
- bdi
->t_updated
, bdi
->penalty
);
279 if (! CHECK_FLAG (bdi
->binfo
->flags
, BGP_INFO_DAMPED
)
280 && (bdi
->penalty
< damp
->suppress_value
))
281 status
= BGP_DAMP_USED
;
282 else if (CHECK_FLAG (bdi
->binfo
->flags
, BGP_INFO_DAMPED
)
283 && (bdi
->penalty
< damp
->reuse_limit
) )
285 bgp_info_unset_flag (rn
, binfo
, BGP_INFO_DAMPED
);
286 bgp_reuse_list_delete (bdi
);
287 BGP_DAMP_LIST_ADD (damp
, bdi
);
288 bdi
->suppress_time
= 0;
289 status
= BGP_DAMP_USED
;
292 status
= BGP_DAMP_SUPPRESSED
;
294 if (bdi
->penalty
> damp
->reuse_limit
/ 2.0)
295 bdi
->t_updated
= t_now
;
297 bgp_damp_info_free (bdi
, 0);
302 /* Remove dampening information and history route. */
304 bgp_damp_scan (struct bgp_info
*binfo
, afi_t afi
, safi_t safi
)
306 time_t t_now
, t_diff
;
307 struct bgp_damp_info
*bdi
;
309 assert (binfo
->extra
&& binfo
->extra
->damp_info
);
311 t_now
= bgp_clock ();
312 bdi
= binfo
->extra
->damp_info
;
314 if (CHECK_FLAG (binfo
->flags
, BGP_INFO_DAMPED
))
316 t_diff
= t_now
- bdi
->suppress_time
;
318 if (t_diff
>= damp
->max_suppress_time
)
320 bgp_info_unset_flag (bdi
->rn
, binfo
, BGP_INFO_DAMPED
);
321 bgp_reuse_list_delete (bdi
);
322 BGP_DAMP_LIST_ADD (damp
, bdi
);
323 bdi
->penalty
= damp
->reuse_limit
;
324 bdi
->suppress_time
= 0;
325 bdi
->t_updated
= t_now
;
327 /* Need to announce UPDATE once this binfo is usable again. */
328 if (bdi
->lastrecord
== BGP_RECORD_UPDATE
)
336 t_diff
= t_now
- bdi
->t_updated
;
337 bdi
->penalty
= bgp_damp_decay (t_diff
, bdi
->penalty
);
339 if (bdi
->penalty
<= damp
->reuse_limit
/ 2.0)
341 /* release the bdi, bdi->binfo. */
342 bgp_damp_info_free (bdi
, 1);
346 bdi
->t_updated
= t_now
;
352 bgp_damp_info_free (struct bgp_damp_info
*bdi
, int withdraw
)
354 struct bgp_info
*binfo
;
360 binfo
->extra
->damp_info
= NULL
;
362 if (CHECK_FLAG (binfo
->flags
, BGP_INFO_DAMPED
))
363 bgp_reuse_list_delete (bdi
);
365 BGP_DAMP_LIST_DEL (damp
, bdi
);
367 bgp_info_unset_flag (bdi
->rn
, binfo
, BGP_INFO_HISTORY
|BGP_INFO_DAMPED
);
369 if (bdi
->lastrecord
== BGP_RECORD_WITHDRAW
&& withdraw
)
370 bgp_info_delete (bdi
->rn
, binfo
);
372 XFREE (MTYPE_BGP_DAMP_INFO
, bdi
);
376 bgp_damp_parameter_set (int hlife
, int reuse
, int sup
, int maxsup
)
378 double reuse_max_ratio
;
382 damp
->suppress_value
= sup
;
383 damp
->half_life
= hlife
;
384 damp
->reuse_limit
= reuse
;
385 damp
->max_suppress_time
= maxsup
;
387 /* Initialize params per bgp_damp_config. */
388 damp
->reuse_index_size
= REUSE_ARRAY_SIZE
;
390 damp
->ceiling
= (int)(damp
->reuse_limit
* (pow(2, (double)damp
->max_suppress_time
/damp
->half_life
)));
392 /* Decay-array computations */
393 damp
->decay_array_size
= ceil ((double) damp
->max_suppress_time
/ DELTA_T
);
394 damp
->decay_array
= XMALLOC (MTYPE_BGP_DAMP_ARRAY
,
395 sizeof(double) * (damp
->decay_array_size
));
396 damp
->decay_array
[0] = 1.0;
397 damp
->decay_array
[1] = exp ((1.0/((double)damp
->half_life
/DELTA_T
)) * log(0.5));
399 /* Calculate decay values for all possible times */
400 for (i
= 2; i
< damp
->decay_array_size
; i
++)
401 damp
->decay_array
[i
] = damp
->decay_array
[i
-1] * damp
->decay_array
[1];
403 /* Reuse-list computations */
404 i
= ceil ((double)damp
->max_suppress_time
/ DELTA_REUSE
) + 1;
405 if (i
> REUSE_LIST_SIZE
|| i
== 0)
407 damp
->reuse_list_size
= i
;
409 damp
->reuse_list
= XCALLOC (MTYPE_BGP_DAMP_ARRAY
,
410 damp
->reuse_list_size
411 * sizeof (struct bgp_reuse_node
*));
413 /* Reuse-array computations */
414 damp
->reuse_index
= XCALLOC (MTYPE_BGP_DAMP_ARRAY
,
415 sizeof(int) * damp
->reuse_index_size
);
417 reuse_max_ratio
= (double)damp
->ceiling
/damp
->reuse_limit
;
418 j
= (exp((double)damp
->max_suppress_time
/damp
->half_life
) * log10(2.0));
419 if ( reuse_max_ratio
> j
&& j
!= 0 )
422 damp
->scale_factor
= (double)damp
->reuse_index_size
/(reuse_max_ratio
- 1);
424 for (i
= 0; i
< damp
->reuse_index_size
; i
++)
426 damp
->reuse_index
[i
] =
427 (int)(((double)damp
->half_life
/ DELTA_REUSE
)
428 * log10 (1.0 / (damp
->reuse_limit
* ( 1.0 + ((double)i
/damp
->scale_factor
)))) / log10(0.5));
433 bgp_damp_enable (struct bgp
*bgp
, afi_t afi
, safi_t safi
, time_t half
,
434 unsigned int reuse
, unsigned int suppress
, time_t max
)
436 if (CHECK_FLAG (bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
))
438 if (damp
->half_life
== half
439 && damp
->reuse_limit
== reuse
440 && damp
->suppress_value
== suppress
441 && damp
->max_suppress_time
== max
)
443 bgp_damp_disable (bgp
, afi
, safi
);
446 SET_FLAG (bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
);
447 bgp_damp_parameter_set (half
, reuse
, suppress
, max
);
449 /* Register reuse timer. */
450 thread_add_timer(bm
->master
, bgp_reuse_timer
, NULL
, DELTA_REUSE
,
457 bgp_damp_config_clean (struct bgp_damp_config
*damp
)
459 /* Free decay array */
460 XFREE (MTYPE_BGP_DAMP_ARRAY
, damp
->decay_array
);
462 /* Free reuse index array */
463 XFREE (MTYPE_BGP_DAMP_ARRAY
, damp
->reuse_index
);
465 /* Free reuse list array. */
466 XFREE (MTYPE_BGP_DAMP_ARRAY
, damp
->reuse_list
);
469 /* Clean all the bgp_damp_info stored in reuse_list. */
471 bgp_damp_info_clean (void)
474 struct bgp_damp_info
*bdi
, *next
;
476 damp
->reuse_offset
= 0;
478 for (i
= 0; i
< damp
->reuse_list_size
; i
++)
480 if (! damp
->reuse_list
[i
])
483 for (bdi
= damp
->reuse_list
[i
]; bdi
; bdi
= next
)
486 bgp_damp_info_free (bdi
, 1);
488 damp
->reuse_list
[i
] = NULL
;
491 for (bdi
= damp
->no_reuse_list
; bdi
; bdi
= next
)
494 bgp_damp_info_free (bdi
, 1);
496 damp
->no_reuse_list
= NULL
;
500 bgp_damp_disable (struct bgp
*bgp
, afi_t afi
, safi_t safi
)
502 /* If it wasn't enabled, there's nothing to do. */
503 if (! CHECK_FLAG (bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
))
506 /* Cancel reuse thread. */
508 thread_cancel (damp
->t_reuse
);
509 damp
->t_reuse
= NULL
;
511 /* Clean BGP dampening information. */
512 bgp_damp_info_clean ();
514 /* Clear configuration */
515 bgp_damp_config_clean (&bgp_damp_cfg
);
517 UNSET_FLAG (bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
);
522 bgp_config_write_damp (struct vty
*vty
)
524 if (bgp_damp_cfg
.half_life
== DEFAULT_HALF_LIFE
*60
525 && bgp_damp_cfg
.reuse_limit
== DEFAULT_REUSE
526 && bgp_damp_cfg
.suppress_value
== DEFAULT_SUPPRESS
527 && bgp_damp_cfg
.max_suppress_time
== bgp_damp_cfg
.half_life
*4)
528 vty_out (vty
, " bgp dampening%s", VTY_NEWLINE
);
529 else if (bgp_damp_cfg
.half_life
!= DEFAULT_HALF_LIFE
*60
530 && bgp_damp_cfg
.reuse_limit
== DEFAULT_REUSE
531 && bgp_damp_cfg
.suppress_value
== DEFAULT_SUPPRESS
532 && bgp_damp_cfg
.max_suppress_time
== bgp_damp_cfg
.half_life
*4)
533 vty_out (vty
, " bgp dampening %lld%s",
534 bgp_damp_cfg
.half_life
/60LL,
537 vty_out (vty
, " bgp dampening %lld %d %d %lld%s",
538 bgp_damp_cfg
.half_life
/60LL,
539 bgp_damp_cfg
.reuse_limit
,
540 bgp_damp_cfg
.suppress_value
,
541 bgp_damp_cfg
.max_suppress_time
/60LL,
546 bgp_get_reuse_time (unsigned int penalty
, char *buf
, size_t len
, u_char use_json
, json_object
*json
)
548 time_t reuse_time
= 0;
549 struct tm
*tm
= NULL
;
552 if (penalty
> damp
->reuse_limit
)
554 reuse_time
= (int) (DELTA_T
* ((log((double)damp
->reuse_limit
/penalty
))/(log(damp
->decay_array
[1]))));
556 if (reuse_time
> damp
->max_suppress_time
)
557 reuse_time
= damp
->max_suppress_time
;
559 tm
= gmtime (&reuse_time
);
564 /* Making formatted timer strings. */
565 #define ONE_DAY_SECOND 60*60*24
566 #define ONE_WEEK_SECOND 60*60*24*7
570 json_object_int_add(json
, "reuseTimerMsecs", 0);
572 snprintf (buf
, len
, "00:00:00");
574 else if (reuse_time
< ONE_DAY_SECOND
)
578 time_store
= (3600000 * tm
->tm_hour
) + (60000 * tm
->tm_min
) + (1000 * tm
->tm_sec
);
579 json_object_int_add(json
, "reuseTimerMsecs", time_store
);
582 snprintf (buf
, len
, "%02d:%02d:%02d",
583 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
585 else if (reuse_time
< ONE_WEEK_SECOND
)
589 time_store
= (86400000 * tm
->tm_yday
) + (3600000 * tm
->tm_hour
) + (60000 * tm
->tm_min
) + (1000 * tm
->tm_sec
);
590 json_object_int_add(json
, "reuseTimerMsecs", time_store
);
593 snprintf (buf
, len
, "%dd%02dh%02dm",
594 tm
->tm_yday
, tm
->tm_hour
, tm
->tm_min
);
600 time_store
= (604800000 * tm
->tm_yday
/7) + (86400000 * (tm
->tm_yday
- ((tm
->tm_yday
/7) * 7))) + (3600000 * tm
->tm_hour
) + (60000 * tm
->tm_min
) + (1000 * tm
->tm_sec
);
601 json_object_int_add(json
, "reuseTimerMsecs", time_store
);
604 snprintf (buf
, len
, "%02dw%dd%02dh",
605 tm
->tm_yday
/7, tm
->tm_yday
- ((tm
->tm_yday
/7) * 7), tm
->tm_hour
);
612 bgp_damp_info_vty (struct vty
*vty
, struct bgp_info
*binfo
,
613 json_object
*json_path
)
615 struct bgp_damp_info
*bdi
;
616 time_t t_now
, t_diff
;
617 char timebuf
[BGP_UPTIME_LEN
];
623 /* BGP dampening information. */
624 bdi
= binfo
->extra
->damp_info
;
626 /* If dampening is not enabled or there is no dampening information,
627 return immediately. */
631 /* Calculate new penalty. */
632 t_now
= bgp_clock ();
633 t_diff
= t_now
- bdi
->t_updated
;
634 penalty
= bgp_damp_decay (t_diff
, bdi
->penalty
);
638 json_object_int_add(json_path
, "dampeningPenalty", penalty
);
639 json_object_int_add(json_path
, "dampeningFlapCount", bdi
->flap
);
640 peer_uptime (bdi
->start_time
, timebuf
, BGP_UPTIME_LEN
, 1, json_path
);
642 if (CHECK_FLAG (binfo
->flags
, BGP_INFO_DAMPED
)
643 && ! CHECK_FLAG (binfo
->flags
, BGP_INFO_HISTORY
))
644 bgp_get_reuse_time (penalty
, timebuf
, BGP_UPTIME_LEN
, 1, json_path
);
648 vty_out (vty
, " Dampinfo: penalty %d, flapped %d times in %s",
650 peer_uptime (bdi
->start_time
, timebuf
, BGP_UPTIME_LEN
, 0, json_path
));
652 if (CHECK_FLAG (binfo
->flags
, BGP_INFO_DAMPED
)
653 && ! CHECK_FLAG (binfo
->flags
, BGP_INFO_HISTORY
))
654 vty_out (vty
, ", reuse in %s",
655 bgp_get_reuse_time (penalty
, timebuf
, BGP_UPTIME_LEN
, 0, json_path
));
657 vty_out (vty
, "%s", VTY_NEWLINE
);
662 bgp_damp_reuse_time_vty (struct vty
*vty
, struct bgp_info
*binfo
,
663 char *timebuf
, size_t len
, u_char use_json
, json_object
*json
)
665 struct bgp_damp_info
*bdi
;
666 time_t t_now
, t_diff
;
672 /* BGP dampening information. */
673 bdi
= binfo
->extra
->damp_info
;
675 /* If dampening is not enabled or there is no dampening information,
676 return immediately. */
680 /* Calculate new penalty. */
681 t_now
= bgp_clock ();
682 t_diff
= t_now
- bdi
->t_updated
;
683 penalty
= bgp_damp_decay (t_diff
, bdi
->penalty
);
685 return bgp_get_reuse_time (penalty
, timebuf
, len
, use_json
, json
);
689 bgp_show_dampening_parameters (struct vty
*vty
, afi_t afi
, safi_t safi
)
692 bgp
= bgp_get_default();
696 vty_out (vty
, "No BGP process is configured%s", VTY_NEWLINE
);
700 if (CHECK_FLAG (bgp
->af_flags
[afi
][safi
], BGP_CONFIG_DAMPENING
))
702 vty_out (vty
, "Half-life time: %lld min%s",
703 (long long)damp
->half_life
/ 60, VTY_NEWLINE
);
704 vty_out (vty
, "Reuse penalty: %d%s",
705 damp
->reuse_limit
, VTY_NEWLINE
);
706 vty_out (vty
, "Suppress penalty: %d%s",
707 damp
->suppress_value
, VTY_NEWLINE
);
708 vty_out (vty
, "Max suppress time: %lld min%s",
709 (long long)damp
->max_suppress_time
/ 60, VTY_NEWLINE
);
710 vty_out (vty
, "Max supress penalty: %u%s",
711 damp
->ceiling
, VTY_NEWLINE
);
712 vty_out (vty
, "%s", VTY_NEWLINE
);
715 vty_out (vty
, "dampening not enabled for %s%s",
716 afi
== AFI_IP
? "IPv4" : "IPv6", VTY_NEWLINE
);