Merge pull request #15911 from opensourcerouting/feature/bgpd_dampening_per_neighbor

bgpd: per-neighbor dampening support
This commit is contained in:
Russ White 2024-05-13 13:55:24 -04:00 committed by GitHub
commit 2e0208602b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 828 additions and 210 deletions

View File

@ -22,19 +22,76 @@
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_vty.h"
/* Global variable to access damping configuration */
static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
static void bgp_reuselist_add(struct reuselist *list, struct bgp_damp_info *info)
{
assert(info);
SLIST_INSERT_HEAD(list, info, entry);
}
/* Utility macro to add and delete BGP dampening information to no
used 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)
static void bgp_reuselist_del(struct reuselist *list, struct bgp_damp_info *info)
{
assert(info);
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. */
static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
{
unsigned int i;
int index;
unsigned int index;
/*
* 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,
struct bgp_damp_config *bdc)
{
int index;
index = bdi->index = bgp_reuse_index(bdi->penalty, bdc);
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;
bgp_damp_info_claim(bdi, bdc);
bdi->index = bgp_reuse_index(bdi->penalty, bdc);
bgp_reuselist_add(&bdc->reuse_list[bdi->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)
{
bgp_damp_info_unclaim(bdi, NULL);
}
static void bgp_no_reuse_list_add(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
bdc->reuse_list[bdi->index] = bdi->next;
bgp_damp_info_claim(bdi, bdc);
bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
bgp_reuselist_add(&bdc->no_reuse_list, bdi);
}
static void bgp_no_reuse_list_delete(struct bgp_damp_info *bdi)
{
bgp_damp_info_unclaim(bdi, NULL);
}
/* 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. */
static void bgp_reuse_timer(struct event *t)
{
struct bgp_damp_info *bdi;
struct bgp_damp_info *next;
struct bgp_damp_info *bdi, *bdi_next;
struct reuselist plist;
struct bgp *bgp;
time_t t_now, t_diff;
struct bgp_damp_config *bdc = EVENT_ARG(t);
bdc->t_reuse = NULL;
@ -112,20 +170,20 @@ static void bgp_reuse_timer(struct event *t)
t_now = monotime(NULL);
/* 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;
/* 1. save a pointer to the current queue head and zero the list head
* list head entry. */
assert(bdc->reuse_offset < bdc->reuse_list_size);
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
rotating the circular queue of list-heads. */
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 ) */
for (; bdi; bdi = next) {
struct bgp *bgp = bdi->path->peer->bgp;
next = bdi->next;
SLIST_FOREACH_SAFE (bdi, &plist, entry, bdi_next) {
bgp = bdi->path->peer->bgp;
/* Set t-diff = t-now - t-updated. */
t_diff = t_now - bdi->t_updated;
@ -154,15 +212,23 @@ static void bgp_reuse_timer(struct event *t)
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
if (bdi->penalty <= bdc->reuse_limit / 2.0) {
bgp_damp_info_free(bdi, &plist, 1);
} else {
bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
bgp_reuselist_switch(&plist, bdi,
&bdc->no_reuse_list);
}
} else {
/* Re-insert into another list (See RFC2439 Section
* 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). */
@ -172,10 +238,13 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest,
time_t t_now;
struct bgp_damp_info *bdi = NULL;
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);
/* Processing Unreachable Messages. */
if (path->extra)
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->start_time = t_now;
bdi->suppress_time = 0;
bdi->index = -1;
bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX;
bdi->afi = afi;
bdi->safi = safi;
(bgp_path_info_extra_get(path))->damp_info = bdi;
BGP_DAMP_LIST_ADD(bdc, bdi);
bgp_no_reuse_list_add(bdi, bdc);
} 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;
/* 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. */
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);
if (bdi->penalty != last_penalty) {
bgp_reuse_list_delete(bdi);
bgp_reuse_list_add(bdi, bdc);
}
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) {
bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED);
bdi->suppress_time = t_now;
BGP_DAMP_LIST_DEL(bdc, bdi);
bgp_no_reuse_list_delete(bdi);
bgp_reuse_list_add(bdi, bdc);
}
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;
struct bgp_damp_info *bdi;
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)))
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)
&& (bdi->penalty < bdc->reuse_limit)) {
bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED);
bgp_reuse_list_delete(bdi, bdc);
BGP_DAMP_LIST_ADD(bdc, bdi);
bgp_reuse_list_delete(bdi);
bgp_no_reuse_list_add(bdi, bdc);
bdi->suppress_time = 0;
status = BGP_DAMP_USED;
} 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)
bdi->t_updated = t_now;
else
bgp_damp_info_free(bdi, 0, afi, safi);
bgp_damp_info_free(bdi, NULL, 0);
return status;
}
void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi,
safi_t safi)
void bgp_damp_info_free(struct bgp_damp_info *bdi, struct reuselist *list,
int withdraw)
{
struct bgp_path_info *path;
struct bgp_damp_config *bdc = &damp[afi][safi];
assert(bdi);
if (!bdi)
return;
afi_t afi = bdi->afi;
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;
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);
bgp_damp_info_unclaim(bdi, list);
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) {
bgp_path_info_delete(bdi->dest, path);
bgp_process(path->peer->bgp, bdi->dest, path, afi, safi);
bgp_aggregate_decrement(bgp, p, bpi, afi, SAFI_UNICAST);
bgp_path_info_delete(dest, bpi);
bgp_process(bgp, dest, bpi, afi, safi);
}
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 =
XCALLOC(MTYPE_BGP_DAMP_ARRAY,
bdc->reuse_list_size * sizeof(struct bgp_reuse_node *));
bdc->reuse_list_size * sizeof(struct reuselist));
/* Reuse-array computations */
bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
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,
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 (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);
bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
bdc->afi = afi;
bdc->safi = safi;
/* Register reuse timer. */
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;
}
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 */
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
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);
bdc->reuse_index_size = 0;
/* Free reuse list array. */
XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
bdc->reuse_list_size = 0;
EVENT_OFF(bdc->t_reuse);
}
/* Clean all the bgp_damp_info stored in reuse_list. */
void bgp_damp_info_clean(afi_t afi, safi_t safi)
{
unsigned int i;
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;
}
/* Disable route flap dampening for a bgp instance.
*
* Please note that this function also gets used to free memory when deleting a
* bgp instance.
*/
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 (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
return 0;
@ -456,54 +543,51 @@ int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
EVENT_OFF(bdc->t_reuse);
/* Clean BGP dampening information. */
bgp_damp_info_clean(afi, safi);
/* Clear configuration */
bgp_damp_config_clean(bdc);
bgp_damp_info_clean(bgp, bdc, afi, safi);
UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
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
&& 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)
struct bgp_damp_config *bdc;
bdc = &bgp->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, " 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 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, " bgp dampening %lld\n", bdc->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);
bdc->half_life / 60LL, bdc->reuse_limit,
bdc->suppress_value, bdc->max_suppress_time / 60LL);
}
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)
static const char *bgp_get_reuse_time(struct bgp_damp_config *bdc,
unsigned int penalty, char *buf,
size_t len, bool use_json,
json_object *json)
{
time_t reuse_time = 0;
struct tm tm;
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 (penalty > bdc->reuse_limit) {
reuse_time = (int)(DELTA_T *
((log((double)bdc->reuse_limit / penalty)) /
(log(bdc->decay_array[1]))));
if (reuse_time > damp[afi][safi].max_suppress_time)
reuse_time = damp[afi][safi].max_suppress_time;
if (reuse_time > bdc->max_suppress_time)
reuse_time = bdc->max_suppress_time;
gmtime_r(&reuse_time, &tm);
} else
@ -555,14 +639,15 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
return buf;
}
void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
safi_t safi, json_object *json_path)
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)
{
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];
struct bgp_damp_config *bdc = &bgp->damp[afi][safi];
if (!path->extra)
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)
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN,
afi, safi, 1, json_path);
bgp_get_reuse_time(bdc, penalty, timebuf,
BGP_UPTIME_LEN, 1, json_path);
} else {
vty_out(vty,
" 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)
&& !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,
bgp_get_reuse_time(bdc, penalty, timebuf,
BGP_UPTIME_LEN, 0,
json_path));
vty_out(vty, "\n");
}
}
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,
@ -618,7 +704,11 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
struct bgp_damp_info *bdi;
time_t t_now, t_diff;
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)
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;
penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json,
json);
return bgp_get_reuse_time(bdc, penalty, timebuf, len, use_json, json);
}
static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
afi_t afi, safi_t safi, bool use_json)
{
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) {
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);
bgp = bgp_get_default();
if (bgp == NULL) {
vty_out(vty, "No BGP process is configured\n");
return CMD_WARNING;
@ -731,3 +820,130 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
}
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);
}
}

