diff options
| -rw-r--r-- | bfdd/bfd_packet.c | 3 | ||||
| -rw-r--r-- | bgpd/bgp_damp.c | 385 | ||||
| -rw-r--r-- | bgpd/bgp_damp.h | 20 | ||||
| -rw-r--r-- | bgpd/bgp_evpn_vty.c | 14 | ||||
| -rw-r--r-- | bgpd/bgp_fsm.c | 5 | ||||
| -rw-r--r-- | bgpd/bgp_nht.c | 21 | ||||
| -rw-r--r-- | bgpd/bgp_nht.h | 8 | ||||
| -rw-r--r-- | bgpd/bgp_packet.c | 21 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 34 | ||||
| -rw-r--r-- | bgpd/bgp_rpki.c | 2 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 10 | ||||
| -rw-r--r-- | doc/developer/next-hop-tracking.rst | 2 | ||||
| -rw-r--r-- | doc/user/basic.rst | 11 | ||||
| -rw-r--r-- | doc/user/bgp.rst | 3 | ||||
| -rw-r--r-- | eigrpd/eigrp_packet.c | 9 | ||||
| -rw-r--r-- | lib/command.c | 40 | ||||
| -rw-r--r-- | lib/command.h | 3 | ||||
| -rw-r--r-- | ospfd/ospf_neighbor.c | 4 | ||||
| -rw-r--r-- | ospfd/ospf_opaque.c | 6 | ||||
| -rw-r--r-- | pimd/pim_zebra.c | 25 | ||||
| -rw-r--r-- | staticd/static_vty.c | 6 | ||||
| -rw-r--r-- | vtysh/vtysh_main.c | 3 | ||||
| -rw-r--r-- | vtysh/vtysh_user.c | 21 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 7 | ||||
| -rw-r--r-- | zebra/sample_plugin.c | 134 | ||||
| -rw-r--r-- | zebra/zebra_dplane.c | 4 | ||||
| -rw-r--r-- | zebra/zebra_mpls.c | 40 | ||||
| -rw-r--r-- | zebra/zebra_nhg.c | 47 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 8 |
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) |
