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