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