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