2 * Copyright (C) 2001 IP Infusion Inc.
4 * This file is part of GNU Zebra.
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
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.
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
36 #include "sockunion.h"
40 #include "bgpd/bgp_damp.h"
41 #include "bgpd/bgpd.h"
42 #include "bgpd/bgp_route.h"
44 /* Time granularity for reuse lists */
45 #define DELTA_REUSE 15
46 /* Time granularity for decay arrays */
49 #define DEFAULT_PENALTY 1000
51 #define DEFAULT_HARF_LIFE 15
52 #define DEFAULT_REUSE 750
53 #define DEFAULT_SUPPRESS 2000
54 #define REUSE_LIST_SIZE 256
55 #define REUSE_ARRAY_SIZE 1024
57 /* Global variable to access damping configuration */
58 struct bgp_damp_config bgp_damp_cfg
;
59 int reuse_array_offset
= 0;
60 struct thread
*bgp_reuse_thread
= NULL
;
61 struct bgp_damp_config
*prev_bgp_damp_cfg
= NULL
;
63 int bgp_reuse_timer(struct thread
*);
64 void bgp_damp_clear_config(struct bgp_damp_config
*);
65 void bgp_damp_clear_reuse_list();
68 bgp_damp_init(struct vty
*vty
, int hlife
, int reuse
, int sup
, int maxsup
)
70 double reuse_max_ratio
;
72 struct bgp_damp_config
*bdc
;
75 hlife
= DEFAULT_HARF_LIFE
* 60;
80 reuse
= DEFAULT_REUSE
;
81 sup
= DEFAULT_SUPPRESS
;
85 /* Clear previous configuration if any */
86 if (prev_bgp_damp_cfg
)
87 bgp_damp_clear_config (&bgp_damp_cfg
);
89 prev_bgp_damp_cfg
= bdc
= &bgp_damp_cfg
;
90 bdc
->suppress_value
= sup
;
91 bdc
->half_life
= hlife
;
92 bdc
->reuse_limit
= reuse
;
93 bdc
->max_suppress_time
= maxsup
;
95 /* Initialize system-wide params */
96 bdc
->reuse_list_size
= REUSE_LIST_SIZE
;
97 bdc
->reuse_index_array_size
= REUSE_ARRAY_SIZE
;
99 bdc
->ceiling
= (int)(bdc
->reuse_limit
*
100 exp((double) (bdc
->max_suppress_time
/bdc
->half_life
)) * log(2.0));
102 /* Decay-array computations */
103 bdc
->decay_array_size
= ceil ((double)bdc
->max_suppress_time
/DELTA_T
);
104 bdc
->decay_array
= XMALLOC (MTYPE_BGP_DAMP_ARRAY
,
105 sizeof(double) * (bdc
->decay_array_size
));
106 bdc
->decay_array
[0] = 1.0;
107 bdc
->decay_array
[1] = exp ((1.0/(bdc
->half_life
/DELTA_T
)) * log(0.5));
109 /* Calculate decay values for all possible times */
110 for (i
= 2; i
< bdc
->decay_array_size
; i
++)
111 bdc
->decay_array
[i
] = bdc
->decay_array
[i
-1] * bdc
->decay_array
[1];
113 /* Reuse-list computations */
114 bdc
->reuse_list_array
= XMALLOC (MTYPE_BGP_DAMP_ARRAY
, bdc
->reuse_list_size
* sizeof (struct bgp_reuse_list
*));
115 memset (bdc
->reuse_list_array
, 0x00, bdc
->reuse_list_size
* sizeof (struct bgp_reuse_list
*));
117 /* Reuse-array computations */
118 bdc
->reuse_index_array
= XMALLOC (MTYPE_BGP_DAMP_ARRAY
,
119 sizeof(int) * bdc
->reuse_index_array_size
);
120 reuse_max_ratio
= bdc
->ceiling
/bdc
->reuse_limit
;
121 i
= (int)exp((1.0/((double)bdc
->half_life
/(bdc
->reuse_list_size
*DELTA_REUSE
))) * log(2.0));
122 if ( reuse_max_ratio
> i
&& i
!= 0 )
125 bdc
->scale_factor
= ceil((double)bdc
->reuse_index_array_size
/(reuse_max_ratio
- 1));
127 for (i
= 0; i
< bdc
->reuse_index_array_size
; i
++)
129 bdc
->reuse_index_array
[i
] =
130 ceil( (bdc
->half_life
/DELTA_REUSE
)
131 * log(1.0/(bdc
->reuse_limit
* ( 1.0 + ((double)i
/bdc
->scale_factor
)))) / log(0.5) );
138 bgp_damp_get_decay(time_t tdiff
)
141 struct bgp_damp_config
*bdc
;
146 if (i
>= bdc
->decay_array_size
)
149 return bdc
->decay_array
[i
];
153 bgp_get_reuse_index(int penalty
)
156 struct bgp_damp_config
*bdc
;
159 i
= (int)(((double)penalty
/ bdc
->reuse_limit
- 1.0) * bdc
->scale_factor
);
161 if ( i
>= bdc
->reuse_index_array_size
)
162 i
= bdc
->reuse_index_array_size
- 1;
163 return (bdc
->reuse_index_array
[i
]);
167 bgp_reuse_list_insert(struct bgp_damp_info
*bdi
)
170 struct bgp_damp_config
*bdc
;
171 static int first_time_insert
= 1;
173 if (first_time_insert
)
175 /* Kick off reuse timer */
177 = thread_add_timer (master
, bgp_reuse_timer
, NULL
, DELTA_REUSE
);
178 first_time_insert
= 0;
183 index
= (reuse_array_offset
+ bgp_get_reuse_index(bdi
->penalty
)) % bdc
->reuse_list_size
;
184 bdi
->reuse_next
= bdc
->reuse_list_array
[index
];
185 bdc
->reuse_list_array
[index
] = bdi
;
190 /* bgp_reuse_timer is called every DELTA_REUSE seconds.
191 * Each route in the current reuse-list is evaluated and is used or requeued
194 bgp_reuse_timer(struct thread
*t
)
196 struct bgp_damp_info
*bdi
, *tbdi
;
197 struct bgp_damp_config
*bdc
;
198 time_t t_now
, t_diff
;
200 /* Restart the reuse timer */
201 bgp_reuse_thread
= thread_add_timer(master
, bgp_reuse_timer
,
204 /* zlog(NULL, LOG_INFO, "DAMP:reuse timer:offset: %d", reuse_array_offset); */
207 bdi
= bdc
->reuse_list_array
[reuse_array_offset
];
208 bdc
->reuse_list_array
[reuse_array_offset
] = NULL
;
209 reuse_array_offset
= (reuse_array_offset
+ 1 ) % bdc
->reuse_list_size
;
213 tbdi
= bdi
->reuse_next
;
214 bdi
->reuse_next
= NULL
;
215 t_diff
= t_now
- bdi
->t_updated
;
216 bdi
->t_updated
= t_now
;
218 if (bdi
->bgp_info
== NULL
)
223 = (int)((double)bdi
->penalty
* bgp_damp_get_decay(t_diff
));
225 /* zlog(NULL, LOG_INFO, "DAMP:reuse timer: updated penalty: %d", bdi->penalty); */
227 if ( bdi
->penalty
<= bdc
->reuse_limit
/2 )
229 UNSET_FLAG (bdi
->bgp_info
->flags
, BGP_INFO_DAMPED
);
230 bdi
->bgp_info
->bgp_damp_info
= NULL
;
233 else if ( bdi
->penalty
< bdc
->reuse_limit
)
234 UNSET_FLAG (bdi
->bgp_info
->flags
, BGP_INFO_DAMPED
);
236 bgp_reuse_list_insert(bdi
);
246 bgp_damp_withdraw(struct bgp_info
*bgp_info
)
249 struct bgp_damp_info
*bdi
;
250 struct bgp_damp_config
*bdc
;
256 return BGP_DAMP_DISABLED
;
258 SET_FLAG (bgp_info
->flags
, BGP_INFO_HISTORY
);
261 bdi
= bgp_info
->bgp_damp_info
;
263 status
= BGP_DAMP_CONTINUE
;
267 bdi
= XMALLOC (MTYPE_BGP_DAMP_INFO
, sizeof (struct bgp_damp_info
));
268 memset (bdi
, 0, sizeof (struct bgp_damp_info
));
269 bgp_info
->bgp_damp_info
= bdi
;
270 bdi
->penalty
= DEFAULT_PENALTY
;
272 bdi
->start_time
= t_now
;
273 bdi
->bgp_info
= bgp_info
;
277 bdi
->penalty
= (int)(bdi
->penalty
* bgp_damp_get_decay(t_now
- bdi
->t_updated
)) + DEFAULT_PENALTY
;
279 if (bdi
->penalty
> bdc
->ceiling
)
280 bdi
->penalty
= bdc
->ceiling
;
283 /* If the penalty is greater than suppress value or the route is damped,
284 * no need to send withdraw to peers.
286 if (CHECK_FLAG (bdi
->bgp_info
->flags
, BGP_INFO_DAMPED
))
287 status
= BGP_DAMP_DISCONTINUE
;
288 else if (bdi
->penalty
>= bdc
->suppress_value
)
290 bgp_reuse_list_insert(bdi
);
291 SET_FLAG (bdi
->bgp_info
->flags
, BGP_INFO_DAMPED
);
293 bdi
->t_updated
= t_now
;
295 /* zlog(NULL, LOG_ERR, "DAMP:Withdraw - penalty: %d, damped: %d", bdi->penalty, bdi->bgp_info->damped); */
301 bgp_damp_update(struct bgp_info
*bgp_info
)
304 struct bgp_damp_info
*bdi
;
305 struct bgp_damp_config
*bdc
;
311 return BGP_DAMP_DISABLED
;
313 if ((bdi
= bgp_info
->bgp_damp_info
) == NULL
)
314 return BGP_DAMP_CONTINUE
;
317 bdi
->penalty
= (int) (bdi
->penalty
* bgp_damp_get_decay(t_now
- bdi
->t_updated
));
319 /* zlog(NULL, LOG_ERR, "UPDATE: penalty: %d", bdi->penalty); */
320 if (! CHECK_FLAG (bgp_info
->flags
, BGP_INFO_DAMPED
)
321 && (bdi
->penalty
< bdc
->suppress_value
))
323 status
= BGP_DAMP_CONTINUE
;
325 else if (CHECK_FLAG (bgp_info
->flags
, BGP_INFO_DAMPED
)
326 && (bdi
->penalty
< bdc
->reuse_limit
) )
328 UNSET_FLAG (bgp_info
->flags
, BGP_INFO_DAMPED
);
329 status
= BGP_DAMP_CONTINUE
;
332 status
= BGP_DAMP_DISCONTINUE
;
334 bdi
->t_updated
= t_now
;
340 bgp_damp_enable(struct vty
*vty
, int argc
, char **argv
)
343 bgp_damp_cfg
.enabled
= 1;
347 if (prev_bgp_damp_cfg
)
349 if (! bgp_reuse_thread
)
351 = thread_add_timer(master
, bgp_reuse_timer
, NULL
, DELTA_REUSE
);
353 /* zlog(NULL, LOG_ERR, "Using old config"); */
358 /* zlog(NULL, LOG_ERR, "Using new config"); */
360 return bgp_damp_init(vty
, -1, -1, -1, -1);
365 return bgp_damp_init (vty
, atoi(argv
[0])*60, -1, -1, -1);
368 return bgp_damp_init (vty
, atoi(argv
[0]) * 60, atoi(argv
[1]), atoi(argv
[2]),
373 bgp_damp_disable( struct vty
*vty
)
375 bgp_damp_cfg
.enabled
= 0;
377 if ( bgp_reuse_thread
)
378 thread_cancel (bgp_reuse_thread
);
380 bgp_reuse_thread
= NULL
;
382 /* Clear the reuse list entries */
383 bgp_damp_clear_reuse_list();
385 /* Clear configuration */
386 bgp_damp_clear_config(&bgp_damp_cfg
);
392 bgp_damp_clear_config(struct bgp_damp_config
*bdc
)
394 /* Free decay array */
395 free (bdc
->decay_array
);
397 /* Free reuse index array */
398 free (bdc
->reuse_index_array
);
400 if ( bgp_reuse_thread
)
401 thread_cancel (bgp_reuse_thread
);
402 bgp_reuse_thread
= NULL
;
404 /* Remove all entries from reuse lists */
405 prev_bgp_damp_cfg
= NULL
;
409 bgp_damp_clear_reuse_list()
411 struct bgp_damp_info
*bdi
, *tbdi
;
412 struct bgp_damp_config
*bdc
;
415 reuse_array_offset
= 0;
418 for (i
= 0; i
< bdc
->reuse_list_size
; i
++)
420 if (bdc
->reuse_list_array
[i
] == NULL
)
423 bdi
= bdc
->reuse_list_array
[i
];
424 bdc
->reuse_list_array
[i
] = NULL
;
428 tbdi
= bdi
->reuse_next
;
432 bdi
->bgp_info
->bgp_damp_info
= NULL
;
433 UNSET_FLAG (bdi
->bgp_info
->flags
, BGP_INFO_DAMPED
);
443 bgp_config_write_damp (struct vty
*vty
)
445 if (bgp_damp_cfg
.enabled
)
447 if (bgp_damp_cfg
.half_life
== DEFAULT_HARF_LIFE
*60
448 && bgp_damp_cfg
.reuse_limit
== DEFAULT_REUSE
449 && bgp_damp_cfg
.suppress_value
== DEFAULT_SUPPRESS
450 && bgp_damp_cfg
.max_suppress_time
== bgp_damp_cfg
.half_life
*4)
451 vty_out (vty
, " bgp dampening%s", VTY_NEWLINE
);
452 else if (bgp_damp_cfg
.half_life
!= DEFAULT_HARF_LIFE
*60
453 && bgp_damp_cfg
.reuse_limit
== DEFAULT_REUSE
454 && bgp_damp_cfg
.suppress_value
== DEFAULT_SUPPRESS
455 && bgp_damp_cfg
.max_suppress_time
== bgp_damp_cfg
.half_life
*4)
456 vty_out (vty
, " bgp dampening %d%s",
457 bgp_damp_cfg
.half_life
/60,
460 vty_out (vty
, " bgp dampening %d %d %d %d%s",
461 bgp_damp_cfg
.half_life
/60,
462 bgp_damp_cfg
.reuse_limit
,
463 bgp_damp_cfg
.suppress_value
,
464 bgp_damp_cfg
.max_suppress_time
/60,
471 #define BGP_UPTIME_LEN 25
474 bgp_damp_info_print (struct vty
*vty
, struct bgp_info
*bgp_info
)
476 struct bgp_damp_info
*bdi
;
478 char timebuf
[BGP_UPTIME_LEN
];
480 if ((bdi
= bgp_info
->bgp_damp_info
) == NULL
)
483 vty_out (vty
, " Dampinfo: penalty %d, flapped %d times in %s",
484 (int)(bdi
->penalty
* bgp_damp_get_decay(t_now
- bdi
->t_updated
)),
485 bdi
->flap
, peer_uptime (bdi
->start_time
, timebuf
, BGP_UPTIME_LEN
));
486 if (CHECK_FLAG (bdi
->bgp_info
->flags
, BGP_INFO_DAMPED
)
487 && ! CHECK_FLAG (bdi
->bgp_info
->flags
, BGP_INFO_HISTORY
))
488 vty_out (vty
, ", reuse in 00:00:00");
489 vty_out (vty
, "%s", VTY_NEWLINE
);