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