blob: 359fce36fead4f712fd7ad4c2f5ce85b02849b54 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP flap dampening
2 Copyright (C) 2001 IP Infusion Inc.
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
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
30#include "bgpd/bgpd.h"
31#include "bgpd/bgp_damp.h"
32#include "bgpd/bgp_table.h"
33#include "bgpd/bgp_route.h"
34#include "bgpd/bgp_attr.h"
35#include "bgpd/bgp_advertise.h"
36
37/* Global variable to access damping configuration */
38struct bgp_damp_config bgp_damp_cfg;
Stephen Hemmingere9dc9f22009-05-15 10:19:31 -070039static struct bgp_damp_config *damp = &bgp_damp_cfg;
paul718e3742002-12-13 20:15:29 +000040
41/* Utility macro to add and delete BGP dampening information to no
42 used list. */
43#define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list)
44#define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list)
David Lamparter6b0655a2014-06-04 06:53:35 +020045
paul718e3742002-12-13 20:15:29 +000046/* Calculate reuse list index by penalty value. */
47static int
48bgp_reuse_index (int penalty)
49{
paulfd79ac92004-10-13 05:06:08 +000050 unsigned int i;
paul718e3742002-12-13 20:15:29 +000051 int index;
52
53 i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor);
54
55 if ( i >= damp->reuse_index_size )
56 i = damp->reuse_index_size - 1;
57
58 index = damp->reuse_index[i] - damp->reuse_index[0];
59
60 return (damp->reuse_offset + index) % damp->reuse_list_size;
61}
62
63/* Add BGP dampening information to reuse list. */
64static void
65bgp_reuse_list_add (struct bgp_damp_info *bdi)
66{
67 int index;
68
69 index = bdi->index = bgp_reuse_index (bdi->penalty);
70
71 bdi->prev = NULL;
72 bdi->next = damp->reuse_list[index];
73 if (damp->reuse_list[index])
74 damp->reuse_list[index]->prev = bdi;
75 damp->reuse_list[index] = bdi;
76}
77
78/* Delete BGP dampening information from reuse list. */
79static void
80bgp_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}
David Lamparter6b0655a2014-06-04 06:53:35 +020089
paul718e3742002-12-13 20:15:29 +000090/* Return decayed penalty value. */
91int
92bgp_damp_decay (time_t tdiff, int penalty)
93{
paulfd79ac92004-10-13 05:06:08 +000094 unsigned int i;
paul718e3742002-12-13 20:15:29 +000095
96 i = (int) ((double) tdiff / DELTA_T);
97
98 if (i == 0)
99 return penalty;
100
101 if (i >= damp->decay_array_size)
102 return 0;
103
104 return (int) (penalty * damp->decay_array[i]);
105}
106
107/* Handler of reuse timer event. Each route in the current reuse-list
108 is evaluated. RFC2439 Section 4.8.7. */
paul94f2b392005-06-28 12:44:16 +0000109static int
paul718e3742002-12-13 20:15:29 +0000110bgp_reuse_timer (struct thread *t)
111{
112 struct bgp_damp_info *bdi;
113 struct bgp_damp_info *next;
114 time_t t_now, t_diff;
paul41200852005-11-03 12:52:18 +0000115
paul718e3742002-12-13 20:15:29 +0000116 damp->t_reuse = NULL;
117 damp->t_reuse =
Donald Sharp774914f2015-10-14 08:50:39 -0400118 thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE);
paul718e3742002-12-13 20:15:29 +0000119
Stephen Hemminger65957882010-01-15 16:22:10 +0300120 t_now = bgp_clock ();
paul718e3742002-12-13 20:15:29 +0000121
122 /* 1. save a pointer to the current zeroth queue head and zero the
123 list head entry. */
124 bdi = damp->reuse_list[damp->reuse_offset];
125 damp->reuse_list[damp->reuse_offset] = NULL;
126
127 /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
128 rotating the circular queue of list-heads. */
129 damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
130
131 /* 3. if ( the saved list head pointer is non-empty ) */
132 for (; bdi; bdi = next)
133 {
paul41200852005-11-03 12:52:18 +0000134 struct bgp *bgp = bdi->binfo->peer->bgp;
135
paul718e3742002-12-13 20:15:29 +0000136 next = bdi->next;
137
138 /* Set t-diff = t-now - t-updated. */
139 t_diff = t_now - bdi->t_updated;
140
141 /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */
142 bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
143
144 /* Set t-updated = t-now. */
145 bdi->t_updated = t_now;
146
147 /* if (figure-of-merit < reuse). */
148 if (bdi->penalty < damp->reuse_limit)
149 {
150 /* Reuse the route. */
Paul Jakma1a392d42006-09-07 00:24:49 +0000151 bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_DAMPED);
paul718e3742002-12-13 20:15:29 +0000152 bdi->suppress_time = 0;
153
154 if (bdi->lastrecord == BGP_RECORD_UPDATE)
155 {
Paul Jakma1a392d42006-09-07 00:24:49 +0000156 bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_HISTORY);
paul718e3742002-12-13 20:15:29 +0000157 bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo,
158 bdi->afi, bdi->safi);
159 bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi);
160 }
161
162 if (bdi->penalty <= damp->reuse_limit / 2.0)
163 bgp_damp_info_free (bdi, 1);
164 else
165 BGP_DAMP_LIST_ADD (damp, bdi);
166 }
167 else
168 /* Re-insert into another list (See RFC2439 Section 4.8.6). */
169 bgp_reuse_list_add (bdi);
170 }
171
172 return 0;
173}
174
175/* A route becomes unreachable (RFC2439 Section 4.8.2). */
176int
177bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn,
178 afi_t afi, safi_t safi, int attr_change)
179{
180 time_t t_now;
Paul Jakmafb982c22007-05-04 20:15:47 +0000181 struct bgp_damp_info *bdi = NULL;
paul718e3742002-12-13 20:15:29 +0000182 double last_penalty = 0;
183
Stephen Hemminger65957882010-01-15 16:22:10 +0300184 t_now = bgp_clock ();
paul718e3742002-12-13 20:15:29 +0000185
186 /* Processing Unreachable Messages. */
Paul Jakmafb982c22007-05-04 20:15:47 +0000187 if (binfo->extra)
188 bdi = binfo->extra->damp_info;
189
paul718e3742002-12-13 20:15:29 +0000190 if (bdi == NULL)
191 {
192 /* If there is no previous stability history. */
193
194 /* RFC2439 said:
195 1. allocate a damping structure.
196 2. set figure-of-merit = 1.
197 3. withdraw the route. */
198
199 bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info));
200 bdi->binfo = binfo;
201 bdi->rn = rn;
202 bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
203 bdi->flap = 1;
204 bdi->start_time = t_now;
205 bdi->suppress_time = 0;
206 bdi->index = -1;
207 bdi->afi = afi;
208 bdi->safi = safi;
Paul Jakmafb982c22007-05-04 20:15:47 +0000209 (bgp_info_extra_get (binfo))->damp_info = bdi;
paul718e3742002-12-13 20:15:29 +0000210 BGP_DAMP_LIST_ADD (damp, bdi);
211 }
212 else
213 {
214 last_penalty = bdi->penalty;
215
216 /* 1. Set t-diff = t-now - t-updated. */
217 bdi->penalty =
218 (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty)
219 + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY));
220
221 if (bdi->penalty > damp->ceiling)
222 bdi->penalty = damp->ceiling;
223
224 bdi->flap++;
225 }
226
Paul Jakma1a392d42006-09-07 00:24:49 +0000227 assert ((rn == bdi->rn) && (binfo == bdi->binfo));
228
paul718e3742002-12-13 20:15:29 +0000229 bdi->lastrecord = BGP_RECORD_WITHDRAW;
230 bdi->t_updated = t_now;
231
232 /* Make this route as historical status. */
Paul Jakma1a392d42006-09-07 00:24:49 +0000233 bgp_info_set_flag (rn, binfo, BGP_INFO_HISTORY);
paul718e3742002-12-13 20:15:29 +0000234
235 /* Remove the route from a reuse list if it is on one. */
236 if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED))
237 {
238 /* If decay rate isn't equal to 0, reinsert brn. */
239 if (bdi->penalty != last_penalty)
240 {
241 bgp_reuse_list_delete (bdi);
242 bgp_reuse_list_add (bdi);
243 }
244 return BGP_DAMP_SUPPRESSED;
245 }
246
247 /* If not suppressed before, do annonunce this withdraw and
248 insert into reuse_list. */
249 if (bdi->penalty >= damp->suppress_value)
250 {
Paul Jakma1a392d42006-09-07 00:24:49 +0000251 bgp_info_set_flag (rn, binfo, BGP_INFO_DAMPED);
paul718e3742002-12-13 20:15:29 +0000252 bdi->suppress_time = t_now;
253 BGP_DAMP_LIST_DEL (damp, bdi);
254 bgp_reuse_list_add (bdi);
255 }
256
257 return BGP_DAMP_USED;
258}
259
260int
261bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn,
262 afi_t afi, safi_t safi)
263{
264 time_t t_now;
265 struct bgp_damp_info *bdi;
266 int status;
267
Paul Jakmafb982c22007-05-04 20:15:47 +0000268 if (!binfo->extra || !((bdi = binfo->extra->damp_info)))
paul718e3742002-12-13 20:15:29 +0000269 return BGP_DAMP_USED;
270
Stephen Hemminger65957882010-01-15 16:22:10 +0300271 t_now = bgp_clock ();
Paul Jakma1a392d42006-09-07 00:24:49 +0000272 bgp_info_unset_flag (rn, binfo, BGP_INFO_HISTORY);
paul718e3742002-12-13 20:15:29 +0000273
274 bdi->lastrecord = BGP_RECORD_UPDATE;
275 bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty);
276
277 if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
278 && (bdi->penalty < damp->suppress_value))
279 status = BGP_DAMP_USED;
280 else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
281 && (bdi->penalty < damp->reuse_limit) )
282 {
Paul Jakma1a392d42006-09-07 00:24:49 +0000283 bgp_info_unset_flag (rn, binfo, BGP_INFO_DAMPED);
paul718e3742002-12-13 20:15:29 +0000284 bgp_reuse_list_delete (bdi);
285 BGP_DAMP_LIST_ADD (damp, bdi);
286 bdi->suppress_time = 0;
287 status = BGP_DAMP_USED;
288 }
289 else
290 status = BGP_DAMP_SUPPRESSED;
291
292 if (bdi->penalty > damp->reuse_limit / 2.0)
293 bdi->t_updated = t_now;
294 else
295 bgp_damp_info_free (bdi, 0);
296
297 return status;
298}
299
300/* Remove dampening information and history route. */
301int
302bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi)
303{
304 time_t t_now, t_diff;
305 struct bgp_damp_info *bdi;
Paul Jakmafb982c22007-05-04 20:15:47 +0000306
307 assert (binfo->extra && binfo->extra->damp_info);
308
Stephen Hemminger65957882010-01-15 16:22:10 +0300309 t_now = bgp_clock ();
Paul Jakmafb982c22007-05-04 20:15:47 +0000310 bdi = binfo->extra->damp_info;
paul718e3742002-12-13 20:15:29 +0000311
312 if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
313 {
314 t_diff = t_now - bdi->suppress_time;
315
316 if (t_diff >= damp->max_suppress_time)
317 {
Paul Jakma1a392d42006-09-07 00:24:49 +0000318 bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_DAMPED);
paul718e3742002-12-13 20:15:29 +0000319 bgp_reuse_list_delete (bdi);
320 BGP_DAMP_LIST_ADD (damp, bdi);
321 bdi->penalty = damp->reuse_limit;
322 bdi->suppress_time = 0;
323 bdi->t_updated = t_now;
324
325 /* Need to announce UPDATE once this binfo is usable again. */
326 if (bdi->lastrecord == BGP_RECORD_UPDATE)
327 return 1;
328 else
329 return 0;
330 }
331 }
332 else
333 {
334 t_diff = t_now - bdi->t_updated;
335 bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
336
337 if (bdi->penalty <= damp->reuse_limit / 2.0)
338 {
339 /* release the bdi, bdi->binfo. */
340 bgp_damp_info_free (bdi, 1);
341 return 0;
342 }
343 else
344 bdi->t_updated = t_now;
345 }
346 return 0;
347}
348
349void
350bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw)
351{
352 struct bgp_info *binfo;
paul718e3742002-12-13 20:15:29 +0000353
354 if (! bdi)
355 return;
356
357 binfo = bdi->binfo;
Paul Jakmafb982c22007-05-04 20:15:47 +0000358 binfo->extra->damp_info = NULL;
paul718e3742002-12-13 20:15:29 +0000359
360 if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
361 bgp_reuse_list_delete (bdi);
362 else
363 BGP_DAMP_LIST_DEL (damp, bdi);
364
Paul Jakma1a392d42006-09-07 00:24:49 +0000365 bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_HISTORY|BGP_INFO_DAMPED);
paul718e3742002-12-13 20:15:29 +0000366
367 if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
paul200df112005-06-01 11:17:05 +0000368 bgp_info_delete (bdi->rn, binfo);
369
paul718e3742002-12-13 20:15:29 +0000370 XFREE (MTYPE_BGP_DAMP_INFO, bdi);
371}
372
paul94f2b392005-06-28 12:44:16 +0000373static void
paul718e3742002-12-13 20:15:29 +0000374bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup)
375{
376 double reuse_max_ratio;
paulfd79ac92004-10-13 05:06:08 +0000377 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000378 double j;
379
380 damp->suppress_value = sup;
381 damp->half_life = hlife;
382 damp->reuse_limit = reuse;
383 damp->max_suppress_time = maxsup;
384
385 /* Initialize params per bgp_damp_config. */
386 damp->reuse_index_size = REUSE_ARRAY_SIZE;
387
388 damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life)));
389
390 /* Decay-array computations */
391 damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T);
392 damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY,
393 sizeof(double) * (damp->decay_array_size));
394 damp->decay_array[0] = 1.0;
395 damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5));
396
397 /* Calculate decay values for all possible times */
398 for (i = 2; i < damp->decay_array_size; i++)
399 damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1];
400
401 /* Reuse-list computations */
402 i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1;
403 if (i > REUSE_LIST_SIZE || i == 0)
404 i = REUSE_LIST_SIZE;
405 damp->reuse_list_size = i;
406
407 damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
408 damp->reuse_list_size
409 * sizeof (struct bgp_reuse_node *));
paul718e3742002-12-13 20:15:29 +0000410
411 /* Reuse-array computations */
Stephen Hemmingerfac9c6b2010-08-05 10:26:30 -0700412 damp->reuse_index = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
paul718e3742002-12-13 20:15:29 +0000413 sizeof(int) * damp->reuse_index_size);
paul718e3742002-12-13 20:15:29 +0000414
415 reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit;
416 j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0));
417 if ( reuse_max_ratio > j && j != 0 )
418 reuse_max_ratio = j;
419
420 damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1);
421
422 for (i = 0; i < damp->reuse_index_size; i++)
423 {
424 damp->reuse_index[i] =
425 (int)(((double)damp->half_life / DELTA_REUSE)
426 * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5));
427 }
428}
429
430int
paulfd79ac92004-10-13 05:06:08 +0000431bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
432 unsigned int reuse, unsigned int suppress, time_t max)
paul718e3742002-12-13 20:15:29 +0000433{
434 if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
435 {
436 if (damp->half_life == half
437 && damp->reuse_limit == reuse
438 && damp->suppress_value == suppress
439 && damp->max_suppress_time == max)
440 return 0;
441 bgp_damp_disable (bgp, afi, safi);
442 }
443
444 SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
445 bgp_damp_parameter_set (half, reuse, suppress, max);
446
447 /* Register reuse timer. */
448 if (! damp->t_reuse)
449 damp->t_reuse =
Donald Sharp774914f2015-10-14 08:50:39 -0400450 thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE);
paul718e3742002-12-13 20:15:29 +0000451
452 return 0;
453}
454
paul94f2b392005-06-28 12:44:16 +0000455static void
paul718e3742002-12-13 20:15:29 +0000456bgp_damp_config_clean (struct bgp_damp_config *damp)
457{
458 /* Free decay array */
459 XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
460
461 /* Free reuse index array */
462 XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
463
464 /* Free reuse list array. */
465 XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
466}
467
468/* Clean all the bgp_damp_info stored in reuse_list. */
469void
paul94f2b392005-06-28 12:44:16 +0000470bgp_damp_info_clean (void)
paul718e3742002-12-13 20:15:29 +0000471{
paulfd79ac92004-10-13 05:06:08 +0000472 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000473 struct bgp_damp_info *bdi, *next;
474
475 damp->reuse_offset = 0;
476
477 for (i = 0; i < damp->reuse_list_size; i++)
478 {
479 if (! damp->reuse_list[i])
480 continue;
481
482 for (bdi = damp->reuse_list[i]; bdi; bdi = next)
483 {
484 next = bdi->next;
485 bgp_damp_info_free (bdi, 1);
486 }
487 damp->reuse_list[i] = NULL;
488 }
489
490 for (bdi = damp->no_reuse_list; bdi; bdi = next)
491 {
492 next = bdi->next;
493 bgp_damp_info_free (bdi, 1);
494 }
495 damp->no_reuse_list = NULL;
496}
497
498int
499bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi)
500{
Jorge Boncompte [DTI2]fa4094a2012-04-13 13:46:09 +0200501 /* If it wasn't enabled, there's nothing to do. */
502 if (! CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
503 return 0;
504
paul718e3742002-12-13 20:15:29 +0000505 /* Cancel reuse thread. */
506 if (damp->t_reuse )
507 thread_cancel (damp->t_reuse);
508 damp->t_reuse = NULL;
509
510 /* Clean BGP dampening information. */
511 bgp_damp_info_clean ();
512
513 /* Clear configuration */
514 bgp_damp_config_clean (&bgp_damp_cfg);
515
516 UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
517 return 0;
518}
519
Stephen Hemmingerf3019af2008-08-17 17:51:47 +0100520void
paul718e3742002-12-13 20:15:29 +0000521bgp_config_write_damp (struct vty *vty)
522{
Stephen Hemmingerf3019af2008-08-17 17:51:47 +0100523 if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60
524 && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
525 && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
526 && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
527 vty_out (vty, " bgp dampening%s", VTY_NEWLINE);
528 else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60
529 && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
530 && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
531 && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
David Lamparteref008d22015-03-03 08:48:11 +0100532 vty_out (vty, " bgp dampening %lld%s",
533 bgp_damp_cfg.half_life/60LL,
Stephen Hemmingerf3019af2008-08-17 17:51:47 +0100534 VTY_NEWLINE);
535 else
David Lamparteref008d22015-03-03 08:48:11 +0100536 vty_out (vty, " bgp dampening %lld %d %d %lld%s",
537 bgp_damp_cfg.half_life/60LL,
Stephen Hemmingerf3019af2008-08-17 17:51:47 +0100538 bgp_damp_cfg.reuse_limit,
539 bgp_damp_cfg.suppress_value,
David Lamparteref008d22015-03-03 08:48:11 +0100540 bgp_damp_cfg.max_suppress_time/60LL,
Stephen Hemmingerf3019af2008-08-17 17:51:47 +0100541 VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000542}
543
Stephen Hemmingere9dc9f22009-05-15 10:19:31 -0700544static const char *
paulfd79ac92004-10-13 05:06:08 +0000545bgp_get_reuse_time (unsigned int penalty, char *buf, size_t len)
paul718e3742002-12-13 20:15:29 +0000546{
547 time_t reuse_time = 0;
548 struct tm *tm = NULL;
549
550 if (penalty > damp->reuse_limit)
551 {
552 reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1]))));
553
554 if (reuse_time > damp->max_suppress_time)
555 reuse_time = damp->max_suppress_time;
556
557 tm = gmtime (&reuse_time);
558 }
559 else
560 reuse_time = 0;
561
562 /* Making formatted timer strings. */
563#define ONE_DAY_SECOND 60*60*24
564#define ONE_WEEK_SECOND 60*60*24*7
565 if (reuse_time == 0)
566 snprintf (buf, len, "00:00:00");
567 else if (reuse_time < ONE_DAY_SECOND)
568 snprintf (buf, len, "%02d:%02d:%02d",
569 tm->tm_hour, tm->tm_min, tm->tm_sec);
570 else if (reuse_time < ONE_WEEK_SECOND)
571 snprintf (buf, len, "%dd%02dh%02dm",
572 tm->tm_yday, tm->tm_hour, tm->tm_min);
573 else
574 snprintf (buf, len, "%02dw%dd%02dh",
575 tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
576
577 return buf;
578}
579
580void
581bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo)
582{
583 struct bgp_damp_info *bdi;
584 time_t t_now, t_diff;
585 char timebuf[BGP_UPTIME_LEN];
586 int penalty;
587
Paul Jakmafb982c22007-05-04 20:15:47 +0000588 if (!binfo->extra)
589 return;
590
paul718e3742002-12-13 20:15:29 +0000591 /* BGP dampening information. */
Paul Jakmafb982c22007-05-04 20:15:47 +0000592 bdi = binfo->extra->damp_info;
paul718e3742002-12-13 20:15:29 +0000593
594 /* If dampening is not enabled or there is no dampening information,
595 return immediately. */
596 if (! damp || ! bdi)
597 return;
598
599 /* Calculate new penalty. */
Stephen Hemminger65957882010-01-15 16:22:10 +0300600 t_now = bgp_clock ();
paul718e3742002-12-13 20:15:29 +0000601 t_diff = t_now - bdi->t_updated;
602 penalty = bgp_damp_decay (t_diff, bdi->penalty);
603
604 vty_out (vty, " Dampinfo: penalty %d, flapped %d times in %s",
605 penalty, bdi->flap,
606 peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN));
607
608 if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
609 && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
610 vty_out (vty, ", reuse in %s",
611 bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN));
612
613 vty_out (vty, "%s", VTY_NEWLINE);
614}
615
Stephen Hemmingere9dc9f22009-05-15 10:19:31 -0700616const char *
Chris Caputo50aef6f2009-06-23 06:06:49 +0000617bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo,
618 char *timebuf, size_t len)
paul718e3742002-12-13 20:15:29 +0000619{
620 struct bgp_damp_info *bdi;
621 time_t t_now, t_diff;
paul718e3742002-12-13 20:15:29 +0000622 int penalty;
Paul Jakmafb982c22007-05-04 20:15:47 +0000623
624 if (!binfo->extra)
625 return NULL;
626
paul718e3742002-12-13 20:15:29 +0000627 /* BGP dampening information. */
Paul Jakmafb982c22007-05-04 20:15:47 +0000628 bdi = binfo->extra->damp_info;
paul718e3742002-12-13 20:15:29 +0000629
630 /* If dampening is not enabled or there is no dampening information,
631 return immediately. */
632 if (! damp || ! bdi)
633 return NULL;
634
635 /* Calculate new penalty. */
Stephen Hemminger65957882010-01-15 16:22:10 +0300636 t_now = bgp_clock ();
paul718e3742002-12-13 20:15:29 +0000637 t_diff = t_now - bdi->t_updated;
638 penalty = bgp_damp_decay (t_diff, bdi->penalty);
639
Chris Caputo50aef6f2009-06-23 06:06:49 +0000640 return bgp_get_reuse_time (penalty, timebuf, len);
paul718e3742002-12-13 20:15:29 +0000641}
Balaji06bd4202015-03-16 16:55:29 +0000642
643int
644bgp_show_dampening_parameters (struct vty *vty, afi_t afi, safi_t safi)
645{
646 struct bgp *bgp;
647 bgp = bgp_get_default();
648
649 if (bgp == NULL)
650 {
651 vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
652 return CMD_WARNING;
653 }
654
655 if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
656 {
657 vty_out (vty, "Half-life time: %ld min%s",
658 damp->half_life / 60, VTY_NEWLINE);
659 vty_out (vty, "Reuse penalty: %d%s",
660 damp->reuse_limit, VTY_NEWLINE);
661 vty_out (vty, "Suppress penalty: %d%s",
662 damp->suppress_value, VTY_NEWLINE);
663 vty_out (vty, "Max suppress time: %ld min%s",
664 damp->max_suppress_time / 60, VTY_NEWLINE);
665 vty_out (vty, "Max supress penalty: %u%s",
666 damp->ceiling, VTY_NEWLINE);
667 vty_out (vty, "%s", VTY_NEWLINE);
668 }
669 else
670 vty_out (vty, "dampening not enabled for %s%s",
671 afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
672
673 return CMD_SUCCESS;
674}