summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd_packet.c3
-rw-r--r--bgpd/bgp_damp.c385
-rw-r--r--bgpd/bgp_damp.h20
-rw-r--r--bgpd/bgp_evpn_vty.c14
-rw-r--r--bgpd/bgp_fsm.c5
-rw-r--r--bgpd/bgp_nht.c21
-rw-r--r--bgpd/bgp_nht.h8
-rw-r--r--bgpd/bgp_packet.c21
-rw-r--r--bgpd/bgp_route.c34
-rw-r--r--bgpd/bgp_rpki.c2
-rw-r--r--bgpd/bgpd.c10
-rw-r--r--doc/developer/next-hop-tracking.rst2
-rw-r--r--doc/user/basic.rst11
-rw-r--r--doc/user/bgp.rst3
-rw-r--r--eigrpd/eigrp_packet.c9
-rw-r--r--lib/command.c40
-rw-r--r--lib/command.h3
-rw-r--r--ospfd/ospf_neighbor.c4
-rw-r--r--ospfd/ospf_opaque.c6
-rw-r--r--pimd/pim_zebra.c25
-rw-r--r--staticd/static_vty.c6
-rw-r--r--vtysh/vtysh_main.c3
-rw-r--r--vtysh/vtysh_user.c21
-rw-r--r--zebra/rt_netlink.c7
-rw-r--r--zebra/sample_plugin.c134
-rw-r--r--zebra/zebra_dplane.c4
-rw-r--r--zebra/zebra_mpls.c40
-rw-r--r--zebra/zebra_nhg.c47
-rw-r--r--zebra/zebra_rib.c8
29 files changed, 547 insertions, 349 deletions
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index ed36bb742e..398719d18c 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -523,13 +523,14 @@ int bfd_recv_cb(struct thread *t)
bool is_mhop;
ssize_t mlen = 0;
uint8_t ttl = 0;
- vrf_id_t vrfid = VRF_DEFAULT;
+ vrf_id_t vrfid;
ifindex_t ifindex = IFINDEX_INTERNAL;
struct sockaddr_any local, peer;
uint8_t msgbuf[1516];
struct bfd_vrf_global *bvrf = THREAD_ARG(t);
vrfid = bvrf->vrf->vrf_id;
+
/* Schedule next read. */
bfd_sd_reschedule(bvrf, sd);
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index cf085e46fb..b0fee079d1 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -37,8 +37,7 @@
#include "bgpd/bgp_advertise.h"
/* Global variable to access damping configuration */
-struct bgp_damp_config bgp_damp_cfg;
-static struct bgp_damp_config *damp = &bgp_damp_cfg;
+static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
/* Utility macro to add and delete BGP dampening information to no
used list. */
@@ -46,49 +45,51 @@ static struct bgp_damp_config *damp = &bgp_damp_cfg;
#define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list)
/* Calculate reuse list index by penalty value. */
-static int bgp_reuse_index(int penalty)
+static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc)
{
unsigned int i;
int index;
- i = (int)(((double)penalty / damp->reuse_limit - 1.0)
- * damp->scale_factor);
+ i = (int)(((double)penalty / bdc->reuse_limit - 1.0)
+ * bdc->scale_factor);
- if (i >= damp->reuse_index_size)
- i = damp->reuse_index_size - 1;
+ if (i >= bdc->reuse_index_size)
+ i = bdc->reuse_index_size - 1;
- index = damp->reuse_index[i] - damp->reuse_index[0];
+ index = bdc->reuse_index[i] - bdc->reuse_index[0];
- return (damp->reuse_offset + index) % damp->reuse_list_size;
+ return (bdc->reuse_offset + index) % bdc->reuse_list_size;
}
/* Add BGP dampening information to reuse list. */
-static void bgp_reuse_list_add(struct bgp_damp_info *bdi)
+static void bgp_reuse_list_add(struct bgp_damp_info *bdi,
+ struct bgp_damp_config *bdc)
{
int index;
- index = bdi->index = bgp_reuse_index(bdi->penalty);
+ index = bdi->index = bgp_reuse_index(bdi->penalty, bdc);
bdi->prev = NULL;
- bdi->next = damp->reuse_list[index];
- if (damp->reuse_list[index])
- damp->reuse_list[index]->prev = bdi;
- damp->reuse_list[index] = bdi;
+ bdi->next = bdc->reuse_list[index];
+ if (bdc->reuse_list[index])
+ bdc->reuse_list[index]->prev = bdi;
+ bdc->reuse_list[index] = bdi;
}
/* Delete BGP dampening information from reuse list. */
-static void bgp_reuse_list_delete(struct bgp_damp_info *bdi)
+static void bgp_reuse_list_delete(struct bgp_damp_info *bdi,
+ struct bgp_damp_config *bdc)
{
if (bdi->next)
bdi->next->prev = bdi->prev;
if (bdi->prev)
bdi->prev->next = bdi->next;
else
- damp->reuse_list[bdi->index] = bdi->next;
+ bdc->reuse_list[bdi->index] = bdi->next;
}
/* Return decayed penalty value. */
-int bgp_damp_decay(time_t tdiff, int penalty)
+int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc)
{
unsigned int i;
@@ -97,10 +98,10 @@ int bgp_damp_decay(time_t tdiff, int penalty)
if (i == 0)
return penalty;
- if (i >= damp->decay_array_size)
+ if (i >= bdc->decay_array_size)
return 0;
- return (int)(penalty * damp->decay_array[i]);
+ return (int)(penalty * bdc->decay_array[i]);
}
/* Handler of reuse timer event. Each route in the current reuse-list
@@ -111,20 +112,22 @@ static int bgp_reuse_timer(struct thread *t)
struct bgp_damp_info *next;
time_t t_now, t_diff;
- damp->t_reuse = NULL;
- thread_add_timer(bm->master, bgp_reuse_timer, NULL, DELTA_REUSE,
- &damp->t_reuse);
+ struct bgp_damp_config *bdc = THREAD_ARG(t);
+
+ bdc->t_reuse = NULL;
+ thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
+ &bdc->t_reuse);
t_now = bgp_clock();
/* 1. save a pointer to the current zeroth queue head and zero the
list head entry. */
- bdi = damp->reuse_list[damp->reuse_offset];
- damp->reuse_list[damp->reuse_offset] = NULL;
+ bdi = bdc->reuse_list[bdc->reuse_offset];
+ bdc->reuse_list[bdc->reuse_offset] = NULL;
/* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby
rotating the circular queue of list-heads. */
- damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size;
+ bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size;
/* 3. if ( the saved list head pointer is non-empty ) */
for (; bdi; bdi = next) {
@@ -137,13 +140,13 @@ static int bgp_reuse_timer(struct thread *t)
/* Set figure-of-merit = figure-of-merit * decay-array-ok
* [t-diff] */
- bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty);
+ bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
/* Set t-updated = t-now. */
bdi->t_updated = t_now;
/* if (figure-of-merit < reuse). */
- if (bdi->penalty < damp->reuse_limit) {
+ if (bdi->penalty < bdc->reuse_limit) {
/* Reuse the route. */
bgp_path_info_unset_flag(bdi->rn, bdi->path,
BGP_PATH_DAMPED);
@@ -158,14 +161,14 @@ static int bgp_reuse_timer(struct thread *t)
bgp_process(bgp, bdi->rn, bdi->afi, bdi->safi);
}
- if (bdi->penalty <= damp->reuse_limit / 2.0)
- bgp_damp_info_free(bdi, 1);
+ if (bdi->penalty <= bdc->reuse_limit / 2.0)
+ bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi);
else
- BGP_DAMP_LIST_ADD(damp, bdi);
+ BGP_DAMP_LIST_ADD(bdc, bdi);
} else
/* Re-insert into another list (See RFC2439 Section
* 4.8.6). */
- bgp_reuse_list_add(bdi);
+ bgp_reuse_list_add(bdi, bdc);
}
return 0;
@@ -178,6 +181,7 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_node *rn,
time_t t_now;
struct bgp_damp_info *bdi = NULL;
unsigned int last_penalty = 0;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
t_now = bgp_clock();
@@ -206,18 +210,18 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_node *rn,
bdi->afi = afi;
bdi->safi = safi;
(bgp_path_info_extra_get(path))->damp_info = bdi;
- BGP_DAMP_LIST_ADD(damp, bdi);
+ BGP_DAMP_LIST_ADD(bdc, bdi);
} else {
last_penalty = bdi->penalty;
/* 1. Set t-diff = t-now - t-updated. */
- bdi->penalty =
- (bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty)
- + (attr_change ? DEFAULT_PENALTY / 2
- : DEFAULT_PENALTY));
+ bdi->penalty = (bgp_damp_decay(t_now - bdi->t_updated,
+ bdi->penalty, bdc)
+ + (attr_change ? DEFAULT_PENALTY / 2
+ : DEFAULT_PENALTY));
- if (bdi->penalty > damp->ceiling)
- bdi->penalty = damp->ceiling;
+ if (bdi->penalty > bdc->ceiling)
+ bdi->penalty = bdc->ceiling;
bdi->flap++;
}
@@ -234,19 +238,19 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_node *rn,
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);
- bgp_reuse_list_add(bdi);
+ bgp_reuse_list_delete(bdi, bdc);
+ bgp_reuse_list_add(bdi, bdc);
}
return BGP_DAMP_SUPPRESSED;
}
/* If not suppressed before, do annonunce this withdraw and
insert into reuse_list. */
- if (bdi->penalty >= damp->suppress_value) {
+ if (bdi->penalty >= bdc->suppress_value) {
bgp_path_info_set_flag(rn, path, BGP_PATH_DAMPED);
bdi->suppress_time = t_now;
- BGP_DAMP_LIST_DEL(damp, bdi);
- bgp_reuse_list_add(bdi);
+ BGP_DAMP_LIST_DEL(bdc, bdi);
+ bgp_reuse_list_add(bdi, bdc);
}
return BGP_DAMP_USED;
@@ -258,6 +262,7 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_node *rn, afi_t afi,
time_t t_now;
struct bgp_damp_info *bdi;
int status;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
if (!path->extra || !((bdi = path->extra->damp_info)))
return BGP_DAMP_USED;
@@ -266,76 +271,35 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_node *rn, afi_t afi,
bgp_path_info_unset_flag(rn, path, BGP_PATH_HISTORY);
bdi->lastrecord = BGP_RECORD_UPDATE;
- bdi->penalty = bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty);
+ bdi->penalty =
+ bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty, bdc);
if (!CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
- && (bdi->penalty < damp->suppress_value))
+ && (bdi->penalty < bdc->suppress_value))
status = BGP_DAMP_USED;
else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)
- && (bdi->penalty < damp->reuse_limit)) {
+ && (bdi->penalty < bdc->reuse_limit)) {
bgp_path_info_unset_flag(rn, path, BGP_PATH_DAMPED);
- bgp_reuse_list_delete(bdi);
- BGP_DAMP_LIST_ADD(damp, bdi);
+ bgp_reuse_list_delete(bdi, bdc);
+ BGP_DAMP_LIST_ADD(bdc, bdi);
bdi->suppress_time = 0;
status = BGP_DAMP_USED;
} else
status = BGP_DAMP_SUPPRESSED;
- if (bdi->penalty > damp->reuse_limit / 2.0)
+ if (bdi->penalty > bdc->reuse_limit / 2.0)
bdi->t_updated = t_now;
else
- bgp_damp_info_free(bdi, 0);
+ bgp_damp_info_free(bdi, 0, afi, safi);
return status;
}
-/* Remove dampening information and history route. */
-int bgp_damp_scan(struct bgp_path_info *path, afi_t afi, safi_t safi)
-{
- time_t t_now, t_diff;
- struct bgp_damp_info *bdi;
-
- assert(path->extra && path->extra->damp_info);
-
- t_now = bgp_clock();
- bdi = path->extra->damp_info;
-
- if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) {
- t_diff = t_now - bdi->suppress_time;
-
- if (t_diff >= damp->max_suppress_time) {
- bgp_path_info_unset_flag(bdi->rn, path,
- BGP_PATH_DAMPED);
- bgp_reuse_list_delete(bdi);
- BGP_DAMP_LIST_ADD(damp, bdi);
- bdi->penalty = damp->reuse_limit;
- bdi->suppress_time = 0;
- bdi->t_updated = t_now;
-
- /* Need to announce UPDATE once this path is usable
- * again. */
- if (bdi->lastrecord == BGP_RECORD_UPDATE)
- return 1;
- else
- return 0;
- }
- } else {
- t_diff = t_now - bdi->t_updated;
- bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty);
-
- if (bdi->penalty <= damp->reuse_limit / 2.0) {
- /* release the bdi, bdi->path. */
- bgp_damp_info_free(bdi, 1);
- return 0;
- } else
- bdi->t_updated = t_now;
- }
- return 0;
-}
-
-void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw)
+void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi,
+ safi_t safi)
{
struct bgp_path_info *path;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
if (!bdi)
return;
@@ -344,9 +308,9 @@ void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw)
path->extra->damp_info = NULL;
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED))
- bgp_reuse_list_delete(bdi);
+ bgp_reuse_list_delete(bdi, bdc);
else
- BGP_DAMP_LIST_DEL(damp, bdi);
+ BGP_DAMP_LIST_DEL(bdc, bdi);
bgp_path_info_unset_flag(bdi->rn, path,
BGP_PATH_HISTORY | BGP_PATH_DAMPED);
@@ -357,68 +321,67 @@ void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw)
XFREE(MTYPE_BGP_DAMP_INFO, bdi);
}
-static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup)
+static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup,
+ struct bgp_damp_config *bdc)
{
double reuse_max_ratio;
unsigned int i;
double j;
- damp->suppress_value = sup;
- damp->half_life = hlife;
- damp->reuse_limit = reuse;
- damp->max_suppress_time = maxsup;
+ bdc->suppress_value = sup;
+ bdc->half_life = hlife;
+ bdc->reuse_limit = reuse;
+ bdc->max_suppress_time = maxsup;
/* Initialize params per bgp_damp_config. */
- damp->reuse_index_size = REUSE_ARRAY_SIZE;
+ bdc->reuse_index_size = REUSE_ARRAY_SIZE;
- damp->ceiling =
- (int)(damp->reuse_limit * (pow(2,
- (double)damp->max_suppress_time
- / damp->half_life)));
+ bdc->ceiling = (int)(bdc->reuse_limit
+ * (pow(2, (double)bdc->max_suppress_time
+ / bdc->half_life)));
/* Decay-array computations */
- damp->decay_array_size =
- ceil((double)damp->max_suppress_time / DELTA_T);
- damp->decay_array = XMALLOC(MTYPE_BGP_DAMP_ARRAY,
- sizeof(double) * (damp->decay_array_size));
- damp->decay_array[0] = 1.0;
- damp->decay_array[1] =
- exp((1.0 / ((double)damp->half_life / DELTA_T)) * log(0.5));
+ bdc->decay_array_size = ceil((double)bdc->max_suppress_time / DELTA_T);
+ bdc->decay_array = XMALLOC(MTYPE_BGP_DAMP_ARRAY,
+ sizeof(double) * (bdc->decay_array_size));
+ bdc->decay_array[0] = 1.0;
+ bdc->decay_array[1] =
+ exp((1.0 / ((double)bdc->half_life / DELTA_T)) * log(0.5));
/* Calculate decay values for all possible times */
- for (i = 2; i < damp->decay_array_size; i++)
- damp->decay_array[i] =
- damp->decay_array[i - 1] * damp->decay_array[1];
+ for (i = 2; i < bdc->decay_array_size; i++)
+ bdc->decay_array[i] =
+ bdc->decay_array[i - 1] * bdc->decay_array[1];
/* Reuse-list computations */
- i = ceil((double)damp->max_suppress_time / DELTA_REUSE) + 1;
+ i = ceil((double)bdc->max_suppress_time / DELTA_REUSE) + 1;
if (i > REUSE_LIST_SIZE || i == 0)
i = REUSE_LIST_SIZE;
- damp->reuse_list_size = i;
+ bdc->reuse_list_size = i;
- damp->reuse_list = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
- damp->reuse_list_size
- * sizeof(struct bgp_reuse_node *));
+ bdc->reuse_list =
+ XCALLOC(MTYPE_BGP_DAMP_ARRAY,
+ bdc->reuse_list_size * sizeof(struct bgp_reuse_node *));
/* Reuse-array computations */
- damp->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
- sizeof(int) * damp->reuse_index_size);
+ bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY,
+ sizeof(int) * bdc->reuse_index_size);
- reuse_max_ratio = (double)damp->ceiling / damp->reuse_limit;
- j = (exp((double)damp->max_suppress_time / damp->half_life)
- * log10(2.0));
+ reuse_max_ratio = (double)bdc->ceiling / bdc->reuse_limit;
+ j = (exp((double)bdc->max_suppress_time / bdc->half_life) * log10(2.0));
if (reuse_max_ratio > j && j != 0)
reuse_max_ratio = j;
- damp->scale_factor =
- (double)damp->reuse_index_size / (reuse_max_ratio - 1);
+ bdc->scale_factor =
+ (double)bdc->reuse_index_size / (reuse_max_ratio - 1);
- for (i = 0; i < damp->reuse_index_size; i++) {
- damp->reuse_index[i] =
- (int)(((double)damp->half_life / DELTA_REUSE)
- * log10(1.0 / (damp->reuse_limit
- * (1.0 + ((double)i
- / damp->scale_factor))))
+ for (i = 0; i < bdc->reuse_index_size; i++) {
+ bdc->reuse_index[i] =
+ (int)(((double)bdc->half_life / DELTA_REUSE)
+ * log10(1.0
+ / (bdc->reuse_limit
+ * (1.0
+ + ((double)i / bdc->scale_factor))))
/ log10(0.5));
}
}
@@ -426,122 +389,129 @@ static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup)
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];
+
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
- if (damp->half_life == half && damp->reuse_limit == reuse
- && damp->suppress_value == suppress
- && damp->max_suppress_time == max)
+ if (bdc->half_life == half && bdc->reuse_limit == reuse
+ && bdc->suppress_value == suppress
+ && bdc->max_suppress_time == max)
return 0;
bgp_damp_disable(bgp, afi, safi);
}
SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
- bgp_damp_parameter_set(half, reuse, suppress, max);
+ bgp_damp_parameter_set(half, reuse, suppress, max, bdc);
/* Register reuse timer. */
- thread_add_timer(bm->master, bgp_reuse_timer, NULL, DELTA_REUSE,
- &damp->t_reuse);
+ thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE,
+ &bdc->t_reuse);
return 0;
}
-static void bgp_damp_config_clean(struct bgp_damp_config *damp)
+static void bgp_damp_config_clean(struct bgp_damp_config *bdc)
{
/* Free decay array */
- XFREE(MTYPE_BGP_DAMP_ARRAY, damp->decay_array);
- damp->decay_array_size = 0;
+ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array);
+ bdc->decay_array_size = 0;
/* Free reuse index array */
- XFREE(MTYPE_BGP_DAMP_ARRAY, damp->reuse_index);
- damp->reuse_index_size = 0;
+ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index);
+ bdc->reuse_index_size = 0;
/* Free reuse list array. */
- XFREE(MTYPE_BGP_DAMP_ARRAY, damp->reuse_list);
- damp->reuse_list_size = 0;
+ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list);
+ bdc->reuse_list_size = 0;
}
/* Clean all the bgp_damp_info stored in reuse_list. */
-void bgp_damp_info_clean(void)
+void bgp_damp_info_clean(afi_t afi, safi_t safi)
{
unsigned int i;
struct bgp_damp_info *bdi, *next;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
- damp->reuse_offset = 0;
+ bdc->reuse_offset = 0;
- for (i = 0; i < damp->reuse_list_size; i++) {
- if (!damp->reuse_list[i])
+ for (i = 0; i < bdc->reuse_list_size; i++) {
+ if (!bdc->reuse_list[i])
continue;
- for (bdi = damp->reuse_list[i]; bdi; bdi = next) {
+ for (bdi = bdc->reuse_list[i]; bdi; bdi = next) {
next = bdi->next;
- bgp_damp_info_free(bdi, 1);
+ bgp_damp_info_free(bdi, 1, afi, safi);
}
- damp->reuse_list[i] = NULL;
+ bdc->reuse_list[i] = NULL;
}
- for (bdi = damp->no_reuse_list; bdi; bdi = next) {
+ for (bdi = bdc->no_reuse_list; bdi; bdi = next) {
next = bdi->next;
- bgp_damp_info_free(bdi, 1);
+ bgp_damp_info_free(bdi, 1, afi, safi);
}
- damp->no_reuse_list = NULL;
+ bdc->no_reuse_list = NULL;
}
int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi)
{
+ struct bgp_damp_config *bdc = &damp[afi][safi];
/* If it wasn't enabled, there's nothing to do. */
if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING))
return 0;
/* Cancel reuse thread. */
- if (damp->t_reuse)
- thread_cancel(damp->t_reuse);
- damp->t_reuse = NULL;
+ if (bdc->t_reuse)
+ thread_cancel(bdc->t_reuse);
+ bdc->t_reuse = NULL;
/* Clean BGP dampening information. */
- bgp_damp_info_clean();
+ bgp_damp_info_clean(afi, safi);
/* Clear configuration */
- bgp_damp_config_clean(&bgp_damp_cfg);
+ bgp_damp_config_clean(bdc);
UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING);
return 0;
}
-void bgp_config_write_damp(struct vty *vty)
+void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi)
{
- if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE * 60
- && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
- && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
- && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life * 4)
- vty_out(vty, " bgp dampening\n");
- else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE * 60
- && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE
- && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS
- && bgp_damp_cfg.max_suppress_time
- == bgp_damp_cfg.half_life * 4)
- vty_out(vty, " bgp dampening %lld\n",
- bgp_damp_cfg.half_life / 60LL);
+ if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60
+ && damp[afi][safi].reuse_limit == DEFAULT_REUSE
+ && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
+ && damp[afi][safi].max_suppress_time
+ == damp[afi][safi].half_life * 4)
+ vty_out(vty, " bgp dampening\n");
+ else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60
+ && damp[afi][safi].reuse_limit == DEFAULT_REUSE
+ && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS
+ && damp[afi][safi].max_suppress_time
+ == damp[afi][safi].half_life * 4)
+ vty_out(vty, " bgp dampening %lld\n",
+ damp[afi][safi].half_life / 60LL);
else
- vty_out(vty, " bgp dampening %lld %d %d %lld\n",
- bgp_damp_cfg.half_life / 60LL, bgp_damp_cfg.reuse_limit,
- bgp_damp_cfg.suppress_value,
- bgp_damp_cfg.max_suppress_time / 60LL);
+ vty_out(vty, " bgp dampening %lld %d %d %lld\n",
+ damp[afi][safi].half_life / 60LL,
+ damp[afi][safi].reuse_limit,
+ damp[afi][safi].suppress_value,
+ damp[afi][safi].max_suppress_time / 60LL);
}
static const char *bgp_get_reuse_time(unsigned int penalty, char *buf,
- size_t len, bool use_json,
- json_object *json)
+ size_t len, afi_t afi, safi_t safi,
+ bool use_json, json_object *json)
{
time_t reuse_time = 0;
struct tm *tm = NULL;
int time_store = 0;
- if (penalty > damp->reuse_limit) {
+ if (penalty > damp[afi][safi].reuse_limit) {
reuse_time = (int)(DELTA_T
- * ((log((double)damp->reuse_limit / penalty))
- / (log(damp->decay_array[1]))));
+ * ((log((double)damp[afi][safi].reuse_limit
+ / penalty))
+ / (log(damp[afi][safi].decay_array[1]))));
- if (reuse_time > damp->max_suppress_time)
- reuse_time = damp->max_suppress_time;
+ if (reuse_time > damp[afi][safi].max_suppress_time)
+ reuse_time = damp[afi][safi].max_suppress_time;
tm = gmtime(&reuse_time);
} else
@@ -593,13 +563,14 @@ 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,
- json_object *json_path)
+void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi,
+ safi_t safi, json_object *json_path)
{
struct bgp_damp_info *bdi;
time_t t_now, t_diff;
char timebuf[BGP_UPTIME_LEN];
int penalty;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
if (!path->extra)
return;
@@ -609,13 +580,13 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path,
/* If dampening is not enabled or there is no dampening information,
return immediately. */
- if (!damp || !bdi)
+ if (!bdc || !bdi)
return;
/* Calculate new penalty. */
t_now = bgp_clock();
t_diff = t_now - bdi->t_updated;
- penalty = bgp_damp_decay(t_diff, bdi->penalty);
+ penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
if (json_path) {
json_object_int_add(json_path, "dampeningPenalty", penalty);
@@ -625,8 +596,8 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path,
if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
- bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN, 1,
- json_path);
+ bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN,
+ afi, safi, 1, json_path);
} else {
vty_out(vty,
" Dampinfo: penalty %d, flapped %d times in %s",
@@ -638,7 +609,7 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path,
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
vty_out(vty, ", reuse in %s",
bgp_get_reuse_time(penalty, timebuf,
- BGP_UPTIME_LEN, 0,
+ BGP_UPTIME_LEN, afi, safi, 0,
json_path));
vty_out(vty, "\n");
@@ -646,12 +617,14 @@ void bgp_damp_info_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, bool use_json,
+ char *timebuf, size_t len, afi_t afi,
+ safi_t safi, bool use_json,
json_object *json)
{
struct bgp_damp_info *bdi;
time_t t_now, t_diff;
int penalty;
+ struct bgp_damp_config *bdc = &damp[afi][safi];
if (!path->extra)
return NULL;
@@ -661,15 +634,16 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
/* If dampening is not enabled or there is no dampening information,
return immediately. */
- if (!damp || !bdi)
+ if (!bdc || !bdi)
return NULL;
/* Calculate new penalty. */
t_now = bgp_clock();
t_diff = t_now - bdi->t_updated;
- penalty = bgp_damp_decay(t_diff, bdi->penalty);
+ penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc);
- return bgp_get_reuse_time(penalty, timebuf, len, use_json, json);
+ return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json,
+ json);
}
int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi)
@@ -684,12 +658,15 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi)
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
vty_out(vty, "Half-life time: %lld min\n",
- (long long)damp->half_life / 60);
- vty_out(vty, "Reuse penalty: %d\n", damp->reuse_limit);
- vty_out(vty, "Suppress penalty: %d\n", damp->suppress_value);
+ (long long)damp[afi][safi].half_life / 60);
+ vty_out(vty, "Reuse penalty: %d\n",
+ damp[afi][safi].reuse_limit);
+ vty_out(vty, "Suppress penalty: %d\n",
+ damp[afi][safi].suppress_value);
vty_out(vty, "Max suppress time: %lld min\n",
- (long long)damp->max_suppress_time / 60);
- vty_out(vty, "Max suppress penalty: %u\n", damp->ceiling);
+ (long long)damp[afi][safi].max_suppress_time / 60);
+ vty_out(vty, "Max suppress penalty: %u\n",
+ damp[afi][safi].ceiling);
vty_out(vty, "\n");
} else
vty_out(vty, "dampening not enabled for %s\n",
diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h
index 18bf561c47..3dd860a29d 100644
--- a/bgpd/bgp_damp.h
+++ b/bgpd/bgp_damp.h
@@ -106,6 +106,9 @@ struct bgp_damp_config {
/* Reuse timer thread per-set base. */
struct thread *t_reuse;
+
+ afi_t afi;
+ safi_t safi;
};
#define BGP_DAMP_NONE 0
@@ -134,17 +137,18 @@ extern int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_node *rn,
afi_t afi, safi_t safi, int attr_change);
extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_node *rn,
afi_t afi, safi_t saff);
-extern int bgp_damp_scan(struct bgp_path_info *path, afi_t afi, safi_t safi);
-extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw);
-extern void bgp_damp_info_clean(void);
-extern int bgp_damp_decay(time_t, int);
-extern void bgp_config_write_damp(struct vty *);
+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 int bgp_damp_decay(time_t, int, struct bgp_damp_config *damp);
+extern void bgp_config_write_damp(struct vty *, afi_t afi, safi_t safi);
extern void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path,
- json_object *json_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,
- bool use_json, json_object *json);
+ char *timebuf, size_t len, afi_t afi,
+ safi_t safi, bool use_json,
+ json_object *json);
extern int bgp_show_dampening_parameters(struct vty *vty, afi_t, safi_t);
#endif /* _QUAGGA_BGP_DAMP_H */
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 55f85eeb83..3bc8345140 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -298,7 +298,7 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty,
if (json)
json_object_string_add(json, "rd", rd_str);
else
- vty_out(vty, "as2 %s\n", rd_str);
+ vty_out(vty, "%s\n", rd_str);
break;
case RD_TYPE_AS4:
@@ -307,7 +307,7 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty,
if (json)
json_object_string_add(json, "rd", rd_str);
else
- vty_out(vty, "as4 %s\n", rd_str);
+ vty_out(vty, "%s\n", rd_str);
break;
case RD_TYPE_IP:
@@ -317,7 +317,7 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty,
if (json)
json_object_string_add(json, "rd", rd_str);
else
- vty_out(vty, "ip %s\n", rd_str);
+ vty_out(vty, "%s\n", rd_str);
break;
default:
@@ -326,7 +326,7 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty,
json_object_string_add(json, "rd", rd_str);
} else {
snprintf(rd_str, len, "Unknown RD type");
- vty_out(vty, "ip %s\n", rd_str);
+ vty_out(vty, "%s\n", rd_str);
}
break;
}
@@ -2619,10 +2619,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
prefix_rd2str((struct prefix_rd *)&rd_rn->p, rd_str,
sizeof(rd_str));
- if (json) {
+ if (json)
json_rd = json_object_new_object();
- json_object_string_add(json_rd, "rd", rd_str);
- }
rd_header = 1;
@@ -2659,7 +2657,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
/* RD header - per RD. */
if (rd_header) {
bgp_evpn_show_route_rd_header(
- vty, rd_rn, NULL, rd_str,
+ vty, rd_rn, json_rd, rd_str,
RD_ADDRSTRLEN);
rd_header = 0;
}
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 0be8becbab..2e5b2e115c 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1359,8 +1359,9 @@ static int bgp_connect_success(struct peer *peer)
flog_err_sys(EC_LIB_SOCKET,
"%s: bgp_getsockname(): failed for peer %s, fd %d",
__FUNCTION__, peer->host, peer->fd);
- bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
- 0); /* internal error */
+ bgp_notify_send(
+ peer, BGP_NOTIFY_FSM_ERR,
+ BGP_NOTIFY_SUBCODE_UNSPECIFIC); /* internal error */
bgp_writes_on(peer);
return -1;
}
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 915963fad8..6be08efb21 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -65,27 +65,6 @@ static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc)
|| (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID)));
}
-int bgp_find_nexthop(struct bgp_path_info *path, int connected)
-{
- struct bgp_nexthop_cache *bnc = path->nexthop;
-
- if (!bnc)
- return 0;
-
- /*
- * We are cheating here. Views have no associated underlying
- * ability to detect nexthops. So when we have a view
- * just tell everyone the nexthop is valid
- */
- if (path->peer && path->peer->bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
- return 1;
-
- if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)))
- return 0;
-
- return (bgp_isvalid_nexthop(bnc));
-}
-
static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
{
if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) {
diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h
index 7daae93b25..e39d55567a 100644
--- a/bgpd/bgp_nht.h
+++ b/bgpd/bgp_nht.h
@@ -27,14 +27,6 @@
extern void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id);
/**
- * bgp_find_nexthop() - lookup the nexthop cache table for the bnc object
- * ARGUMENTS:
- * p - path for which the nexthop object is being looked up
- * connected - True if NH MUST be a connected route
- */
-extern int bgp_find_nexthop(struct bgp_path_info *p, int connected);
-
-/**
* bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc
* object. If not found, create a new object and register with ZEBRA for
* nexthop notification.
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index c7c1780c21..5296246b31 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1420,7 +1420,8 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
"%s [FSM] Update packet received under status %s",
peer->host,
lookup_msg(bgp_status_msg, peer->status, NULL));
- bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0);
+ bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
+ BGP_NOTIFY_SUBCODE_UNSPECIFIC);
return BGP_Stop;
}
@@ -1792,7 +1793,8 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
"%s [Error] Route refresh packet received under status %s",
peer->host,
lookup_msg(bgp_status_msg, peer->status, NULL));
- bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0);
+ bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
+ BGP_NOTIFY_SUBCODE_UNSPECIFIC);
return BGP_Stop;
}
@@ -1827,7 +1829,8 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
< 5) {
zlog_info("%s ORF route refresh length error",
peer->host);
- bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_SUBCODE_UNSPECIFIC);
return BGP_Stop;
}
@@ -2061,7 +2064,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
* length. */
if (pnt + 3 > end) {
zlog_info("%s Capability length error", peer->host);
- bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_SUBCODE_UNSPECIFIC);
return BGP_Stop;
}
action = *pnt;
@@ -2072,7 +2076,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
&& action != CAPABILITY_ACTION_UNSET) {
zlog_info("%s Capability Action Value error %d",
peer->host, action);
- bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_SUBCODE_UNSPECIFIC);
return BGP_Stop;
}
@@ -2084,7 +2089,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
/* Capability length check. */
if ((pnt + hdr->length + 3) > end) {
zlog_info("%s Capability length error", peer->host);
- bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_SUBCODE_UNSPECIFIC);
return BGP_Stop;
}
@@ -2188,7 +2194,8 @@ int bgp_capability_receive(struct peer *peer, bgp_size_t size)
"%s [Error] Dynamic capability packet received under status %s",
peer->host,
lookup_msg(bgp_status_msg, peer->status, NULL));
- bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0);
+ bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
+ BGP_NOTIFY_SUBCODE_UNSPECIFIC);
return BGP_Stop;
}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 2642266486..261fe77800 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -196,7 +196,8 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
e = *extra;
if (e->damp_info)
- bgp_damp_info_free(e->damp_info, 0);
+ bgp_damp_info_free(e->damp_info, 0, e->damp_info->afi,
+ e->damp_info->safi);
e->damp_info = NULL;
if (e->parent) {
@@ -7883,7 +7884,7 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p,
/* dampening route */
static void damp_route_vty_out(struct vty *vty, struct prefix *p,
- struct bgp_path_info *path, int display,
+ struct bgp_path_info *path, int display, afi_t afi,
safi_t safi, bool use_json, json_object *json)
{
struct attr *attr;
@@ -7914,13 +7915,13 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p,
}
if (use_json)
- bgp_damp_reuse_time_vty(vty, path, timebuf, BGP_UPTIME_LEN,
- use_json, json);
+ bgp_damp_reuse_time_vty(vty, path, timebuf, BGP_UPTIME_LEN, afi,
+ safi, use_json, json);
else
vty_out(vty, "%s ",
bgp_damp_reuse_time_vty(vty, path, timebuf,
- BGP_UPTIME_LEN, use_json,
- json));
+ BGP_UPTIME_LEN, afi, safi,
+ use_json, json));
/* Print attribute */
attr = path->attr;
@@ -7947,7 +7948,7 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p,
/* flap route */
static void flap_route_vty_out(struct vty *vty, struct prefix *p,
- struct bgp_path_info *path, int display,
+ struct bgp_path_info *path, int display, afi_t afi,
safi_t safi, bool use_json, json_object *json)
{
struct attr *attr;
@@ -8006,12 +8007,13 @@ static void flap_route_vty_out(struct vty *vty, struct prefix *p,
&& !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) {
if (use_json)
bgp_damp_reuse_time_vty(vty, path, timebuf,
- BGP_UPTIME_LEN, use_json, json);
+ BGP_UPTIME_LEN, afi, safi,
+ use_json, json);
else
vty_out(vty, "%s ",
bgp_damp_reuse_time_vty(vty, path, timebuf,
- BGP_UPTIME_LEN,
- use_json, json));
+ BGP_UPTIME_LEN, afi,
+ safi, use_json, json));
} else {
if (!use_json)
vty_out(vty, "%*s ", 8, " ");
@@ -8879,7 +8881,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp,
}
if (path->extra && path->extra->damp_info)
- bgp_damp_info_vty(vty, path, json_path);
+ bgp_damp_info_vty(vty, path, afi, safi, json_path);
/* Remote Label */
if (path->extra && bgp_is_valid_label(&path->extra->label[0])
@@ -9292,11 +9294,11 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
}
if (type == bgp_show_type_dampend_paths
|| type == bgp_show_type_damp_neighbor)
- damp_route_vty_out(vty, &rn->p, pi, display,
+ damp_route_vty_out(vty, &rn->p, pi, display, AFI_IP,
safi, use_json, json_paths);
else if (type == bgp_show_type_flap_statistics
|| type == bgp_show_type_flap_neighbor)
- flap_route_vty_out(vty, &rn->p, pi, display,
+ flap_route_vty_out(vty, &rn->p, pi, display, AFI_IP,
safi, use_json, json_paths);
else
route_vty_out(vty, &rn->p, pi, display, safi,
@@ -12199,7 +12201,7 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
pi_temp = pi->next;
bgp_damp_info_free(
pi->extra->damp_info,
- 1);
+ 1, afi, safi);
pi = pi_temp;
} else
pi = pi->next;
@@ -12219,7 +12221,7 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name,
pi_temp = pi->next;
bgp_damp_info_free(
pi->extra->damp_info,
- 1);
+ 1, afi, safi);
pi = pi_temp;
} else
pi = pi->next;
@@ -12241,7 +12243,7 @@ DEFUN (clear_ip_bgp_dampening,
BGP_STR
"Clear route flap dampening information\n")
{
- bgp_damp_info_clean();
+ bgp_damp_info_clean(AFI_IP, SAFI_UNICAST);
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 1267e35097..3b89e50ce4 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -406,7 +406,7 @@ static int bgpd_sync_callback(struct thread *thread)
}
}
- prefix_free(prefix);
+ prefix_free(&prefix);
return 0;
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 7621d7ef0f..e6a742d9c4 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -7266,6 +7266,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
vty_out(vty, "\n");
}
+ /* BGP flag dampening. */
+ if (CHECK_FLAG(bgp->af_flags[afi][safi],
+ BGP_CONFIG_DAMPENING))
+ bgp_config_write_damp(vty, afi, safi);
+
/* Route reflector client. */
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_REFLECTOR_CLIENT)) {
@@ -7739,11 +7744,6 @@ int bgp_config_write(struct vty *vty)
? ""
: "no ");
- /* BGP flag dampening. */
- if (CHECK_FLAG(bgp->af_flags[AFI_IP][SAFI_UNICAST],
- BGP_CONFIG_DAMPENING))
- bgp_config_write_damp(vty);
-
/* BGP timers configuration. */
if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE
&& bgp->default_holdtime != BGP_DEFAULT_HOLDTIME)
diff --git a/doc/developer/next-hop-tracking.rst b/doc/developer/next-hop-tracking.rst
index a9af5e749c..99e1d65c2b 100644
--- a/doc/developer/next-hop-tracking.rst
+++ b/doc/developer/next-hop-tracking.rst
@@ -111,8 +111,6 @@ provides the following APIs:
+============================+==================================================+
| bgp_find_or_add_nexthop() | find or add a nexthop in BGP nexthop table |
+----------------------------+--------------------------------------------------+
-| bgp_find_nexthop() | find a nexthop in BGP nexthop table |
-+----------------------------+--------------------------------------------------+
| bgp_parse_nexthop_update() | parse a nexthop update message coming from zebra |
+----------------------------+--------------------------------------------------+
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index c7d722164a..f946c37a73 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -238,6 +238,17 @@ Basic Config Commands
Set default motd string.
+.. index:: banner motd file FILE
+.. clicmd:: banner motd file FILE
+
+ Set motd string from file. The file must be in directory specified
+ under ``--sysconfdir``.
+
+.. index:: banner motd line LINE
+.. clicmd:: banner motd line LINE
+
+ Set motd string from an input.
+
.. index:: no banner motd
.. clicmd:: no banner motd
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 6c20658214..4b3113cf3b 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -440,6 +440,9 @@ Route Flap Dampening
The route-flap damping algorithm is compatible with :rfc:`2439`. The use of
this command is not recommended nowadays.
+ At the moment, route-flap dampening is not working per VRF and is working only
+ for IPv4 unicast and multicast.
+
.. seealso::
https://www.ripe.net/publications/docs/ripe-378
diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c
index ba8271d46e..6367ef58ab 100644
--- a/eigrpd/eigrp_packet.c
+++ b/eigrpd/eigrp_packet.c
@@ -485,7 +485,7 @@ int eigrp_read(struct thread *thread)
struct eigrp_header *eigrph;
struct interface *ifp;
struct eigrp_neighbor *nbr;
-
+ struct in_addr srcaddr;
uint16_t opcode = 0;
uint16_t length = 0;
@@ -511,6 +511,7 @@ int eigrp_read(struct thread *thread)
if (iph->ip_v == 4)
length = (iph->ip_len) - 20U;
+ srcaddr = iph->ip_src;
/* IP Header dump. */
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)
@@ -526,7 +527,7 @@ int eigrp_read(struct thread *thread)
and also platforms (such as Solaris 8) that claim to support
ifindex
retrieval but do not. */
- c = if_lookup_address((void *)&iph->ip_src, AF_INET,
+ c = if_lookup_address((void *)&srcaddr, AF_INET,
eigrp->vrf_id);
if (c == NULL)
@@ -549,11 +550,11 @@ int eigrp_read(struct thread *thread)
/* Self-originated packet should be discarded silently. */
if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src)
- || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address.u.prefix4))) {
+ || (IPV4_ADDR_SAME(&srcaddr, &ei->address.u.prefix4))) {
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
zlog_debug(
"eigrp_read[%s]: Dropping self-originated packet",
- inet_ntoa(iph->ip_src));
+ inet_ntoa(srcaddr));
return 0;
}
diff --git a/lib/command.c b/lib/command.c
index e52893f0ba..59668e95fc 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -198,9 +198,6 @@ static struct cmd_node enable_node = {
static struct cmd_node config_node = {CONFIG_NODE, "%s(config)# ", 1};
-/* Default motd string. */
-static const char *default_motd = FRR_DEFAULT_MOTD;
-
static const struct facility_map {
int facility;
const char *name;
@@ -592,6 +589,10 @@ static int config_write_host(struct vty *vty)
if (host.motdfile)
vty_out(vty, "banner motd file %s\n", host.motdfile);
+ else if (host.motd
+ && strncmp(host.motd, FRR_DEFAULT_MOTD,
+ strlen(host.motd)))
+ vty_out(vty, "banner motd line %s\n", host.motd);
else if (!host.motd)
vty_out(vty, "no banner motd\n");
}
@@ -2668,6 +2669,13 @@ int cmd_banner_motd_file(const char *file)
return success;
}
+void cmd_banner_motd_line(const char *line)
+{
+ if (host.motd)
+ XFREE(MTYPE_HOST, host.motd);
+ host.motd = XSTRDUP(MTYPE_HOST, line);
+}
+
DEFUN (banner_motd_file,
banner_motd_file_cmd,
"banner motd file FILE",
@@ -2688,6 +2696,26 @@ DEFUN (banner_motd_file,
return cmd;
}
+DEFUN (banner_motd_line,
+ banner_motd_line_cmd,
+ "banner motd line LINE...",
+ "Set banner\n"
+ "Banner for motd\n"
+ "Banner from an input\n"
+ "Text\n")
+{
+ int idx = 0;
+ char *motd;
+
+ argv_find(argv, argc, "LINE", &idx);
+ motd = argv_concat(argv, argc, idx);
+
+ cmd_banner_motd_line(motd);
+ XFREE(MTYPE_TMP, motd);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (banner_motd_default,
banner_motd_default_cmd,
"banner motd default",
@@ -2695,7 +2723,7 @@ DEFUN (banner_motd_default,
"Strings for motd\n"
"Default string\n")
{
- host.motd = default_motd;
+ cmd_banner_motd_line(FRR_DEFAULT_MOTD);
return CMD_SUCCESS;
}
@@ -2864,7 +2892,7 @@ void cmd_init(int terminal)
host.config = NULL;
host.noconfig = (terminal < 0);
host.lines = -1;
- host.motd = default_motd;
+ cmd_banner_motd_line(FRR_DEFAULT_MOTD);
host.motdfile = NULL;
/* Install top nodes. */
@@ -2944,6 +2972,7 @@ void cmd_init(int terminal)
install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
install_element(CONFIG_NODE, &banner_motd_default_cmd);
install_element(CONFIG_NODE, &banner_motd_file_cmd);
+ install_element(CONFIG_NODE, &banner_motd_line_cmd);
install_element(CONFIG_NODE, &no_banner_motd_cmd);
install_element(CONFIG_NODE, &service_terminal_length_cmd);
install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
@@ -2988,6 +3017,7 @@ void cmd_terminate(void)
XFREE(MTYPE_HOST, host.logfile);
XFREE(MTYPE_HOST, host.motdfile);
XFREE(MTYPE_HOST, host.config);
+ XFREE(MTYPE_HOST, host.motd);
list_delete(&varhandlers);
qobj_finish();
diff --git a/lib/command.h b/lib/command.h
index d5dc129c72..73c15469e7 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -78,7 +78,7 @@ struct host {
int encrypt;
/* Banner configuration. */
- const char *motd;
+ char *motd;
char *motdfile;
};
@@ -499,6 +499,7 @@ extern void host_config_set(const char *);
extern void print_version(const char *);
extern int cmd_banner_motd_file(const char *);
+extern void cmd_banner_motd_line(const char *line);
/* struct host global, ick */
extern struct host host;
diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c
index a58bd93b6e..a9247dd0ec 100644
--- a/ospfd/ospf_neighbor.c
+++ b/ospfd/ospf_neighbor.c
@@ -402,12 +402,14 @@ void ospf_renegotiate_optional_capabilities(struct ospf *top)
struct ospf_neighbor *ospf_nbr_lookup(struct ospf_interface *oi, struct ip *iph,
struct ospf_header *ospfh)
{
+ struct in_addr srcaddr = iph->ip_src;
+
if (oi->type == OSPF_IFTYPE_VIRTUALLINK
|| oi->type == OSPF_IFTYPE_POINTOPOINT)
return (ospf_nbr_lookup_by_routerid(oi->nbrs,
&ospfh->router_id));
else
- return (ospf_nbr_lookup_by_addr(oi->nbrs, &iph->ip_src));
+ return (ospf_nbr_lookup_by_addr(oi->nbrs, &srcaddr));
}
static struct ospf_neighbor *ospf_nbr_add(struct ospf_interface *oi,
diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c
index 147773ce23..a989b8468c 100644
--- a/ospfd/ospf_opaque.c
+++ b/ospfd/ospf_opaque.c
@@ -430,9 +430,9 @@ void ospf_delete_opaque_functab(uint8_t lsa_type, uint8_t opaque_type)
/* Cleanup internal control information, if it
* still remains. */
if (functab->oipt != NULL) {
+ free_opaque_info_owner(functab->oipt);
free_opaque_info_per_type(
functab->oipt);
- free_opaque_info_owner(functab->oipt);
}
/* Dequeue listnode entry from the list. */
@@ -554,8 +554,8 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab,
case OSPF_OPAQUE_AS_LSA:
top = ospf_lookup_by_vrf_id(new->vrf_id);
if (new->area != NULL && (top = new->area->ospf) == NULL) {
- free_opaque_info_per_type((void *)oipt);
free_opaque_info_owner(oipt);
+ free_opaque_info_per_type(oipt);
oipt = NULL;
goto out; /* This case may not exist. */
}
@@ -567,8 +567,8 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab,
EC_OSPF_LSA_UNEXPECTED,
"register_opaque_info_per_type: Unexpected LSA-type(%u)",
new->data->type);
- free_opaque_info_per_type((void *)oipt);
free_opaque_info_owner(oipt);
+ free_opaque_info_per_type(oipt);
oipt = NULL;
goto out; /* This case may not exist. */
}
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index dfddee99d0..b297615435 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -855,27 +855,24 @@ void igmp_source_forward_start(struct pim_instance *pim,
}
}
- result = pim_channel_add_oif(source->source_channel_oil,
- group->group_igmp_sock->interface,
- PIM_OIF_FLAG_PROTO_IGMP);
- if (result) {
- if (PIM_DEBUG_MROUTE) {
- zlog_warn("%s: add_oif() failed with return=%d",
- __func__, result);
+ if (PIM_I_am_DR(pim_oif)) {
+ result = pim_channel_add_oif(source->source_channel_oil,
+ group->group_igmp_sock->interface,
+ PIM_OIF_FLAG_PROTO_IGMP);
+ if (result) {
+ if (PIM_DEBUG_MROUTE) {
+ zlog_warn("%s: add_oif() failed with return=%d",
+ __func__, result);
+ }
+ return;
}
- return;
- }
-
- if (!(PIM_I_am_DR(pim_oif))) {
+ } else {
if (PIM_DEBUG_IGMP_TRACE)
zlog_debug("%s: %s was received on %s interface but we are not DR for that interface",
__PRETTY_FUNCTION__,
pim_str_sg_dump(&sg),
group->group_igmp_sock->interface->name);
- pim_channel_del_oif(source->source_channel_oil,
- group->group_igmp_sock->interface,
- PIM_OIF_FLAG_PROTO_IGMP);
return;
}
/*
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index f926e1d9cd..8cc4ccced1 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -426,9 +426,9 @@ static int static_route_leak(
/* Null0 static route. */
if (ifname != NULL) {
- if (strncasecmp(ifname, "Null0", strlen(ifname)) == 0
- || strncasecmp(ifname, "reject", strlen(ifname)) == 0
- || strncasecmp(ifname, "blackhole", strlen(ifname)) == 0) {
+ if (strcasecmp(ifname, "Null0") == 0
+ || strcasecmp(ifname, "reject") == 0
+ || strcasecmp(ifname, "blackhole") == 0) {
if (vty)
vty_out(vty,
"%% Nexthop interface cannot be Null0, reject or blackhole\n");
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index d536263db0..c7e1d252c7 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -535,6 +535,9 @@ int main(int argc, char **argv, char **env)
/* Do not connect until we have passed authentication. */
if (vtysh_connect_all(daemon_name) <= 0) {
fprintf(stderr, "Exiting: failed to connect to any daemons.\n");
+ if (geteuid() != 0)
+ fprintf(stderr,
+ "Hint: if this seems wrong, try running me as a privileged user!\n");
if (no_error)
exit(0);
else
diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c
index 17e5a7331c..a7067984c4 100644
--- a/vtysh/vtysh_user.c
+++ b/vtysh/vtysh_user.c
@@ -147,6 +147,26 @@ DEFUN (vtysh_banner_motd_file,
return cmd_banner_motd_file(argv[idx_file]->arg);
}
+DEFUN (vtysh_banner_motd_line,
+ vtysh_banner_motd_line_cmd,
+ "banner motd line LINE...",
+ "Set banner\n"
+ "Banner for motd\n"
+ "Banner from an input\n"
+ "Text\n")
+{
+ int idx = 0;
+ char *motd;
+
+ argv_find(argv, argc, "LINE", &idx);
+ motd = argv_concat(argv, argc, idx);
+
+ cmd_banner_motd_line(motd);
+ XFREE(MTYPE_TMP, motd);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (username_nopassword,
username_nopassword_cmd,
"username WORD nopassword",
@@ -203,4 +223,5 @@ void vtysh_user_init(void)
userlist = list_new();
install_element(CONFIG_NODE, &username_nopassword_cmd);
install_element(CONFIG_NODE, &vtysh_banner_motd_file_cmd);
+ install_element(CONFIG_NODE, &vtysh_banner_motd_line_cmd);
}
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 915ad1a10c..c9a9a81b18 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -2456,7 +2456,6 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
return 0;
}
-#if 0 /* Force off kernel nexthop group installs for now */
/**
* netlink_request_nexthop() - Request nextop information from the kernel
* @zns: Zebra namespace
@@ -2515,12 +2514,6 @@ int netlink_nexthop_read(struct zebra_ns *zns)
return ret;
}
-#else
-int netlink_nexthop_read(struct zebra_ns *zns)
-{
- return 0;
-}
-#endif
int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
diff --git a/zebra/sample_plugin.c b/zebra/sample_plugin.c
new file mode 100644
index 0000000000..c96a86cc73
--- /dev/null
+++ b/zebra/sample_plugin.c
@@ -0,0 +1,134 @@
+/*
+ * Sample plugin for the FRR zebra dataplane.
+ *
+ * Copyright (c) 2019 Volta Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Should be possible to build this plugin using this sort of command:
+ *
+ * gcc -I ~/work/frr/ -I ~/work/frr/lib -I ~/work/frr/zebra \
+ * -g -O0 -o sample_plugin.so -shared -fPIC sample_plugin.c
+ *
+ * where 'frr' is a configured and built frr sandbox.
+ *
+ * Run zebra with '-M /path/to/sample_plugin.so' to load the module.
+ */
+
+#include "config.h" /* Include this explicitly */
+#include "lib/zebra.h"
+#include "lib/libfrr.h"
+#include "zebra/zebra_dplane.h"
+#include "zebra/debug.h"
+
+static const char *plugin_name = "SAMPLE";
+
+static struct zebra_dplane_provider *prov_p;
+
+/*
+ * Startup/init callback, called from the dataplane.
+ */
+static int sample_start(struct zebra_dplane_provider *prov)
+{
+ /* Nothing special to do - we don't allocate anything. */
+ return 0;
+}
+
+
+/*
+ * Shutdown/cleanup callback, called from the dataplane pthread.
+ */
+static int sample_fini(struct zebra_dplane_provider *prov, bool early)
+{
+ /* Nothing special to do. */
+ return 0;
+}
+
+/*
+ * Callback from the dataplane to process incoming work; this runs in the
+ * dplane pthread.
+ */
+static int sample_process(struct zebra_dplane_provider *prov)
+{
+ int counter, limit;
+ struct zebra_dplane_ctx *ctx;
+
+ limit = dplane_provider_get_work_limit(prov_p);
+
+ /* Respect the configured limit on the amount of work to do in
+ * any one call.
+ */
+ for (counter = 0; counter < limit; counter++) {
+ ctx = dplane_provider_dequeue_in_ctx(prov_p);
+ if (!ctx)
+ break;
+
+ /* Just set 'success' status and return to the dataplane */
+ dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS);
+ dplane_provider_enqueue_out_ctx(prov_p, ctx);
+ }
+
+ return 0;
+}
+
+/*
+ * Init entry point called during zebra startup. This is registered during
+ * module init.
+ */
+static int init_sample_plugin(struct thread_master *tm)
+{
+ int ret;
+ struct zebra_dplane_provider *prov = NULL;
+
+ /* Note that we don't use or store the thread_master 'tm'. We
+ * don't use the zebra main pthread: our plugin code will run in
+ * the zebra dataplane pthread context.
+ */
+
+ /* Register the plugin with the dataplane infrastructure. We
+ * register to be called before the kernel, and we register
+ * our init, process work, and shutdown callbacks.
+ */
+ ret = dplane_provider_register(plugin_name, DPLANE_PRIO_PRE_KERNEL,
+ DPLANE_PROV_FLAGS_DEFAULT,
+ sample_start,
+ sample_process,
+ sample_fini,
+ NULL,
+ &prov_p);
+
+ if (IS_ZEBRA_DEBUG_DPLANE)
+ zlog_debug("sample plugin register => %d", ret);
+
+ return 0;
+}
+
+/*
+ * Base FRR loadable module info: basic info including module entry-point.
+ */
+static int module_init(void)
+{
+ hook_register(frr_late_init, init_sample_plugin);
+ return 0;
+}
+
+FRR_MODULE_SETUP(
+ .name = "dplane_sample",
+ .version = "0.0.1",
+ .description = "Dataplane Sample Plugin",
+ .init = module_init,
+ )
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index a88b0a38da..7f993442a6 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -3752,7 +3752,9 @@ void zebra_dplane_shutdown(void)
zdplane_info.dg_run = false;
- THREAD_OFF(zdplane_info.dg_t_update);
+ if (zdplane_info.dg_t_update)
+ thread_cancel_async(zdplane_info.dg_t_update->master,
+ &zdplane_info.dg_t_update, NULL);
frr_pthread_stop(zdplane_info.dg_pthread, NULL);
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index ef1bd02608..6942a37989 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -2565,6 +2565,16 @@ void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf,
fec_print(rn->info, vty);
}
+static void mpls_zebra_nhg_update(struct route_entry *re, afi_t afi,
+ struct nexthop_group *new_grp)
+{
+ struct nhg_hash_entry *nhe;
+
+ nhe = zebra_nhg_rib_find(0, new_grp, afi);
+
+ zebra_nhg_re_update_ref(re, nhe);
+}
+
static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop,
enum lsp_types_t type, mpls_label_t label)
{
@@ -2591,7 +2601,6 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
struct route_entry *re;
struct nexthop *nexthop;
struct nexthop_group new_grp = {};
- struct nhg_hash_entry *nhe = NULL;
bool found;
afi_t afi = family2afi(prefix->family);
@@ -2658,12 +2667,11 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type,
}
if (found) {
- nhe = zebra_nhg_rib_find(0, &new_grp, afi);
-
- zebra_nhg_re_update_ref(re, nhe);
-
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+
+ mpls_zebra_nhg_update(re, afi, &new_grp);
+
rib_queue_add(rn);
}
@@ -2680,10 +2688,11 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
struct route_node *rn;
struct route_entry *re;
struct nexthop *nexthop;
+ struct nexthop_group new_grp = {};
+ afi_t afi = family2afi(prefix->family);
/* Lookup table. */
- table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST,
- zvrf_id(zvrf));
+ table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf));
if (!table)
return -1;
@@ -2698,11 +2707,18 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
if (re == NULL)
return -1;
- for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next)
+ nexthop_group_copy(&new_grp, re->ng);
+
+ for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next)
nexthop_del_labels(nexthop);
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED);
+
+ mpls_zebra_nhg_update(re, afi, &new_grp);
+
+ nexthops_free(new_grp.nexthop);
+
rib_queue_add(rn);
return 0;
@@ -2904,7 +2920,6 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
update = 0;
RNODE_FOREACH_RE (rn, re) {
struct nexthop_group new_grp = {};
- struct nhg_hash_entry *nhe = NULL;
nexthop_group_copy(&new_grp, re->ng);
@@ -2920,11 +2935,8 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf,
update = 1;
}
- if (CHECK_FLAG(re->status,
- ROUTE_ENTRY_LABELS_CHANGED)) {
- nhe = zebra_nhg_rib_find(0, &new_grp, afi);
- zebra_nhg_re_update_ref(re, nhe);
- }
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
+ mpls_zebra_nhg_update(re, afi, &new_grp);
nexthops_free(new_grp.nexthop);
}
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 05da25b2b8..d33f3a432a 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -360,6 +360,8 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
{
const struct nhg_hash_entry *nhe1 = arg1;
const struct nhg_hash_entry *nhe2 = arg2;
+ struct nexthop *nexthop1;
+ struct nexthop *nexthop2;
/* No matter what if they equal IDs, assume equal */
if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
@@ -371,12 +373,47 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
if (nhe1->afi != nhe2->afi)
return false;
- if (nexthop_group_active_nexthop_num_no_recurse(nhe1->nhg)
- != nexthop_group_active_nexthop_num_no_recurse(nhe2->nhg))
- return false;
+ /* Nexthops should be sorted */
+ for (nexthop1 = nhe1->nhg->nexthop, nexthop2 = nhe2->nhg->nexthop;
+ nexthop1 || nexthop2;
+ nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) {
+ if (nexthop1 && !nexthop2)
+ return false;
- if (!nexthop_group_equal_no_recurse(nhe1->nhg, nhe2->nhg))
- return false;
+ if (!nexthop1 && nexthop2)
+ return false;
+
+ /*
+ * We have to check the active flag of each individual one,
+ * not just the overall active_num. This solves the special case
+ * issue of a route with a nexthop group with one nexthop
+ * resolving to itself and thus marking it inactive. If we
+ * have two different routes each wanting to mark a different
+ * nexthop inactive, they need to hash to two different groups.
+ *
+ * If we just hashed on num_active, they would hash the same
+ * which is incorrect.
+ *
+ * ex)
+ * 1.1.1.0/24
+ * -> 1.1.1.1 dummy1 (inactive)
+ * -> 1.1.2.1 dummy2
+ *
+ * 1.1.2.0/24
+ * -> 1.1.1.1 dummy1
+ * -> 1.1.2.1 dummy2 (inactive)
+ *
+ * Without checking each individual one, they would hash to
+ * the same group and both have 1.1.1.1 dummy1 marked inactive.
+ *
+ */
+ if (CHECK_FLAG(nexthop1->flags, NEXTHOP_FLAG_ACTIVE)
+ != CHECK_FLAG(nexthop2->flags, NEXTHOP_FLAG_ACTIVE))
+ return false;
+
+ if (!nexthop_same(nexthop1, nexthop2))
+ return false;
+ }
return true;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index c24a518afb..781963793e 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -570,14 +570,6 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
nexthops_free(old->fib_ng.nexthop);
old->fib_ng.nexthop = NULL;
}
-
- if (!RIB_SYSTEM_ROUTE(old)) {
- /* Clear old route's FIB flags */
- for (ALL_NEXTHOPS_PTR(old->ng, nexthop)) {
- UNSET_FLAG(nexthop->flags,
- NEXTHOP_FLAG_FIB);
- }
- }
}
if (zvrf)