Coverage Report

Created: 2026-01-13 06:56

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