]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_damp.c
debianpkg: Add Debian 9 Package support
[mirror_frr.git] / bgpd / bgp_damp.c
CommitLineData
718e3744 1/* 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"
3f9c7369 29#include "queue.h"
039f3a34 30#include "filter.h"
718e3744 31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_damp.h"
34#include "bgpd/bgp_table.h"
35#include "bgpd/bgp_route.h"
ac4d0be5 36#include "bgpd/bgp_attr.h"
718e3744 37#include "bgpd/bgp_advertise.h"
38
39/* Global variable to access damping configuration */
40struct bgp_damp_config bgp_damp_cfg;
e9dc9f24 41static struct bgp_damp_config *damp = &bgp_damp_cfg;
718e3744 42
43/* Utility macro to add and delete BGP dampening information to no
44 used list. */
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)
6b0655a2 47
718e3744 48/* Calculate reuse list index by penalty value. */
ac4d0be5 49static int bgp_reuse_index(int penalty)
718e3744 50{
ac4d0be5 51 unsigned int i;
52 int index;
718e3744 53
ac4d0be5 54 i = (int)(((double)penalty / damp->reuse_limit - 1.0)
55 * damp->scale_factor);
718e3744 56
ac4d0be5 57 if (i >= damp->reuse_index_size)
58 i = damp->reuse_index_size - 1;
718e3744 59
ac4d0be5 60 index = damp->reuse_index[i] - damp->reuse_index[0];
61
62 return (damp->reuse_offset + index) % damp->reuse_list_size;
718e3744 63}
64
65/* Add BGP dampening information to reuse list. */
ac4d0be5 66static void bgp_reuse_list_add(struct bgp_damp_info *bdi)
718e3744 67{
ac4d0be5 68 int index;
718e3744 69
ac4d0be5 70 index = bdi->index = bgp_reuse_index(bdi->penalty);
718e3744 71
ac4d0be5 72 bdi->prev = NULL;
73 bdi->next = damp->reuse_list[index];
74 if (damp->reuse_list[index])
75 damp->reuse_list[index]->prev = bdi;
76 damp->reuse_list[index] = bdi;
718e3744 77}
78
79/* Delete BGP dampening information from reuse list. */
ac4d0be5 80static void bgp_reuse_list_delete(struct bgp_damp_info *bdi)
718e3744 81{
ac4d0be5 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}
6b0655a2 89
718e3744 90/* Return decayed penalty value. */
ac4d0be5 91int bgp_damp_decay(time_t tdiff, int penalty)
718e3744 92{
ac4d0be5 93 unsigned int i;
94
95 i = (int)((double)tdiff / DELTA_T);
718e3744 96
ac4d0be5 97 if (i == 0)
98 return penalty;
718e3744 99
ac4d0be5 100 if (i >= damp->decay_array_size)
101 return 0;
718e3744 102
ac4d0be5 103 return (int)(penalty * damp->decay_array[i]);
718e3744 104}
105
106/* Handler of reuse timer event. Each route in the current reuse-list
107 is evaluated. RFC2439 Section 4.8.7. */
ac4d0be5 108static int bgp_reuse_timer(struct thread *t)
718e3744 109{
ac4d0be5 110 struct bgp_damp_info *bdi;
111 struct bgp_damp_info *next;
112 time_t t_now, t_diff;
113
114 damp->t_reuse = NULL;
115 damp->t_reuse = thread_add_timer(bm->master, bgp_reuse_timer, NULL,
116 DELTA_REUSE);
117
118 t_now = bgp_clock();
119
120 /* 1. save a pointer to the current zeroth queue head and zero the
121 list head entry. */
122 bdi = damp->reuse_list[damp->reuse_offset];
123 damp->reuse_list[damp->reuse_offset] = NULL;
124
125 /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
126 rotating the circular queue of list-heads. */
127 damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
128
129 /* 3. if ( the saved list head pointer is non-empty ) */
130 for (; bdi; bdi = next) {
131 struct bgp *bgp = bdi->binfo->peer->bgp;
132
133 next = bdi->next;
134
135 /* Set t-diff = t-now - t-updated. */
136 t_diff = t_now - bdi->t_updated;
137
138 /* Set figure-of-merit = figure-of-merit * decay-array-ok
139 * [t-diff] */
140 bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty);
141
142 /* Set t-updated = t-now. */
143 bdi->t_updated = t_now;
144
145 /* if (figure-of-merit < reuse). */
146 if (bdi->penalty < damp->reuse_limit) {
147 /* Reuse the route. */
148 bgp_info_unset_flag(bdi->rn, bdi->binfo,
149 BGP_INFO_DAMPED);
150 bdi->suppress_time = 0;
151
152 if (bdi->lastrecord == BGP_RECORD_UPDATE) {
153 bgp_info_unset_flag(bdi->rn, bdi->binfo,
154 BGP_INFO_HISTORY);
155 bgp_aggregate_increment(bgp, &bdi->rn->p,
156 bdi->binfo, bdi->afi,
157 bdi->safi);
158 bgp_process(bgp, bdi->rn, bdi->afi, bdi->safi);
159 }
160
161 if (bdi->penalty <= damp->reuse_limit / 2.0)
162 bgp_damp_info_free(bdi, 1);
163 else
164 BGP_DAMP_LIST_ADD(damp, bdi);
165 } else
166 /* Re-insert into another list (See RFC2439 Section
167 * 4.8.6). */
168 bgp_reuse_list_add(bdi);
718e3744 169 }
718e3744 170
ac4d0be5 171 return 0;
718e3744 172}
173
174/* A route becomes unreachable (RFC2439 Section 4.8.2). */
ac4d0be5 175int bgp_damp_withdraw(struct bgp_info *binfo, struct bgp_node *rn, afi_t afi,
176 safi_t safi, int attr_change)
718e3744 177{
ac4d0be5 178 time_t t_now;
179 struct bgp_damp_info *bdi = NULL;
180 double last_penalty = 0;
181
182 t_now = bgp_clock();
183
184 /* Processing Unreachable Messages. */
185 if (binfo->extra)
186 bdi = binfo->extra->damp_info;
187
188 if (bdi == NULL) {
189 /* If there is no previous stability history. */
190
191 /* RFC2439 said:
192 1. allocate a damping structure.
193 2. set figure-of-merit = 1.
194 3. withdraw the route. */
195
196 bdi = XCALLOC(MTYPE_BGP_DAMP_INFO,
197 sizeof(struct bgp_damp_info));
198 bdi->binfo = binfo;
199 bdi->rn = rn;
200 bdi->penalty =
201 (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
202 bdi->flap = 1;
203 bdi->start_time = t_now;
204 bdi->suppress_time = 0;
205 bdi->index = -1;
206 bdi->afi = afi;
207 bdi->safi = safi;
208 (bgp_info_extra_get(binfo))->damp_info = bdi;
209 BGP_DAMP_LIST_ADD(damp, bdi);
210 } else {
211 last_penalty = bdi->penalty;
212
213 /* 1. Set t-diff = t-now - t-updated. */
214 bdi->penalty =
215 (bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty)
216 + (attr_change ? DEFAULT_PENALTY / 2
217 : DEFAULT_PENALTY));
218
219 if (bdi->penalty > damp->ceiling)
220 bdi->penalty = damp->ceiling;
221
222 bdi->flap++;
223 }
224
225 assert((rn == bdi->rn) && (binfo == bdi->binfo));
226
227 bdi->lastrecord = BGP_RECORD_WITHDRAW;
228 bdi->t_updated = t_now;
229
230 /* Make this route as historical status. */
231 bgp_info_set_flag(rn, binfo, BGP_INFO_HISTORY);
232
233 /* Remove the route from a reuse list if it is on one. */
234 if (CHECK_FLAG(bdi->binfo->flags, BGP_INFO_DAMPED)) {
235 /* If decay rate isn't equal to 0, reinsert brn. */
236 if (bdi->penalty != last_penalty) {
237 bgp_reuse_list_delete(bdi);
238 bgp_reuse_list_add(bdi);
239 }
240 return BGP_DAMP_SUPPRESSED;
718e3744 241 }
ac4d0be5 242
243 /* If not suppressed before, do annonunce this withdraw and
244 insert into reuse_list. */
245 if (bdi->penalty >= damp->suppress_value) {
246 bgp_info_set_flag(rn, binfo, BGP_INFO_DAMPED);
247 bdi->suppress_time = t_now;
248 BGP_DAMP_LIST_DEL(damp, bdi);
249 bgp_reuse_list_add(bdi);
250 }
251
252 return BGP_DAMP_USED;
718e3744 253}
254
ac4d0be5 255int bgp_damp_update(struct bgp_info *binfo, struct bgp_node *rn, afi_t afi,
256 safi_t safi)
718e3744 257{
ac4d0be5 258 time_t t_now;
259 struct bgp_damp_info *bdi;
260 int status;
261
262 if (!binfo->extra || !((bdi = binfo->extra->damp_info)))
263 return BGP_DAMP_USED;
264
265 t_now = bgp_clock();
266 bgp_info_unset_flag(rn, binfo, BGP_INFO_HISTORY);
267
268 bdi->lastrecord = BGP_RECORD_UPDATE;
269 bdi->penalty = bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty);
270
271 if (!CHECK_FLAG(bdi->binfo->flags, BGP_INFO_DAMPED)
272 && (bdi->penalty < damp->suppress_value))
273 status = BGP_DAMP_USED;
274 else if (CHECK_FLAG(bdi->binfo->flags, BGP_INFO_DAMPED)
275 && (bdi->penalty < damp->reuse_limit)) {
276 bgp_info_unset_flag(rn, binfo, BGP_INFO_DAMPED);
277 bgp_reuse_list_delete(bdi);
278 BGP_DAMP_LIST_ADD(damp, bdi);
279 bdi->suppress_time = 0;
280 status = BGP_DAMP_USED;
281 } else
282 status = BGP_DAMP_SUPPRESSED;
283
284 if (bdi->penalty > damp->reuse_limit / 2.0)
285 bdi->t_updated = t_now;
286 else
287 bgp_damp_info_free(bdi, 0);
288
289 return status;
718e3744 290}
291
292/* Remove dampening information and history route. */
ac4d0be5 293int bgp_damp_scan(struct bgp_info *binfo, afi_t afi, safi_t safi)
718e3744 294{
ac4d0be5 295 time_t t_now, t_diff;
296 struct bgp_damp_info *bdi;
297
298 assert(binfo->extra && binfo->extra->damp_info);
299
300 t_now = bgp_clock();
301 bdi = binfo->extra->damp_info;
302
303 if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED)) {
304 t_diff = t_now - bdi->suppress_time;
305
306 if (t_diff >= damp->max_suppress_time) {
307 bgp_info_unset_flag(bdi->rn, binfo, BGP_INFO_DAMPED);
308 bgp_reuse_list_delete(bdi);
309 BGP_DAMP_LIST_ADD(damp, bdi);
310 bdi->penalty = damp->reuse_limit;
311 bdi->suppress_time = 0;
312 bdi->t_updated = t_now;
313
314 /* Need to announce UPDATE once this binfo is usable
315 * again. */
316 if (bdi->lastrecord == BGP_RECORD_UPDATE)
317 return 1;
318 else
319 return 0;
320 }
321 } else {
322 t_diff = t_now - bdi->t_updated;
323 bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty);
324
325 if (bdi->penalty <= damp->reuse_limit / 2.0) {
326 /* release the bdi, bdi->binfo. */
327 bgp_damp_info_free(bdi, 1);
328 return 0;
329 } else
330 bdi->t_updated = t_now;
331 }
332 return 0;
718e3744 333}
334
ac4d0be5 335void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw)
718e3744 336{
ac4d0be5 337 struct bgp_info *binfo;
338
339 if (!bdi)
340 return;
718e3744 341
ac4d0be5 342 binfo = bdi->binfo;
343 binfo->extra->damp_info = NULL;
718e3744 344
ac4d0be5 345 if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED))
346 bgp_reuse_list_delete(bdi);
347 else
348 BGP_DAMP_LIST_DEL(damp, bdi);
718e3744 349
ac4d0be5 350 bgp_info_unset_flag(bdi->rn, binfo, BGP_INFO_HISTORY | BGP_INFO_DAMPED);
718e3744 351
ac4d0be5 352 if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
353 bgp_info_delete(bdi->rn, binfo);
718e3744 354
ac4d0be5 355 XFREE(MTYPE_BGP_DAMP_INFO, bdi);
718e3744 356}
357
ac4d0be5 358static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup)
718e3744 359{
ac4d0be5 360 double reuse_max_ratio;
361 unsigned int i;
362 double j;
363
364 damp->suppress_value = sup;
365 damp->half_life = hlife;
366 damp->reuse_limit = reuse;
367 damp->max_suppress_time = maxsup;
368
369 /* Initialize params per bgp_damp_config. */
370 damp->reuse_index_size = REUSE_ARRAY_SIZE;
371
372 damp->ceiling =
373 (int)(damp->reuse_limit * (pow(2,
374 (double)damp->max_suppress_time
375 / damp->half_life)));
376
377 /* Decay-array computations */
378 damp->decay_array_size =
379 ceil((double)damp->max_suppress_time / DELTA_T);
380 damp->decay_array = XMALLOC(MTYPE_BGP_DAMP_ARRAY,
381 sizeof(double) * (damp->decay_array_size));
382 damp->decay_array[0] = 1.0;
383 damp->decay_array[1] =
384 exp((1.0 / ((double)damp->half_life / DELTA_T)) * log(0.5));
385
386 /* Calculate decay values for all possible times */
387 for (i = 2; i < damp->decay_array_size; i++)
388 damp->decay_array[i] =
389 damp->decay_array[i - 1] * damp->decay_array[1];
390
391 /* Reuse-list computations */
392 i = ceil((double)damp->max_suppress_time / DELTA_REUSE) + 1;
393 if (i > REUSE_LIST_SIZE || i == 0)
394 i = REUSE_LIST_SIZE;
395 damp->reuse_list_size = i;
396
397 damp->reuse_list = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
398 damp->reuse_list_size
399 * sizeof(struct bgp_reuse_node *));
400
401 /* Reuse-array computations */
402 damp->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
403 sizeof(int) * damp->reuse_index_size);
404
405 reuse_max_ratio = (double)damp->ceiling / damp->reuse_limit;
406 j = (exp((double)damp->max_suppress_time / damp->half_life)
407 * log10(2.0));
408 if (reuse_max_ratio > j && j != 0)
409 reuse_max_ratio = j;
410
411 damp->scale_factor =
412 (double)damp->reuse_index_size / (reuse_max_ratio - 1);
413
414 for (i = 0; i < damp->reuse_index_size; i++) {
415 damp->reuse_index[i] =
416 (int)(((double)damp->half_life / DELTA_REUSE)
417 * log10(1.0 / (damp->reuse_limit
418 * (1.0 + ((double)i
419 / damp->scale_factor))))
420 / log10(0.5));
421 }
718e3744 422}
423
ac4d0be5 424int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
425 unsigned int reuse, unsigned int suppress, time_t max)
718e3744 426{
ac4d0be5 427 if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
428 if (damp->half_life == half && damp->reuse_limit == reuse
429 && damp->suppress_value == suppress
430 && damp->max_suppress_time == max)
431 return 0;
432 bgp_damp_disable(bgp, afi, safi);
433 }
718e3744 434
ac4d0be5 435 SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
436 bgp_damp_parameter_set(half, reuse, suppress, max);
718e3744 437
ac4d0be5 438 /* Register reuse timer. */
439 if (!damp->t_reuse)
440 damp->t_reuse = thread_add_timer(bm->master, bgp_reuse_timer,
441 NULL, DELTA_REUSE);
718e3744 442
ac4d0be5 443 return 0;
718e3744 444}
445
ac4d0be5 446static void bgp_damp_config_clean(struct bgp_damp_config *damp)
718e3744 447{
ac4d0be5 448 /* Free decay array */
449 XFREE(MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
718e3744 450
ac4d0be5 451 /* Free reuse index array */
452 XFREE(MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
718e3744 453
ac4d0be5 454 /* Free reuse list array. */
455 XFREE(MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
718e3744 456}
457
458/* Clean all the bgp_damp_info stored in reuse_list. */
ac4d0be5 459void bgp_damp_info_clean(void)
718e3744 460{
ac4d0be5 461 unsigned int i;
462 struct bgp_damp_info *bdi, *next;
718e3744 463
ac4d0be5 464 damp->reuse_offset = 0;
718e3744 465
ac4d0be5 466 for (i = 0; i < damp->reuse_list_size; i++) {
467 if (!damp->reuse_list[i])
468 continue;
718e3744 469
ac4d0be5 470 for (bdi = damp->reuse_list[i]; bdi; bdi = next) {
471 next = bdi->next;
472 bgp_damp_info_free(bdi, 1);
473 }
474 damp->reuse_list[i] = NULL;
718e3744 475 }
ac4d0be5 476
477 for (bdi = damp->no_reuse_list; bdi; bdi = next) {
478 next = bdi->next;
479 bgp_damp_info_free(bdi, 1);
480 }
481 damp->no_reuse_list = NULL;
718e3744 482}
483
ac4d0be5 484int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
718e3744 485{
ac4d0be5 486 /* If it wasn't enabled, there's nothing to do. */
487 if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
488 return 0;
fa4094ac 489
ac4d0be5 490 /* Cancel reuse thread. */
491 if (damp->t_reuse)
492 thread_cancel(damp->t_reuse);
493 damp->t_reuse = NULL;
718e3744 494
ac4d0be5 495 /* Clean BGP dampening information. */
496 bgp_damp_info_clean();
718e3744 497
ac4d0be5 498 /* Clear configuration */
499 bgp_damp_config_clean(&bgp_damp_cfg);
718e3744 500
ac4d0be5 501 UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
502 return 0;
718e3744 503}
504
ac4d0be5 505void bgp_config_write_damp(struct vty *vty)
718e3744 506{
ac4d0be5 507 if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE * 60
508 && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
509 && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
510 && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life * 4)
511 vty_out(vty, " bgp dampening%s", VTY_NEWLINE);
512 else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE * 60
513 && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
514 && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
515 && bgp_damp_cfg.max_suppress_time
516 == bgp_damp_cfg.half_life * 4)
517 vty_out(vty, " bgp dampening %lld%s",
518 bgp_damp_cfg.half_life / 60LL, VTY_NEWLINE);
519 else
520 vty_out(vty, " bgp dampening %lld %d %d %lld%s",
521 bgp_damp_cfg.half_life / 60LL, bgp_damp_cfg.reuse_limit,
522 bgp_damp_cfg.suppress_value,
523 bgp_damp_cfg.max_suppress_time / 60LL, VTY_NEWLINE);
718e3744 524}
525
ac4d0be5 526static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
527 size_t len, u_char use_json,
528 json_object *json)
718e3744 529{
ac4d0be5 530 time_t reuse_time = 0;
531 struct tm *tm = NULL;
532 int time_store = 0;
718e3744 533
ac4d0be5 534 if (penalty > damp->reuse_limit) {
535 reuse_time = (int)(DELTA_T
536 * ((log((double)damp->reuse_limit / penalty))
537 / (log(damp->decay_array[1]))));
718e3744 538
ac4d0be5 539 if (reuse_time > damp->max_suppress_time)
540 reuse_time = damp->max_suppress_time;
718e3744 541
ac4d0be5 542 tm = gmtime(&reuse_time);
543 } else
544 reuse_time = 0;
718e3744 545
ac4d0be5 546/* Making formatted timer strings. */
718e3744 547#define ONE_DAY_SECOND 60*60*24
548#define ONE_WEEK_SECOND 60*60*24*7
ac4d0be5 549 if (reuse_time == 0) {
550 if (use_json)
551 json_object_int_add(json, "reuseTimerMsecs", 0);
552 else
553 snprintf(buf, len, "00:00:00");
554 } else if (reuse_time < ONE_DAY_SECOND) {
555 if (use_json) {
556 time_store = (3600000 * tm->tm_hour)
557 + (60000 * tm->tm_min)
558 + (1000 * tm->tm_sec);
559 json_object_int_add(json, "reuseTimerMsecs",
560 time_store);
561 } else
562 snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour,
563 tm->tm_min, tm->tm_sec);
564 } else if (reuse_time < ONE_WEEK_SECOND) {
565 if (use_json) {
566 time_store = (86400000 * tm->tm_yday)
567 + (3600000 * tm->tm_hour)
568 + (60000 * tm->tm_min)
569 + (1000 * tm->tm_sec);
570 json_object_int_add(json, "reuseTimerMsecs",
571 time_store);
572 } else
573 snprintf(buf, len, "%dd%02dh%02dm", tm->tm_yday,
574 tm->tm_hour, tm->tm_min);
575 } else {
576 if (use_json) {
577 time_store =
578 (604800000 * tm->tm_yday / 7)
579 + (86400000
580 * (tm->tm_yday - ((tm->tm_yday / 7) * 7)))
581 + (3600000 * tm->tm_hour) + (60000 * tm->tm_min)
582 + (1000 * tm->tm_sec);
583 json_object_int_add(json, "reuseTimerMsecs",
584 time_store);
585 } else
586 snprintf(buf, len, "%02dw%dd%02dh", tm->tm_yday / 7,
587 tm->tm_yday - ((tm->tm_yday / 7) * 7),
588 tm->tm_hour);
589 }
590
591 return buf;
718e3744 592}
ac4d0be5 593
594void bgp_damp_info_vty(struct vty *vty, struct bgp_info *binfo,
595 json_object *json_path)
718e3744 596{
ac4d0be5 597 struct bgp_damp_info *bdi;
598 time_t t_now, t_diff;
599 char timebuf[BGP_UPTIME_LEN];
600 int penalty;
601
602 if (!binfo->extra)
603 return;
604
605 /* BGP dampening information. */
606 bdi = binfo->extra->damp_info;
607
608 /* If dampening is not enabled or there is no dampening information,
609 return immediately. */
610 if (!damp || !bdi)
611 return;
612
613 /* Calculate new penalty. */
614 t_now = bgp_clock();
615 t_diff = t_now - bdi->t_updated;
616 penalty = bgp_damp_decay(t_diff, bdi->penalty);
617
618 if (json_path) {
619 json_object_int_add(json_path, "dampeningPenalty", penalty);
620 json_object_int_add(json_path, "dampeningFlapCount", bdi->flap);
621 peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 1,
622 json_path);
623
624 if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED)
625 && !CHECK_FLAG(binfo->flags, BGP_INFO_HISTORY))
626 bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN, 1,
627 json_path);
628 } else {
629 vty_out(vty,
630 " Dampinfo: penalty %d, flapped %d times in %s",
631 penalty, bdi->flap,
632 peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 0,
633 json_path));
634
635 if (CHECK_FLAG(binfo->flags, BGP_INFO_DAMPED)
636 && !CHECK_FLAG(binfo->flags, BGP_INFO_HISTORY))
637 vty_out(vty, ", reuse in %s",
638 bgp_get_reuse_time(penalty, timebuf,
639 BGP_UPTIME_LEN, 0,
640 json_path));
641
642 vty_out(vty, "%s", VTY_NEWLINE);
643 }
718e3744 644}
645
ac4d0be5 646const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_info *binfo,
647 char *timebuf, size_t len, u_char use_json,
648 json_object *json)
718e3744 649{
ac4d0be5 650 struct bgp_damp_info *bdi;
651 time_t t_now, t_diff;
652 int penalty;
653
654 if (!binfo->extra)
655 return NULL;
656
657 /* BGP dampening information. */
658 bdi = binfo->extra->damp_info;
659
660 /* If dampening is not enabled or there is no dampening information,
661 return immediately. */
662 if (!damp || !bdi)
663 return NULL;
664
665 /* Calculate new penalty. */
666 t_now = bgp_clock();
667 t_diff = t_now - bdi->t_updated;
668 penalty = bgp_damp_decay(t_diff, bdi->penalty);
669
670 return bgp_get_reuse_time(penalty, timebuf, len, use_json, json);
718e3744 671}
9914e022 672
ac4d0be5 673int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi)
9914e022 674{
ac4d0be5 675 struct bgp *bgp;
676 bgp = bgp_get_default();
677
678 if (bgp == NULL) {
679 vty_out(vty, "No BGP process is configured%s", VTY_NEWLINE);
680 return CMD_WARNING;
681 }
682
683 if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
684 vty_out(vty, "Half-life time: %lld min%s",
685 (long long)damp->half_life / 60, VTY_NEWLINE);
686 vty_out(vty, "Reuse penalty: %d%s", damp->reuse_limit,
687 VTY_NEWLINE);
688 vty_out(vty, "Suppress penalty: %d%s", damp->suppress_value,
689 VTY_NEWLINE);
690 vty_out(vty, "Max suppress time: %lld min%s",
691 (long long)damp->max_suppress_time / 60, VTY_NEWLINE);
692 vty_out(vty, "Max supress penalty: %u%s", damp->ceiling,
693 VTY_NEWLINE);
694 vty_out(vty, "%s", VTY_NEWLINE);
695 } else
696 vty_out(vty, "dampening not enabled for %s%s",
697 afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
698
699 return CMD_SUCCESS;
9914e022 700}