]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_damp.c
bgpd: add counter of displayed show bgp summary when filtering
[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
40ec3340
DS
40static void bgp_reuselist_add(struct reuselist *list,
41 struct bgp_damp_info *info)
42{
43 struct reuselist_node *new_node;
44
45 assert(info);
46 new_node = XCALLOC(MTYPE_BGP_DAMP_REUSELIST, sizeof(*new_node));
47 new_node->info = info;
48 SLIST_INSERT_HEAD(list, new_node, entry);
49}
50
51static void bgp_reuselist_del(struct reuselist *list,
52 struct reuselist_node **node)
53{
54 if ((*node) == NULL)
55 return;
56 assert(list && node && *node);
57 SLIST_REMOVE(list, (*node), reuselist_node, entry);
58 XFREE(MTYPE_BGP_DAMP_REUSELIST, (*node));
59 *node = NULL;
60}
718e3744 61
40ec3340
DS
62static void bgp_reuselist_switch(struct reuselist *source,
63 struct reuselist_node *node,
64 struct reuselist *target)
65{
66 assert(source && target && node);
67 SLIST_REMOVE(source, node, reuselist_node, entry);
68 SLIST_INSERT_HEAD(target, node, entry);
69}
70
71static void bgp_reuselist_free(struct reuselist *list)
72{
73 struct reuselist_node *rn;
74
75 assert(list);
76 while ((rn = SLIST_FIRST(list)) != NULL)
77 bgp_reuselist_del(list, &rn);
78}
79
80static struct reuselist_node *bgp_reuselist_find(struct reuselist *list,
81 struct bgp_damp_info *info)
82{
83 struct reuselist_node *rn;
84
85 assert(list && info);
86 SLIST_FOREACH (rn, list, entry) {
87 if (rn->info == info)
88 return rn;
89 }
90 return NULL;
91}
92
93static void bgp_damp_info_unclaim(struct bgp_damp_info *bdi)
94{
95 struct reuselist_node *node;
96
97 assert(bdi && bdi->config);
98 if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX) {
99 node = bgp_reuselist_find(&bdi->config->no_reuse_list, bdi);
100 if (node)
101 bgp_reuselist_del(&bdi->config->no_reuse_list, &node);
102 } else {
103 node = bgp_reuselist_find(&bdi->config->reuse_list[bdi->index],
104 bdi);
105 if (node)
106 bgp_reuselist_del(&bdi->config->reuse_list[bdi->index],
107 &node);
108 }
109 bdi->config = NULL;
110}
111
112static void bgp_damp_info_claim(struct bgp_damp_info *bdi,
113 struct bgp_damp_config *bdc)
114{
115 assert(bdc && bdi);
116 if (bdi->config == NULL) {
117 bdi->config = bdc;
118 return;
119 }
120 bgp_damp_info_unclaim(bdi);
121 bdi->config = bdc;
122 bdi->afi = bdc->afi;
123 bdi->safi = bdc->safi;
124}
125
126struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi,
127 afi_t afi, safi_t safi)
128{
129 if (!pi)
130 return NULL;
131 if (CHECK_FLAG(pi->peer->af_flags[afi][safi],
132 PEER_FLAG_CONFIG_DAMPENING))
133 return &pi->peer->damp[afi][safi];
134 if (peer_group_active(pi->peer))
135 if (CHECK_FLAG(pi->peer->group->conf->af_flags[afi][safi],
136 PEER_FLAG_CONFIG_DAMPENING))
137 return &pi->peer->group->conf->damp[afi][safi];
138 if (CHECK_FLAG(pi->peer->bgp->af_flags[afi][safi],
139 BGP_CONFIG_DAMPENING))
140 return &pi->peer->bgp->damp[afi][safi];
141 return NULL;
142}
6b0655a2 143
718e3744 144/* Calculate reuse list index by penalty value. */
a935f597 145static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
718e3744 146{
d62a17ae 147 unsigned int i;
40ec3340 148 unsigned int index;
718e3744 149
3ec5c500
DA
150 /*
151 * reuse_limit can't be zero, this is for Coverity
152 * to bypass division by zero test.
153 */
154 assert(bdc->reuse_limit);
155
a935f597
DA
156 i = (int)(((double)penalty / bdc->reuse_limit - 1.0)
157 * bdc->scale_factor);
718e3744 158
a935f597
DA
159 if (i >= bdc->reuse_index_size)
160 i = bdc->reuse_index_size - 1;
718e3744 161
a935f597 162 index = bdc->reuse_index[i] - bdc->reuse_index[0];
d62a17ae 163
a935f597 164 return (bdc->reuse_offset + index) % bdc->reuse_list_size;
718e3744 165}
166
167/* Add BGP dampening information to reuse list. */
a935f597
DA
168static void bgp_reuse_list_add(struct bgp_damp_info *bdi,
169 struct bgp_damp_config *bdc)
718e3744 170{
40ec3340
DS
171 bgp_damp_info_claim(bdi, bdc);
172 bdi->index = bgp_reuse_index(bdi->penalty, bdc);
173 bgp_reuselist_add(&bdc->reuse_list[bdi->index], bdi);
718e3744 174}
175
176/* Delete BGP dampening information from reuse list. */
a935f597
DA
177static void bgp_reuse_list_delete(struct bgp_damp_info *bdi,
178 struct bgp_damp_config *bdc)
718e3744 179{
40ec3340
DS
180 struct reuselist *list;
181 struct reuselist_node *rn;
182
183 list = &bdc->reuse_list[bdi->index];
184 rn = bgp_reuselist_find(list, bdi);
185 bgp_damp_info_unclaim(bdi);
186 bgp_reuselist_del(list, &rn);
187}
188
189static void bgp_no_reuse_list_add(struct bgp_damp_info *bdi,
190 struct bgp_damp_config *bdc)
191{
192 bgp_damp_info_claim(bdi, bdc);
193 bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
194 bgp_reuselist_add(&bdc->no_reuse_list, bdi);
195}
196
197static void bgp_no_reuse_list_delete(struct bgp_damp_info *bdi,
198 struct bgp_damp_config *bdc)
199{
200 struct reuselist_node *rn;
201
202 assert(bdc && bdi);
203 if (bdi->config == NULL) {
204 bgp_damp_info_unclaim(bdi);
205 return;
206 }
207 bdi->config = NULL;
208 rn = bgp_reuselist_find(&bdc->no_reuse_list, bdi);
209 bgp_reuselist_del(&bdc->no_reuse_list, &rn);
d62a17ae 210}
6b0655a2 211
718e3744 212/* Return decayed penalty value. */
a935f597 213int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc)
718e3744 214{
d62a17ae 215 unsigned int i;
216
217 i = (int)((double)tdiff / DELTA_T);
718e3744 218
d62a17ae 219 if (i == 0)
220 return penalty;
718e3744 221
a935f597 222 if (i >= bdc->decay_array_size)
d62a17ae 223 return 0;
718e3744 224
a935f597 225 return (int)(penalty * bdc->decay_array[i]);
718e3744 226}
227
228/* Handler of reuse timer event. Each route in the current reuse-list
229 is evaluated. RFC2439 Section 4.8.7. */
d62a17ae 230static int bgp_reuse_timer(struct thread *t)
718e3744 231{
40ec3340 232 struct bgp_damp_config *bdc = THREAD_ARG(t);
d62a17ae 233 struct bgp_damp_info *bdi;
40ec3340
DS
234 struct reuselist plist;
235 struct reuselist_node *node;
236 struct bgp *bgp;
d62a17ae 237 time_t t_now, t_diff;
238
a935f597
DA
239 thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
240 &bdc->t_reuse);
d62a17ae 241
242 t_now = bgp_clock();
243
40ec3340
DS
244 /* 1. save a pointer to the current queue head and zero the list head
245 * list head entry. */
246 assert(bdc->reuse_offset < bdc->reuse_list_size);
247 plist = bdc->reuse_list[bdc->reuse_offset];
248 node = SLIST_FIRST(&plist);
249 SLIST_INIT(&bdc->reuse_list[bdc->reuse_offset]);
d62a17ae 250
251 /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
252 rotating the circular queue of list-heads. */
a935f597 253 bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size;
40ec3340 254 assert(bdc->reuse_offset < bdc->reuse_list_size);
d62a17ae 255
256 /* 3. if ( the saved list head pointer is non-empty ) */
40ec3340
DS
257 while ((node = SLIST_FIRST(&plist)) != NULL) {
258 bdi = node->info;
259 bgp = bdi->path->peer->bgp;
d62a17ae 260
261 /* Set t-diff = t-now - t-updated. */
262 t_diff = t_now - bdi->t_updated;
263
264 /* Set figure-of-merit = figure-of-merit * decay-array-ok
265 * [t-diff] */
a935f597 266 bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
d62a17ae 267
268 /* Set t-updated = t-now. */
269 bdi->t_updated = t_now;
270
271 /* if (figure-of-merit < reuse). */
a935f597 272 if (bdi->penalty < bdc->reuse_limit) {
d62a17ae 273 /* Reuse the route. */
9bcb3eef 274 bgp_path_info_unset_flag(bdi->dest, bdi->path,
18ee8310 275 BGP_PATH_DAMPED);
d62a17ae 276 bdi->suppress_time = 0;
277
278 if (bdi->lastrecord == BGP_RECORD_UPDATE) {
9bcb3eef 279 bgp_path_info_unset_flag(bdi->dest, bdi->path,
18ee8310 280 BGP_PATH_HISTORY);
b54892e0 281 bgp_aggregate_increment(
9bcb3eef 282 bgp, bgp_dest_get_prefix(bdi->dest),
b54892e0 283 bdi->path, bdi->afi, bdi->safi);
9bcb3eef
DS
284 bgp_process(bgp, bdi->dest, bdi->afi,
285 bdi->safi);
d62a17ae 286 }
287
40ec3340
DS
288 if (bdi->penalty <= bdc->reuse_limit / 2.0) {
289 bgp_damp_info_free(&bdi, bdc, 1, bdi->afi,
290 bdi->safi);
291 bgp_reuselist_del(&plist, &node);
292 } else {
293 node->info->index =
294 BGP_DAMP_NO_REUSE_LIST_INDEX;
295 bgp_reuselist_switch(&plist, node,
296 &bdc->no_reuse_list);
297 }
298 } else {
d62a17ae 299 /* Re-insert into another list (See RFC2439 Section
300 * 4.8.6). */
40ec3340
DS
301 bdi->index = bgp_reuse_index(bdi->penalty, bdc);
302 bgp_reuselist_switch(&plist, node,
303 &bdc->reuse_list[bdi->index]);
304 }
718e3744 305 }
718e3744 306
40ec3340
DS
307 assert(SLIST_EMPTY(&plist));
308
d62a17ae 309 return 0;
718e3744 310}
311
312/* A route becomes unreachable (RFC2439 Section 4.8.2). */
9bcb3eef 313int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
4b7e6066 314 afi_t afi, safi_t safi, int attr_change)
718e3744 315{
d62a17ae 316 time_t t_now;
317 struct bgp_damp_info *bdi = NULL;
3cf7af1d 318 unsigned int last_penalty = 0;
40ec3340 319 struct bgp_damp_config *bdc;
d62a17ae 320
40ec3340
DS
321 bdc = get_active_bdc_from_pi(path, afi, safi);
322 if (!bdc)
323 return BGP_DAMP_USED;
d62a17ae 324
40ec3340 325 t_now = bgp_clock();
d62a17ae 326 /* Processing Unreachable Messages. */
9b6d8fcf
DS
327 if (path->extra)
328 bdi = path->extra->damp_info;
d62a17ae 329
330 if (bdi == NULL) {
331 /* If there is no previous stability history. */
332
333 /* RFC2439 said:
334 1. allocate a damping structure.
335 2. set figure-of-merit = 1.
336 3. withdraw the route. */
337
338 bdi = XCALLOC(MTYPE_BGP_DAMP_INFO,
339 sizeof(struct bgp_damp_info));
9b6d8fcf 340 bdi->path = path;
9bcb3eef 341 bdi->dest = dest;
d62a17ae 342 bdi->penalty =
343 (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
344 bdi->flap = 1;
345 bdi->start_time = t_now;
346 bdi->suppress_time = 0;
40ec3340 347 bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
d62a17ae 348 bdi->afi = afi;
349 bdi->safi = safi;
9b6d8fcf 350 (bgp_path_info_extra_get(path))->damp_info = bdi;
40ec3340 351 bgp_no_reuse_list_add(bdi, bdc);
d62a17ae 352 } else {
40ec3340 353 bgp_damp_info_claim(bdi, bdc);
d62a17ae 354 last_penalty = bdi->penalty;
355
356 /* 1. Set t-diff = t-now - t-updated. */
a935f597
DA
357 bdi->penalty = (bgp_damp_decay(t_now - bdi->t_updated,
358 bdi->penalty, bdc)
359 + (attr_change ? DEFAULT_PENALTY / 2
360 : DEFAULT_PENALTY));
d62a17ae 361
a935f597
DA
362 if (bdi->penalty > bdc->ceiling)
363 bdi->penalty = bdc->ceiling;
d62a17ae 364
365 bdi->flap++;
366 }
367
9bcb3eef 368 assert((dest == bdi->dest) && (path == bdi->path));
d62a17ae 369
370 bdi->lastrecord = BGP_RECORD_WITHDRAW;
371 bdi->t_updated = t_now;
372
373 /* Make this route as historical status. */
9bcb3eef 374 bgp_path_info_set_flag(dest, path, BGP_PATH_HISTORY);
d62a17ae 375
376 /* Remove the route from a reuse list if it is on one. */
9b6d8fcf 377 if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) {
d62a17ae 378 /* If decay rate isn't equal to 0, reinsert brn. */
40ec3340 379 if (bdi->penalty != last_penalty) {
a935f597
DA
380 bgp_reuse_list_delete(bdi, bdc);
381 bgp_reuse_list_add(bdi, bdc);
d62a17ae 382 }
383 return BGP_DAMP_SUPPRESSED;
718e3744 384 }
d62a17ae 385
386 /* If not suppressed before, do annonunce this withdraw and
387 insert into reuse_list. */
a935f597 388 if (bdi->penalty >= bdc->suppress_value) {
9bcb3eef 389 bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED);
d62a17ae 390 bdi->suppress_time = t_now;
40ec3340 391 bgp_no_reuse_list_delete(bdi, bdc);
a935f597 392 bgp_reuse_list_add(bdi, bdc);
d62a17ae 393 }
d62a17ae 394 return BGP_DAMP_USED;
718e3744 395}
396
9bcb3eef
DS
397int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
398 afi_t afi, safi_t safi)
718e3744 399{
d62a17ae 400 time_t t_now;
401 struct bgp_damp_info *bdi;
402 int status;
40ec3340
DS
403 struct bgp_damp_config *bdc;
404
405 bdc = get_active_bdc_from_pi(path, afi, safi);
406 assert(bdc);
d62a17ae 407
9b6d8fcf 408 if (!path->extra || !((bdi = path->extra->damp_info)))
d62a17ae 409 return BGP_DAMP_USED;
410
411 t_now = bgp_clock();
9bcb3eef 412 bgp_path_info_unset_flag(dest, path, BGP_PATH_HISTORY);
d62a17ae 413
414 bdi->lastrecord = BGP_RECORD_UPDATE;
a935f597
DA
415 bdi->penalty =
416 bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty, bdc);
d62a17ae 417
9b6d8fcf 418 if (!CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
a935f597 419 && (bdi->penalty < bdc->suppress_value))
d62a17ae 420 status = BGP_DAMP_USED;
9b6d8fcf 421 else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
a935f597 422 && (bdi->penalty < bdc->reuse_limit)) {
9bcb3eef 423 bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED);
a935f597 424 bgp_reuse_list_delete(bdi, bdc);
40ec3340 425 bgp_no_reuse_list_add(bdi, bdc);
d62a17ae 426 bdi->suppress_time = 0;
427 status = BGP_DAMP_USED;
428 } else
429 status = BGP_DAMP_SUPPRESSED;
430
a935f597 431 if (bdi->penalty > bdc->reuse_limit / 2.0)
d62a17ae 432 bdi->t_updated = t_now;
40ec3340
DS
433 else {
434 bgp_damp_info_unclaim(bdi);
435 bgp_damp_info_free(&bdi, bdc, 0, afi, safi);
436 }
d62a17ae 437
438 return status;
718e3744 439}
440
40ec3340
DS
441void bgp_damp_info_free(struct bgp_damp_info **bdi, struct bgp_damp_config *bdc,
442 int withdraw, afi_t afi, safi_t safi)
718e3744 443{
40ec3340 444 assert(bdc && bdi && *bdi);
d62a17ae 445
40ec3340
DS
446 if ((*bdi)->path == NULL) {
447 XFREE(MTYPE_BGP_DAMP_INFO, (*bdi));
d62a17ae 448 return;
40ec3340 449 }
718e3744 450
40ec3340
DS
451 (*bdi)->path->extra->damp_info = NULL;
452 bgp_path_info_unset_flag((*bdi)->dest, (*bdi)->path,
18ee8310 453 BGP_PATH_HISTORY | BGP_PATH_DAMPED);
40ec3340
DS
454 if ((*bdi)->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
455 bgp_path_info_delete((*bdi)->dest, (*bdi)->path);
718e3744 456}
457
a935f597
DA
458static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup,
459 struct bgp_damp_config *bdc)
718e3744 460{
d62a17ae 461 double reuse_max_ratio;
462 unsigned int i;
463 double j;
464
a935f597
DA
465 bdc->suppress_value = sup;
466 bdc->half_life = hlife;
467 bdc->reuse_limit = reuse;
468 bdc->max_suppress_time = maxsup;
d62a17ae 469
470 /* Initialize params per bgp_damp_config. */
a935f597 471 bdc->reuse_index_size = REUSE_ARRAY_SIZE;
d62a17ae 472
a935f597
DA
473 bdc->ceiling = (int)(bdc->reuse_limit
474 * (pow(2, (double)bdc->max_suppress_time
475 / bdc->half_life)));
d62a17ae 476
477 /* Decay-array computations */
a935f597
DA
478 bdc->decay_array_size = ceil((double)bdc->max_suppress_time / DELTA_T);
479 bdc->decay_array = XMALLOC(MTYPE_BGP_DAMP_ARRAY,
480 sizeof(double) * (bdc->decay_array_size));
481 bdc->decay_array[0] = 1.0;
482 bdc->decay_array[1] =
483 exp((1.0 / ((double)bdc->half_life / DELTA_T)) * log(0.5));
d62a17ae 484
485 /* Calculate decay values for all possible times */
a935f597
DA
486 for (i = 2; i < bdc->decay_array_size; i++)
487 bdc->decay_array[i] =
488 bdc->decay_array[i - 1] * bdc->decay_array[1];
d62a17ae 489
490 /* Reuse-list computations */
a935f597 491 i = ceil((double)bdc->max_suppress_time / DELTA_REUSE) + 1;
d62a17ae 492 if (i > REUSE_LIST_SIZE || i == 0)
493 i = REUSE_LIST_SIZE;
a935f597 494 bdc->reuse_list_size = i;
d62a17ae 495
a935f597
DA
496 bdc->reuse_list =
497 XCALLOC(MTYPE_BGP_DAMP_ARRAY,
40ec3340 498 bdc->reuse_list_size * sizeof(struct reuselist));
d62a17ae 499 /* Reuse-array computations */
a935f597
DA
500 bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
501 sizeof(int) * bdc->reuse_index_size);
d62a17ae 502
a935f597
DA
503 reuse_max_ratio = (double)bdc->ceiling / bdc->reuse_limit;
504 j = (exp((double)bdc->max_suppress_time / bdc->half_life) * log10(2.0));
d62a17ae 505 if (reuse_max_ratio > j && j != 0)
506 reuse_max_ratio = j;
507
a935f597
DA
508 bdc->scale_factor =
509 (double)bdc->reuse_index_size / (reuse_max_ratio - 1);
d62a17ae 510
a935f597
DA
511 for (i = 0; i < bdc->reuse_index_size; i++) {
512 bdc->reuse_index[i] =
513 (int)(((double)bdc->half_life / DELTA_REUSE)
514 * log10(1.0
515 / (bdc->reuse_limit
516 * (1.0
517 + ((double)i / bdc->scale_factor))))
d62a17ae 518 / log10(0.5));
519 }
718e3744 520}
521
d62a17ae 522int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
523 unsigned int reuse, unsigned int suppress, time_t max)
718e3744 524{
40ec3340 525 struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
a935f597 526
d62a17ae 527 if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
a935f597
DA
528 if (bdc->half_life == half && bdc->reuse_limit == reuse
529 && bdc->suppress_value == suppress
530 && bdc->max_suppress_time == max)
d62a17ae 531 return 0;
532 bgp_damp_disable(bgp, afi, safi);
533 }
718e3744 534
d62a17ae 535 SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
a935f597 536 bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
40ec3340
DS
537 bdc->afi = afi;
538 bdc->safi = safi;
718e3744 539
d62a17ae 540 /* Register reuse timer. */
a935f597
DA
541 thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
542 &bdc->t_reuse);
718e3744 543
d62a17ae 544 return 0;
718e3744 545}
546
40ec3340 547/* Clean all the bgp_damp_info stored in reuse_list and no_reuse_list. */
c8ddbd48 548void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc,
549 afi_t afi, safi_t safi)
718e3744 550{
40ec3340
DS
551 struct bgp_damp_info *bdi;
552 struct reuselist_node *rn;
553 struct reuselist *list;
554 unsigned int i;
555
556 bdc->reuse_offset = 0;
557 for (i = 0; i < bdc->reuse_list_size; ++i) {
558 list = &bdc->reuse_list[i];
559 while ((rn = SLIST_FIRST(list)) != NULL) {
560 bdi = rn->info;
c8ddbd48 561 if (bdi->lastrecord == BGP_RECORD_UPDATE) {
562 bgp_aggregate_increment(bgp, &bdi->dest->p,
563 bdi->path, bdi->afi,
564 bdi->safi);
565 bgp_process(bgp, bdi->dest, bdi->afi,
566 bdi->safi);
567 }
40ec3340
DS
568 bgp_reuselist_del(list, &rn);
569 bgp_damp_info_free(&bdi, bdc, 1, afi, safi);
570 }
571 }
572
573 while ((rn = SLIST_FIRST(&bdc->no_reuse_list)) != NULL) {
574 bdi = rn->info;
575 bgp_reuselist_del(&bdc->no_reuse_list, &rn);
576 bgp_damp_info_free(&bdi, bdc, 1, afi, safi);
577 }
578
d62a17ae 579 /* Free decay array */
a935f597
DA
580 XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
581 bdc->decay_array_size = 0;
718e3744 582
d62a17ae 583 /* Free reuse index array */
a935f597
DA
584 XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index);
585 bdc->reuse_index_size = 0;
718e3744 586
d62a17ae 587 /* Free reuse list array. */
40ec3340
DS
588 for (i = 0; i < bdc->reuse_list_size; ++i)
589 bgp_reuselist_free(&bdc->reuse_list[i]);
590
a935f597
DA
591 XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
592 bdc->reuse_list_size = 0;
d62a17ae 593
40ec3340 594 THREAD_OFF(bdc->t_reuse);
718e3744 595}
596
40ec3340
DS
597/* Disable route flap dampening for a bgp instance.
598 *
599 * Please note that this function also gets used to free memory when deleting a
600 * bgp instance.
601 */
d62a17ae 602int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
718e3744 603{
40ec3340
DS
604 struct bgp_damp_config *bdc;
605
606 bdc = &bgp->damp[afi][safi];
607 if (!bdc)
608 return 0;
609
d62a17ae 610 /* If it wasn't enabled, there's nothing to do. */
611 if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
612 return 0;
fa4094ac 613
b3d6bc6e 614 /* Cancel reuse event. */
40ec3340 615 thread_cancel(&bdc->t_reuse);
718e3744 616
d62a17ae 617 /* Clean BGP dampening information. */
c8ddbd48 618 bgp_damp_info_clean(bgp, bdc, afi, safi);
718e3744 619
d62a17ae 620 UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
40ec3340 621
d62a17ae 622 return 0;
718e3744 623}
624
40ec3340
DS
625void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
626 safi_t safi)
718e3744 627{
40ec3340
DS
628 struct bgp_damp_config *bdc;
629
630 bdc = &bgp->damp[afi][safi];
631 if (bdc->half_life == DEFAULT_HALF_LIFE * 60
632 && bdc->reuse_limit == DEFAULT_REUSE
633 && bdc->suppress_value == DEFAULT_SUPPRESS
634 && bdc->max_suppress_time == bdc->half_life * 4)
a935f597 635 vty_out(vty, " bgp dampening\n");
40ec3340
DS
636 else if (bdc->half_life != DEFAULT_HALF_LIFE * 60
637 && bdc->reuse_limit == DEFAULT_REUSE
638 && bdc->suppress_value == DEFAULT_SUPPRESS
639 && bdc->max_suppress_time == bdc->half_life * 4)
640 vty_out(vty, " bgp dampening %lld\n", bdc->half_life / 60LL);
d62a17ae 641 else
a935f597 642 vty_out(vty, " bgp dampening %lld %d %d %lld\n",
40ec3340
DS
643 bdc->half_life / 60LL, bdc->reuse_limit,
644 bdc->suppress_value, bdc->max_suppress_time / 60LL);
718e3744 645}
646
40ec3340
DS
647static const char *bgp_get_reuse_time(struct bgp_damp_config *bdc,
648 unsigned int penalty, char *buf,
649 size_t len, bool use_json,
650 json_object *json)
718e3744 651{
d62a17ae 652 time_t reuse_time = 0;
a2700b50 653 struct tm tm;
d62a17ae 654 int time_store = 0;
718e3744 655
40ec3340 656 if (penalty > bdc->reuse_limit) {
d62a17ae 657 reuse_time = (int)(DELTA_T
40ec3340
DS
658 * ((log((double)bdc->reuse_limit / penalty))
659 / (log(bdc->decay_array[1]))));
718e3744 660
40ec3340
DS
661 if (reuse_time > bdc->max_suppress_time)
662 reuse_time = bdc->max_suppress_time;
718e3744 663
a2700b50 664 gmtime_r(&reuse_time, &tm);
d62a17ae 665 } else
666 reuse_time = 0;
718e3744 667
996c9314 668 /* Making formatted timer strings. */
d62a17ae 669 if (reuse_time == 0) {
670 if (use_json)
671 json_object_int_add(json, "reuseTimerMsecs", 0);
672 else
673 snprintf(buf, len, "00:00:00");
674 } else if (reuse_time < ONE_DAY_SECOND) {
675 if (use_json) {
a2700b50
MS
676 time_store = (3600000 * tm.tm_hour)
677 + (60000 * tm.tm_min)
678 + (1000 * tm.tm_sec);
d62a17ae 679 json_object_int_add(json, "reuseTimerMsecs",
680 time_store);
681 } else
a2700b50
MS
682 snprintf(buf, len, "%02d:%02d:%02d", tm.tm_hour,
683 tm.tm_min, tm.tm_sec);
d62a17ae 684 } else if (reuse_time < ONE_WEEK_SECOND) {
685 if (use_json) {
a2700b50
MS
686 time_store = (86400000 * tm.tm_yday)
687 + (3600000 * tm.tm_hour)
688 + (60000 * tm.tm_min)
689 + (1000 * tm.tm_sec);
d62a17ae 690 json_object_int_add(json, "reuseTimerMsecs",
691 time_store);
692 } else
a2700b50
MS
693 snprintf(buf, len, "%dd%02dh%02dm", tm.tm_yday,
694 tm.tm_hour, tm.tm_min);
d62a17ae 695 } else {
696 if (use_json) {
697 time_store =
a2700b50 698 (604800000 * tm.tm_yday / 7)
d62a17ae 699 + (86400000
a2700b50
MS
700 * (tm.tm_yday - ((tm.tm_yday / 7) * 7)))
701 + (3600000 * tm.tm_hour) + (60000 * tm.tm_min)
702 + (1000 * tm.tm_sec);
d62a17ae 703 json_object_int_add(json, "reuseTimerMsecs",
704 time_store);
705 } else
a2700b50
MS
706 snprintf(buf, len, "%02dw%dd%02dh", tm.tm_yday / 7,
707 tm.tm_yday - ((tm.tm_yday / 7) * 7),
708 tm.tm_hour);
d62a17ae 709 }
710
711 return buf;
718e3744 712}
d62a17ae 713
40ec3340
DS
714void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp,
715 struct bgp_path_info *path, afi_t afi, safi_t safi,
716 json_object *json_path)
718e3744 717{
d62a17ae 718 struct bgp_damp_info *bdi;
719 time_t t_now, t_diff;
720 char timebuf[BGP_UPTIME_LEN];
721 int penalty;
40ec3340 722 struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
d62a17ae 723
9b6d8fcf 724 if (!path->extra)
d62a17ae 725 return;
726
727 /* BGP dampening information. */
9b6d8fcf 728 bdi = path->extra->damp_info;
d62a17ae 729
730 /* If dampening is not enabled or there is no dampening information,
731 return immediately. */
a935f597 732 if (!bdc || !bdi)
d62a17ae 733 return;
734
735 /* Calculate new penalty. */
736 t_now = bgp_clock();
737 t_diff = t_now - bdi->t_updated;
a935f597 738 penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
d62a17ae 739
740 if (json_path) {
741 json_object_int_add(json_path, "dampeningPenalty", penalty);
742 json_object_int_add(json_path, "dampeningFlapCount", bdi->flap);
743 peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 1,
744 json_path);
745
9b6d8fcf
DS
746 if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
747 && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
40ec3340
DS
748 bgp_get_reuse_time(bdc, penalty, timebuf,
749 BGP_UPTIME_LEN, 1, json_path);
d62a17ae 750 } else {
751 vty_out(vty,
752 " Dampinfo: penalty %d, flapped %d times in %s",
753 penalty, bdi->flap,
754 peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 0,
755 json_path));
756
9b6d8fcf
DS
757 if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
758 && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
d62a17ae 759 vty_out(vty, ", reuse in %s",
40ec3340
DS
760 bgp_get_reuse_time(bdc, penalty, timebuf,
761 BGP_UPTIME_LEN, 0,
d62a17ae 762 json_path));
763
764 vty_out(vty, "\n");
765 }
718e3744 766}
767
40ec3340 768
9b6d8fcf 769const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
a935f597
DA
770 char *timebuf, size_t len, afi_t afi,
771 safi_t safi, bool use_json,
d62a17ae 772 json_object *json)
718e3744 773{
d62a17ae 774 struct bgp_damp_info *bdi;
775 time_t t_now, t_diff;
776 int penalty;
40ec3340
DS
777 struct bgp_damp_config *bdc;
778
779 bdc = get_active_bdc_from_pi(path, afi, safi);
780 if (!bdc)
781 return NULL;
d62a17ae 782
9b6d8fcf 783 if (!path->extra)
d62a17ae 784 return NULL;
785
786 /* BGP dampening information. */
9b6d8fcf 787 bdi = path->extra->damp_info;
d62a17ae 788
789 /* If dampening is not enabled or there is no dampening information,
790 return immediately. */
a935f597 791 if (!bdc || !bdi)
d62a17ae 792 return NULL;
793
794 /* Calculate new penalty. */
795 t_now = bgp_clock();
796 t_diff = t_now - bdi->t_updated;
a935f597 797 penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
d62a17ae 798
40ec3340 799 return bgp_get_reuse_time(bdc, penalty, timebuf, len, use_json, json);
718e3744 800}
9914e022 801
40ec3340 802
96f3485c
MK
803static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
804 afi_t afi, safi_t safi)
9914e022 805{
40ec3340 806 struct bgp_damp_config *bdc;
d62a17ae 807 if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
40ec3340 808 bdc = &bgp->damp[afi][safi];
d62a17ae 809 vty_out(vty, "Half-life time: %lld min\n",
40ec3340
DS
810 (long long)bdc->half_life / 60);
811 vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit);
812 vty_out(vty, "Suppress penalty: %d\n", bdc->suppress_value);
d62a17ae 813 vty_out(vty, "Max suppress time: %lld min\n",
40ec3340
DS
814 (long long)bdc->max_suppress_time / 60);
815 vty_out(vty, "Max suppress penalty: %u\n", bdc->ceiling);
d62a17ae 816 vty_out(vty, "\n");
817 } else
818 vty_out(vty, "dampening not enabled for %s\n",
96f3485c
MK
819 get_afi_safi_str(afi, safi, false));
820
821 return CMD_SUCCESS;
822}
823
824int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
825 uint8_t show_flags)
826{
827 struct bgp *bgp;
96f3485c 828
40ec3340 829 bgp = bgp_get_default();
96f3485c
MK
830 if (bgp == NULL) {
831 vty_out(vty, "No BGP process is configured\n");
832 return CMD_WARNING;
833 }
834
835 if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL))
836 return bgp_print_dampening_parameters(bgp, vty, afi, safi);
837
838 if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP)
839 || CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6)) {
840 afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) ? AFI_IP
841 : AFI_IP6;
842 FOREACH_SAFI (safi) {
843 if (strmatch(get_afi_safi_str(afi, safi, true),
844 "Unknown"))
845 continue;
d62a17ae 846
96f3485c
MK
847 if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON))
848 vty_out(vty, "\nFor address family: %s\n\n",
849 get_afi_safi_str(afi, safi, false));
850
851 bgp_print_dampening_parameters(bgp, vty, afi, safi);
852 }
853 } else {
854 FOREACH_AFI_SAFI (afi, safi) {
855 if (strmatch(get_afi_safi_str(afi, safi, true),
856 "Unknown"))
857 continue;
858
859 if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON))
860 vty_out(vty, "\nFor address family: %s\n",
861 get_afi_safi_str(afi, safi, false));
862
863 bgp_print_dampening_parameters(bgp, vty, afi, safi);
864 }
865 }
d62a17ae 866 return CMD_SUCCESS;
9914e022 867}
40ec3340
DS
868
869void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi,
870 time_t half, unsigned int reuse,
871 unsigned int suppress, time_t max)
872{
873 struct bgp_damp_config *bdc;
874
875 if (!peer)
876 return;
877 bdc = &peer->damp[afi][safi];
878 if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING)) {
879 if (bdc->half_life == half && bdc->reuse_limit == reuse
880 && bdc->suppress_value == suppress
881 && bdc->max_suppress_time == max)
882 return;
883 bgp_peer_damp_disable(peer, afi, safi);
884 }
885 SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
886 bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
887 bdc->afi = afi;
888 bdc->safi = safi;
889 thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
890 &bdc->t_reuse);
891}
892
893/* Disable route flap dampening for a peer.
894 *
895 * Please note that this function also gets used to free memory when deleting a
896 * peer or peer group.
897 */
898void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi)
899{
900 struct bgp_damp_config *bdc;
901
902 if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING))
903 return;
904 bdc = &peer->damp[afi][safi];
905 if (!bdc)
906 return;
c8ddbd48 907 bgp_damp_info_clean(peer->bgp, bdc, afi, safi);
40ec3340
DS
908 UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
909}
910
911void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer, afi_t afi,
912 safi_t safi)
913{
914 struct bgp_damp_config *bdc;
915
916 bdc = &peer->damp[afi][safi];
917 if (bdc->half_life == DEFAULT_HALF_LIFE * 60
918 && bdc->reuse_limit == DEFAULT_REUSE
919 && bdc->suppress_value == DEFAULT_SUPPRESS
920 && bdc->max_suppress_time == bdc->half_life * 4)
921 vty_out(vty, " neighbor %s dampening\n", peer->host);
922 else if (bdc->half_life != DEFAULT_HALF_LIFE * 60
923 && bdc->reuse_limit == DEFAULT_REUSE
924 && bdc->suppress_value == DEFAULT_SUPPRESS
925 && bdc->max_suppress_time == bdc->half_life * 4)
926 vty_out(vty, " neighbor %s dampening %lld\n", peer->host,
927 bdc->half_life / 60LL);
928 else
929 vty_out(vty, " neighbor %s dampening %lld %d %d %lld\n",
930 peer->host, bdc->half_life / 60LL, bdc->reuse_limit,
931 bdc->suppress_value, bdc->max_suppress_time / 60LL);
932}
933
934static void bgp_print_peer_dampening_parameters(struct vty *vty,
935 struct peer *peer, afi_t afi,
936 safi_t safi, bool use_json,
937 json_object *json)
938{
939 struct bgp_damp_config *bdc;
940
941 if (!peer)
942 return;
943 if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING)) {
944 bdc = &peer->damp[afi][safi];
945 if (!bdc)
946 return;
947 if (use_json) {
948 json_object_int_add(json, "halfLifeSecs",
949 bdc->half_life);
950 json_object_int_add(json, "reusePenalty",
951 bdc->reuse_limit);
952 json_object_int_add(json, "suppressPenalty",
953 bdc->suppress_value);
954 json_object_int_add(json, "maxSuppressTimeSecs",
955 bdc->max_suppress_time);
956 json_object_int_add(json, "maxSuppressPenalty",
957 bdc->ceiling);
958 } else {
959 vty_out(vty, "Half-life time: %lld min\n",
960 (long long)bdc->half_life / 60);
961 vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit);
962 vty_out(vty, "Suppress penalty: %d\n",
963 bdc->suppress_value);
964 vty_out(vty, "Max suppress time: %lld min\n",
965 (long long)bdc->max_suppress_time / 60);
966 vty_out(vty, "Max suppress penalty: %u\n",
967 bdc->ceiling);
968 vty_out(vty, "\n");
969 }
970 } else if (!use_json)
971 vty_out(vty, "neighbor dampening not enabled for %s\n",
972 get_afi_safi_str(afi, safi, false));
973}
974
975void bgp_show_peer_dampening_parameters(struct vty *vty, struct peer *peer,
976 afi_t afi, safi_t safi, bool use_json)
977{
978 json_object *json;
979
980 if (use_json) {
981 json = json_object_new_object();
982 json_object_string_add(json, "addressFamily",
983 get_afi_safi_str(afi, safi, false));
984 bgp_print_peer_dampening_parameters(vty, peer, afi, safi, true,
985 json);
986 vty_out(vty, "%s\n",
987 json_object_to_json_string_ext(
988 json, JSON_C_TO_STRING_PRETTY));
989 json_object_free(json);
990 } else {
991 vty_out(vty, "\nFor address family: %s\n",
992 get_afi_safi_str(afi, safi, false));
993 bgp_print_peer_dampening_parameters(vty, peer, afi, safi, false,
994 NULL);
995 }
996}