View File

@ -10,11 +10,6 @@
/* Structure maintained on a per-route basis. */
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. */
unsigned int penalty;
@ -30,6 +25,9 @@ struct bgp_damp_info {
/* Time of route start to be suppressed. */
time_t suppress_time;
/* Back reference to associated dampening configuration. */
struct bgp_damp_config *config;
/* Back reference to bgp_path_info. */
struct bgp_path_info *path;
@ -38,6 +36,8 @@ struct bgp_damp_info {
/* Current index in the reuse_list. */
int index;
#define BGP_DAMP_NO_REUSE_LIST_INDEX \
(-1) /* index for elements on no_reuse_list */
/* Last time message type. */
uint8_t lastrecord;
@ -46,8 +46,12 @@ struct bgp_damp_info {
afi_t afi;
safi_t safi;
SLIST_ENTRY(bgp_damp_info) entry;
};
SLIST_HEAD(reuselist, bgp_damp_info);
/* Specified parameter set configuration. */
struct bgp_damp_config {
/* Value over which routes suppressed. */
@ -84,12 +88,12 @@ struct bgp_damp_config {
int *reuse_index;
/* Reuse list array per-set based. */
struct bgp_damp_info **reuse_list;
int reuse_offset;
struct reuselist *reuse_list;
unsigned int reuse_offset;
safi_t safi;
/* 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. */
struct event *t_reuse;
@ -116,6 +120,8 @@ struct bgp_damp_config {
#define REUSE_LIST_SIZE 256
#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,
unsigned int reuse, unsigned int suppress,
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);
extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest,
afi_t afi, safi_t saff);
extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw,
afi_t afi, safi_t safi);
extern void bgp_damp_info_clean(afi_t afi, safi_t safi);
extern void bgp_damp_info_free(struct bgp_damp_info *bdi,
struct reuselist *list, int withdraw);
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,
struct bgp_damp_config *damp);
extern void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi);
extern 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_config *bdc);
extern void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi);
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,
struct bgp_path_info *path,
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);
extern int bgp_show_dampening_parameters(struct vty *vty, afi_t afi,
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 */

View File

@ -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, BGP_DAMP_INFO, "Dampening info");
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_AGGREGATE, "BGP aggregate");
DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address");

