Line data Source code
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
17 : along with GNU Zebra; see the file COPYING. If not, write to the Free
18 : Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 : 02111-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 */
38 : struct bgp_damp_config bgp_damp_cfg;
39 : static struct bgp_damp_config *damp = &bgp_damp_cfg;
40 :
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)
45 :
46 : /* Calculate reuse list index by penalty value. */
47 : static int
48 0 : bgp_reuse_index (int penalty)
49 : {
50 : unsigned int i;
51 : int index;
52 :
53 0 : i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor);
54 :
55 0 : if ( i >= damp->reuse_index_size )
56 0 : i = damp->reuse_index_size - 1;
57 :
58 0 : index = damp->reuse_index[i] - damp->reuse_index[0];
59 :
60 0 : return (damp->reuse_offset + index) % damp->reuse_list_size;
61 : }
62 :
63 : /* Add BGP dampening information to reuse list. */
64 : static void
65 0 : bgp_reuse_list_add (struct bgp_damp_info *bdi)
66 : {
67 : int index;
68 :
69 0 : index = bdi->index = bgp_reuse_index (bdi->penalty);
70 :
71 0 : bdi->prev = NULL;
72 0 : bdi->next = damp->reuse_list[index];
73 0 : if (damp->reuse_list[index])
74 0 : damp->reuse_list[index]->prev = bdi;
75 0 : damp->reuse_list[index] = bdi;
76 0 : }
77 :
78 : /* Delete BGP dampening information from reuse list. */
79 : static void
80 0 : bgp_reuse_list_delete (struct bgp_damp_info *bdi)
81 : {
82 0 : if (bdi->next)
83 0 : bdi->next->prev = bdi->prev;
84 0 : if (bdi->prev)
85 0 : bdi->prev->next = bdi->next;
86 : else
87 0 : damp->reuse_list[bdi->index] = bdi->next;
88 0 : }
89 :
90 : /* Return decayed penalty value. */
91 : int
92 0 : bgp_damp_decay (time_t tdiff, int penalty)
93 : {
94 : unsigned int i;
95 :
96 0 : i = (int) ((double) tdiff / DELTA_T);
97 :
98 0 : if (i == 0)
99 0 : return penalty;
100 :
101 0 : if (i >= damp->decay_array_size)
102 0 : return 0;
103 :
104 0 : 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. */
109 : static int
110 0 : bgp_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;
115 :
116 0 : damp->t_reuse = NULL;
117 0 : damp->t_reuse =
118 0 : thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
119 :
120 0 : t_now = bgp_clock ();
121 :
122 : /* 1. save a pointer to the current zeroth queue head and zero the
123 : list head entry. */
124 0 : bdi = damp->reuse_list[damp->reuse_offset];
125 0 : 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 0 : damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
130 :
131 : /* 3. if ( the saved list head pointer is non-empty ) */
132 0 : for (; bdi; bdi = next)
133 : {
134 0 : struct bgp *bgp = bdi->binfo->peer->bgp;
135 :
136 0 : next = bdi->next;
137 :
138 : /* Set t-diff = t-now - t-updated. */
139 0 : t_diff = t_now - bdi->t_updated;
140 :
141 : /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */
142 0 : bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
143 :
144 : /* Set t-updated = t-now. */
145 0 : bdi->t_updated = t_now;
146 :
147 : /* if (figure-of-merit < reuse). */
148 0 : if (bdi->penalty < damp->reuse_limit)
149 : {
150 : /* Reuse the route. */
151 0 : bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_DAMPED);
152 0 : bdi->suppress_time = 0;
153 :
154 0 : if (bdi->lastrecord == BGP_RECORD_UPDATE)
155 : {
156 0 : bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_HISTORY);
157 0 : bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo,
158 0 : bdi->afi, bdi->safi);
159 0 : bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi);
160 : }
161 :
162 0 : if (bdi->penalty <= damp->reuse_limit / 2.0)
163 0 : bgp_damp_info_free (bdi, 1);
164 : else
165 0 : BGP_DAMP_LIST_ADD (damp, bdi);
166 : }
167 : else
168 : /* Re-insert into another list (See RFC2439 Section 4.8.6). */
169 0 : bgp_reuse_list_add (bdi);
170 : }
171 :
172 0 : return 0;
173 : }
174 :
175 : /* A route becomes unreachable (RFC2439 Section 4.8.2). */
176 : int
177 0 : bgp_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;
181 0 : struct bgp_damp_info *bdi = NULL;
182 0 : double last_penalty = 0;
183 :
184 0 : t_now = bgp_clock ();
185 :
186 : /* Processing Unreachable Messages. */
187 0 : if (binfo->extra)
188 0 : bdi = binfo->extra->damp_info;
189 :
190 0 : 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 0 : bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info));
200 0 : bdi->binfo = binfo;
201 0 : bdi->rn = rn;
202 0 : bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
203 0 : bdi->flap = 1;
204 0 : bdi->start_time = t_now;
205 0 : bdi->suppress_time = 0;
206 0 : bdi->index = -1;
207 0 : bdi->afi = afi;
208 0 : bdi->safi = safi;
209 0 : (bgp_info_extra_get (binfo))->damp_info = bdi;
210 0 : BGP_DAMP_LIST_ADD (damp, bdi);
211 : }
212 : else
213 : {
214 0 : last_penalty = bdi->penalty;
215 :
216 : /* 1. Set t-diff = t-now - t-updated. */
217 0 : bdi->penalty =
218 0 : (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty)
219 0 : + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY));
220 :
221 0 : if (bdi->penalty > damp->ceiling)
222 0 : bdi->penalty = damp->ceiling;
223 :
224 0 : bdi->flap++;
225 : }
226 :
227 0 : assert ((rn == bdi->rn) && (binfo == bdi->binfo));
228 :
229 0 : bdi->lastrecord = BGP_RECORD_WITHDRAW;
230 0 : bdi->t_updated = t_now;
231 :
232 : /* Make this route as historical status. */
233 0 : bgp_info_set_flag (rn, binfo, BGP_INFO_HISTORY);
234 :
235 : /* Remove the route from a reuse list if it is on one. */
236 0 : if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED))
237 : {
238 : /* If decay rate isn't equal to 0, reinsert brn. */
239 0 : if (bdi->penalty != last_penalty)
240 : {
241 0 : bgp_reuse_list_delete (bdi);
242 0 : bgp_reuse_list_add (bdi);
243 : }
244 0 : return BGP_DAMP_SUPPRESSED;
245 : }
246 :
247 : /* If not suppressed before, do annonunce this withdraw and
248 : insert into reuse_list. */
249 0 : if (bdi->penalty >= damp->suppress_value)
250 : {
251 0 : bgp_info_set_flag (rn, binfo, BGP_INFO_DAMPED);
252 0 : bdi->suppress_time = t_now;
253 0 : BGP_DAMP_LIST_DEL (damp, bdi);
254 0 : bgp_reuse_list_add (bdi);
255 : }
256 :
257 0 : return BGP_DAMP_USED;
258 : }
259 :
260 : int
261 0 : bgp_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 :
268 0 : if (!binfo->extra || !((bdi = binfo->extra->damp_info)))
269 0 : return BGP_DAMP_USED;
270 :
271 0 : t_now = bgp_clock ();
272 0 : bgp_info_unset_flag (rn, binfo, BGP_INFO_HISTORY);
273 :
274 0 : bdi->lastrecord = BGP_RECORD_UPDATE;
275 0 : bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty);
276 :
277 0 : if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
278 0 : && (bdi->penalty < damp->suppress_value))
279 0 : status = BGP_DAMP_USED;
280 0 : else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
281 0 : && (bdi->penalty < damp->reuse_limit) )
282 : {
283 0 : bgp_info_unset_flag (rn, binfo, BGP_INFO_DAMPED);
284 0 : bgp_reuse_list_delete (bdi);
285 0 : BGP_DAMP_LIST_ADD (damp, bdi);
286 0 : bdi->suppress_time = 0;
287 0 : status = BGP_DAMP_USED;
288 : }
289 : else
290 0 : status = BGP_DAMP_SUPPRESSED;
291 :
292 0 : if (bdi->penalty > damp->reuse_limit / 2.0)
293 0 : bdi->t_updated = t_now;
294 : else
295 0 : bgp_damp_info_free (bdi, 0);
296 :
297 0 : return status;
298 : }
299 :
300 : /* Remove dampening information and history route. */
301 : int
302 0 : bgp_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;
306 :
307 0 : assert (binfo->extra && binfo->extra->damp_info);
308 :
309 0 : t_now = bgp_clock ();
310 0 : bdi = binfo->extra->damp_info;
311 :
312 0 : if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
313 : {
314 0 : t_diff = t_now - bdi->suppress_time;
315 :
316 0 : if (t_diff >= damp->max_suppress_time)
317 : {
318 0 : bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_DAMPED);
319 0 : bgp_reuse_list_delete (bdi);
320 0 : BGP_DAMP_LIST_ADD (damp, bdi);
321 0 : bdi->penalty = damp->reuse_limit;
322 0 : bdi->suppress_time = 0;
323 0 : bdi->t_updated = t_now;
324 :
325 : /* Need to announce UPDATE once this binfo is usable again. */
326 0 : if (bdi->lastrecord == BGP_RECORD_UPDATE)
327 0 : return 1;
328 : else
329 0 : return 0;
330 : }
331 : }
332 : else
333 : {
334 0 : t_diff = t_now - bdi->t_updated;
335 0 : bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
336 :
337 0 : if (bdi->penalty <= damp->reuse_limit / 2.0)
338 : {
339 : /* release the bdi, bdi->binfo. */
340 0 : bgp_damp_info_free (bdi, 1);
341 0 : return 0;
342 : }
343 : else
344 0 : bdi->t_updated = t_now;
345 : }
346 0 : return 0;
347 : }
348 :
349 : void
350 0 : bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw)
351 : {
352 : struct bgp_info *binfo;
353 :
354 0 : if (! bdi)
355 0 : return;
356 :
357 0 : binfo = bdi->binfo;
358 0 : binfo->extra->damp_info = NULL;
359 :
360 0 : if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
361 0 : bgp_reuse_list_delete (bdi);
362 : else
363 0 : BGP_DAMP_LIST_DEL (damp, bdi);
364 :
365 0 : bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_HISTORY|BGP_INFO_DAMPED);
366 :
367 0 : if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
368 0 : bgp_info_delete (bdi->rn, binfo);
369 :
370 0 : XFREE (MTYPE_BGP_DAMP_INFO, bdi);
371 : }
372 :
373 : static void
374 0 : bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup)
375 : {
376 : double reuse_max_ratio;
377 : unsigned int i;
378 : double j;
379 :
380 0 : damp->suppress_value = sup;
381 0 : damp->half_life = hlife;
382 0 : damp->reuse_limit = reuse;
383 0 : damp->max_suppress_time = maxsup;
384 :
385 : /* Initialize params per bgp_damp_config. */
386 0 : damp->reuse_index_size = REUSE_ARRAY_SIZE;
387 :
388 0 : damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life)));
389 :
390 : /* Decay-array computations */
391 0 : damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T);
392 0 : damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY,
393 : sizeof(double) * (damp->decay_array_size));
394 0 : damp->decay_array[0] = 1.0;
395 0 : 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 0 : for (i = 2; i < damp->decay_array_size; i++)
399 0 : damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1];
400 :
401 : /* Reuse-list computations */
402 0 : i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1;
403 0 : if (i > REUSE_LIST_SIZE || i == 0)
404 0 : i = REUSE_LIST_SIZE;
405 0 : damp->reuse_list_size = i;
406 :
407 0 : damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
408 : damp->reuse_list_size
409 : * sizeof (struct bgp_reuse_node *));
410 :
411 : /* Reuse-array computations */
412 0 : damp->reuse_index = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
413 : sizeof(int) * damp->reuse_index_size);
414 :
415 0 : reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit;
416 0 : j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0));
417 0 : if ( reuse_max_ratio > j && j != 0 )
418 0 : reuse_max_ratio = j;
419 :
420 0 : damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1);
421 :
422 0 : for (i = 0; i < damp->reuse_index_size; i++)
423 : {
424 0 : damp->reuse_index[i] =
425 0 : (int)(((double)damp->half_life / DELTA_REUSE)
426 0 : * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5));
427 : }
428 0 : }
429 :
430 : int
431 0 : bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
432 : unsigned int reuse, unsigned int suppress, time_t max)
433 : {
434 0 : if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
435 : {
436 0 : if (damp->half_life == half
437 0 : && damp->reuse_limit == reuse
438 0 : && damp->suppress_value == suppress
439 0 : && damp->max_suppress_time == max)
440 0 : return 0;
441 0 : bgp_damp_disable (bgp, afi, safi);
442 : }
443 :
444 0 : SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
445 0 : bgp_damp_parameter_set (half, reuse, suppress, max);
446 :
447 : /* Register reuse timer. */
448 0 : if (! damp->t_reuse)
449 0 : damp->t_reuse =
450 0 : thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE);
451 :
452 0 : return 0;
453 : }
454 :
455 : static void
456 0 : bgp_damp_config_clean (struct bgp_damp_config *damp)
457 : {
458 : /* Free decay array */
459 0 : XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
460 :
461 : /* Free reuse index array */
462 0 : XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
463 :
464 : /* Free reuse list array. */
465 0 : XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
466 0 : }
467 :
468 : /* Clean all the bgp_damp_info stored in reuse_list. */
469 : void
470 0 : bgp_damp_info_clean (void)
471 : {
472 : unsigned int i;
473 : struct bgp_damp_info *bdi, *next;
474 :
475 0 : damp->reuse_offset = 0;
476 :
477 0 : for (i = 0; i < damp->reuse_list_size; i++)
478 : {
479 0 : if (! damp->reuse_list[i])
480 0 : continue;
481 :
482 0 : for (bdi = damp->reuse_list[i]; bdi; bdi = next)
483 : {
484 0 : next = bdi->next;
485 0 : bgp_damp_info_free (bdi, 1);
486 : }
487 0 : damp->reuse_list[i] = NULL;
488 : }
489 :
490 0 : for (bdi = damp->no_reuse_list; bdi; bdi = next)
491 : {
492 0 : next = bdi->next;
493 0 : bgp_damp_info_free (bdi, 1);
494 : }
495 0 : damp->no_reuse_list = NULL;
496 0 : }
497 :
498 : int
499 0 : bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi)
500 : {
501 : /* If it wasn't enabled, there's nothing to do. */
502 0 : if (! CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
503 0 : return 0;
504 :
505 : /* Cancel reuse thread. */
506 0 : if (damp->t_reuse )
507 0 : thread_cancel (damp->t_reuse);
508 0 : damp->t_reuse = NULL;
509 :
510 : /* Clean BGP dampening information. */
511 0 : bgp_damp_info_clean ();
512 :
513 : /* Clear configuration */
514 0 : bgp_damp_config_clean (&bgp_damp_cfg);
515 :
516 0 : UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
517 0 : return 0;
518 : }
519 :
520 : void
521 0 : bgp_config_write_damp (struct vty *vty)
522 : {
523 0 : if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60
524 0 : && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
525 0 : && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
526 0 : && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
527 0 : vty_out (vty, " bgp dampening%s", VTY_NEWLINE);
528 0 : else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60
529 0 : && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
530 0 : && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
531 0 : && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
532 0 : vty_out (vty, " bgp dampening %ld%s",
533 0 : bgp_damp_cfg.half_life/60,
534 0 : VTY_NEWLINE);
535 : else
536 0 : vty_out (vty, " bgp dampening %ld %d %d %ld%s",
537 0 : bgp_damp_cfg.half_life/60,
538 : bgp_damp_cfg.reuse_limit,
539 : bgp_damp_cfg.suppress_value,
540 0 : bgp_damp_cfg.max_suppress_time/60,
541 0 : VTY_NEWLINE);
542 0 : }
543 :
544 : static const char *
545 0 : bgp_get_reuse_time (unsigned int penalty, char *buf, size_t len)
546 : {
547 0 : time_t reuse_time = 0;
548 0 : struct tm *tm = NULL;
549 :
550 0 : if (penalty > damp->reuse_limit)
551 : {
552 0 : reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1]))));
553 :
554 0 : if (reuse_time > damp->max_suppress_time)
555 0 : reuse_time = damp->max_suppress_time;
556 :
557 0 : tm = gmtime (&reuse_time);
558 : }
559 : else
560 0 : 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 0 : if (reuse_time == 0)
566 0 : snprintf (buf, len, "00:00:00");
567 0 : else if (reuse_time < ONE_DAY_SECOND)
568 0 : snprintf (buf, len, "%02d:%02d:%02d",
569 : tm->tm_hour, tm->tm_min, tm->tm_sec);
570 0 : else if (reuse_time < ONE_WEEK_SECOND)
571 0 : snprintf (buf, len, "%dd%02dh%02dm",
572 : tm->tm_yday, tm->tm_hour, tm->tm_min);
573 : else
574 0 : snprintf (buf, len, "%02dw%dd%02dh",
575 0 : tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
576 :
577 0 : return buf;
578 : }
579 :
580 : void
581 0 : bgp_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 :
588 0 : if (!binfo->extra)
589 0 : return;
590 :
591 : /* BGP dampening information. */
592 0 : bdi = binfo->extra->damp_info;
593 :
594 : /* If dampening is not enabled or there is no dampening information,
595 : return immediately. */
596 0 : if (! damp || ! bdi)
597 0 : return;
598 :
599 : /* Calculate new penalty. */
600 0 : t_now = bgp_clock ();
601 0 : t_diff = t_now - bdi->t_updated;
602 0 : penalty = bgp_damp_decay (t_diff, bdi->penalty);
603 :
604 0 : 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 0 : if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
609 0 : && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
610 0 : vty_out (vty, ", reuse in %s",
611 : bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN));
612 :
613 0 : vty_out (vty, "%s", VTY_NEWLINE);
614 : }
615 :
616 : const char *
617 0 : bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo,
618 : char *timebuf, size_t len)
619 : {
620 : struct bgp_damp_info *bdi;
621 : time_t t_now, t_diff;
622 : int penalty;
623 :
624 0 : if (!binfo->extra)
625 0 : return NULL;
626 :
627 : /* BGP dampening information. */
628 0 : bdi = binfo->extra->damp_info;
629 :
630 : /* If dampening is not enabled or there is no dampening information,
631 : return immediately. */
632 0 : if (! damp || ! bdi)
633 0 : return NULL;
634 :
635 : /* Calculate new penalty. */
636 0 : t_now = bgp_clock ();
637 0 : t_diff = t_now - bdi->t_updated;
638 0 : penalty = bgp_damp_decay (t_diff, bdi->penalty);
639 :
640 0 : return bgp_get_reuse_time (penalty, timebuf, len);
641 : }
|