mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-10 08:39:33 +00:00
Merge pull request #15911 from opensourcerouting/feature/bgpd_dampening_per_neighbor
bgpd: per-neighbor dampening support
This commit is contained in:
commit
2e0208602b
508
bgpd/bgp_damp.c
508
bgpd/bgp_damp.c
@ -22,19 +22,76 @@
|
|||||||
#include "bgpd/bgp_advertise.h"
|
#include "bgpd/bgp_advertise.h"
|
||||||
#include "bgpd/bgp_vty.h"
|
#include "bgpd/bgp_vty.h"
|
||||||
|
|
||||||
/* Global variable to access damping configuration */
|
static void bgp_reuselist_add(struct reuselist *list, struct bgp_damp_info *info)
|
||||||
static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
|
{
|
||||||
|
assert(info);
|
||||||
|
SLIST_INSERT_HEAD(list, info, entry);
|
||||||
|
}
|
||||||
|
|
||||||
/* Utility macro to add and delete BGP dampening information to no
|
static void bgp_reuselist_del(struct reuselist *list, struct bgp_damp_info *info)
|
||||||
used list. */
|
{
|
||||||
#define BGP_DAMP_LIST_ADD(N, A) BGP_PATH_INFO_ADD(N, A, no_reuse_list)
|
assert(info);
|
||||||
#define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list)
|
SLIST_REMOVE(list, info, bgp_damp_info, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bgp_reuselist_switch(struct reuselist *source,
|
||||||
|
struct bgp_damp_info *info,
|
||||||
|
struct reuselist *target)
|
||||||
|
{
|
||||||
|
assert(source && target && info);
|
||||||
|
SLIST_REMOVE(source, info, bgp_damp_info, entry);
|
||||||
|
SLIST_INSERT_HEAD(target, info, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bgp_damp_info_unclaim(struct bgp_damp_info *bdi,
|
||||||
|
struct reuselist *list)
|
||||||
|
{
|
||||||
|
assert(bdi && bdi->config);
|
||||||
|
if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX)
|
||||||
|
bgp_reuselist_del(&bdi->config->no_reuse_list, bdi);
|
||||||
|
else
|
||||||
|
bgp_reuselist_del(list ? list
|
||||||
|
: &bdi->config->reuse_list[bdi->index],
|
||||||
|
bdi);
|
||||||
|
bdi->config = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bgp_damp_info_claim(struct bgp_damp_info *bdi,
|
||||||
|
struct bgp_damp_config *bdc)
|
||||||
|
{
|
||||||
|
assert(bdc && bdi);
|
||||||
|
if (bdi->config == NULL) {
|
||||||
|
bdi->config = bdc;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bgp_damp_info_unclaim(bdi, NULL);
|
||||||
|
bdi->config = bdc;
|
||||||
|
bdi->afi = bdc->afi;
|
||||||
|
bdi->safi = bdc->safi;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi,
|
||||||
|
afi_t afi, safi_t safi)
|
||||||
|
{
|
||||||
|
if (!pi)
|
||||||
|
return NULL;
|
||||||
|
if (CHECK_FLAG(pi->peer->af_flags[afi][safi],
|
||||||
|
PEER_FLAG_CONFIG_DAMPENING))
|
||||||
|
return &pi->peer->damp[afi][safi];
|
||||||
|
if (peer_group_active(pi->peer))
|
||||||
|
if (CHECK_FLAG(pi->peer->group->conf->af_flags[afi][safi],
|
||||||
|
PEER_FLAG_CONFIG_DAMPENING))
|
||||||
|
return &pi->peer->group->conf->damp[afi][safi];
|
||||||
|
if (CHECK_FLAG(pi->peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
|
||||||
|
return &pi->peer->bgp->damp[afi][safi];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate reuse list index by penalty value. */
|
/* Calculate reuse list index by penalty value. */
|
||||||
static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
|
static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int index;
|
unsigned int index;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* reuse_limit can't be zero, this is for Coverity
|
* reuse_limit can't be zero, this is for Coverity
|
||||||
@ -57,27 +114,28 @@ static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
|
|||||||
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)
|
struct bgp_damp_config *bdc)
|
||||||
{
|
{
|
||||||
int index;
|
bgp_damp_info_claim(bdi, bdc);
|
||||||
|
bdi->index = bgp_reuse_index(bdi->penalty, bdc);
|
||||||
index = bdi->index = bgp_reuse_index(bdi->penalty, bdc);
|
bgp_reuselist_add(&bdc->reuse_list[bdi->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. */
|
/* 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)
|
||||||
|
{
|
||||||
|
bgp_damp_info_unclaim(bdi, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bgp_no_reuse_list_add(struct bgp_damp_info *bdi,
|
||||||
struct bgp_damp_config *bdc)
|
struct bgp_damp_config *bdc)
|
||||||
{
|
{
|
||||||
if (bdi->next)
|
bgp_damp_info_claim(bdi, bdc);
|
||||||
bdi->next->prev = bdi->prev;
|
bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
|
||||||
if (bdi->prev)
|
bgp_reuselist_add(&bdc->no_reuse_list, bdi);
|
||||||
bdi->prev->next = bdi->next;
|
}
|
||||||
else
|
|
||||||
bdc->reuse_list[bdi->index] = bdi->next;
|
static void bgp_no_reuse_list_delete(struct bgp_damp_info *bdi)
|
||||||
|
{
|
||||||
|
bgp_damp_info_unclaim(bdi, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return decayed penalty value. */
|
/* Return decayed penalty value. */
|
||||||
@ -100,10 +158,10 @@ int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc)
|
|||||||
is evaluated. RFC2439 Section 4.8.7. */
|
is evaluated. RFC2439 Section 4.8.7. */
|
||||||
static void bgp_reuse_timer(struct event *t)
|
static void bgp_reuse_timer(struct event *t)
|
||||||
{
|
{
|
||||||
struct bgp_damp_info *bdi;
|
struct bgp_damp_info *bdi, *bdi_next;
|
||||||
struct bgp_damp_info *next;
|
struct reuselist plist;
|
||||||
|
struct bgp *bgp;
|
||||||
time_t t_now, t_diff;
|
time_t t_now, t_diff;
|
||||||
|
|
||||||
struct bgp_damp_config *bdc = EVENT_ARG(t);
|
struct bgp_damp_config *bdc = EVENT_ARG(t);
|
||||||
|
|
||||||
bdc->t_reuse = NULL;
|
bdc->t_reuse = NULL;
|
||||||
@ -112,20 +170,20 @@ static void bgp_reuse_timer(struct event *t)
|
|||||||
|
|
||||||
t_now = monotime(NULL);
|
t_now = monotime(NULL);
|
||||||
|
|
||||||
/* 1. save a pointer to the current zeroth queue head and zero the
|
/* 1. save a pointer to the current queue head and zero the list head
|
||||||
list head entry. */
|
* list head entry. */
|
||||||
bdi = bdc->reuse_list[bdc->reuse_offset];
|
assert(bdc->reuse_offset < bdc->reuse_list_size);
|
||||||
bdc->reuse_list[bdc->reuse_offset] = NULL;
|
plist = bdc->reuse_list[bdc->reuse_offset];
|
||||||
|
SLIST_INIT(&bdc->reuse_list[bdc->reuse_offset]);
|
||||||
|
|
||||||
/* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
|
/* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
|
||||||
rotating the circular queue of list-heads. */
|
rotating the circular queue of list-heads. */
|
||||||
bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size;
|
bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size;
|
||||||
|
assert(bdc->reuse_offset < bdc->reuse_list_size);
|
||||||
|
|
||||||
/* 3. if ( the saved list head pointer is non-empty ) */
|
/* 3. if ( the saved list head pointer is non-empty ) */
|
||||||
for (; bdi; bdi = next) {
|
SLIST_FOREACH_SAFE (bdi, &plist, entry, bdi_next) {
|
||||||
struct bgp *bgp = bdi->path->peer->bgp;
|
bgp = bdi->path->peer->bgp;
|
||||||
|
|
||||||
next = bdi->next;
|
|
||||||
|
|
||||||
/* Set t-diff = t-now - t-updated. */
|
/* Set t-diff = t-now - t-updated. */
|
||||||
t_diff = t_now - bdi->t_updated;
|
t_diff = t_now - bdi->t_updated;
|
||||||
@ -154,15 +212,23 @@ static void bgp_reuse_timer(struct event *t)
|
|||||||
bdi->safi);
|
bdi->safi);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bdi->penalty <= bdc->reuse_limit / 2.0)
|
if (bdi->penalty <= bdc->reuse_limit / 2.0) {
|
||||||
bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi);
|
bgp_damp_info_free(bdi, &plist, 1);
|
||||||
else
|
} else {
|
||||||
BGP_DAMP_LIST_ADD(bdc, bdi);
|
bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
|
||||||
} else
|
bgp_reuselist_switch(&plist, bdi,
|
||||||
|
&bdc->no_reuse_list);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
/* Re-insert into another list (See RFC2439 Section
|
/* Re-insert into another list (See RFC2439 Section
|
||||||
* 4.8.6). */
|
* 4.8.6). */
|
||||||
bgp_reuse_list_add(bdi, bdc);
|
bdi->index = bgp_reuse_index(bdi->penalty, bdc);
|
||||||
|
bgp_reuselist_switch(&plist, bdi,
|
||||||
|
&bdc->reuse_list[bdi->index]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(SLIST_EMPTY(&plist));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A route becomes unreachable (RFC2439 Section 4.8.2). */
|
/* A route becomes unreachable (RFC2439 Section 4.8.2). */
|
||||||
@ -172,10 +238,13 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
|
|||||||
time_t t_now;
|
time_t t_now;
|
||||||
struct bgp_damp_info *bdi = NULL;
|
struct bgp_damp_info *bdi = NULL;
|
||||||
unsigned int last_penalty = 0;
|
unsigned int last_penalty = 0;
|
||||||
struct bgp_damp_config *bdc = &damp[afi][safi];
|
struct bgp_damp_config *bdc;
|
||||||
|
|
||||||
|
bdc = get_active_bdc_from_pi(path, afi, safi);
|
||||||
|
if (!bdc)
|
||||||
|
return BGP_DAMP_USED;
|
||||||
|
|
||||||
t_now = monotime(NULL);
|
t_now = monotime(NULL);
|
||||||
|
|
||||||
/* Processing Unreachable Messages. */
|
/* Processing Unreachable Messages. */
|
||||||
if (path->extra)
|
if (path->extra)
|
||||||
bdi = path->extra->damp_info;
|
bdi = path->extra->damp_info;
|
||||||
@ -197,12 +266,20 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
|
|||||||
bdi->flap = 1;
|
bdi->flap = 1;
|
||||||
bdi->start_time = t_now;
|
bdi->start_time = t_now;
|
||||||
bdi->suppress_time = 0;
|
bdi->suppress_time = 0;
|
||||||
bdi->index = -1;
|
bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
|
||||||
bdi->afi = afi;
|
bdi->afi = afi;
|
||||||
bdi->safi = safi;
|
bdi->safi = safi;
|
||||||
(bgp_path_info_extra_get(path))->damp_info = bdi;
|
(bgp_path_info_extra_get(path))->damp_info = bdi;
|
||||||
BGP_DAMP_LIST_ADD(bdc, bdi);
|
bgp_no_reuse_list_add(bdi, bdc);
|
||||||
} else {
|
} else {
|
||||||
|
if (bdi->config != bdc) {
|
||||||
|
bgp_damp_info_claim(bdi, bdc);
|
||||||
|
if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX)
|
||||||
|
bgp_reuselist_add(&bdc->no_reuse_list, bdi);
|
||||||
|
else
|
||||||
|
bgp_reuselist_add(&bdc->reuse_list[bdi->index],
|
||||||
|
bdi);
|
||||||
|
}
|
||||||
last_penalty = bdi->penalty;
|
last_penalty = bdi->penalty;
|
||||||
|
|
||||||
/* 1. Set t-diff = t-now - t-updated. */
|
/* 1. Set t-diff = t-now - t-updated. */
|
||||||
@ -228,8 +305,8 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
|
|||||||
/* Remove the route from a reuse list if it is on one. */
|
/* Remove the route from a reuse list if it is on one. */
|
||||||
if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) {
|
if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) {
|
||||||
/* If decay rate isn't equal to 0, reinsert brn. */
|
/* If decay rate isn't equal to 0, reinsert brn. */
|
||||||
if (bdi->penalty != last_penalty && bdi->index >= 0) {
|
if (bdi->penalty != last_penalty) {
|
||||||
bgp_reuse_list_delete(bdi, bdc);
|
bgp_reuse_list_delete(bdi);
|
||||||
bgp_reuse_list_add(bdi, bdc);
|
bgp_reuse_list_add(bdi, bdc);
|
||||||
}
|
}
|
||||||
return BGP_DAMP_SUPPRESSED;
|
return BGP_DAMP_SUPPRESSED;
|
||||||
@ -240,10 +317,9 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
|
|||||||
if (bdi->penalty >= bdc->suppress_value) {
|
if (bdi->penalty >= bdc->suppress_value) {
|
||||||
bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED);
|
bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED);
|
||||||
bdi->suppress_time = t_now;
|
bdi->suppress_time = t_now;
|
||||||
BGP_DAMP_LIST_DEL(bdc, bdi);
|
bgp_no_reuse_list_delete(bdi);
|
||||||
bgp_reuse_list_add(bdi, bdc);
|
bgp_reuse_list_add(bdi, bdc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return BGP_DAMP_USED;
|
return BGP_DAMP_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +329,10 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
|
|||||||
time_t t_now;
|
time_t t_now;
|
||||||
struct bgp_damp_info *bdi;
|
struct bgp_damp_info *bdi;
|
||||||
int status;
|
int status;
|
||||||
struct bgp_damp_config *bdc = &damp[afi][safi];
|
struct bgp_damp_config *bdc;
|
||||||
|
|
||||||
|
bdc = get_active_bdc_from_pi(path, afi, safi);
|
||||||
|
assert(bdc);
|
||||||
|
|
||||||
if (!path->extra || !((bdi = path->extra->damp_info)))
|
if (!path->extra || !((bdi = path->extra->damp_info)))
|
||||||
return BGP_DAMP_USED;
|
return BGP_DAMP_USED;
|
||||||
@ -271,8 +350,8 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
|
|||||||
else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
|
else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
|
||||||
&& (bdi->penalty < bdc->reuse_limit)) {
|
&& (bdi->penalty < bdc->reuse_limit)) {
|
||||||
bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED);
|
bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED);
|
||||||
bgp_reuse_list_delete(bdi, bdc);
|
bgp_reuse_list_delete(bdi);
|
||||||
BGP_DAMP_LIST_ADD(bdc, bdi);
|
bgp_no_reuse_list_add(bdi, bdc);
|
||||||
bdi->suppress_time = 0;
|
bdi->suppress_time = 0;
|
||||||
status = BGP_DAMP_USED;
|
status = BGP_DAMP_USED;
|
||||||
} else
|
} else
|
||||||
@ -281,34 +360,31 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
|
|||||||
if (bdi->penalty > bdc->reuse_limit / 2.0)
|
if (bdi->penalty > bdc->reuse_limit / 2.0)
|
||||||
bdi->t_updated = t_now;
|
bdi->t_updated = t_now;
|
||||||
else
|
else
|
||||||
bgp_damp_info_free(bdi, 0, afi, safi);
|
bgp_damp_info_free(bdi, NULL, 0);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi,
|
void bgp_damp_info_free(struct bgp_damp_info *bdi, struct reuselist *list,
|
||||||
safi_t safi)
|
int withdraw)
|
||||||
{
|
{
|
||||||
struct bgp_path_info *path;
|
assert(bdi);
|
||||||
struct bgp_damp_config *bdc = &damp[afi][safi];
|
|
||||||
|
|
||||||
if (!bdi)
|
afi_t afi = bdi->afi;
|
||||||
return;
|
safi_t safi = bdi->safi;
|
||||||
|
struct bgp_path_info *bpi = bdi->path;
|
||||||
|
struct bgp_dest *dest = bdi->dest;
|
||||||
|
struct bgp *bgp = bpi->peer->bgp;
|
||||||
|
const struct prefix *p = bgp_dest_get_prefix(bdi->dest);
|
||||||
|
|
||||||
path = bdi->path;
|
bgp_damp_info_unclaim(bdi, list);
|
||||||
path->extra->damp_info = NULL;
|
|
||||||
|
|
||||||
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED))
|
|
||||||
bgp_reuse_list_delete(bdi, bdc);
|
|
||||||
else
|
|
||||||
BGP_DAMP_LIST_DEL(bdc, bdi);
|
|
||||||
|
|
||||||
bgp_path_info_unset_flag(bdi->dest, path,
|
|
||||||
BGP_PATH_HISTORY | BGP_PATH_DAMPED);
|
|
||||||
|
|
||||||
|
bpi->extra->damp_info = NULL;
|
||||||
|
bgp_path_info_unset_flag(dest, bpi, BGP_PATH_HISTORY | BGP_PATH_DAMPED);
|
||||||
if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) {
|
if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) {
|
||||||
bgp_path_info_delete(bdi->dest, path);
|
bgp_aggregate_decrement(bgp, p, bpi, afi, SAFI_UNICAST);
|
||||||
bgp_process(path->peer->bgp, bdi->dest, path, afi, safi);
|
bgp_path_info_delete(dest, bpi);
|
||||||
|
bgp_process(bgp, dest, bpi, afi, safi);
|
||||||
}
|
}
|
||||||
|
|
||||||
XFREE(MTYPE_BGP_DAMP_INFO, bdi);
|
XFREE(MTYPE_BGP_DAMP_INFO, bdi);
|
||||||
@ -355,8 +431,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse,
|
|||||||
|
|
||||||
bdc->reuse_list =
|
bdc->reuse_list =
|
||||||
XCALLOC(MTYPE_BGP_DAMP_ARRAY,
|
XCALLOC(MTYPE_BGP_DAMP_ARRAY,
|
||||||
bdc->reuse_list_size * sizeof(struct bgp_reuse_node *));
|
bdc->reuse_list_size * sizeof(struct reuselist));
|
||||||
|
|
||||||
/* Reuse-array computations */
|
/* Reuse-array computations */
|
||||||
bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
|
bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
|
||||||
sizeof(int) * bdc->reuse_index_size);
|
sizeof(int) * bdc->reuse_index_size);
|
||||||
@ -383,7 +458,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse,
|
|||||||
int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
|
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)
|
unsigned int reuse, unsigned int suppress, time_t max)
|
||||||
{
|
{
|
||||||
struct bgp_damp_config *bdc = &damp[afi][safi];
|
struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
|
||||||
|
|
||||||
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
|
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
|
||||||
if (bdc->half_life == half && bdc->reuse_limit == reuse
|
if (bdc->half_life == half && bdc->reuse_limit == reuse
|
||||||
@ -395,6 +470,8 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
|
|||||||
|
|
||||||
SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
|
SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
|
||||||
bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
|
bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
|
||||||
|
bdc->afi = afi;
|
||||||
|
bdc->safi = safi;
|
||||||
|
|
||||||
/* Register reuse timer. */
|
/* Register reuse timer. */
|
||||||
event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
|
event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
|
||||||
@ -403,8 +480,34 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
|
/* Clean all the bgp_damp_info stored in reuse_list and no_reuse_list. */
|
||||||
|
void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc,
|
||||||
|
afi_t afi, safi_t safi)
|
||||||
{
|
{
|
||||||
|
struct bgp_damp_info *bdi;
|
||||||
|
struct reuselist *list;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
bdc->reuse_offset = 0;
|
||||||
|
for (i = 0; i < bdc->reuse_list_size; ++i) {
|
||||||
|
list = &bdc->reuse_list[i];
|
||||||
|
while ((bdi = SLIST_FIRST(list)) != NULL) {
|
||||||
|
if (bdi->lastrecord == BGP_RECORD_UPDATE) {
|
||||||
|
bgp_aggregate_increment(bgp,
|
||||||
|
bgp_dest_get_prefix(
|
||||||
|
bdi->dest),
|
||||||
|
bdi->path, bdi->afi,
|
||||||
|
bdi->safi);
|
||||||
|
bgp_process(bgp, bdi->dest, bdi->path, bdi->afi,
|
||||||
|
bdi->safi);
|
||||||
|
}
|
||||||
|
bgp_damp_info_free(bdi, list, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((bdi = SLIST_FIRST(&bdc->no_reuse_list)) != NULL)
|
||||||
|
bgp_damp_info_free(bdi, &bdc->no_reuse_list, 1);
|
||||||
|
|
||||||
/* Free decay array */
|
/* Free decay array */
|
||||||
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
|
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
|
||||||
bdc->decay_array_size = 0;
|
bdc->decay_array_size = 0;
|
||||||
@ -413,41 +516,25 @@ static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
|
|||||||
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index);
|
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index);
|
||||||
bdc->reuse_index_size = 0;
|
bdc->reuse_index_size = 0;
|
||||||
|
|
||||||
/* Free reuse list array. */
|
|
||||||
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
|
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
|
||||||
bdc->reuse_list_size = 0;
|
bdc->reuse_list_size = 0;
|
||||||
|
|
||||||
|
EVENT_OFF(bdc->t_reuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean all the bgp_damp_info stored in reuse_list. */
|
/* Disable route flap dampening for a bgp instance.
|
||||||
void bgp_damp_info_clean(afi_t afi, safi_t safi)
|
*
|
||||||
{
|
* Please note that this function also gets used to free memory when deleting a
|
||||||
unsigned int i;
|
* bgp instance.
|
||||||
struct bgp_damp_info *bdi, *next;
|
*/
|
||||||
struct bgp_damp_config *bdc = &damp[afi][safi];
|
|
||||||
|
|
||||||
bdc->reuse_offset = 0;
|
|
||||||
|
|
||||||
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 = bdc->no_reuse_list; bdi; bdi = next) {
|
|
||||||
next = bdi->next;
|
|
||||||
bgp_damp_info_free(bdi, 1, afi, safi);
|
|
||||||
}
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
struct bgp_damp_config *bdc = &damp[afi][safi];
|
struct bgp_damp_config *bdc;
|
||||||
|
|
||||||
|
bdc = &bgp->damp[afi][safi];
|
||||||
|
if (!bdc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* If it wasn't enabled, there's nothing to do. */
|
/* If it wasn't enabled, there's nothing to do. */
|
||||||
if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
|
if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
|
||||||
return 0;
|
return 0;
|
||||||
@ -456,54 +543,51 @@ int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
|
|||||||
EVENT_OFF(bdc->t_reuse);
|
EVENT_OFF(bdc->t_reuse);
|
||||||
|
|
||||||
/* Clean BGP dampening information. */
|
/* Clean BGP dampening information. */
|
||||||
bgp_damp_info_clean(afi, safi);
|
bgp_damp_info_clean(bgp, bdc, afi, safi);
|
||||||
|
|
||||||
/* Clear configuration */
|
|
||||||
bgp_damp_config_clean(bdc);
|
|
||||||
|
|
||||||
UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
|
UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi)
|
void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||||
|
safi_t safi)
|
||||||
{
|
{
|
||||||
if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60
|
struct bgp_damp_config *bdc;
|
||||||
&& damp[afi][safi].reuse_limit == DEFAULT_REUSE
|
|
||||||
&& damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
|
bdc = &bgp->damp[afi][safi];
|
||||||
&& damp[afi][safi].max_suppress_time
|
if (bdc->half_life == DEFAULT_HALF_LIFE * 60 &&
|
||||||
== damp[afi][safi].half_life * 4)
|
bdc->reuse_limit == DEFAULT_REUSE &&
|
||||||
|
bdc->suppress_value == DEFAULT_SUPPRESS &&
|
||||||
|
bdc->max_suppress_time == bdc->half_life * 4)
|
||||||
vty_out(vty, " bgp dampening\n");
|
vty_out(vty, " bgp dampening\n");
|
||||||
else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60
|
else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 &&
|
||||||
&& damp[afi][safi].reuse_limit == DEFAULT_REUSE
|
bdc->reuse_limit == DEFAULT_REUSE &&
|
||||||
&& damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
|
bdc->suppress_value == DEFAULT_SUPPRESS &&
|
||||||
&& damp[afi][safi].max_suppress_time
|
bdc->max_suppress_time == bdc->half_life * 4)
|
||||||
== damp[afi][safi].half_life * 4)
|
vty_out(vty, " bgp dampening %lld\n", bdc->half_life / 60LL);
|
||||||
vty_out(vty, " bgp dampening %lld\n",
|
|
||||||
damp[afi][safi].half_life / 60LL);
|
|
||||||
else
|
else
|
||||||
vty_out(vty, " bgp dampening %lld %d %d %lld\n",
|
vty_out(vty, " bgp dampening %lld %d %d %lld\n",
|
||||||
damp[afi][safi].half_life / 60LL,
|
bdc->half_life / 60LL, bdc->reuse_limit,
|
||||||
damp[afi][safi].reuse_limit,
|
bdc->suppress_value, bdc->max_suppress_time / 60LL);
|
||||||
damp[afi][safi].suppress_value,
|
|
||||||
damp[afi][safi].max_suppress_time / 60LL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
|
static const char *bgp_get_reuse_time(struct bgp_damp_config *bdc,
|
||||||
size_t len, afi_t afi, safi_t safi,
|
unsigned int penalty, char *buf,
|
||||||
bool use_json, json_object *json)
|
size_t len, bool use_json,
|
||||||
|
json_object *json)
|
||||||
{
|
{
|
||||||
time_t reuse_time = 0;
|
time_t reuse_time = 0;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
int time_store = 0;
|
int time_store = 0;
|
||||||
|
|
||||||
if (penalty > damp[afi][safi].reuse_limit) {
|
if (penalty > bdc->reuse_limit) {
|
||||||
reuse_time = (int)(DELTA_T
|
reuse_time = (int)(DELTA_T *
|
||||||
* ((log((double)damp[afi][safi].reuse_limit
|
((log((double)bdc->reuse_limit / penalty)) /
|
||||||
/ penalty))
|
(log(bdc->decay_array[1]))));
|
||||||
/ (log(damp[afi][safi].decay_array[1]))));
|
|
||||||
|
|
||||||
if (reuse_time > damp[afi][safi].max_suppress_time)
|
if (reuse_time > bdc->max_suppress_time)
|
||||||
reuse_time = damp[afi][safi].max_suppress_time;
|
reuse_time = bdc->max_suppress_time;
|
||||||
|
|
||||||
gmtime_r(&reuse_time, &tm);
|
gmtime_r(&reuse_time, &tm);
|
||||||
} else
|
} else
|
||||||
@ -555,14 +639,15 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
|
void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp,
|
||||||
safi_t safi, json_object *json_path)
|
struct bgp_path_info *path, afi_t afi, safi_t safi,
|
||||||
|
json_object *json_path)
|
||||||
{
|
{
|
||||||
struct bgp_damp_info *bdi;
|
struct bgp_damp_info *bdi;
|
||||||
time_t t_now, t_diff;
|
time_t t_now, t_diff;
|
||||||
char timebuf[BGP_UPTIME_LEN] = {};
|
char timebuf[BGP_UPTIME_LEN] = {};
|
||||||
int penalty;
|
int penalty;
|
||||||
struct bgp_damp_config *bdc = &damp[afi][safi];
|
struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
|
||||||
|
|
||||||
if (!path->extra)
|
if (!path->extra)
|
||||||
return;
|
return;
|
||||||
@ -590,8 +675,8 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
|
|||||||
|
|
||||||
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
|
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
|
||||||
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
|
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
|
||||||
bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN,
|
bgp_get_reuse_time(bdc, penalty, timebuf,
|
||||||
afi, safi, 1, json_path);
|
BGP_UPTIME_LEN, 1, json_path);
|
||||||
} else {
|
} else {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
" Dampinfo: penalty %d, flapped %d times in %s",
|
" Dampinfo: penalty %d, flapped %d times in %s",
|
||||||
@ -602,14 +687,15 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
|
|||||||
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
|
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
|
||||||
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
|
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
|
||||||
vty_out(vty, ", reuse in %s",
|
vty_out(vty, ", reuse in %s",
|
||||||
bgp_get_reuse_time(penalty, timebuf,
|
bgp_get_reuse_time(bdc, penalty, timebuf,
|
||||||
BGP_UPTIME_LEN, afi, safi, 0,
|
BGP_UPTIME_LEN, 0,
|
||||||
json_path));
|
json_path));
|
||||||
|
|
||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
|
const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
|
||||||
char *timebuf, size_t len, afi_t afi,
|
char *timebuf, size_t len, afi_t afi,
|
||||||
safi_t safi, bool use_json,
|
safi_t safi, bool use_json,
|
||||||
@ -618,7 +704,11 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
|
|||||||
struct bgp_damp_info *bdi;
|
struct bgp_damp_info *bdi;
|
||||||
time_t t_now, t_diff;
|
time_t t_now, t_diff;
|
||||||
int penalty;
|
int penalty;
|
||||||
struct bgp_damp_config *bdc = &damp[afi][safi];
|
struct bgp_damp_config *bdc;
|
||||||
|
|
||||||
|
bdc = get_active_bdc_from_pi(path, afi, safi);
|
||||||
|
if (!bdc)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (!path->extra)
|
if (!path->extra)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -638,15 +728,15 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
|
|||||||
t_diff = t_now - bdi->t_updated;
|
t_diff = t_now - bdi->t_updated;
|
||||||
penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
|
penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
|
||||||
|
|
||||||
return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json,
|
return bgp_get_reuse_time(bdc, penalty, timebuf, len, use_json, json);
|
||||||
json);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
|
static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
|
||||||
afi_t afi, safi_t safi, bool use_json)
|
afi_t afi, safi_t safi, bool use_json)
|
||||||
{
|
{
|
||||||
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
|
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
|
||||||
struct bgp_damp_config *bdc = &damp[afi][safi];
|
struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
|
||||||
|
|
||||||
if (use_json) {
|
if (use_json) {
|
||||||
json_object *json = json_object_new_object();
|
json_object *json = json_object_new_object();
|
||||||
@ -689,7 +779,6 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
|
|||||||
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
|
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
|
||||||
|
|
||||||
bgp = bgp_get_default();
|
bgp = bgp_get_default();
|
||||||
|
|
||||||
if (bgp == NULL) {
|
if (bgp == NULL) {
|
||||||
vty_out(vty, "No BGP process is configured\n");
|
vty_out(vty, "No BGP process is configured\n");
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
@ -731,3 +820,130 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
|
|||||||
}
|
}
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi, time_t half,
|
||||||
|
unsigned int reuse, unsigned int suppress, time_t max)
|
||||||
|
{
|
||||||
|
struct bgp_damp_config *bdc;
|
||||||
|
|
||||||
|
if (!peer)
|
||||||
|
return;
|
||||||
|
bdc = &peer->damp[afi][safi];
|
||||||
|
if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING)) {
|
||||||
|
if (bdc->half_life == half && bdc->reuse_limit == reuse &&
|
||||||
|
bdc->suppress_value == suppress &&
|
||||||
|
bdc->max_suppress_time == max)
|
||||||
|
return;
|
||||||
|
bgp_peer_damp_disable(peer, afi, safi);
|
||||||
|
}
|
||||||
|
SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
|
||||||
|
bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
|
||||||
|
bdc->afi = afi;
|
||||||
|
bdc->safi = safi;
|
||||||
|
event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
|
||||||
|
&bdc->t_reuse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable route flap dampening for a peer.
|
||||||
|
*
|
||||||
|
* Please note that this function also gets used to free memory when deleting a
|
||||||
|
* peer or peer group.
|
||||||
|
*/
|
||||||
|
void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi)
|
||||||
|
{
|
||||||
|
struct bgp_damp_config *bdc;
|
||||||
|
|
||||||
|
if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING))
|
||||||
|
return;
|
||||||
|
bdc = &peer->damp[afi][safi];
|
||||||
|
if (!bdc)
|
||||||
|
return;
|
||||||
|
bgp_damp_info_clean(peer->bgp, bdc, afi, safi);
|
||||||
|
UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer, afi_t afi,
|
||||||
|
safi_t safi)
|
||||||
|
{
|
||||||
|
struct bgp_damp_config *bdc;
|
||||||
|
|
||||||
|
bdc = &peer->damp[afi][safi];
|
||||||
|
if (bdc->half_life == DEFAULT_HALF_LIFE * 60 &&
|
||||||
|
bdc->reuse_limit == DEFAULT_REUSE &&
|
||||||
|
bdc->suppress_value == DEFAULT_SUPPRESS &&
|
||||||
|
bdc->max_suppress_time == bdc->half_life * 4)
|
||||||
|
vty_out(vty, " neighbor %s dampening\n", peer->host);
|
||||||
|
else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 &&
|
||||||
|
bdc->reuse_limit == DEFAULT_REUSE &&
|
||||||
|
bdc->suppress_value == DEFAULT_SUPPRESS &&
|
||||||
|
bdc->max_suppress_time == bdc->half_life * 4)
|
||||||
|
vty_out(vty, " neighbor %s dampening %lld\n", peer->host,
|
||||||
|
bdc->half_life / 60LL);
|
||||||
|
else
|
||||||
|
vty_out(vty, " neighbor %s dampening %lld %d %d %lld\n",
|
||||||
|
peer->host, bdc->half_life / 60LL, bdc->reuse_limit,
|
||||||
|
bdc->suppress_value, bdc->max_suppress_time / 60LL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bgp_print_peer_dampening_parameters(struct vty *vty,
|
||||||
|
struct peer *peer, afi_t afi,
|
||||||
|
safi_t safi, bool use_json,
|
||||||
|
json_object *json)
|
||||||
|
{
|
||||||
|
struct bgp_damp_config *bdc;
|
||||||
|
|
||||||
|
if (!peer)
|
||||||
|
return;
|
||||||
|
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING)) {
|
||||||
|
bdc = &peer->damp[afi][safi];
|
||||||
|
if (!bdc)
|
||||||
|
return;
|
||||||
|
if (use_json) {
|
||||||
|
json_object_int_add(json, "halfLifeSecs",
|
||||||
|
bdc->half_life);
|
||||||
|
json_object_int_add(json, "reusePenalty",
|
||||||
|
bdc->reuse_limit);
|
||||||
|
json_object_int_add(json, "suppressPenalty",
|
||||||
|
bdc->suppress_value);
|
||||||
|
json_object_int_add(json, "maxSuppressTimeSecs",
|
||||||
|
bdc->max_suppress_time);
|
||||||
|
json_object_int_add(json, "maxSuppressPenalty",
|
||||||
|
bdc->ceiling);
|
||||||
|
} else {
|
||||||
|
vty_out(vty, "Half-life time: %lld min\n",
|
||||||
|
(long long)bdc->half_life / 60);
|
||||||
|
vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit);
|
||||||
|
vty_out(vty, "Suppress penalty: %d\n",
|
||||||
|
bdc->suppress_value);
|
||||||
|
vty_out(vty, "Max suppress time: %lld min\n",
|
||||||
|
(long long)bdc->max_suppress_time / 60);
|
||||||
|
vty_out(vty, "Max suppress penalty: %u\n", bdc->ceiling);
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
}
|
||||||
|
} else if (!use_json)
|
||||||
|
vty_out(vty, "neighbor dampening not enabled for %s\n",
|
||||||
|
get_afi_safi_str(afi, safi, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void bgp_show_peer_dampening_parameters(struct vty *vty, struct peer *peer,
|
||||||
|
afi_t afi, safi_t safi, bool use_json)
|
||||||
|
{
|
||||||
|
json_object *json;
|
||||||
|
|
||||||
|
if (use_json) {
|
||||||
|
json = json_object_new_object();
|
||||||
|
json_object_string_add(json, "addressFamily",
|
||||||
|
get_afi_safi_str(afi, safi, false));
|
||||||
|
bgp_print_peer_dampening_parameters(vty, peer, afi, safi, true,
|
||||||
|
json);
|
||||||
|
vty_out(vty, "%s\n",
|
||||||
|
json_object_to_json_string_ext(json,
|
||||||
|
JSON_C_TO_STRING_PRETTY));
|
||||||
|
json_object_free(json);
|
||||||
|
} else {
|
||||||
|
vty_out(vty, "\nFor address family: %s\n",
|
||||||
|
get_afi_safi_str(afi, safi, false));
|
||||||
|
bgp_print_peer_dampening_parameters(vty, peer, afi, safi, false,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,11 +10,6 @@
|
|||||||
|
|
||||||
/* Structure maintained on a per-route basis. */
|
/* Structure maintained on a per-route basis. */
|
||||||
struct bgp_damp_info {
|
struct bgp_damp_info {
|
||||||
/* Doubly linked list. This information must be linked to
|
|
||||||
reuse_list or no_reuse_list. */
|
|
||||||
struct bgp_damp_info *next;
|
|
||||||
struct bgp_damp_info *prev;
|
|
||||||
|
|
||||||
/* Figure-of-merit. */
|
/* Figure-of-merit. */
|
||||||
unsigned int penalty;
|
unsigned int penalty;
|
||||||
|
|
||||||
@ -30,6 +25,9 @@ struct bgp_damp_info {
|
|||||||
/* Time of route start to be suppressed. */
|
/* Time of route start to be suppressed. */
|
||||||
time_t suppress_time;
|
time_t suppress_time;
|
||||||
|
|
||||||
|
/* Back reference to associated dampening configuration. */
|
||||||
|
struct bgp_damp_config *config;
|
||||||
|
|
||||||
/* Back reference to bgp_path_info. */
|
/* Back reference to bgp_path_info. */
|
||||||
struct bgp_path_info *path;
|
struct bgp_path_info *path;
|
||||||
|
|
||||||
@ -38,6 +36,8 @@ struct bgp_damp_info {
|
|||||||
|
|
||||||
/* Current index in the reuse_list. */
|
/* Current index in the reuse_list. */
|
||||||
int index;
|
int index;
|
||||||
|
#define BGP_DAMP_NO_REUSE_LIST_INDEX \
|
||||||
|
(-1) /* index for elements on no_reuse_list */
|
||||||
|
|
||||||
/* Last time message type. */
|
/* Last time message type. */
|
||||||
uint8_t lastrecord;
|
uint8_t lastrecord;
|
||||||
@ -46,8 +46,12 @@ struct bgp_damp_info {
|
|||||||
|
|
||||||
afi_t afi;
|
afi_t afi;
|
||||||
safi_t safi;
|
safi_t safi;
|
||||||
|
|
||||||
|
SLIST_ENTRY(bgp_damp_info) entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SLIST_HEAD(reuselist, bgp_damp_info);
|
||||||
|
|
||||||
/* Specified parameter set configuration. */
|
/* Specified parameter set configuration. */
|
||||||
struct bgp_damp_config {
|
struct bgp_damp_config {
|
||||||
/* Value over which routes suppressed. */
|
/* Value over which routes suppressed. */
|
||||||
@ -84,12 +88,12 @@ struct bgp_damp_config {
|
|||||||
int *reuse_index;
|
int *reuse_index;
|
||||||
|
|
||||||
/* Reuse list array per-set based. */
|
/* Reuse list array per-set based. */
|
||||||
struct bgp_damp_info **reuse_list;
|
struct reuselist *reuse_list;
|
||||||
int reuse_offset;
|
unsigned int reuse_offset;
|
||||||
safi_t safi;
|
safi_t safi;
|
||||||
|
|
||||||
/* All dampening information which is not on reuse list. */
|
/* All dampening information which is not on reuse list. */
|
||||||
struct bgp_damp_info *no_reuse_list;
|
struct reuselist no_reuse_list;
|
||||||
|
|
||||||
/* Reuse timer thread per-set base. */
|
/* Reuse timer thread per-set base. */
|
||||||
struct event *t_reuse;
|
struct event *t_reuse;
|
||||||
@ -116,6 +120,8 @@ struct bgp_damp_config {
|
|||||||
#define REUSE_LIST_SIZE 256
|
#define REUSE_LIST_SIZE 256
|
||||||
#define REUSE_ARRAY_SIZE 1024
|
#define REUSE_ARRAY_SIZE 1024
|
||||||
|
|
||||||
|
extern struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi,
|
||||||
|
afi_t afi, safi_t safi);
|
||||||
extern int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
|
extern int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half,
|
||||||
unsigned int reuse, unsigned int suppress,
|
unsigned int reuse, unsigned int suppress,
|
||||||
time_t max);
|
time_t max);
|
||||||
@ -124,14 +130,18 @@ extern int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
|
|||||||
afi_t afi, safi_t safi, int attr_change);
|
afi_t afi, safi_t safi, int attr_change);
|
||||||
extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
|
extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
|
||||||
afi_t afi, safi_t saff);
|
afi_t afi, safi_t saff);
|
||||||
extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw,
|
extern void bgp_damp_info_free(struct bgp_damp_info *bdi,
|
||||||
afi_t afi, safi_t safi);
|
struct reuselist *list, int withdraw);
|
||||||
extern void bgp_damp_info_clean(afi_t afi, safi_t safi);
|
extern void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc,
|
||||||
|
afi_t afi, safi_t safi);
|
||||||
|
extern void bgp_damp_config_clean(struct bgp_damp_config *bdc);
|
||||||
extern int bgp_damp_decay(time_t tdiff, int penalty,
|
extern int bgp_damp_decay(time_t tdiff, int penalty,
|
||||||
struct bgp_damp_config *damp);
|
struct bgp_damp_config *bdc);
|
||||||
extern void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi);
|
extern void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||||
extern void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path,
|
safi_t safi);
|
||||||
afi_t afi, safi_t safi, json_object *json_path);
|
extern void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp,
|
||||||
|
struct bgp_path_info *path, afi_t afi,
|
||||||
|
safi_t safi, json_object *json_path);
|
||||||
extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
|
extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
|
||||||
struct bgp_path_info *path,
|
struct bgp_path_info *path,
|
||||||
char *timebuf, size_t len, afi_t afi,
|
char *timebuf, size_t len, afi_t afi,
|
||||||
@ -139,5 +149,14 @@ extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
|
|||||||
json_object *json);
|
json_object *json);
|
||||||
extern int bgp_show_dampening_parameters(struct vty *vty, afi_t afi,
|
extern int bgp_show_dampening_parameters(struct vty *vty, afi_t afi,
|
||||||
safi_t safi, uint16_t show_flags);
|
safi_t safi, uint16_t show_flags);
|
||||||
|
extern void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi,
|
||||||
|
time_t half, unsigned int reuse,
|
||||||
|
unsigned int suppress, time_t max);
|
||||||
|
extern void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi);
|
||||||
|
extern void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer,
|
||||||
|
afi_t afi, safi_t safi);
|
||||||
|
extern void bgp_show_peer_dampening_parameters(struct vty *vty,
|
||||||
|
struct peer *peer, afi_t afi,
|
||||||
|
safi_t safi, bool use_json);
|
||||||
|
|
||||||
#endif /* _QUAGGA_BGP_DAMP_H */
|
#endif /* _QUAGGA_BGP_DAMP_H */
|
||||||
|
@ -91,6 +91,7 @@ DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface");
|
|||||||
DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface");
|
DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface");
|
||||||
DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info");
|
DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info");
|
||||||
DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array");
|
DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array");
|
||||||
|
DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list");
|
||||||
DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp");
|
DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp");
|
||||||
DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate");
|
DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate");
|
||||||
DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address");
|
DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address");
|
||||||
|
@ -87,6 +87,7 @@ DECLARE_MTYPE(PEER_UPDATE_SOURCE);
|
|||||||
DECLARE_MTYPE(PEER_CONF_IF);
|
DECLARE_MTYPE(PEER_CONF_IF);
|
||||||
DECLARE_MTYPE(BGP_DAMP_INFO);
|
DECLARE_MTYPE(BGP_DAMP_INFO);
|
||||||
DECLARE_MTYPE(BGP_DAMP_ARRAY);
|
DECLARE_MTYPE(BGP_DAMP_ARRAY);
|
||||||
|
DECLARE_MTYPE(BGP_DAMP_REUSELIST);
|
||||||
DECLARE_MTYPE(BGP_REGEXP);
|
DECLARE_MTYPE(BGP_REGEXP);
|
||||||
DECLARE_MTYPE(BGP_AGGREGATE);
|
DECLARE_MTYPE(BGP_AGGREGATE);
|
||||||
DECLARE_MTYPE(BGP_ADDR);
|
DECLARE_MTYPE(BGP_ADDR);
|
||||||
|
@ -249,10 +249,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
e = *extra;
|
e = *extra;
|
||||||
if (e->damp_info)
|
|
||||||
bgp_damp_info_free(e->damp_info, 0, e->damp_info->afi,
|
|
||||||
e->damp_info->safi);
|
|
||||||
|
|
||||||
|
if (e->damp_info)
|
||||||
|
bgp_damp_info_free(e->damp_info, NULL, 0);
|
||||||
e->damp_info = NULL;
|
e->damp_info = NULL;
|
||||||
if (e->vrfleak && e->vrfleak->parent) {
|
if (e->vrfleak && e->vrfleak->parent) {
|
||||||
struct bgp_path_info *bpi =
|
struct bgp_path_info *bpi =
|
||||||
@ -4279,14 +4278,16 @@ static void bgp_rib_withdraw(struct bgp_dest *dest, struct bgp_path_info *pi,
|
|||||||
/* apply dampening, if result is suppressed, we'll be retaining
|
/* apply dampening, if result is suppressed, we'll be retaining
|
||||||
* the bgp_path_info in the RIB for historical reference.
|
* the bgp_path_info in the RIB for historical reference.
|
||||||
*/
|
*/
|
||||||
if (CHECK_FLAG(peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
|
if (peer->sort == BGP_PEER_EBGP) {
|
||||||
&& peer->sort == BGP_PEER_EBGP)
|
if (get_active_bdc_from_pi(pi, afi, safi)) {
|
||||||
if ((bgp_damp_withdraw(pi, dest, afi, safi, 0))
|
if (bgp_damp_withdraw(pi, dest, afi, safi, 0) ==
|
||||||
== BGP_DAMP_SUPPRESSED) {
|
BGP_DAMP_SUPPRESSED) {
|
||||||
bgp_aggregate_decrement(peer->bgp, p, pi, afi,
|
bgp_aggregate_decrement(peer->bgp, p, pi, afi,
|
||||||
safi);
|
safi);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_BGP_VNC
|
#ifdef ENABLE_BGP_VNC
|
||||||
if (safi == SAFI_MPLS_VPN) {
|
if (safi == SAFI_MPLS_VPN) {
|
||||||
@ -4855,10 +4856,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
|
|||||||
bgp_labels_same((const mpls_label_t *)pi->extra->label,
|
bgp_labels_same((const mpls_label_t *)pi->extra->label,
|
||||||
pi->extra->num_labels, label,
|
pi->extra->num_labels, label,
|
||||||
num_labels)))) {
|
num_labels)))) {
|
||||||
if (CHECK_FLAG(bgp->af_flags[afi][safi],
|
if (get_active_bdc_from_pi(pi, afi, safi) &&
|
||||||
BGP_CONFIG_DAMPENING)
|
peer->sort == BGP_PEER_EBGP &&
|
||||||
&& peer->sort == BGP_PEER_EBGP
|
CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
|
||||||
&& CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
|
|
||||||
if (bgp_debug_update(peer, p, NULL, 1)) {
|
if (bgp_debug_update(peer, p, NULL, 1)) {
|
||||||
bgp_debug_rdpfxpath2str(
|
bgp_debug_rdpfxpath2str(
|
||||||
afi, safi, prd, p, label,
|
afi, safi, prd, p, label,
|
||||||
@ -4959,11 +4959,11 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
|
|||||||
bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED);
|
bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED);
|
||||||
|
|
||||||
/* Update bgp route dampening information. */
|
/* Update bgp route dampening information. */
|
||||||
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
|
if (get_active_bdc_from_pi(pi, afi, safi) &&
|
||||||
&& peer->sort == BGP_PEER_EBGP) {
|
peer->sort == BGP_PEER_EBGP) {
|
||||||
/* This is implicit withdraw so we should update
|
/* This is implicit withdraw so we should update
|
||||||
dampening
|
* dampening information.
|
||||||
information. */
|
*/
|
||||||
if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
|
if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
|
||||||
bgp_damp_withdraw(pi, dest, afi, safi, 1);
|
bgp_damp_withdraw(pi, dest, afi, safi, 1);
|
||||||
}
|
}
|
||||||
@ -5074,8 +5074,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Update bgp route dampening information. */
|
/* Update bgp route dampening information. */
|
||||||
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
|
if (get_active_bdc_from_pi(pi, afi, safi) &&
|
||||||
&& peer->sort == BGP_PEER_EBGP) {
|
peer->sort == BGP_PEER_EBGP) {
|
||||||
/* Now we do normal update dampening. */
|
/* Now we do normal update dampening. */
|
||||||
ret = bgp_damp_update(pi, dest, afi, safi);
|
ret = bgp_damp_update(pi, dest, afi, safi);
|
||||||
if (ret == BGP_DAMP_SUPPRESSED) {
|
if (ret == BGP_DAMP_SUPPRESSED) {
|
||||||
@ -11272,7 +11272,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (path->extra && path->extra->damp_info)
|
if (path->extra && path->extra->damp_info)
|
||||||
bgp_damp_info_vty(vty, path, afi, safi, json_path);
|
bgp_damp_info_vty(vty, bgp, path, afi, safi, json_path);
|
||||||
|
|
||||||
/* Remote Label */
|
/* Remote Label */
|
||||||
if (path->extra && bgp_is_valid_label(&path->extra->label[0])
|
if (path->extra && bgp_is_valid_label(&path->extra->label[0])
|
||||||
@ -15824,9 +15824,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
|
|||||||
while (pi) {
|
while (pi) {
|
||||||
if (pi->extra && pi->extra->damp_info) {
|
if (pi->extra && pi->extra->damp_info) {
|
||||||
pi_temp = pi->next;
|
pi_temp = pi->next;
|
||||||
bgp_damp_info_free(
|
bgp_damp_info_free(pi->extra->damp_info,
|
||||||
pi->extra->damp_info,
|
NULL, 1);
|
||||||
1, afi, safi);
|
|
||||||
pi = pi_temp;
|
pi = pi_temp;
|
||||||
} else
|
} else
|
||||||
pi = pi->next;
|
pi = pi->next;
|
||||||
@ -15837,26 +15836,38 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dest = bgp_node_match(bgp->rib[afi][safi], &match);
|
dest = bgp_node_match(bgp->rib[afi][safi], &match);
|
||||||
if (dest != NULL) {
|
if (!dest)
|
||||||
const struct prefix *dest_p = bgp_dest_get_prefix(dest);
|
return CMD_SUCCESS;
|
||||||
|
|
||||||
if (!prefix_check
|
const struct prefix *dest_p = bgp_dest_get_prefix(dest);
|
||||||
|| dest_p->prefixlen == match.prefixlen) {
|
|
||||||
pi = bgp_dest_get_bgp_path_info(dest);
|
if (prefix_check || dest_p->prefixlen != match.prefixlen)
|
||||||
while (pi) {
|
return CMD_SUCCESS;
|
||||||
if (pi->extra && pi->extra->damp_info) {
|
|
||||||
pi_temp = pi->next;
|
pi = bgp_dest_get_bgp_path_info(dest);
|
||||||
bgp_damp_info_free(
|
while (pi) {
|
||||||
pi->extra->damp_info,
|
if (!(pi->extra && pi->extra->damp_info)) {
|
||||||
1, afi, safi);
|
pi = pi->next;
|
||||||
pi = pi_temp;
|
continue;
|
||||||
} else
|
|
||||||
pi = pi->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bgp_dest_unlock_node(dest);
|
pi_temp = pi->next;
|
||||||
|
struct bgp_damp_info *bdi = pi->extra->damp_info;
|
||||||
|
|
||||||
|
if (bdi->lastrecord != BGP_RECORD_UPDATE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bgp_aggregate_increment(bgp,
|
||||||
|
bgp_dest_get_prefix(bdi->dest),
|
||||||
|
bdi->path, bdi->afi, bdi->safi);
|
||||||
|
bgp_process(bgp, bdi->dest, bdi->path, bdi->afi,
|
||||||
|
bdi->safi);
|
||||||
|
|
||||||
|
bgp_damp_info_free(pi->extra->damp_info, NULL, 1);
|
||||||
|
pi = pi_temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bgp_dest_unlock_node(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
@ -15870,7 +15881,9 @@ DEFUN (clear_ip_bgp_dampening,
|
|||||||
BGP_STR
|
BGP_STR
|
||||||
"Clear route flap dampening information\n")
|
"Clear route flap dampening information\n")
|
||||||
{
|
{
|
||||||
bgp_damp_info_clean(AFI_IP, SAFI_UNICAST);
|
VTY_DECLVAR_CONTEXT(bgp, bgp);
|
||||||
|
bgp_damp_info_clean(bgp, &bgp->damp[AFI_IP][SAFI_UNICAST], AFI_IP,
|
||||||
|
SAFI_UNICAST);
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
114
bgpd/bgp_vty.c
114
bgpd/bgp_vty.c
@ -9476,6 +9476,92 @@ DEFPY(no_neighbor_path_attribute_treat_as_withdraw,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFPY(neighbor_damp,
|
||||||
|
neighbor_damp_cmd,
|
||||||
|
"neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor dampening [(1-45)$half [(1-20000)$reuse (1-20000)$suppress (1-255)$max]]",
|
||||||
|
NEIGHBOR_STR
|
||||||
|
NEIGHBOR_ADDR_STR2
|
||||||
|
"Enable neighbor route-flap dampening\n"
|
||||||
|
"Half-life time for the penalty\n"
|
||||||
|
"Value to start reusing a route\n"
|
||||||
|
"Value to start suppressing a route\n"
|
||||||
|
"Maximum duration to suppress a stable route\n")
|
||||||
|
{
|
||||||
|
struct peer *peer = peer_and_group_lookup_vty(vty, neighbor);
|
||||||
|
|
||||||
|
if (!peer)
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
if (!half)
|
||||||
|
half = DEFAULT_HALF_LIFE;
|
||||||
|
if (!reuse) {
|
||||||
|
reuse = DEFAULT_REUSE;
|
||||||
|
suppress = DEFAULT_SUPPRESS;
|
||||||
|
max = half * 4;
|
||||||
|
}
|
||||||
|
if (suppress < reuse) {
|
||||||
|
vty_out(vty, "Suppress value cannot be less than reuse value\n");
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
}
|
||||||
|
bgp_peer_damp_enable(peer, bgp_node_afi(vty), bgp_node_safi(vty),
|
||||||
|
half * 60, reuse, suppress, max * 60);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY(no_neighbor_damp,
|
||||||
|
no_neighbor_damp_cmd,
|
||||||
|
"no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor dampening [HALF [REUSE SUPPRESS MAX]]",
|
||||||
|
NO_STR
|
||||||
|
NEIGHBOR_STR
|
||||||
|
NEIGHBOR_ADDR_STR2
|
||||||
|
"Enable neighbor route-flap dampening\n"
|
||||||
|
"Half-life time for the penalty\n"
|
||||||
|
"Value to start reusing a route\n"
|
||||||
|
"Value to start suppressing a route\n"
|
||||||
|
"Maximum duration to suppress a stable route\n")
|
||||||
|
{
|
||||||
|
struct peer *peer = peer_and_group_lookup_vty(vty, neighbor);
|
||||||
|
|
||||||
|
if (!peer)
|
||||||
|
return CMD_WARNING_CONFIG_FAILED;
|
||||||
|
bgp_peer_damp_disable(peer, bgp_node_afi(vty), bgp_node_safi(vty));
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFPY (show_ip_bgp_neighbor_damp_param,
|
||||||
|
show_ip_bgp_neighbor_damp_param_cmd,
|
||||||
|
"show [ip] bgp [<ipv4|ipv6> [unicast]] neighbors <A.B.C.D|X:X::X:X|WORD>$neighbor dampening parameters [json]$json",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
BGP_STR
|
||||||
|
BGP_AFI_HELP_STR
|
||||||
|
"Address Family modifier\n"
|
||||||
|
NEIGHBOR_STR
|
||||||
|
NEIGHBOR_ADDR_STR2
|
||||||
|
"Neighbor route-flap dampening information\n"
|
||||||
|
"Display detail of configured dampening parameters\n"
|
||||||
|
JSON_STR)
|
||||||
|
{
|
||||||
|
bool use_json = false;
|
||||||
|
int idx = 0;
|
||||||
|
afi_t afi = AFI_IP;
|
||||||
|
safi_t safi = SAFI_UNICAST;
|
||||||
|
struct peer *peer;
|
||||||
|
|
||||||
|
if (argv_find(argv, argc, "ip", &idx))
|
||||||
|
afi = AFI_IP;
|
||||||
|
if (argv_find(argv, argc, "ipv4", &idx))
|
||||||
|
afi = AFI_IP;
|
||||||
|
if (argv_find(argv, argc, "ipv6", &idx))
|
||||||
|
afi = AFI_IP6;
|
||||||
|
peer = peer_and_group_lookup_vty(vty, neighbor);
|
||||||
|
if (!peer)
|
||||||
|
return CMD_WARNING;
|
||||||
|
if (json)
|
||||||
|
use_json = true;
|
||||||
|
bgp_show_peer_dampening_parameters(vty, peer, afi, safi, use_json);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
|
static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
|
||||||
struct ecommunity **list, bool is_rt6)
|
struct ecommunity **list, bool is_rt6)
|
||||||
{
|
{
|
||||||
@ -19010,7 +19096,16 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
|
|||||||
|
|
||||||
/* BGP flag dampening. */
|
/* BGP flag dampening. */
|
||||||
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
|
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
|
||||||
bgp_config_write_damp(vty, afi, safi);
|
bgp_config_write_damp(vty, bgp, afi, safi);
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bgp->group, node, group))
|
||||||
|
if (peer_af_flag_check(group->conf, afi, safi,
|
||||||
|
PEER_FLAG_CONFIG_DAMPENING))
|
||||||
|
bgp_config_write_peer_damp(vty, group->conf, afi, safi);
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer))
|
||||||
|
if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) &&
|
||||||
|
peer_af_flag_check(peer, afi, safi,
|
||||||
|
PEER_FLAG_CONFIG_DAMPENING))
|
||||||
|
bgp_config_write_peer_damp(vty, peer, afi, safi);
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group))
|
for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group))
|
||||||
bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi);
|
bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi);
|
||||||
@ -21389,6 +21484,23 @@ void bgp_vty_init(void)
|
|||||||
install_element(BGP_EVPN_NODE, &neighbor_soo_cmd);
|
install_element(BGP_EVPN_NODE, &neighbor_soo_cmd);
|
||||||
install_element(BGP_EVPN_NODE, &no_neighbor_soo_cmd);
|
install_element(BGP_EVPN_NODE, &no_neighbor_soo_cmd);
|
||||||
|
|
||||||
|
/* "neighbor dampening" commands. */
|
||||||
|
install_element(BGP_NODE, &neighbor_damp_cmd);
|
||||||
|
install_element(BGP_NODE, &no_neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV4_NODE, &neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV4_NODE, &no_neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV4M_NODE, &neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV4M_NODE, &no_neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV4L_NODE, &neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV4L_NODE, &no_neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV6_NODE, &neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV6_NODE, &no_neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV6M_NODE, &neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV6M_NODE, &no_neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV6L_NODE, &neighbor_damp_cmd);
|
||||||
|
install_element(BGP_IPV6L_NODE, &no_neighbor_damp_cmd);
|
||||||
|
install_element(VIEW_NODE, &show_ip_bgp_neighbor_damp_param_cmd);
|
||||||
|
|
||||||
/* address-family commands. */
|
/* address-family commands. */
|
||||||
install_element(BGP_NODE, &address_family_ipv4_safi_cmd);
|
install_element(BGP_NODE, &address_family_ipv4_safi_cmd);
|
||||||
install_element(BGP_NODE, &address_family_ipv6_safi_cmd);
|
install_element(BGP_NODE, &address_family_ipv6_safi_cmd);
|
||||||
|
13
bgpd/bgpd.c
13
bgpd/bgpd.c
@ -2708,6 +2708,14 @@ int peer_delete(struct peer *peer)
|
|||||||
if (peer->bfd_config)
|
if (peer->bfd_config)
|
||||||
bgp_peer_remove_bfd_config(peer);
|
bgp_peer_remove_bfd_config(peer);
|
||||||
|
|
||||||
|
/* Delete peer route flap dampening configuration. This needs to happen
|
||||||
|
* before removing the peer from peer groups.
|
||||||
|
*/
|
||||||
|
FOREACH_AFI_SAFI (afi, safi)
|
||||||
|
if (peer_af_flag_check(peer, afi, safi,
|
||||||
|
PEER_FLAG_CONFIG_DAMPENING))
|
||||||
|
bgp_peer_damp_disable(peer, afi, safi);
|
||||||
|
|
||||||
/* If this peer belongs to peer group, clear up the
|
/* If this peer belongs to peer group, clear up the
|
||||||
relationship. */
|
relationship. */
|
||||||
if (peer->group) {
|
if (peer->group) {
|
||||||
@ -3960,6 +3968,11 @@ int bgp_delete(struct bgp *bgp)
|
|||||||
EVENT_OFF(gr_info->t_route_select);
|
EVENT_OFF(gr_info->t_route_select);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Delete route flap dampening configuration */
|
||||||
|
FOREACH_AFI_SAFI (afi, safi) {
|
||||||
|
bgp_damp_disable(bgp, afi, safi);
|
||||||
|
}
|
||||||
|
|
||||||
if (BGP_DEBUG(zebra, ZEBRA)) {
|
if (BGP_DEBUG(zebra, ZEBRA)) {
|
||||||
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
|
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
|
||||||
zlog_debug("Deleting Default VRF");
|
zlog_debug("Deleting Default VRF");
|
||||||
|
@ -33,6 +33,7 @@ PREDECL_LIST(zebra_announce);
|
|||||||
#include "bgp_addpath_types.h"
|
#include "bgp_addpath_types.h"
|
||||||
#include "bgp_nexthop.h"
|
#include "bgp_nexthop.h"
|
||||||
#include "bgp_io.h"
|
#include "bgp_io.h"
|
||||||
|
#include "bgp_damp.h"
|
||||||
|
|
||||||
#include "lib/bfd.h"
|
#include "lib/bfd.h"
|
||||||
|
|
||||||
@ -834,6 +835,9 @@ struct bgp {
|
|||||||
|
|
||||||
enum asnotation_mode asnotation;
|
enum asnotation_mode asnotation;
|
||||||
|
|
||||||
|
/* BGP route flap dampening configuration */
|
||||||
|
struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
|
||||||
|
|
||||||
QOBJ_FIELDS;
|
QOBJ_FIELDS;
|
||||||
};
|
};
|
||||||
DECLARE_QOBJ_TYPE(bgp);
|
DECLARE_QOBJ_TYPE(bgp);
|
||||||
@ -1508,6 +1512,9 @@ struct peer {
|
|||||||
/* Last update packet sent time */
|
/* Last update packet sent time */
|
||||||
time_t pkt_stime[AFI_MAX][SAFI_MAX];
|
time_t pkt_stime[AFI_MAX][SAFI_MAX];
|
||||||
|
|
||||||
|
/* Peer / peer group route flap dampening configuration */
|
||||||
|
struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
|
||||||
|
|
||||||
/* Peer Per AF flags */
|
/* Peer Per AF flags */
|
||||||
/*
|
/*
|
||||||
* Please consult the comments for *flags_override*, *flags_invert* and
|
* Please consult the comments for *flags_override*, *flags_invert* and
|
||||||
@ -1549,6 +1556,7 @@ struct peer {
|
|||||||
#define PEER_FLAG_SOO (1ULL << 28)
|
#define PEER_FLAG_SOO (1ULL << 28)
|
||||||
#define PEER_FLAG_SEND_EXT_COMMUNITY_RPKI (1ULL << 29)
|
#define PEER_FLAG_SEND_EXT_COMMUNITY_RPKI (1ULL << 29)
|
||||||
#define PEER_FLAG_ADDPATH_RX_PATHS_LIMIT (1ULL << 30)
|
#define PEER_FLAG_ADDPATH_RX_PATHS_LIMIT (1ULL << 30)
|
||||||
|
#define PEER_FLAG_CONFIG_DAMPENING (1U << 31)
|
||||||
#define PEER_FLAG_ACCEPT_OWN (1ULL << 63)
|
#define PEER_FLAG_ACCEPT_OWN (1ULL << 63)
|
||||||
|
|
||||||
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
|
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
|
||||||
|
@ -589,26 +589,52 @@ Route Flap Dampening
|
|||||||
|
|
||||||
.. clicmd:: bgp dampening (1-45) (1-20000) (1-50000) (1-255)
|
.. clicmd:: bgp dampening (1-45) (1-20000) (1-50000) (1-255)
|
||||||
|
|
||||||
This command enables BGP route-flap dampening and specifies dampening parameters.
|
This command enables (with optionally specified dampening parameters) or
|
||||||
|
disables route-flap dampening for all routes of a BGP instance.
|
||||||
|
|
||||||
|
.. clicmd:: neighbor PEER dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
|
||||||
|
|
||||||
|
This command enables (with optionally specified dampening parameters) or
|
||||||
|
disables route-flap dampening for all routes learned from a BGP peer.
|
||||||
|
|
||||||
|
.. clicmd:: neighbor GROUP dampening [(1-45) [(1-20000) (1-20000) (1-255)]]
|
||||||
|
|
||||||
|
This command enables (with optionally specified dampening parameters) or
|
||||||
|
disables route-flap dampening for all routes learned from peers of a peer
|
||||||
|
group.
|
||||||
|
|
||||||
half-life
|
half-life
|
||||||
Half-life time for the penalty
|
Half-life time for the penalty in minutes (default value: 15).
|
||||||
|
|
||||||
reuse-threshold
|
reuse-threshold
|
||||||
Value to start reusing a route
|
Value to start reusing a route (default value: 750).
|
||||||
|
|
||||||
suppress-threshold
|
suppress-threshold
|
||||||
Value to start suppressing a route
|
Value to start suppressing a route (default value: 2000).
|
||||||
|
|
||||||
max-suppress
|
max-suppress
|
||||||
Maximum duration to suppress a stable route
|
Maximum duration to suppress a stable route in minutes (default value:
|
||||||
|
60).
|
||||||
|
|
||||||
The route-flap damping algorithm is compatible with :rfc:`2439`. The use of
|
The route-flap damping algorithm is compatible with :rfc:`2439`. The use of
|
||||||
this command is not recommended nowadays.
|
these commands is not recommended nowadays.
|
||||||
|
|
||||||
At the moment, route-flap dampening is not working per VRF and is working only
|
At the moment, route-flap dampening is not working per VRF and is working only
|
||||||
for IPv4 unicast and multicast.
|
for IPv4 unicast and multicast.
|
||||||
|
|
||||||
|
With different parameter sets configurable for BGP instances, peer groups and
|
||||||
|
peers, the active dampening profile for a route is chosen on the fly,
|
||||||
|
allowing for various changes in configuration (i.e. peer group memberships)
|
||||||
|
during runtime. The parameter sets are taking precedence in the following
|
||||||
|
order:
|
||||||
|
|
||||||
|
1. Peer
|
||||||
|
2. Peer group
|
||||||
|
3. BGP instance
|
||||||
|
|
||||||
|
The negating commands do not allow to exclude a peer/peer group from a peer
|
||||||
|
group/BGP instances configuration.
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
https://www.ripe.net/publications/docs/ripe-378
|
https://www.ripe.net/publications/docs/ripe-378
|
||||||
|
|
||||||
@ -1335,7 +1361,7 @@ OSPFv3 into ``address-family ipv4 unicast`` as OSPFv3 supports IPv6.
|
|||||||
.. clicmd:: redistribute <babel|connected|eigrp|isis|kernel|openfabric|ospf|ospf6|rip|ripng|sharp|static> [metric (0-4294967295)] [route-map WORD]
|
.. clicmd:: redistribute <babel|connected|eigrp|isis|kernel|openfabric|ospf|ospf6|rip|ripng|sharp|static> [metric (0-4294967295)] [route-map WORD]
|
||||||
|
|
||||||
Redistribute routes from other protocols into BGP.
|
Redistribute routes from other protocols into BGP.
|
||||||
|
|
||||||
Note - When redistributing a static route, or any better Admin Distance route,
|
Note - When redistributing a static route, or any better Admin Distance route,
|
||||||
into BGP for which the same path is learned dynamically from another BGP
|
into BGP for which the same path is learned dynamically from another BGP
|
||||||
speaker, if the redistribute path is more preferred from a BGP Best Path
|
speaker, if the redistribute path is more preferred from a BGP Best Path
|
||||||
|
0
tests/topotests/bgp_dampening_per_peer/__init__.py
Normal file
0
tests/topotests/bgp_dampening_per_peer/__init__.py
Normal file
15
tests/topotests/bgp_dampening_per_peer/r1/frr.conf
Normal file
15
tests/topotests/bgp_dampening_per_peer/r1/frr.conf
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
!
|
||||||
|
int r1-eth0
|
||||||
|
ip address 192.168.1.1/24
|
||||||
|
!
|
||||||
|
router bgp 65001
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 192.168.1.2 remote-as external
|
||||||
|
neighbor 192.168.1.2 timers 1 3
|
||||||
|
neighbor 192.168.1.2 timers connect 1
|
||||||
|
neighbor 192.168.1.2 capability dynamic
|
||||||
|
!
|
||||||
|
address-family ipv4 unicast
|
||||||
|
neighbor 192.168.1.2 dampening 1 1 1 1
|
||||||
|
exit-address-family
|
||||||
|
!
|
17
tests/topotests/bgp_dampening_per_peer/r2/frr.conf
Normal file
17
tests/topotests/bgp_dampening_per_peer/r2/frr.conf
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
!
|
||||||
|
int lo
|
||||||
|
ip address 10.10.10.10/32
|
||||||
|
!
|
||||||
|
int r2-eth0
|
||||||
|
ip address 192.168.1.2/24
|
||||||
|
!
|
||||||
|
router bgp 65002
|
||||||
|
no bgp ebgp-requires-policy
|
||||||
|
neighbor 192.168.1.1 remote-as external
|
||||||
|
neighbor 192.168.1.1 timers 1 3
|
||||||
|
neighbor 192.168.1.1 timers connect 1
|
||||||
|
!
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
exit-address-family
|
||||||
|
!
|
@ -0,0 +1,177 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# SPDX-License-Identifier: ISC
|
||||||
|
|
||||||
|
# Copyright (c) 2024 by
|
||||||
|
# Donatas Abraitis <donatas@opensourcerouting.org>
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import functools
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.bgpd]
|
||||||
|
|
||||||
|
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
sys.path.append(os.path.join(CWD, "../"))
|
||||||
|
|
||||||
|
# pylint: disable=C0413
|
||||||
|
from lib import topotest
|
||||||
|
from lib.topogen import Topogen, get_topogen
|
||||||
|
|
||||||
|
|
||||||
|
def setup_module(mod):
|
||||||
|
topodef = {"s1": ("r1", "r2")}
|
||||||
|
tgen = Topogen(topodef, mod.__name__)
|
||||||
|
tgen.start_topology()
|
||||||
|
|
||||||
|
router_list = tgen.routers()
|
||||||
|
|
||||||
|
for _, (rname, router) in enumerate(router_list.items(), 1):
|
||||||
|
router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
|
||||||
|
|
||||||
|
tgen.start_router()
|
||||||
|
|
||||||
|
|
||||||
|
def teardown_module(mod):
|
||||||
|
tgen = get_topogen()
|
||||||
|
tgen.stop_topology()
|
||||||
|
|
||||||
|
|
||||||
|
def test_bgp_dampening_per_peer():
|
||||||
|
tgen = get_topogen()
|
||||||
|
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
r1 = tgen.gears["r1"]
|
||||||
|
r2 = tgen.gears["r2"]
|
||||||
|
|
||||||
|
def _converge():
|
||||||
|
output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json"))
|
||||||
|
expected = {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"valid": True,
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"hostname": "r2",
|
||||||
|
"accessible": True,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
test_func = functools.partial(
|
||||||
|
_converge,
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||||
|
assert result is None, "Can't converge"
|
||||||
|
|
||||||
|
####
|
||||||
|
# Withdraw 10.10.10.10/32, and check if it's flagged as history.
|
||||||
|
####
|
||||||
|
r2.vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
router bgp
|
||||||
|
address-family ipv4 unicast
|
||||||
|
no redistribute connected
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
def _check_bgp_dampening_history():
|
||||||
|
output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json"))
|
||||||
|
expected = {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"dampeningHistoryEntry": True,
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"hostname": "r2",
|
||||||
|
"accessible": True,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
test_func = functools.partial(
|
||||||
|
_check_bgp_dampening_history,
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||||
|
assert result is None, "10.10.10.10/32 is not flagged as history entry"
|
||||||
|
|
||||||
|
####
|
||||||
|
# Reannounce 10.10.10.10/32, and check if it's flagged as dampened.
|
||||||
|
####
|
||||||
|
r2.vtysh_cmd(
|
||||||
|
"""
|
||||||
|
configure terminal
|
||||||
|
router bgp
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
def _check_bgp_dampening_dampened():
|
||||||
|
output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json"))
|
||||||
|
expected = {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"valid": True,
|
||||||
|
"dampeningSuppressed": True,
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"hostname": "r2",
|
||||||
|
"accessible": True,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
test_func = functools.partial(
|
||||||
|
_check_bgp_dampening_dampened,
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||||
|
assert result is None, "10.10.10.10/32 is not flagged as dampened entry"
|
||||||
|
|
||||||
|
####
|
||||||
|
# Check if the route becomes non-dampened again after some time.
|
||||||
|
####
|
||||||
|
def _check_bgp_dampening_undampened():
|
||||||
|
output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json"))
|
||||||
|
expected = {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"valid": True,
|
||||||
|
"dampeningHistoryEntry": None,
|
||||||
|
"dampeningSuppressed": None,
|
||||||
|
"nexthops": [
|
||||||
|
{
|
||||||
|
"hostname": "r2",
|
||||||
|
"accessible": True,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
return topotest.json_cmp(output, expected)
|
||||||
|
|
||||||
|
test_func = functools.partial(
|
||||||
|
_check_bgp_dampening_undampened,
|
||||||
|
)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=120, wait=10)
|
||||||
|
assert result is None, "10.10.10.10/32 is flagged as history/dampened"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = ["-s"] + sys.argv[1:]
|
||||||
|
sys.exit(pytest.main(args))
|
Loading…
Reference in New Issue
Block a user