View File

@ -87,6 +87,7 @@ DECLARE_MTYPE(PEER_UPDATE_SOURCE);
DECLARE_MTYPE(PEER_CONF_IF);
DECLARE_MTYPE(BGP_DAMP_INFO);
DECLARE_MTYPE(BGP_DAMP_ARRAY);
DECLARE_MTYPE(BGP_DAMP_REUSELIST);
DECLARE_MTYPE(BGP_REGEXP);
DECLARE_MTYPE(BGP_AGGREGATE);
DECLARE_MTYPE(BGP_ADDR);

View File

@ -249,10 +249,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
return;
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;
if (e->vrfleak && e->vrfleak->parent) {
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
* the bgp_path_info in the RIB for historical reference.
*/
if (CHECK_FLAG(peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
&& peer->sort == BGP_PEER_EBGP)
if ((bgp_damp_withdraw(pi, dest, afi, safi, 0))
== BGP_DAMP_SUPPRESSED) {
bgp_aggregate_decrement(peer->bgp, p, pi, afi,
safi);
return;
if (peer->sort == BGP_PEER_EBGP) {
if (get_active_bdc_from_pi(pi, afi, safi)) {
if (bgp_damp_withdraw(pi, dest, afi, safi, 0) ==
BGP_DAMP_SUPPRESSED) {
bgp_aggregate_decrement(peer->bgp, p, pi, afi,
safi);
return;
}
}
}
#ifdef ENABLE_BGP_VNC
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,
pi->extra->num_labels, label,
num_labels)))) {
if (CHECK_FLAG(bgp->af_flags[afi][safi],
BGP_CONFIG_DAMPENING)
&& peer->sort == BGP_PEER_EBGP
&& CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
if (get_active_bdc_from_pi(pi, afi, safi) &&
peer->sort == BGP_PEER_EBGP &&
CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
if (bgp_debug_update(peer, p, NULL, 1)) {
bgp_debug_rdpfxpath2str(
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);
/* Update bgp route dampening information. */
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
&& peer->sort == BGP_PEER_EBGP) {
if (get_active_bdc_from_pi(pi, afi, safi) &&
peer->sort == BGP_PEER_EBGP) {
/* This is implicit withdraw so we should update
dampening
information. */
* dampening information.
*/
if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
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
/* Update bgp route dampening information. */
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
&& peer->sort == BGP_PEER_EBGP) {
if (get_active_bdc_from_pi(pi, afi, safi) &&
peer->sort == BGP_PEER_EBGP) {
/* Now we do normal update dampening. */
ret = bgp_damp_update(pi, dest, afi, safi);
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)
bgp_damp_info_vty(vty, path, afi, safi, json_path);
bgp_damp_info_vty(vty, bgp, path, afi, safi, json_path);
/* Remote Label */
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) {
if (pi->extra && pi->extra->damp_info) {
pi_temp = pi->next;
bgp_damp_info_free(
pi->extra->damp_info,
1, afi, safi);
bgp_damp_info_free(pi->extra->damp_info,
NULL, 1);
pi = pi_temp;
} else
pi = pi->next;
@ -15837,26 +15836,38 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
}
} else {
dest = bgp_node_match(bgp->rib[afi][safi], &match);
if (dest != NULL) {
const struct prefix *dest_p = bgp_dest_get_prefix(dest);
if (!dest)
return CMD_SUCCESS;
if (!prefix_check
|| dest_p->prefixlen == match.prefixlen) {
pi = bgp_dest_get_bgp_path_info(dest);
while (pi) {
if (pi->extra && pi->extra->damp_info) {
pi_temp = pi->next;
bgp_damp_info_free(
pi->extra->damp_info,
1, afi, safi);
pi = pi_temp;
} else
pi = pi->next;
}
const struct prefix *dest_p = bgp_dest_get_prefix(dest);
if (prefix_check || dest_p->prefixlen != match.prefixlen)
return CMD_SUCCESS;
pi = bgp_dest_get_bgp_path_info(dest);
while (pi) {
if (!(pi->extra && pi->extra->damp_info)) {
pi = pi->next;
continue;
}
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;
@ -15870,7 +15881,9 @@ DEFUN (clear_ip_bgp_dampening,
BGP_STR
"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;
}

View File

@ -9476,6 +9476,92 @@ DEFPY(no_neighbor_path_attribute_treat_as_withdraw,
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,
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. */
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))
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, &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. */
install_element(BGP_NODE, &address_family_ipv4_safi_cmd);
install_element(BGP_NODE, &address_family_ipv6_safi_cmd);

View File

@ -2708,6 +2708,14 @@ int peer_delete(struct peer *peer)
if (peer->bfd_config)
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
relationship. */
if (peer->group) {
@ -3960,6 +3968,11 @@ int bgp_delete(struct bgp *bgp)
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->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
zlog_debug("Deleting Default VRF");

View File

@ -33,6 +33,7 @@ PREDECL_LIST(zebra_announce);
#include "bgp_addpath_types.h"
#include "bgp_nexthop.h"
#include "bgp_io.h"
#include "bgp_damp.h"
#include "lib/bfd.h"
@ -834,6 +835,9 @@ struct bgp {
enum asnotation_mode asnotation;
/* BGP route flap dampening configuration */
struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bgp);
@ -1508,6 +1512,9 @@ struct peer {
/* Last update packet sent time */
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 */
/*
* 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_SEND_EXT_COMMUNITY_RPKI (1ULL << 29)
#define PEER_FLAG_ADDPATH_RX_PATHS_LIMIT (1ULL << 30)
#define PEER_FLAG_CONFIG_DAMPENING (1U << 31)
#define PEER_FLAG_ACCEPT_OWN (1ULL << 63)
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];

View File

@ -589,26 +589,52 @@ Route Flap Dampening
.. 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 time for the penalty
Half-life time for the penalty in minutes (default value: 15).
reuse-threshold
Value to start reusing a route
Value to start reusing a route (default value: 750).
suppress-threshold
Value to start suppressing a route
Value to start suppressing a route (default value: 2000).
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
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
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::
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]
Redistribute routes from other protocols into BGP.
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
speaker, if the redistribute path is more preferred from a BGP Best Path

View 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
!

View 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
!

View File

@ -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))