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