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