/* BGP flap dampening
- Copyright (C) 2001 IP Infusion Inc.
-
-This file is part of GNU Zebra.
-
-GNU Zebra is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-GNU Zebra is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Zebra; see the file COPYING. If not, write to the Free
-Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+ * Copyright (C) 2001 IP Infusion Inc.
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
#include <zebra.h>
#include <math.h>
#include "bgpd/bgp_damp.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
-#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_advertise.h"
/* Global variable to access damping configuration */
-struct bgp_damp_config bgp_damp_cfg;
-static struct bgp_damp_config *damp = &bgp_damp_cfg;
+static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
/* Utility macro to add and delete BGP dampening information to no
used list. */
-#define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list)
-#define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list)
+#define BGP_DAMP_LIST_ADD(N, A) BGP_PATH_INFO_ADD(N, A, no_reuse_list)
+#define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list)
/* Calculate reuse list index by penalty value. */
-static int
-bgp_reuse_index (int penalty)
+static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
{
- unsigned int i;
- int index;
+ unsigned int i;
+ int index;
+
+ i = (int)(((double)penalty / bdc->reuse_limit - 1.0)
+ * bdc->scale_factor);
- i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor);
-
- if ( i >= damp->reuse_index_size )
- i = damp->reuse_index_size - 1;
+ if (i >= bdc->reuse_index_size)
+ i = bdc->reuse_index_size - 1;
- index = damp->reuse_index[i] - damp->reuse_index[0];
+ index = bdc->reuse_index[i] - bdc->reuse_index[0];
- return (damp->reuse_offset + index) % damp->reuse_list_size;
+ return (bdc->reuse_offset + index) % bdc->reuse_list_size;
}
/* Add BGP dampening information to reuse list. */
-static void
-bgp_reuse_list_add (struct bgp_damp_info *bdi)
+static void bgp_reuse_list_add(struct bgp_damp_info *bdi,
+ struct bgp_damp_config *bdc)
{
- int index;
+ int index;
- index = bdi->index = bgp_reuse_index (bdi->penalty);
+ index = bdi->index = bgp_reuse_index(bdi->penalty, bdc);
- bdi->prev = NULL;
- bdi->next = damp->reuse_list[index];
- if (damp->reuse_list[index])
- damp->reuse_list[index]->prev = bdi;
- damp->reuse_list[index] = bdi;
+ bdi->prev = NULL;
+ bdi->next = bdc->reuse_list[index];
+ if (bdc->reuse_list[index])
+ bdc->reuse_list[index]->prev = bdi;
+ bdc->reuse_list[index] = bdi;
}
/* Delete BGP dampening information from reuse list. */
-static void
-bgp_reuse_list_delete (struct bgp_damp_info *bdi)
+static void bgp_reuse_list_delete(struct bgp_damp_info *bdi,
+ struct bgp_damp_config *bdc)
{
- if (bdi->next)
- bdi->next->prev = bdi->prev;
- if (bdi->prev)
- bdi->prev->next = bdi->next;
- else
- damp->reuse_list[bdi->index] = bdi->next;
-}
+ if (bdi->next)
+ bdi->next->prev = bdi->prev;
+ if (bdi->prev)
+ bdi->prev->next = bdi->next;
+ else
+ bdc->reuse_list[bdi->index] = bdi->next;
+}
/* Return decayed penalty value. */
-int
-bgp_damp_decay (time_t tdiff, int penalty)
+int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc)
{
- unsigned int i;
+ unsigned int i;
+
+ i = (int)((double)tdiff / DELTA_T);
- i = (int) ((double) tdiff / DELTA_T);
+ if (i == 0)
+ return penalty;
- if (i == 0)
- return penalty;
-
- if (i >= damp->decay_array_size)
- return 0;
+ if (i >= bdc->decay_array_size)
+ return 0;
- return (int) (penalty * damp->decay_array[i]);
+ return (int)(penalty * bdc->decay_array[i]);
}
/* Handler of reuse timer event. Each route in the current reuse-list
is evaluated. RFC2439 Section 4.8.7. */
-static int
-bgp_reuse_timer (struct thread *t)
+static int bgp_reuse_timer(struct thread *t)
{
- struct bgp_damp_info *bdi;
- struct bgp_damp_info *next;
- time_t t_now, t_diff;
-
- damp->t_reuse = NULL;
- damp->t_reuse =
- thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE);
-
- t_now = bgp_clock ();
-
- /* 1. save a pointer to the current zeroth queue head and zero the
- list head entry. */
- bdi = damp->reuse_list[damp->reuse_offset];
- damp->reuse_list[damp->reuse_offset] = NULL;
-
- /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
- rotating the circular queue of list-heads. */
- damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
-
- /* 3. if ( the saved list head pointer is non-empty ) */
- for (; bdi; bdi = next)
- {
- struct bgp *bgp = bdi->binfo->peer->bgp;
-
- next = bdi->next;
-
- /* Set t-diff = t-now - t-updated. */
- t_diff = t_now - bdi->t_updated;
-
- /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */
- bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
-
- /* Set t-updated = t-now. */
- bdi->t_updated = t_now;
-
- /* if (figure-of-merit < reuse). */
- if (bdi->penalty < damp->reuse_limit)
- {
- /* Reuse the route. */
- bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_DAMPED);
- bdi->suppress_time = 0;
-
- if (bdi->lastrecord == BGP_RECORD_UPDATE)
- {
- bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_HISTORY);
- bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo,
- bdi->afi, bdi->safi);
- bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi);
- }
-
- if (bdi->penalty <= damp->reuse_limit / 2.0)
- bgp_damp_info_free (bdi, 1);
- else
- BGP_DAMP_LIST_ADD (damp, bdi);
+ struct bgp_damp_info *bdi;
+ struct bgp_damp_info *next;
+ time_t t_now, t_diff;
+
+ struct bgp_damp_config *bdc = THREAD_ARG(t);
+
+ bdc->t_reuse = NULL;
+ thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
+ &bdc->t_reuse);
+
+ t_now = bgp_clock();
+
+ /* 1. save a pointer to the current zeroth queue head and zero the
+ list head entry. */
+ bdi = bdc->reuse_list[bdc->reuse_offset];
+ bdc->reuse_list[bdc->reuse_offset] = NULL;
+
+ /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
+ rotating the circular queue of list-heads. */
+ bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size;
+
+ /* 3. if ( the saved list head pointer is non-empty ) */
+ for (; bdi; bdi = next) {
+ struct bgp *bgp = bdi->path->peer->bgp;
+
+ next = bdi->next;
+
+ /* Set t-diff = t-now - t-updated. */
+ t_diff = t_now - bdi->t_updated;
+
+ /* Set figure-of-merit = figure-of-merit * decay-array-ok
+ * [t-diff] */
+ bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
+
+ /* Set t-updated = t-now. */
+ bdi->t_updated = t_now;
+
+ /* if (figure-of-merit < reuse). */
+ if (bdi->penalty < bdc->reuse_limit) {
+ /* Reuse the route. */
+ bgp_path_info_unset_flag(bdi->rn, bdi->path,
+ BGP_PATH_DAMPED);
+ bdi->suppress_time = 0;
+
+ if (bdi->lastrecord == BGP_RECORD_UPDATE) {
+ bgp_path_info_unset_flag(bdi->rn, bdi->path,
+ BGP_PATH_HISTORY);
+ bgp_aggregate_increment(bgp, &bdi->rn->p,
+ bdi->path, bdi->afi,
+ bdi->safi);
+ bgp_process(bgp, bdi->rn, bdi->afi, bdi->safi);
+ }
+
+ if (bdi->penalty <= bdc->reuse_limit / 2.0)
+ bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi);
+ else
+ BGP_DAMP_LIST_ADD(bdc, bdi);
+ } else
+ /* Re-insert into another list (See RFC2439 Section
+ * 4.8.6). */
+ bgp_reuse_list_add(bdi, bdc);
}
- else
- /* Re-insert into another list (See RFC2439 Section 4.8.6). */
- bgp_reuse_list_add (bdi);
- }
- return 0;
+ return 0;
}
/* A route becomes unreachable (RFC2439 Section 4.8.2). */
-int
-bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn,
- afi_t afi, safi_t safi, int attr_change)
+int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_node *rn,
+ afi_t afi, safi_t safi, int attr_change)
{
- time_t t_now;
- struct bgp_damp_info *bdi = NULL;
- double last_penalty = 0;
-
- t_now = bgp_clock ();
-
- /* Processing Unreachable Messages. */
- if (binfo->extra)
- bdi = binfo->extra->damp_info;
-
- if (bdi == NULL)
- {
- /* If there is no previous stability history. */
-
- /* RFC2439 said:
- 1. allocate a damping structure.
- 2. set figure-of-merit = 1.
- 3. withdraw the route. */
-
- bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info));
- bdi->binfo = binfo;
- bdi->rn = rn;
- bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
- bdi->flap = 1;
- bdi->start_time = t_now;
- bdi->suppress_time = 0;
- bdi->index = -1;
- bdi->afi = afi;
- bdi->safi = safi;
- (bgp_info_extra_get (binfo))->damp_info = bdi;
- BGP_DAMP_LIST_ADD (damp, bdi);
- }
- else
- {
- last_penalty = bdi->penalty;
-
- /* 1. Set t-diff = t-now - t-updated. */
- bdi->penalty =
- (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty)
- + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY));
-
- if (bdi->penalty > damp->ceiling)
- bdi->penalty = damp->ceiling;
-
- bdi->flap++;
- }
-
- assert ((rn == bdi->rn) && (binfo == bdi->binfo));
-
- bdi->lastrecord = BGP_RECORD_WITHDRAW;
- bdi->t_updated = t_now;
-
- /* Make this route as historical status. */
- bgp_info_set_flag (rn, binfo, BGP_INFO_HISTORY);
-
- /* Remove the route from a reuse list if it is on one. */
- if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED))
- {
- /* If decay rate isn't equal to 0, reinsert brn. */
- if (bdi->penalty != last_penalty)
- {
- bgp_reuse_list_delete (bdi);
- bgp_reuse_list_add (bdi);
+ time_t t_now;
+ struct bgp_damp_info *bdi = NULL;
+ unsigned int last_penalty = 0;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
+
+ t_now = bgp_clock();
+
+ /* Processing Unreachable Messages. */
+ if (path->extra)
+ bdi = path->extra->damp_info;
+
+ if (bdi == NULL) {
+ /* If there is no previous stability history. */
+
+ /* RFC2439 said:
+ 1. allocate a damping structure.
+ 2. set figure-of-merit = 1.
+ 3. withdraw the route. */
+
+ bdi = XCALLOC(MTYPE_BGP_DAMP_INFO,
+ sizeof(struct bgp_damp_info));
+ bdi->path = path;
+ bdi->rn = rn;
+ bdi->penalty =
+ (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY);
+ bdi->flap = 1;
+ bdi->start_time = t_now;
+ bdi->suppress_time = 0;
+ bdi->index = -1;
+ bdi->afi = afi;
+ bdi->safi = safi;
+ (bgp_path_info_extra_get(path))->damp_info = bdi;
+ BGP_DAMP_LIST_ADD(bdc, bdi);
+ } else {
+ last_penalty = bdi->penalty;
+
+ /* 1. Set t-diff = t-now - t-updated. */
+ bdi->penalty = (bgp_damp_decay(t_now - bdi->t_updated,
+ bdi->penalty, bdc)
+ + (attr_change ? DEFAULT_PENALTY / 2
+ : DEFAULT_PENALTY));
+
+ if (bdi->penalty > bdc->ceiling)
+ bdi->penalty = bdc->ceiling;
+
+ bdi->flap++;
}
- return BGP_DAMP_SUPPRESSED;
- }
-
- /* If not suppressed before, do annonunce this withdraw and
- insert into reuse_list. */
- if (bdi->penalty >= damp->suppress_value)
- {
- bgp_info_set_flag (rn, binfo, BGP_INFO_DAMPED);
- bdi->suppress_time = t_now;
- BGP_DAMP_LIST_DEL (damp, bdi);
- bgp_reuse_list_add (bdi);
- }
-
- return BGP_DAMP_USED;
-}
-int
-bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn,
- afi_t afi, safi_t safi)
-{
- time_t t_now;
- struct bgp_damp_info *bdi;
- int status;
-
- if (!binfo->extra || !((bdi = binfo->extra->damp_info)))
- return BGP_DAMP_USED;
-
- t_now = bgp_clock ();
- bgp_info_unset_flag (rn, binfo, BGP_INFO_HISTORY);
-
- bdi->lastrecord = BGP_RECORD_UPDATE;
- bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty);
-
- if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
- && (bdi->penalty < damp->suppress_value))
- status = BGP_DAMP_USED;
- else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)
- && (bdi->penalty < damp->reuse_limit) )
- {
- bgp_info_unset_flag (rn, binfo, BGP_INFO_DAMPED);
- bgp_reuse_list_delete (bdi);
- BGP_DAMP_LIST_ADD (damp, bdi);
- bdi->suppress_time = 0;
- status = BGP_DAMP_USED;
- }
- else
- status = BGP_DAMP_SUPPRESSED;
-
- if (bdi->penalty > damp->reuse_limit / 2.0)
- bdi->t_updated = t_now;
- else
- bgp_damp_info_free (bdi, 0);
-
- return status;
+ assert((rn == bdi->rn) && (path == bdi->path));
+
+ bdi->lastrecord = BGP_RECORD_WITHDRAW;
+ bdi->t_updated = t_now;
+
+ /* Make this route as historical status. */
+ bgp_path_info_set_flag(rn, path, BGP_PATH_HISTORY);
+
+ /* Remove the route from a reuse list if it is on one. */
+ if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) {
+ /* If decay rate isn't equal to 0, reinsert brn. */
+ if (bdi->penalty != last_penalty && bdi->index >= 0) {
+ bgp_reuse_list_delete(bdi, bdc);
+ bgp_reuse_list_add(bdi, bdc);
+ }
+ return BGP_DAMP_SUPPRESSED;
+ }
+
+ /* If not suppressed before, do annonunce this withdraw and
+ insert into reuse_list. */
+ if (bdi->penalty >= bdc->suppress_value) {
+ bgp_path_info_set_flag(rn, path, BGP_PATH_DAMPED);
+ bdi->suppress_time = t_now;
+ BGP_DAMP_LIST_DEL(bdc, bdi);
+ bgp_reuse_list_add(bdi, bdc);
+ }
+
+ return BGP_DAMP_USED;
}
-/* Remove dampening information and history route. */
-int
-bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi)
+int bgp_damp_update(struct bgp_path_info *path, struct bgp_node *rn, afi_t afi,
+ safi_t safi)
{
- time_t t_now, t_diff;
- struct bgp_damp_info *bdi;
-
- assert (binfo->extra && binfo->extra->damp_info);
-
- t_now = bgp_clock ();
- bdi = binfo->extra->damp_info;
-
- if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
- {
- t_diff = t_now - bdi->suppress_time;
-
- if (t_diff >= damp->max_suppress_time)
- {
- bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_DAMPED);
- bgp_reuse_list_delete (bdi);
- BGP_DAMP_LIST_ADD (damp, bdi);
- bdi->penalty = damp->reuse_limit;
- bdi->suppress_time = 0;
- bdi->t_updated = t_now;
-
- /* Need to announce UPDATE once this binfo is usable again. */
- if (bdi->lastrecord == BGP_RECORD_UPDATE)
- return 1;
- else
- return 0;
- }
- }
- else
- {
- t_diff = t_now - bdi->t_updated;
- bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty);
-
- if (bdi->penalty <= damp->reuse_limit / 2.0)
- {
- /* release the bdi, bdi->binfo. */
- bgp_damp_info_free (bdi, 1);
- return 0;
- }
- else
- bdi->t_updated = t_now;
- }
- return 0;
+ time_t t_now;
+ struct bgp_damp_info *bdi;
+ int status;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
+
+ if (!path->extra || !((bdi = path->extra->damp_info)))
+ return BGP_DAMP_USED;
+
+ t_now = bgp_clock();
+ bgp_path_info_unset_flag(rn, path, BGP_PATH_HISTORY);
+
+ bdi->lastrecord = BGP_RECORD_UPDATE;
+ bdi->penalty =
+ bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty, bdc);
+
+ if (!CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
+ && (bdi->penalty < bdc->suppress_value))
+ status = BGP_DAMP_USED;
+ else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
+ && (bdi->penalty < bdc->reuse_limit)) {
+ bgp_path_info_unset_flag(rn, path, BGP_PATH_DAMPED);
+ bgp_reuse_list_delete(bdi, bdc);
+ BGP_DAMP_LIST_ADD(bdc, bdi);
+ bdi->suppress_time = 0;
+ status = BGP_DAMP_USED;
+ } else
+ status = BGP_DAMP_SUPPRESSED;
+
+ if (bdi->penalty > bdc->reuse_limit / 2.0)
+ bdi->t_updated = t_now;
+ else
+ bgp_damp_info_free(bdi, 0, afi, safi);
+
+ return status;
}
-void
-bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw)
+void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi,
+ safi_t safi)
{
- struct bgp_info *binfo;
+ struct bgp_path_info *path;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
- if (! bdi)
- return;
+ if (!bdi)
+ return;
- binfo = bdi->binfo;
- binfo->extra->damp_info = NULL;
+ path = bdi->path;
+ path->extra->damp_info = NULL;
- if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED))
- bgp_reuse_list_delete (bdi);
- else
- BGP_DAMP_LIST_DEL (damp, bdi);
+ if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED))
+ bgp_reuse_list_delete(bdi, bdc);
+ else
+ BGP_DAMP_LIST_DEL(bdc, bdi);
- bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_HISTORY|BGP_INFO_DAMPED);
+ bgp_path_info_unset_flag(bdi->rn, path,
+ BGP_PATH_HISTORY | BGP_PATH_DAMPED);
- if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
- bgp_info_delete (bdi->rn, binfo);
-
- XFREE (MTYPE_BGP_DAMP_INFO, bdi);
+ if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw)
+ bgp_path_info_delete(bdi->rn, path);
+
+ XFREE(MTYPE_BGP_DAMP_INFO, bdi);
}
-static void
-bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup)
+static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup,
+ struct bgp_damp_config *bdc)
{
- double reuse_max_ratio;
- unsigned int i;
- double j;
-
- damp->suppress_value = sup;
- damp->half_life = hlife;
- damp->reuse_limit = reuse;
- damp->max_suppress_time = maxsup;
-
- /* Initialize params per bgp_damp_config. */
- damp->reuse_index_size = REUSE_ARRAY_SIZE;
-
- damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life)));
-
- /* Decay-array computations */
- damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T);
- damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY,
- sizeof(double) * (damp->decay_array_size));
- damp->decay_array[0] = 1.0;
- damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5));
-
- /* Calculate decay values for all possible times */
- for (i = 2; i < damp->decay_array_size; i++)
- damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1];
-
- /* Reuse-list computations */
- i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1;
- if (i > REUSE_LIST_SIZE || i == 0)
- i = REUSE_LIST_SIZE;
- damp->reuse_list_size = i;
-
- damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
- damp->reuse_list_size
- * sizeof (struct bgp_reuse_node *));
-
- /* Reuse-array computations */
- damp->reuse_index = XCALLOC (MTYPE_BGP_DAMP_ARRAY,
- sizeof(int) * damp->reuse_index_size);
-
- reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit;
- j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0));
- if ( reuse_max_ratio > j && j != 0 )
- reuse_max_ratio = j;
-
- damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1);
-
- for (i = 0; i < damp->reuse_index_size; i++)
- {
- damp->reuse_index[i] =
- (int)(((double)damp->half_life / DELTA_REUSE)
- * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5));
- }
+ double reuse_max_ratio;
+ unsigned int i;
+ double j;
+
+ bdc->suppress_value = sup;
+ bdc->half_life = hlife;
+ bdc->reuse_limit = reuse;
+ bdc->max_suppress_time = maxsup;
+
+ /* Initialize params per bgp_damp_config. */
+ bdc->reuse_index_size = REUSE_ARRAY_SIZE;
+
+ bdc->ceiling = (int)(bdc->reuse_limit
+ * (pow(2, (double)bdc->max_suppress_time
+ / bdc->half_life)));
+
+ /* Decay-array computations */
+ bdc->decay_array_size = ceil((double)bdc->max_suppress_time / DELTA_T);
+ bdc->decay_array = XMALLOC(MTYPE_BGP_DAMP_ARRAY,
+ sizeof(double) * (bdc->decay_array_size));
+ bdc->decay_array[0] = 1.0;
+ bdc->decay_array[1] =
+ exp((1.0 / ((double)bdc->half_life / DELTA_T)) * log(0.5));
+
+ /* Calculate decay values for all possible times */
+ for (i = 2; i < bdc->decay_array_size; i++)
+ bdc->decay_array[i] =
+ bdc->decay_array[i - 1] * bdc->decay_array[1];
+
+ /* Reuse-list computations */
+ i = ceil((double)bdc->max_suppress_time / DELTA_REUSE) + 1;
+ if (i > REUSE_LIST_SIZE || i == 0)
+ i = REUSE_LIST_SIZE;
+ bdc->reuse_list_size = i;
+
+ bdc->reuse_list =
+ XCALLOC(MTYPE_BGP_DAMP_ARRAY,
+ bdc->reuse_list_size * sizeof(struct bgp_reuse_node *));
+
+ /* Reuse-array computations */
+ bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
+ sizeof(int) * bdc->reuse_index_size);
+
+ reuse_max_ratio = (double)bdc->ceiling / bdc->reuse_limit;
+ j = (exp((double)bdc->max_suppress_time / bdc->half_life) * log10(2.0));
+ if (reuse_max_ratio > j && j != 0)
+ reuse_max_ratio = j;
+
+ bdc->scale_factor =
+ (double)bdc->reuse_index_size / (reuse_max_ratio - 1);
+
+ for (i = 0; i < bdc->reuse_index_size; i++) {
+ bdc->reuse_index[i] =
+ (int)(((double)bdc->half_life / DELTA_REUSE)
+ * log10(1.0
+ / (bdc->reuse_limit
+ * (1.0
+ + ((double)i / bdc->scale_factor))))
+ / log10(0.5));
+ }
}
-int
-bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
- unsigned int reuse, unsigned int suppress, time_t max)
+int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
+ unsigned int reuse, unsigned int suppress, time_t max)
{
- if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
- {
- if (damp->half_life == half
- && damp->reuse_limit == reuse
- && damp->suppress_value == suppress
- && damp->max_suppress_time == max)
- return 0;
- bgp_damp_disable (bgp, afi, safi);
- }
+ struct bgp_damp_config *bdc = &damp[afi][safi];
+
+ if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
+ if (bdc->half_life == half && bdc->reuse_limit == reuse
+ && bdc->suppress_value == suppress
+ && bdc->max_suppress_time == max)
+ return 0;
+ bgp_damp_disable(bgp, afi, safi);
+ }
- SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
- bgp_damp_parameter_set (half, reuse, suppress, max);
+ SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
+ bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
- /* Register reuse timer. */
- if (! damp->t_reuse)
- damp->t_reuse =
- thread_add_timer (bm->master, bgp_reuse_timer, NULL, DELTA_REUSE);
+ /* Register reuse timer. */
+ thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
+ &bdc->t_reuse);
- return 0;
+ return 0;
}
-static void
-bgp_damp_config_clean (struct bgp_damp_config *damp)
+static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
{
- /* Free decay array */
- XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
+ /* Free decay array */
+ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
+ bdc->decay_array_size = 0;
- /* Free reuse index array */
- XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
+ /* Free reuse index array */
+ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index);
+ bdc->reuse_index_size = 0;
- /* Free reuse list array. */
- XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
+ /* Free reuse list array. */
+ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
+ bdc->reuse_list_size = 0;
}
/* Clean all the bgp_damp_info stored in reuse_list. */
-void
-bgp_damp_info_clean (void)
+void bgp_damp_info_clean(afi_t afi, safi_t safi)
{
- unsigned int i;
- struct bgp_damp_info *bdi, *next;
+ unsigned int i;
+ struct bgp_damp_info *bdi, *next;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
- damp->reuse_offset = 0;
+ bdc->reuse_offset = 0;
- for (i = 0; i < damp->reuse_list_size; i++)
- {
- if (! damp->reuse_list[i])
- continue;
+ for (i = 0; i < bdc->reuse_list_size; i++) {
+ if (!bdc->reuse_list[i])
+ continue;
+
+ for (bdi = bdc->reuse_list[i]; bdi; bdi = next) {
+ next = bdi->next;
+ bgp_damp_info_free(bdi, 1, afi, safi);
+ }
+ bdc->reuse_list[i] = NULL;
+ }
- for (bdi = damp->reuse_list[i]; bdi; bdi = next)
- {
- next = bdi->next;
- bgp_damp_info_free (bdi, 1);
+ for (bdi = bdc->no_reuse_list; bdi; bdi = next) {
+ next = bdi->next;
+ bgp_damp_info_free(bdi, 1, afi, safi);
}
- damp->reuse_list[i] = NULL;
- }
-
- for (bdi = damp->no_reuse_list; bdi; bdi = next)
- {
- next = bdi->next;
- bgp_damp_info_free (bdi, 1);
- }
- damp->no_reuse_list = NULL;
+ bdc->no_reuse_list = NULL;
}
-int
-bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi)
+int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
{
- /* If it wasn't enabled, there's nothing to do. */
- if (! CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
- return 0;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
+ /* If it wasn't enabled, there's nothing to do. */
+ if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
+ return 0;
- /* Cancel reuse thread. */
- if (damp->t_reuse )
- thread_cancel (damp->t_reuse);
- damp->t_reuse = NULL;
+ /* Cancel reuse thread. */
+ if (bdc->t_reuse)
+ thread_cancel(bdc->t_reuse);
+ bdc->t_reuse = NULL;
- /* Clean BGP dampening information. */
- bgp_damp_info_clean ();
+ /* Clean BGP dampening information. */
+ bgp_damp_info_clean(afi, safi);
- /* Clear configuration */
- bgp_damp_config_clean (&bgp_damp_cfg);
+ /* Clear configuration */
+ bgp_damp_config_clean(bdc);
- UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
- return 0;
+ UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
+ return 0;
}
-void
-bgp_config_write_damp (struct vty *vty)
+void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi)
{
- if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60
- && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
- && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
- && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
- vty_out (vty, " bgp dampening%s", VTY_NEWLINE);
- else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60
- && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
- && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
- && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4)
- vty_out (vty, " bgp dampening %lld%s",
- bgp_damp_cfg.half_life/60LL,
- VTY_NEWLINE);
- else
- vty_out (vty, " bgp dampening %lld %d %d %lld%s",
- bgp_damp_cfg.half_life/60LL,
- bgp_damp_cfg.reuse_limit,
- bgp_damp_cfg.suppress_value,
- bgp_damp_cfg.max_suppress_time/60LL,
- VTY_NEWLINE);
+ if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60
+ && damp[afi][safi].reuse_limit == DEFAULT_REUSE
+ && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
+ && damp[afi][safi].max_suppress_time
+ == damp[afi][safi].half_life * 4)
+ vty_out(vty, " bgp dampening\n");
+ else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60
+ && damp[afi][safi].reuse_limit == DEFAULT_REUSE
+ && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
+ && damp[afi][safi].max_suppress_time
+ == damp[afi][safi].half_life * 4)
+ vty_out(vty, " bgp dampening %lld\n",
+ damp[afi][safi].half_life / 60LL);
+ else
+ vty_out(vty, " bgp dampening %lld %d %d %lld\n",
+ damp[afi][safi].half_life / 60LL,
+ damp[afi][safi].reuse_limit,
+ damp[afi][safi].suppress_value,
+ damp[afi][safi].max_suppress_time / 60LL);
}
-static const char *
-bgp_get_reuse_time (unsigned int penalty, char *buf, size_t len, u_char use_json, json_object *json)
+static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
+ size_t len, afi_t afi, safi_t safi,
+ bool use_json, json_object *json)
{
- time_t reuse_time = 0;
- struct tm *tm = NULL;
- int time_store = 0;
-
- if (penalty > damp->reuse_limit)
- {
- reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1]))));
-
- if (reuse_time > damp->max_suppress_time)
- reuse_time = damp->max_suppress_time;
-
- tm = gmtime (&reuse_time);
- }
- else
- reuse_time = 0;
-
- /* Making formatted timer strings. */
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND 60*60*24*7
- if (reuse_time == 0)
- {
- if (use_json)
- json_object_int_add(json, "reuseTimerMsecs", 0);
- else
- snprintf (buf, len, "00:00:00");
- }
- else if (reuse_time < ONE_DAY_SECOND)
- {
- if (use_json)
- {
- time_store = (3600000 * tm->tm_hour) + (60000 * tm->tm_min) + (1000 * tm->tm_sec);
- json_object_int_add(json, "reuseTimerMsecs", time_store);
- }
- else
- snprintf (buf, len, "%02d:%02d:%02d",
- tm->tm_hour, tm->tm_min, tm->tm_sec);
- }
- else if (reuse_time < ONE_WEEK_SECOND)
- {
- if (use_json)
- {
- time_store = (86400000 * tm->tm_yday) + (3600000 * tm->tm_hour) + (60000 * tm->tm_min) + (1000 * tm->tm_sec);
- json_object_int_add(json, "reuseTimerMsecs", time_store);
- }
- else
- snprintf (buf, len, "%dd%02dh%02dm",
- tm->tm_yday, tm->tm_hour, tm->tm_min);
- }
- else
- {
- if (use_json)
- {
- time_store = (604800000 * tm->tm_yday/7) + (86400000 * (tm->tm_yday - ((tm->tm_yday/7) * 7))) + (3600000 * tm->tm_hour) + (60000 * tm->tm_min) + (1000 * tm->tm_sec);
- json_object_int_add(json, "reuseTimerMsecs", time_store);
- }
- else
- snprintf (buf, len, "%02dw%dd%02dh",
- tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
- }
-
- return buf;
+ time_t reuse_time = 0;
+ struct tm *tm = NULL;
+ int time_store = 0;
+
+ if (penalty > damp[afi][safi].reuse_limit) {
+ reuse_time = (int)(DELTA_T
+ * ((log((double)damp[afi][safi].reuse_limit
+ / penalty))
+ / (log(damp[afi][safi].decay_array[1]))));
+
+ if (reuse_time > damp[afi][safi].max_suppress_time)
+ reuse_time = damp[afi][safi].max_suppress_time;
+
+ tm = gmtime(&reuse_time);
+ } else
+ reuse_time = 0;
+
+ /* Making formatted timer strings. */
+ if (reuse_time == 0) {
+ if (use_json)
+ json_object_int_add(json, "reuseTimerMsecs", 0);
+ else
+ snprintf(buf, len, "00:00:00");
+ } else if (reuse_time < ONE_DAY_SECOND) {
+ if (use_json) {
+ time_store = (3600000 * tm->tm_hour)
+ + (60000 * tm->tm_min)
+ + (1000 * tm->tm_sec);
+ json_object_int_add(json, "reuseTimerMsecs",
+ time_store);
+ } else
+ snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour,
+ tm->tm_min, tm->tm_sec);
+ } else if (reuse_time < ONE_WEEK_SECOND) {
+ if (use_json) {
+ time_store = (86400000 * tm->tm_yday)
+ + (3600000 * tm->tm_hour)
+ + (60000 * tm->tm_min)
+ + (1000 * tm->tm_sec);
+ json_object_int_add(json, "reuseTimerMsecs",
+ time_store);
+ } else
+ snprintf(buf, len, "%dd%02dh%02dm", tm->tm_yday,
+ tm->tm_hour, tm->tm_min);
+ } else {
+ if (use_json) {
+ time_store =
+ (604800000 * tm->tm_yday / 7)
+ + (86400000
+ * (tm->tm_yday - ((tm->tm_yday / 7) * 7)))
+ + (3600000 * tm->tm_hour) + (60000 * tm->tm_min)
+ + (1000 * tm->tm_sec);
+ json_object_int_add(json, "reuseTimerMsecs",
+ time_store);
+ } else
+ snprintf(buf, len, "%02dw%dd%02dh", tm->tm_yday / 7,
+ tm->tm_yday - ((tm->tm_yday / 7) * 7),
+ tm->tm_hour);
+ }
+
+ return buf;
}
-
-void
-bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo,
- json_object *json_path)
+
+void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
+ safi_t safi, json_object *json_path)
{
- struct bgp_damp_info *bdi;
- time_t t_now, t_diff;
- char timebuf[BGP_UPTIME_LEN];
- int penalty;
-
- if (!binfo->extra)
- return;
-
- /* BGP dampening information. */
- bdi = binfo->extra->damp_info;
-
- /* If dampening is not enabled or there is no dampening information,
- return immediately. */
- if (! damp || ! bdi)
- return;
-
- /* Calculate new penalty. */
- t_now = bgp_clock ();
- t_diff = t_now - bdi->t_updated;
- penalty = bgp_damp_decay (t_diff, bdi->penalty);
-
- if (json_path)
- {
- json_object_int_add(json_path, "dampeningPenalty", penalty);
- json_object_int_add(json_path, "dampeningFlapCount", bdi->flap);
- peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN, 1, json_path);
-
- if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
- && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
- bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN, 1, json_path);
- }
- else
- {
- vty_out (vty, " Dampinfo: penalty %d, flapped %d times in %s",
- penalty, bdi->flap,
- peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN, 0, json_path));
-
- if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)
- && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY))
- vty_out (vty, ", reuse in %s",
- bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN, 0, json_path));
-
- vty_out (vty, "%s", VTY_NEWLINE);
- }
+ struct bgp_damp_info *bdi;
+ time_t t_now, t_diff;
+ char timebuf[BGP_UPTIME_LEN];
+ int penalty;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
+
+ if (!path->extra)
+ return;
+
+ /* BGP dampening information. */
+ bdi = path->extra->damp_info;
+
+ /* If dampening is not enabled or there is no dampening information,
+ return immediately. */
+ if (!bdc || !bdi)
+ return;
+
+ /* Calculate new penalty. */
+ t_now = bgp_clock();
+ t_diff = t_now - bdi->t_updated;
+ penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
+
+ if (json_path) {
+ json_object_int_add(json_path, "dampeningPenalty", penalty);
+ json_object_int_add(json_path, "dampeningFlapCount", bdi->flap);
+ peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 1,
+ json_path);
+
+ if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
+ && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
+ bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN,
+ afi, safi, 1, json_path);
+ } else {
+ vty_out(vty,
+ " Dampinfo: penalty %d, flapped %d times in %s",
+ penalty, bdi->flap,
+ peer_uptime(bdi->start_time, timebuf, BGP_UPTIME_LEN, 0,
+ json_path));
+
+ if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
+ && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
+ vty_out(vty, ", reuse in %s",
+ bgp_get_reuse_time(penalty, timebuf,
+ BGP_UPTIME_LEN, afi, safi, 0,
+ json_path));
+
+ vty_out(vty, "\n");
+ }
}
-const char *
-bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo,
- char *timebuf, size_t len, u_char use_json, json_object *json)
+const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
+ char *timebuf, size_t len, afi_t afi,
+ safi_t safi, bool use_json,
+ json_object *json)
{
- struct bgp_damp_info *bdi;
- time_t t_now, t_diff;
- int penalty;
-
- if (!binfo->extra)
- return NULL;
-
- /* BGP dampening information. */
- bdi = binfo->extra->damp_info;
-
- /* If dampening is not enabled or there is no dampening information,
- return immediately. */
- if (! damp || ! bdi)
- return NULL;
-
- /* Calculate new penalty. */
- t_now = bgp_clock ();
- t_diff = t_now - bdi->t_updated;
- penalty = bgp_damp_decay (t_diff, bdi->penalty);
-
- return bgp_get_reuse_time (penalty, timebuf, len, use_json, json);
+ struct bgp_damp_info *bdi;
+ time_t t_now, t_diff;
+ int penalty;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
+
+ if (!path->extra)
+ return NULL;
+
+ /* BGP dampening information. */
+ bdi = path->extra->damp_info;
+
+ /* If dampening is not enabled or there is no dampening information,
+ return immediately. */
+ if (!bdc || !bdi)
+ return NULL;
+
+ /* Calculate new penalty. */
+ t_now = bgp_clock();
+ t_diff = t_now - bdi->t_updated;
+ penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
+
+ return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json,
+ json);
}
-int
-bgp_show_dampening_parameters (struct vty *vty, afi_t afi, safi_t safi)
+int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi)
{
- struct bgp *bgp;
- bgp = bgp_get_default();
-
- if (bgp == NULL)
- {
- vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
- {
- vty_out (vty, "Half-life time: %lld min%s",
- (long long)damp->half_life / 60, VTY_NEWLINE);
- vty_out (vty, "Reuse penalty: %d%s",
- damp->reuse_limit, VTY_NEWLINE);
- vty_out (vty, "Suppress penalty: %d%s",
- damp->suppress_value, VTY_NEWLINE);
- vty_out (vty, "Max suppress time: %lld min%s",
- (long long)damp->max_suppress_time / 60, VTY_NEWLINE);
- vty_out (vty, "Max supress penalty: %u%s",
- damp->ceiling, VTY_NEWLINE);
- vty_out (vty, "%s", VTY_NEWLINE);
- }
- else
- vty_out (vty, "dampening not enabled for %s%s",
- afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
-
- return CMD_SUCCESS;
+ struct bgp *bgp;
+ bgp = bgp_get_default();
+
+ if (bgp == NULL) {
+ vty_out(vty, "No BGP process is configured\n");
+ return CMD_WARNING;
+ }
+
+ if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
+ vty_out(vty, "Half-life time: %lld min\n",
+ (long long)damp[afi][safi].half_life / 60);
+ vty_out(vty, "Reuse penalty: %d\n",
+ damp[afi][safi].reuse_limit);
+ vty_out(vty, "Suppress penalty: %d\n",
+ damp[afi][safi].suppress_value);
+ vty_out(vty, "Max suppress time: %lld min\n",
+ (long long)damp[afi][safi].max_suppress_time / 60);
+ vty_out(vty, "Max suppress penalty: %u\n",
+ damp[afi][safi].ceiling);
+ vty_out(vty, "\n");
+ } else
+ vty_out(vty, "dampening not enabled for %s\n",
+ afi == AFI_IP ? "IPv4" : "IPv6");
+
+ return CMD_SUCCESS;
}