diff options
119 files changed, 1822 insertions, 829 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7cdf98cba7..596d820f1b 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -480,16 +480,6 @@ static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt, int length, return false; } -static uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi) -{ - uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr); - - if (bpi->nexthop) - return aigp + bpi->nexthop->metric; - else - return aigp; -} - static void stream_put_bgp_aigp_tlv_metric(struct stream *s, struct bgp_path_info *bpi) { @@ -1187,8 +1177,7 @@ struct attr *bgp_attr_aggregate_intern( SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN)); /* MED */ - attr.med = 0; - SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)); + bgp_attr_set_med(&attr, 0); /* AS path attribute. */ if (aspath) @@ -1943,9 +1932,7 @@ static enum bgp_attr_parse_ret bgp_attr_med(struct bgp_attr_parser_args *args) args->total); } - attr->med = stream_getl(peer->curr); - - SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)); + bgp_attr_set_med(attr, stream_getl(peer->curr)); return BGP_ATTR_PARSE_PROCEED; } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index a8ca8c1fa6..0a43399be6 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -593,9 +593,23 @@ static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr) static inline void bgp_attr_set_aigp_metric(struct attr *attr, uint64_t aigp) { attr->aigp_metric = aigp; + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)); +} + +static inline uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi) +{ + uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr); - if (aigp) - SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)); + if (bpi->nexthop) + return aigp + bpi->nexthop->metric; + else + return aigp; +} + +static inline void bgp_attr_set_med(struct attr *attr, uint32_t med) +{ + attr->med = med; + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)); } static inline struct cluster_list *bgp_attr_get_cluster(const struct attr *attr) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 08f8b8b734..59efb35235 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -489,7 +489,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) &uptime_real); /* Local Address (16 bytes) */ - if (!peer->su_local || is_locrib) + if (is_locrib) stream_put(s, 0, 16); else if (peer->su_local->sa.sa_family == AF_INET6) stream_put(s, &peer->su_local->sin6.sin6_addr, 16); @@ -501,14 +501,14 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) } /* Local Port, Remote Port */ - if (is_locrib) + if (!peer->su_local || is_locrib) stream_putw(s, 0); else if (peer->su_local->sa.sa_family == AF_INET6) stream_putw(s, htons(peer->su_local->sin6.sin6_port)); else if (peer->su_local->sa.sa_family == AF_INET) stream_putw(s, htons(peer->su_local->sin.sin_port)); - if (is_locrib) + if (!peer->su_remote || is_locrib) stream_putw(s, 0); else if (peer->su_remote->sa.sa_family == AF_INET6) stream_putw(s, htons(peer->su_remote->sin6.sin6_port)); diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index 2d96b444b6..a99d0201e7 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -30,8 +30,8 @@ bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table, dummy_attr = *pi->attr; /* Fill temp path_info */ - prep_for_rmap_apply(&path, &path_extra, dest, pi, - pi->peer, &dummy_attr); + prep_for_rmap_apply(&path, &path_extra, dest, pi, pi->peer, NULL, + &dummy_attr); RESET_FLAG(dummy_attr.rmap_change_flags); @@ -99,8 +99,8 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, advmap_attr = *pi->attr; /* Fill temp path_info */ - prep_for_rmap_apply(&path, &path_extra, dest, pi, - pi->peer, &advmap_attr); + prep_for_rmap_apply(&path, &path_extra, dest, pi, pi->peer, NULL, + &advmap_attr); RESET_FLAG(advmap_attr.rmap_change_flags); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 0a8ce61548..ad29828ade 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -5392,9 +5392,8 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, tmp_attr = *pi->attr; /* Fill temp path_info */ - prep_for_rmap_apply(&tmp_pi, &tmp_pie, - dest, pi, pi->peer, - &tmp_attr); + prep_for_rmap_apply(&tmp_pi, &tmp_pie, dest, pi, pi->peer, + NULL, &tmp_attr); RESET_FLAG(tmp_attr.rmap_change_flags); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index cdd9b7ae4d..567af5bb75 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -2776,99 +2776,72 @@ int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) const char *print_peer_gr_mode(enum peer_mode pr_mode) { - const char *peer_gr_mode = NULL; - switch (pr_mode) { case PEER_HELPER: - peer_gr_mode = "PEER_HELPER"; - break; + return "PEER_HELPER"; case PEER_GR: - peer_gr_mode = "PEER_GR"; - break; + return "PEER_GR"; case PEER_DISABLE: - peer_gr_mode = "PEER_DISABLE"; - break; + return "PEER_DISABLE"; case PEER_INVALID: - peer_gr_mode = "PEER_INVALID"; - break; + return "PEER_INVALID"; case PEER_GLOBAL_INHERIT: - peer_gr_mode = "PEER_GLOBAL_INHERIT"; - break; + return "PEER_GLOBAL_INHERIT"; } - return peer_gr_mode; + return NULL; } const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd) { - const char *peer_gr_cmd = NULL; - switch (pr_gr_cmd) { case PEER_GR_CMD: - peer_gr_cmd = "PEER_GR_CMD"; - break; + return "PEER_GR_CMD"; case NO_PEER_GR_CMD: - peer_gr_cmd = "NO_PEER_GR_CMD"; - break; + return "NO_PEER_GR_CMD"; case PEER_DISABLE_CMD: - peer_gr_cmd = "PEER_DISABLE_GR_CMD"; - break; + return "PEER_DISABLE_GR_CMD"; case NO_PEER_DISABLE_CMD: - peer_gr_cmd = "NO_PEER_DISABLE_GR_CMD"; - break; + return "NO_PEER_DISABLE_GR_CMD"; case PEER_HELPER_CMD: - peer_gr_cmd = "PEER_HELPER_CMD"; - break; + return "PEER_HELPER_CMD"; case NO_PEER_HELPER_CMD: - peer_gr_cmd = "NO_PEER_HELPER_CMD"; - break; + return "NO_PEER_HELPER_CMD"; } - return peer_gr_cmd; + return NULL; } const char *print_global_gr_mode(enum global_mode gl_mode) { - const char *global_gr_mode = "???"; - switch (gl_mode) { case GLOBAL_HELPER: - global_gr_mode = "GLOBAL_HELPER"; - break; + return "GLOBAL_HELPER"; case GLOBAL_GR: - global_gr_mode = "GLOBAL_GR"; - break; + return "GLOBAL_GR"; case GLOBAL_DISABLE: - global_gr_mode = "GLOBAL_DISABLE"; - break; + return "GLOBAL_DISABLE"; case GLOBAL_INVALID: - global_gr_mode = "GLOBAL_INVALID"; - break; + return "GLOBAL_INVALID"; } - return global_gr_mode; + return "???"; } const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd) { - const char *global_gr_cmd = NULL; - switch (gl_gr_cmd) { case GLOBAL_GR_CMD: - global_gr_cmd = "GLOBAL_GR_CMD"; - break; + return "GLOBAL_GR_CMD"; case NO_GLOBAL_GR_CMD: - global_gr_cmd = "NO_GLOBAL_GR_CMD"; - break; + return "NO_GLOBAL_GR_CMD"; case GLOBAL_DISABLE_CMD: - global_gr_cmd = "GLOBAL_DISABLE_CMD"; - break; + return "GLOBAL_DISABLE_CMD"; case NO_GLOBAL_DISABLE_CMD: - global_gr_cmd = "NO_GLOBAL_DISABLE_CMD"; - break; + return "NO_GLOBAL_DISABLE_CMD"; } - return global_gr_cmd; + return NULL; } enum global_mode bgp_global_gr_mode_get(struct bgp *bgp) diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index b07e69ac31..9e9251c854 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -512,7 +512,13 @@ static uint16_t bgp_read(struct peer_connection *connection, int *code_p) readsize = MIN(ibuf_work_space, sizeof(ibuf_scratch)); +#ifdef __clang_analyzer__ + /* clang-SA doesn't want you to call read() while holding a mutex */ + (void)readsize; + nbytes = 0; +#else nbytes = read(connection->fd, ibuf_scratch, readsize); +#endif /* EAGAIN or EWOULDBLOCK; come back later */ if (nbytes < 0 && ERRNO_IO_RETRY(errno)) { diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 564ad118eb..401549c4e8 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1377,16 +1377,9 @@ char *bgp_nexthop_dump_bnc_change_flags(struct bgp_nexthop_cache *bnc, return buf; } - snprintfrr(buf, len, "%s%s%s", - CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED) - ? "Changed " - : "", - CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED) - ? "Metric " - : "", - CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CONNECTED_CHANGED) - ? "Connected " - : ""); + snprintfrr(buf, len, "%s%s", + CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED) ? "Changed " : "", + CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED) ? "Metric " : ""); return buf; } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 5014eb8f34..6a4a02dcc8 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -45,11 +45,10 @@ struct bgp_nexthop_cache { */ bool is_evpn_gwip_nexthop; - uint16_t change_flags; + uint8_t change_flags; #define BGP_NEXTHOP_CHANGED (1 << 0) #define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) -#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2) -#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3) +#define BGP_NEXTHOP_MACIP_CHANGED (1 << 2) struct nexthop *nexthop; time_t last_update; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9cefec0706..ed1dbc6b42 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1068,8 +1068,8 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (CHECK_FLAG(newattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) && CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP)) { - uint64_t new_aigp = bgp_attr_get_aigp_metric(newattr); - uint64_t exist_aigp = bgp_attr_get_aigp_metric(existattr); + uint64_t new_aigp = bgp_aigp_metric_total(new); + uint64_t exist_aigp = bgp_aigp_metric_total(exist); if (new_aigp < exist_aigp) { *reason = bgp_path_selection_aigp; @@ -2148,7 +2148,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, struct attr *piattr; route_map_result_t ret; int transparent; - int reflect; + int ibgp_to_ibgp; afi_t afi; safi_t safi; int samepeer_safe = 0; /* for synthetic mplsvpns routes */ @@ -2357,14 +2357,14 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, } } - /* Route-Reflect check. */ + /* iBGP to iBGP check. */ if (from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) - reflect = 1; + ibgp_to_ibgp = 1; else - reflect = 0; + ibgp_to_ibgp = 0; /* IBGP reflection check. */ - if (reflect && !samepeer_safe) { + if (ibgp_to_ibgp && !samepeer_safe) { /* A route from a Client peer. */ if (CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) { @@ -2410,8 +2410,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* If originator-id is not set and the route is to be reflected, set the originator id */ - if (reflect - && (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))) { + if (ibgp_to_ibgp && (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))) { IPV4_ADDR_COPY(&(attr->originator_id), &(from->remote_id)); SET_FLAG(attr->flag, BGP_ATTR_ORIGINATOR_ID); } @@ -2444,7 +2443,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * announced to an EBGP peer (and they have the same attributes barring * their nexthop). */ - if (reflect) + if (ibgp_to_ibgp) SET_FLAG(attr->rmap_change_flags, BATTR_REFLECTED); #define NEXTHOP_IS_V6 \ @@ -2472,7 +2471,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, */ if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) global_and_ll = true; - } else if (!reflect && !transparent && + } else if (!ibgp_to_ibgp && !transparent && + !CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT) && IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) && peer->shared_network && (from == bgp->peer_self || peer->sort == BGP_PEER_EBGP)) global_and_ll = true; @@ -2512,8 +2512,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, struct attr dummy_attr = *attr; /* Fill temp path_info */ - prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest, - pi, peer, &dummy_attr); + prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest, pi, peer, NULL, + &dummy_attr); struct route_map *amap = route_map_lookup_by_name(filter->advmap.aname); @@ -2537,9 +2537,13 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, struct bgp_path_info_extra dummy_rmap_path_extra = {0}; struct attr dummy_attr = {0}; - /* Fill temp path_info */ - prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest, - pi, peer, attr); + /* Fill temp path_info. + * Inject the peer structure of the source peer (from). + * This is useful for e.g. `match peer ...` in outgoing + * direction. + */ + prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest, pi, peer, from, attr); + /* * The route reflector is not allowed to modify the attributes * of the reflected IBGP routes unless explicitly allowed. @@ -2694,9 +2698,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, PEER_FLAG_NEXTHOP_SELF) || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_FORCE_NEXTHOP_SELF)) { - if (!reflect - || CHECK_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_FORCE_NEXTHOP_SELF)) { + if (!ibgp_to_ibgp || + CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_FORCE_NEXTHOP_SELF)) { subgroup_announce_reset_nhop( (peer_cap_enhe(peer, afi, safi) ? AF_INET6 @@ -3427,9 +3430,8 @@ static void bgp_process_evpn_route_injection(struct bgp *bgp, afi_t afi, dummy_attr = *new_select->attr; /* Fill temp path_info */ - prep_for_rmap_apply(&rmap_path, &rmap_path_extra, dest, - new_select, new_select->peer, - &dummy_attr); + prep_for_rmap_apply(&rmap_path, &rmap_path_extra, dest, new_select, + new_select->peer, NULL, &dummy_attr); RESET_FLAG(dummy_attr.rmap_change_flags); @@ -3727,11 +3729,10 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, /* If there is a change of interest to peers, reannounce the * route. */ - if (CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED) - || CHECK_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG) - || CHECK_FLAG(dest->flags, BGP_NODE_LABEL_CHANGED)) { + if (CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED) || + CHECK_FLAG(dest->flags, BGP_NODE_LABEL_CHANGED) || + bgp_zebra_has_route_changed(old_select)) { group_announce_route(bgp, afi, safi, dest, new_select); - /* unicast routes must also be annouced to * labeled-unicast update-groups */ if (safi == SAFI_UNICAST) @@ -6747,15 +6748,12 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, bgp_attr_default_set(&attr, bgp, BGP_ORIGIN_IGP); attr.nexthop = bgp_static->igpnexthop; - attr.med = bgp_static->igpmetric; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); + + bgp_attr_set_med(&attr, bgp_static->igpmetric); if (afi == AFI_IP) attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - if (bgp_static->igpmetric) - bgp_attr_set_aigp_metric(&attr, bgp_static->igpmetric); - if (bgp_static->atomic) attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE); @@ -9015,14 +9013,10 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, else UNSET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); - attr.med = metric; + bgp_attr_set_med(&attr, metric); attr.distance = distance; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); attr.tag = tag; - if (metric) - bgp_attr_set_aigp_metric(&attr, metric); - afi = family2afi(p->family); red = bgp_redist_lookup(bgp, afi, type, instance); @@ -9032,10 +9026,8 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, /* Copy attribute for modification. */ attr_new = attr; - if (red->redist_metric_flag) { + if (red->redist_metric_flag) attr_new.med = red->redist_metric; - bgp_attr_set_aigp_metric(&attr_new, red->redist_metric); - } /* Apply route-map. */ if (red->rmap.name) { @@ -11787,8 +11779,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa dummy_attr = *pi->attr; - prep_for_rmap_apply(&path, &extra, dest, pi, - pi->peer, &dummy_attr); + prep_for_rmap_apply(&path, &extra, dest, pi, pi->peer, NULL, + &dummy_attr); ret = route_map_apply(rmap, dest_p, &path); bgp_attr_flush(&dummy_attr); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index d71bfd3ebc..1df0ffd300 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -284,6 +284,9 @@ struct bgp_path_info { /* Peer structure. */ struct peer *peer; + /* From peer structure */ + struct peer *from; + /* Attribute structure. */ struct attr *attr; @@ -619,13 +622,13 @@ static inline bool is_pi_family_matching(struct bgp_path_info *pi, } static inline void prep_for_rmap_apply(struct bgp_path_info *dst_pi, - struct bgp_path_info_extra *dst_pie, - struct bgp_dest *dest, - struct bgp_path_info *src_pi, - struct peer *peer, struct attr *attr) + struct bgp_path_info_extra *dst_pie, struct bgp_dest *dest, + struct bgp_path_info *src_pi, struct peer *peer, + struct peer *from, struct attr *attr) { memset(dst_pi, 0, sizeof(struct bgp_path_info)); dst_pi->peer = peer; + dst_pi->from = from; dst_pi->attr = attr; dst_pi->net = dest; dst_pi->flags = src_pi->flags; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 4900bb3ce3..8dd48575e5 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -125,6 +125,10 @@ o Local extensions #define RMAP_VALUE_ADD 1 #define RMAP_VALUE_SUB 2 +#define RMAP_VALUE_TYPE_RTT 1 +#define RMAP_VALUE_TYPE_IGP 2 +#define RMAP_VALUE_TYPE_AIGP 3 + struct rmap_value { uint8_t action; uint8_t variable; @@ -140,14 +144,21 @@ static int route_value_match(struct rmap_value *rv, uint32_t value) } static uint32_t route_value_adjust(struct rmap_value *rv, uint32_t current, - struct peer *peer) + struct bgp_path_info *bpi) { uint32_t value; + struct peer *peer = bpi->peer; switch (rv->variable) { - case 1: + case RMAP_VALUE_TYPE_RTT: value = peer->rtt; break; + case RMAP_VALUE_TYPE_IGP: + value = bpi->extra ? bpi->extra->igpmetric : 0; + break; + case RMAP_VALUE_TYPE_AIGP: + value = MIN(bpi->attr->aigp_metric, UINT32_MAX); + break; default: value = rv->value; break; @@ -187,11 +198,14 @@ static void *route_value_compile(const char *arg) larg = strtoul(arg, &endptr, 10); if (*arg == 0 || *endptr != 0 || errno || larg > UINT32_MAX) return NULL; + } else if (strmatch(arg, "rtt")) { + var = RMAP_VALUE_TYPE_RTT; + } else if (strmatch(arg, "igp")) { + var = RMAP_VALUE_TYPE_IGP; + } else if (strmatch(arg, "aigp")) { + var = RMAP_VALUE_TYPE_AIGP; } else { - if (strcmp(arg, "rtt") == 0) - var = 1; - else - return NULL; + return NULL; } rv = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_value)); @@ -333,6 +347,66 @@ static const struct route_map_rule_cmd route_match_peer_cmd = { route_match_peer_free }; +static enum route_map_cmd_result_t route_match_src_peer(void *rule, const struct prefix *prefix, + void *object) +{ + struct bgp_match_peer_compiled *pc; + union sockunion *su; + struct peer_group *group; + struct peer *peer; + struct listnode *node, *nnode; + struct bgp_path_info *bpi; + + pc = rule; + su = &pc->su; + bpi = object; + peer = bpi->from; + + /* Fallback to destination (current) peer. This is mostly + * happens if `match src-peer ...` is used at incoming direction. + */ + if (!peer) + peer = bpi->peer; + + if (!peer) + return RMAP_NOMATCH; + + if (pc->interface) { + if (!peer->conf_if && !peer->group) + return RMAP_NOMATCH; + + if (peer->conf_if && strcmp(peer->conf_if, pc->interface) == 0) + return RMAP_MATCH; + + if (peer->group && strcmp(peer->group->name, pc->interface) == 0) + return RMAP_MATCH; + + return RMAP_NOMATCH; + } + + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + if (sockunion_same(su, &peer->connection->su)) + return RMAP_MATCH; + + return RMAP_NOMATCH; + } + + group = peer->group; + for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { + if (sockunion_same(su, &peer->connection->su)) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +static const struct route_map_rule_cmd route_match_src_peer_cmd = { + "src-peer", + route_match_src_peer, + route_match_peer_compile, + route_match_peer_free +}; + #ifdef HAVE_SCRIPTING enum frrlua_rm_status { @@ -2145,7 +2219,7 @@ route_set_local_pref(void *rule, const struct prefix *prefix, void *object) locpref = path->attr->local_pref; path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); - path->attr->local_pref = route_value_adjust(rv, locpref, path->peer); + path->attr->local_pref = route_value_adjust(rv, locpref, path); return RMAP_OKAY; } @@ -2172,7 +2246,7 @@ route_set_weight(void *rule, const struct prefix *prefix, void *object) path = object; /* Set weight value. */ - path->attr->weight = route_value_adjust(rv, 0, path->peer); + path->attr->weight = route_value_adjust(rv, 0, path); return RMAP_OKAY; } @@ -2222,8 +2296,7 @@ route_set_metric(void *rule, const struct prefix *prefix, void *object) if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) med = path->attr->med; - path->attr->med = route_value_adjust(rv, med, path->peer); - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); + bgp_attr_set_med(path->attr, route_value_adjust(rv, med, path)); return RMAP_OKAY; } @@ -3451,19 +3524,15 @@ route_set_aigp_metric(void *rule, const struct prefix *pfx, void *object) { const char *aigp_metric = rule; struct bgp_path_info *path = object; - uint32_t aigp = 0; - - if (strmatch(aigp_metric, "igp-metric")) { - if (!path->nexthop) - return RMAP_NOMATCH; + uint32_t aigp; - bgp_attr_set_aigp_metric(path->attr, path->nexthop->metric); - } else { + /* Note: the metric is stored as MED for a locally redistributed. */ + if (strmatch(aigp_metric, "igp-metric")) + aigp = path->nexthop ? path->nexthop->metric : path->attr->med; + else aigp = atoi(aigp_metric); - bgp_attr_set_aigp_metric(path->attr, aigp); - } - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AIGP); + bgp_attr_set_aigp_metric(path->attr, aigp); return RMAP_OKAY; } @@ -5274,6 +5343,52 @@ DEFUN_YANG (no_match_peer, return nb_cli_apply_changes(vty, NULL); } +DEFPY_YANG (match_src_peer, + match_src_peer_cmd, + "match src-peer <A.B.C.D$addrv4|X:X::X:X$addrv6|WORD$intf>", + MATCH_STR + "Match source peer address\n" + "IP address of peer\n" + "IPv6 address of peer\n" + "Interface name of peer or peer group name\n") +{ + const char *xpath = "./match-condition[condition='frr-bgp-route-map:src-peer']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:src-peer-ipv4-address", xpath); + nb_cli_enqueue_change(vty, xpath_value, addrv4_str ? NB_OP_MODIFY : NB_OP_DESTROY, + addrv4_str); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:src-peer-ipv6-address", xpath); + nb_cli_enqueue_change(vty, xpath_value, addrv6_str ? NB_OP_MODIFY : NB_OP_DESTROY, + addrv6_str); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:src-peer-interface", xpath); + nb_cli_enqueue_change(vty, xpath_value, intf ? NB_OP_MODIFY : NB_OP_DESTROY, intf); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_match_src_peer, + no_match_src_peer_cmd, + "no match src-peer [<A.B.C.D|X:X::X:X|WORD>]", + NO_STR + MATCH_STR + "Match peer address\n" + "IP address of peer\n" + "IPv6 address of peer\n" + "Interface name of peer\n") +{ + const char *xpath = "./match-condition[condition='frr-bgp-route-map:src-peer']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + #ifdef HAVE_SCRIPTING DEFUN_YANG (match_script, match_script_cmd, @@ -7765,6 +7880,7 @@ void bgp_route_map_init(void) route_map_no_set_tag_hook(generic_set_delete); route_map_install_match(&route_match_peer_cmd); + route_map_install_match(&route_match_src_peer_cmd); route_map_install_match(&route_match_alias_cmd); route_map_install_match(&route_match_local_pref_cmd); #ifdef HAVE_SCRIPTING @@ -7832,6 +7948,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &match_peer_cmd); install_element(RMAP_NODE, &match_peer_local_cmd); + install_element(RMAP_NODE, &match_src_peer_cmd); + install_element(RMAP_NODE, &no_match_src_peer_cmd); install_element(RMAP_NODE, &no_match_peer_cmd); install_element(RMAP_NODE, &match_ip_route_source_cmd); install_element(RMAP_NODE, &no_match_ip_route_source_cmd); diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index 096502aaa9..d8fdb4fbc4 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -110,6 +110,27 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { } }, { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-ipv4-address", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-interface", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-ipv6-address", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_destroy, + } + }, + { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:list-name", .cbs = { .modify = lib_route_map_entry_match_condition_rmap_match_condition_list_name_modify, diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index d7f0cea30e..f59686f386 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -46,6 +46,18 @@ int lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_m int lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_peer_local_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_peer_local_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_modify( + struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_destroy( + struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_modify( + struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_destroy( + struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_modify( + struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_destroy( + struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_extended_modify(struct nb_cb_modify_args *args); diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 15c32eaa28..0dca196ed6 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -809,6 +809,162 @@ lib_route_map_entry_match_condition_rmap_match_condition_peer_local_destroy( } /* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-ipv4-address + */ +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "src-peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "src-peer", peer, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-interface + */ +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "src-peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "src-peer", peer, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-ipv6-address + */ +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "src-peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "src-peer", peer, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:list-name */ int diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 250378af68..1a66df59fc 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -906,8 +906,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, bool withdraw) assert(attr.aspath); aspath = attr.aspath; - attr.med = 0; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); + + bgp_attr_set_med(&attr, 0); if ((afi == AFI_IP6) || peer_cap_enhe(peer, afi, safi)) { /* IPv6 global nexthop must be included. */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 1877d451ad..62b79541bf 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -4493,16 +4493,6 @@ DEFUN (bgp_network_import_check, return CMD_SUCCESS; } -#if CONFDATE > 20241013 -CPP_NOTICE("Drop `bgp network import-check exact` command") -#endif -ALIAS_HIDDEN(bgp_network_import_check, bgp_network_import_check_exact_cmd, - "bgp network import-check exact", - BGP_STR - "BGP network command\n" - "Check BGP network route exists in IGP\n" - "Match route precisely\n") - DEFUN (no_bgp_network_import_check, no_bgp_network_import_check_cmd, "no bgp network import-check", @@ -20658,7 +20648,6 @@ void bgp_vty_init(void) /* "bgp network import-check" commands. */ install_element(BGP_NODE, &bgp_network_import_check_cmd); - install_element(BGP_NODE, &bgp_network_import_check_exact_cmd); install_element(BGP_NODE, &no_bgp_network_import_check_cmd); /* "bgp default local-preference" commands. */ diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 23e3eb4823..61d154f1b4 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -667,10 +667,8 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); } - if (med) { - attr.med = *med; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); - } + if (med) + bgp_attr_set_med(&attr, *med); /* override default weight assigned by bgp_attr_default_set() */ attr.weight = rfd->peer ? rfd->peer->weight[afi][safi] : 0; @@ -863,10 +861,8 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ red = bgp_redist_lookup(bgp, afi, type, 0); - if (red && red->redist_metric_flag) { - attr.med = red->redist_metric; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); - } + if (red && red->redist_metric_flag) + bgp_attr_set_med(&attr, red->redist_metric); bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd); diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c index 4de2306609..c9a058ea44 100644 --- a/bgpd/rfapi/vnc_export_bgp.c +++ b/bgpd/rfapi/vnc_export_bgp.c @@ -96,15 +96,16 @@ static void encap_attr_export_ce(struct attr *new, struct attr *orig, * neighbor NEIGHBOR attribute-unchanged med */ if (!CHECK_FLAG(new->flag, BGP_ATTR_MULTI_EXIT_DISC)) { + uint32_t med = 255; + if (CHECK_FLAG(new->flag, BGP_ATTR_LOCAL_PREF)) { if (new->local_pref > 255) - new->med = 0; + med = 0; else - new->med = 255 - new->local_pref; - } else { - new->med = 255; /* shouldn't happen */ + med = 255 - new->local_pref; } - new->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); + + bgp_attr_set_med(new, med); } /* @@ -642,15 +643,16 @@ encap_attr_export(struct attr *new, struct attr *orig, * neighbor NEIGHBOR attribute-unchanged med */ if (!CHECK_FLAG(new->flag, BGP_ATTR_MULTI_EXIT_DISC)) { + uint32_t med = 255; + if (CHECK_FLAG(new->flag, BGP_ATTR_LOCAL_PREF)) { if (new->local_pref > 255) - new->med = 0; + med = 0; else - new->med = 255 - new->local_pref; - } else { - new->med = 255; /* shouldn't happen */ + med = 255 - new->local_pref; } - new->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); + + bgp_attr_set_med(new, med); } /* diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 9034af39c5..60e458a28a 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -190,6 +190,12 @@ Route Map Match Command do the exact matching of the communities, while ``any`` - can match any community specified in COMMUNITY_LIST. +.. clicmd:: match src-peer [IPV4_ADDR|IPV6_ADDR|INTERFACE_NAME|PEER_GROUP_NAME] + + This is a BGP specific match command. Matches the source peer if the neighbor + was specified in this manner. Useful to announce the routes that was originated + by the source peer. + .. clicmd:: match peer IPV4_ADDR This is a BGP specific match command. Matches the peer ip address @@ -305,13 +311,18 @@ Route Map Set Command Set the route's weight. -.. clicmd:: set metric <[+|-](1-4294967295)|rtt|+rtt|-rtt> +.. clicmd:: set metric <[+|-](1-4294967295)|rtt|+rtt|-rtt|igp|aigp> Set the route metric. When used with BGP, set the BGP attribute MED to a specific value. Use `+`/`-` to add or subtract the specified value to/from the existing/MED. Use `rtt` to set the MED to the round trip time or `+rtt`/`-rtt` to add/subtract the round trip time to/from the MED. + If ``igp`` is specified, then the actual value from the IGP protocol is used. + + If ``aigp`` is specified, then the actual value from the AIGP metric is used + (encoded as MED instead of AIGP attribute). + .. clicmd:: set min-metric <(0-4294967295)> Set the minimum metric for the route. diff --git a/isisd/isis_vty_fabricd.c b/isisd/isis_vty_fabricd.c index 0d25f66109..85ef2c40a1 100644 --- a/isisd/isis_vty_fabricd.c +++ b/isisd/isis_vty_fabricd.c @@ -218,17 +218,9 @@ DEFUN (ip_router_isis, if (!area) isis_area_create(area_tag, VRF_DEFAULT_NAME); - if (!circuit) { + if (!circuit) circuit = isis_circuit_new(ifp, area_tag); - if (circuit->state != C_STATE_CONF - && circuit->state != C_STATE_UP) { - vty_out(vty, - "Couldn't bring up interface, please check log.\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - bool ip = circuit->ip_router, ipv6 = circuit->ipv6_router; if (af[2] != '\0') ipv6 = true; diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 6e844c0aa1..0a3a03bc38 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -459,6 +459,8 @@ static void ldpe_dispatch_main(struct event *thread) tnbr_update_all(AF_UNSPEC); break; case IMSG_RECONF_CONF: + if (nconf) + ldp_clear_config(nconf); if ((nconf = malloc(sizeof(struct ldpd_conf))) == NULL) fatal(NULL); memcpy(nconf, imsg.data, sizeof(struct ldpd_conf)); diff --git a/lib/command.h b/lib/command.h index f369a35243..c60751789f 100644 --- a/lib/command.h +++ b/lib/command.h @@ -84,6 +84,7 @@ enum node_type { CONFIG_NODE, /* Config node. Default mode of config file. */ PREFIX_NODE, /* ip prefix-list node. */ PREFIX_IPV6_NODE, /* ipv6 prefix-list node. */ + RMAP_NODE, /* Route map node. */ LIB_DEBUG_NODE, /* frrlib debug node. */ DEBUG_NODE, /* Debug node. */ VRF_DEBUG_NODE, /* Vrf Debug node. */ @@ -136,7 +137,6 @@ enum node_type { AS_LIST_NODE, /* AS list node. */ COMMUNITY_LIST_NODE, /* Community list node. */ COMMUNITY_ALIAS_NODE, /* Community alias node. */ - RMAP_NODE, /* Route map node. */ PBRMAP_NODE, /* PBR map node. */ SMUX_NODE, /* SNMP configuration node. */ DUMP_NODE, /* Packet dump node. */ diff --git a/lib/defun_lex.l b/lib/defun_lex.l index 3104e48063..9528e44852 100644 --- a/lib/defun_lex.l +++ b/lib/defun_lex.l @@ -157,6 +157,9 @@ SPECIAL [(),] %% +#else +extern int def_yylex(void); +extern int def_yylex_destroy(void); #endif /* __clang_analyzer__ */ static int yylex_clr(char **retbuf) diff --git a/lib/netns_linux.c b/lib/netns_linux.c index 8fa4bc6fe0..82162abfd4 100644 --- a/lib/netns_linux.c +++ b/lib/netns_linux.c @@ -258,7 +258,7 @@ static void ns_disable_internal(struct ns *ns) if (ns_master.ns_disable_hook) (*ns_master.ns_disable_hook)(ns); - if (have_netns()) + if (have_netns() && ns->fd >= 0) close(ns->fd); ns->fd = -1; diff --git a/lib/ntop.c b/lib/ntop.c index 89b4d5ecdc..edf03cd076 100644 --- a/lib/ntop.c +++ b/lib/ntop.c @@ -116,7 +116,18 @@ inet4: best = i - curlen; bestlen = curlen; } - /* do we want ::ffff:A.B.C.D? */ + if (best == 0 && bestlen == 5 && b[10] == 0xff && b[11] == 0xff) { + /* ::ffff:A.B.C.D */ + *o++ = ':'; + *o++ = ':'; + *o++ = 'f'; + *o++ = 'f'; + *o++ = 'f'; + *o++ = 'f'; + *o++ = ':'; + b += 12; + goto inet4; + } if (best == 0 && bestlen == 6) { *o++ = ':'; *o++ = ':'; diff --git a/lib/ptm_lib.c b/lib/ptm_lib.c index ac800be0a5..737c60775f 100644 --- a/lib/ptm_lib.c +++ b/lib/ptm_lib.c @@ -308,22 +308,18 @@ static int _ptm_lib_read_ptm_socket(int fd, char *buf, int len) while (bytes_read != len) { rc = recv(fd, (void *)(buf + bytes_read), (len - bytes_read), MSG_DONTWAIT); - if (rc <= 0) { - if (errno && (errno != EAGAIN) - && (errno != EWOULDBLOCK)) { - ERRLOG("fatal recv error(%s), closing connection, rc %d\n", - strerror(errno), rc); - return (rc); - } else { - if (retries++ < 2) { - usleep(10000); - continue; - } - DLOG("max retries - recv error(%d - %s) bytes read %d (%d)\n", - errno, strerror(errno), bytes_read, len); - return (bytes_read); + if (rc < 0 && (errno != EAGAIN) && (errno != EWOULDBLOCK)) { + ERRLOG("fatal recv error(%s), closing connection, rc %d\n", strerror(errno), + rc); + return (rc); + } else if (rc <= 0) { + if (retries++ < 2) { + usleep(10000); + continue; } - break; + DLOG("max retries - recv error(%d - %s) bytes read %d (%d)\n", errno, + strerror(errno), bytes_read, len); + return (bytes_read); } else { bytes_read += rc; } diff --git a/lib/routemap.h b/lib/routemap.h index dfb84ced5b..ef9b3cb160 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -278,6 +278,7 @@ DECLARE_QOBJ_TYPE(route_map); #define IS_MATCH_SRC_VRF(C) \ (strmatch(C, "frr-bgp-route-map:source-vrf")) #define IS_MATCH_PEER(C) (strmatch(C, "frr-bgp-route-map:peer")) +#define IS_MATCH_SRC_PEER(C) (strmatch(C, "frr-bgp-route-map:src-peer")) #define IS_MATCH_AS_LIST(C) \ (strmatch(C, "frr-bgp-route-map:as-path-list")) #define IS_MATCH_MAC_LIST(C) \ diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index f64c3c2376..69b942064b 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -756,6 +756,18 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, acl = "local"; vty_out(vty, " match peer %s\n", acl); + } else if (IS_MATCH_SRC_PEER(condition)) { + acl = NULL; + ln = yang_dnode_get(dnode, + "./rmap-match-condition/frr-bgp-route-map:src-peer-ipv4-address"); + if (!ln) + ln = yang_dnode_get(dnode, + "./rmap-match-condition/frr-bgp-route-map:src-peer-ipv6-address"); + if (!ln) + ln = yang_dnode_get(dnode, + "./rmap-match-condition/frr-bgp-route-map:src-peer-interface"); + acl = yang_dnode_get_string(ln, NULL); + vty_out(vty, " match src-peer %s\n", acl); } else if (IS_MATCH_AS_LIST(condition)) { vty_out(vty, " match as-path %s\n", yang_dnode_get_string( @@ -922,13 +934,15 @@ DEFPY_YANG( DEFPY_YANG( set_metric, set_metric_cmd, - "set metric <(-4294967295-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt>", + "set metric <(-4294967295-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|igp$igp|aigp$aigp>", SET_STR "Metric value for destination routing protocol\n" "Metric value (use +/- for additions or subtractions)\n" "Assign round trip time\n" "Add round trip time\n" - "Subtract round trip time\n") + "Subtract round trip time\n" + "Metric value from IGP protocol\n" + "Metric value from AIGP (Accumulated IGP)\n") { const char *xpath = "./set-action[action='frr-route-map:set-metric']"; char xpath_value[XPATH_MAXLEN]; @@ -939,6 +953,12 @@ DEFPY_YANG( snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-set-action/use-round-trip-time", xpath); snprintf(value, sizeof(value), "true"); + } else if (igp) { + snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-set-action/use-igp", xpath); + snprintf(value, sizeof(value), "true"); + } else if (aigp) { + snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-set-action/use-aigp", xpath); + snprintf(value, sizeof(value), "true"); } else if (artt) { snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-set-action/add-round-trip-time", xpath); @@ -1148,23 +1168,19 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode, if (yang_dnode_get(dnode, "./rmap-set-action/use-round-trip-time")) { vty_out(vty, " set metric rtt\n"); - } else if (yang_dnode_get( - dnode, - "./rmap-set-action/add-round-trip-time")) { + } else if (yang_dnode_get(dnode, "./rmap-set-action/use-igp")) { + vty_out(vty, " set metric igp\n"); + } else if (yang_dnode_get(dnode, "./rmap-set-action/use-aigp")) { + vty_out(vty, " set metric aigp\n"); + } else if (yang_dnode_get(dnode, "./rmap-set-action/add-round-trip-time")) { vty_out(vty, " set metric +rtt\n"); - } else if ( - yang_dnode_get( - dnode, - "./rmap-set-action/subtract-round-trip-time")) { + } else if (yang_dnode_get(dnode, "./rmap-set-action/subtract-round-trip-time")) { vty_out(vty, " set metric -rtt\n"); - } else if (yang_dnode_get(dnode, - "./rmap-set-action/add-metric")) { + } else if (yang_dnode_get(dnode, "./rmap-set-action/add-metric")) { vty_out(vty, " set metric +%s\n", yang_dnode_get_string( dnode, "./rmap-set-action/add-metric")); - } else if (yang_dnode_get( - dnode, - "./rmap-set-action/subtract-metric")) { + } else if (yang_dnode_get(dnode, "./rmap-set-action/subtract-metric")) { vty_out(vty, " set metric -%s\n", yang_dnode_get_string( dnode, diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 1bba4dad47..0ee055e653 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -1214,6 +1214,34 @@ static int lib_route_map_entry_set_action_use_round_trip_time_destroy( } /* + * XPath: /frr-route-map:lib/route-map/entry/set-action/use-igp + */ +static int lib_route_map_entry_set_action_use_igp_modify(struct nb_cb_modify_args *args) +{ + return set_action_modify(args->event, args->dnode, args->resource, "igp", args->errmsg, + args->errmsg_len); +} + +static int lib_route_map_entry_set_action_use_igp_destroy(struct nb_cb_destroy_args *args) +{ + return lib_route_map_entry_set_action_value_destroy(args); +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/use-aigp + */ +static int lib_route_map_entry_set_action_use_aigp_modify(struct nb_cb_modify_args *args) +{ + return set_action_modify(args->event, args->dnode, args->resource, "aigp", args->errmsg, + args->errmsg_len); +} + +static int lib_route_map_entry_set_action_use_aigp_destroy(struct nb_cb_destroy_args *args) +{ + return lib_route_map_entry_set_action_value_destroy(args); +} + +/* * XPath: /frr-route-map:lib/route-map/entry/set-action/add-round-trip-time */ static int lib_route_map_entry_set_action_add_round_trip_time_modify( @@ -1517,6 +1545,20 @@ const struct frr_yang_module_info frr_route_map_info = { } }, { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/use-igp", + .cbs = { + .modify = lib_route_map_entry_set_action_use_igp_modify, + .destroy = lib_route_map_entry_set_action_use_igp_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/use-aigp", + .cbs = { + .modify = lib_route_map_entry_set_action_use_aigp_modify, + .destroy = lib_route_map_entry_set_action_use_aigp_destroy, + } + }, + { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-round-trip-time", .cbs = { .modify = lib_route_map_entry_set_action_add_round_trip_time_modify, diff --git a/lib/zclient.c b/lib/zclient.c index 0e832f0d8f..557d9c3eb9 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2374,7 +2374,7 @@ static bool zapi_nexthop_update_decode(struct stream *s, struct prefix *match, STREAM_GETW(s, nhr->instance); STREAM_GETC(s, nhr->distance); STREAM_GETL(s, nhr->metric); - STREAM_GETC(s, nhr->nexthop_num); + STREAM_GETW(s, nhr->nexthop_num); for (i = 0; i < nhr->nexthop_num; i++) { if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0, 0) != 0) diff --git a/lib/zclient.h b/lib/zclient.h index 91c0c9ed6d..6da9558aa5 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -251,21 +251,16 @@ enum zebra_error_types { static inline const char *zebra_error_type2str(enum zebra_error_types type) { - const char *ret = "UNKNOWN"; - switch (type) { case ZEBRA_UNKNOWN_ERROR: - ret = "ZEBRA_UNKNOWN_ERROR"; - break; + return "ZEBRA_UNKNOWN_ERROR"; case ZEBRA_NO_VRF: - ret = "ZEBRA_NO_VRF"; - break; + return "ZEBRA_NO_VRF"; case ZEBRA_INVALID_MSG_TYPE: - ret = "ZEBRA_INVALID_MSG_TYPE"; - break; + return "ZEBRA_INVALID_MSG_TYPE"; } - return ret; + return "UNKNOWN"; } struct redist_proto { @@ -780,69 +775,51 @@ enum zclient_send_status { static inline const char * zapi_nhg_notify_owner2str(enum zapi_nhg_notify_owner note) { - const char *ret = "UNKNOWN"; - switch (note) { case ZAPI_NHG_FAIL_INSTALL: - ret = "ZAPI_NHG_FAIL_INSTALL"; - break; + return "ZAPI_NHG_FAIL_INSTALL"; case ZAPI_NHG_INSTALLED: - ret = "ZAPI_NHG_INSTALLED"; - break; + return "ZAPI_NHG_INSTALLED"; case ZAPI_NHG_REMOVE_FAIL: - ret = "ZAPI_NHG_REMOVE_FAIL"; - break; + return "ZAPI_NHG_REMOVE_FAIL"; case ZAPI_NHG_REMOVED: - ret = "ZAPI_NHG_REMOVED"; - break; + return "ZAPI_NHG_REMOVED"; } - return ret; + return "UNKNOWN"; } static inline const char * zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note) { - const char *ret = "UNKNOWN"; - switch (note) { case ZAPI_RULE_FAIL_INSTALL: - ret = "ZAPI_RULE_FAIL_INSTALL"; - break; + return "ZAPI_RULE_FAIL_INSTALL"; case ZAPI_RULE_INSTALLED: - ret = "ZAPI_RULE_INSTALLED"; - break; + return "ZAPI_RULE_INSTALLED"; case ZAPI_RULE_FAIL_REMOVE: - ret = "ZAPI_RULE_FAIL_REMOVE"; - break; + return "ZAPI_RULE_FAIL_REMOVE"; case ZAPI_RULE_REMOVED: - ret = "ZAPI_RULE_REMOVED"; - break; + return "ZAPI_RULE_REMOVED"; } - return ret; + return "UNKNOWN"; } static inline const char *zapi_srv6_sid_notify2str(enum zapi_srv6_sid_notify note) { - const char *ret = "UNKNOWN"; - switch (note) { case ZAPI_SRV6_SID_FAIL_ALLOC: - ret = "ZAPI_SRV6_SID_FAIL_ALLOC"; - break; + return "ZAPI_SRV6_SID_FAIL_ALLOC"; case ZAPI_SRV6_SID_ALLOCATED: - ret = "ZAPI_SRV6_SID_ALLOCATED"; - break; + return "ZAPI_SRV6_SID_ALLOCATED"; case ZAPI_SRV6_SID_FAIL_RELEASE: - ret = "ZAPI_SRV6_SID_FAIL_RELEASE"; - break; + return "ZAPI_SRV6_SID_FAIL_RELEASE"; case ZAPI_SRV6_SID_RELEASED: - ret = "ZAPI_SRV6_SID_RELEASED"; - break; + return "ZAPI_SRV6_SID_RELEASED"; } - return ret; + return "UNKNOWN"; } /* Zebra MAC types */ diff --git a/lib/zlog_5424_cli.c b/lib/zlog_5424_cli.c index 3003df542f..f97c426463 100644 --- a/lib/zlog_5424_cli.c +++ b/lib/zlog_5424_cli.c @@ -674,6 +674,7 @@ static int log_5424_config_write(struct vty *vty) vty_out(vty, "log extended %s\n", cfg->name); + (void)fmt_str; /* clang-SA */ switch (cfg->cfg.fmt) { case ZLOG_FMT_5424: fmt_str = " format rfc5424"; diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index f125fa93b1..a8b8de6d5b 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2613,8 +2613,7 @@ void ospf_external_lsa_refresh_default(struct ospf *ospf) } } -void ospf_external_lsa_refresh_type(struct ospf *ospf, uint8_t type, - unsigned short instance, int force) +void ospf_external_lsa_refresh_type(struct ospf *ospf, uint8_t type, uint8_t instance, int force) { struct route_node *rn; struct external_info *ei; @@ -3170,9 +3169,9 @@ int ospf_check_nbr_status(struct ospf *ospf) } -void ospf_maxage_lsa_remover(struct event *thread) +void ospf_maxage_lsa_remover(struct event *event) { - struct ospf *ospf = EVENT_ARG(thread); + struct ospf *ospf = EVENT_ARG(event); struct ospf_lsa *lsa, *old; struct route_node *rn; int reschedule = 0; @@ -3202,7 +3201,7 @@ void ospf_maxage_lsa_remover(struct event *thread) } /* TODO: maybe convert this function to a work-queue */ - if (event_should_yield(thread)) { + if (event_should_yield(event)) { OSPF_TIMER_ON(ospf->t_maxage, ospf_maxage_lsa_remover, 0); route_unlock_node( @@ -3418,9 +3417,9 @@ static int ospf_lsa_maxage_walker_remover(struct ospf *ospf, } /* Periodical check of MaxAge LSA. */ -void ospf_lsa_maxage_walker(struct event *thread) +void ospf_lsa_maxage_walker(struct event *event) { - struct ospf *ospf = EVENT_ARG(thread); + struct ospf *ospf = EVENT_ARG(event); struct route_node *rn; struct ospf_lsa *lsa; struct ospf_area *area; @@ -4157,11 +4156,11 @@ void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa) } } -void ospf_lsa_refresh_walker(struct event *t) +void ospf_lsa_refresh_walker(struct event *e) { struct list *refresh_list; struct listnode *node, *nnode; - struct ospf *ospf = EVENT_ARG(t); + struct ospf *ospf = EVENT_ARG(e); struct ospf_lsa *lsa; int i; struct list *lsa_to_refresh = list_new(); diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index d5ca0694cc..c751f081fb 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -225,122 +225,111 @@ enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE }; /* Prototypes. */ /* XXX: Eek, time functions, similar are in lib/thread.c */ extern struct timeval int2tv(int); -extern struct timeval msec2tv(int); +extern struct timeval msec2tv(int a); -extern int get_age(struct ospf_lsa *); -extern uint16_t ospf_lsa_checksum(struct lsa_header *); -extern int ospf_lsa_checksum_valid(struct lsa_header *); -extern int ospf_lsa_refresh_delay(struct ospf_lsa *); +extern int get_age(struct ospf_lsa *lsa); +extern uint16_t ospf_lsa_checksum(struct lsa_header *lsah); +extern int ospf_lsa_checksum_valid(struct lsa_header *lsah); +extern int ospf_lsa_refresh_delay(struct ospf_lsa *lsa); -extern const char *dump_lsa_key(struct ospf_lsa *); -extern uint32_t lsa_seqnum_increment(struct ospf_lsa *); -extern void lsa_header_set(struct stream *, uint8_t, uint8_t, struct in_addr, - struct in_addr); -extern struct ospf_neighbor *ospf_nbr_lookup_ptop(struct ospf_interface *); -extern int ospf_check_nbr_status(struct ospf *); +extern const char *dump_lsa_key(struct ospf_lsa *lsa); +extern uint32_t lsa_seqnum_increment(struct ospf_lsa *lsa); +extern void lsa_header_set(struct stream *s, uint8_t options, uint8_t type, struct in_addr id, + struct in_addr router_id); +extern struct ospf_neighbor *ospf_nbr_lookup_ptop(struct ospf_interface *oi); +extern int ospf_check_nbr_status(struct ospf *ospf); /* Prototype for LSA primitive. */ extern struct ospf_lsa *ospf_lsa_new(void); extern struct ospf_lsa *ospf_lsa_new_and_data(size_t size); -extern struct ospf_lsa *ospf_lsa_dup(struct ospf_lsa *); -extern void ospf_lsa_free(struct ospf_lsa *); -extern struct ospf_lsa *ospf_lsa_lock(struct ospf_lsa *); -extern void ospf_lsa_unlock(struct ospf_lsa **); -extern void ospf_lsa_discard(struct ospf_lsa *); -extern int ospf_lsa_flush_schedule(struct ospf *, struct ospf_lsa *); -extern struct lsa_header *ospf_lsa_data_new(size_t); -extern struct lsa_header *ospf_lsa_data_dup(struct lsa_header *); -extern void ospf_lsa_data_free(struct lsa_header *); +extern struct ospf_lsa *ospf_lsa_dup(struct ospf_lsa *lsa); +extern void ospf_lsa_free(struct ospf_lsa *lsa); +extern struct ospf_lsa *ospf_lsa_lock(struct ospf_lsa *lsa); +extern void ospf_lsa_unlock(struct ospf_lsa **lsa); +extern void ospf_lsa_discard(struct ospf_lsa *lsa); +extern int ospf_lsa_flush_schedule(struct ospf *ospf, struct ospf_lsa *lsa); +extern struct lsa_header *ospf_lsa_data_new(size_t size); +extern struct lsa_header *ospf_lsa_data_dup(struct lsa_header *lsah); +extern void ospf_lsa_data_free(struct lsa_header *lsah); /* Prototype for various LSAs */ extern void ospf_router_lsa_body_set(struct stream **s, struct ospf_area *area); extern uint8_t router_lsa_flags(struct ospf_area *area); -extern int ospf_router_lsa_update(struct ospf *); -extern int ospf_router_lsa_update_area(struct ospf_area *); +extern int ospf_router_lsa_update(struct ospf *ospf); +extern int ospf_router_lsa_update_area(struct ospf_area *area); -extern void ospf_network_lsa_update(struct ospf_interface *); +extern void ospf_network_lsa_update(struct ospf_interface *oi); -extern struct ospf_lsa * -ospf_summary_lsa_originate(struct prefix_ipv4 *, uint32_t, struct ospf_area *); -extern struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *, - uint32_t, - struct ospf_area *); +extern struct ospf_lsa *ospf_summary_lsa_originate(struct prefix_ipv4 *p, uint32_t metric, + struct ospf_area *area); +extern struct ospf_lsa *ospf_summary_asbr_lsa_originate(struct prefix_ipv4 *p, uint32_t metric, + struct ospf_area *area); -extern struct ospf_lsa *ospf_lsa_install(struct ospf *, struct ospf_interface *, - struct ospf_lsa *); +extern struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi, + struct ospf_lsa *lsa); extern void ospf_nssa_lsa_flush(struct ospf *ospf, struct prefix_ipv4 *p); -extern void ospf_external_lsa_flush(struct ospf *, uint8_t, - struct prefix_ipv4 *, +extern void ospf_external_lsa_flush(struct ospf *ospf, uint8_t type, struct prefix_ipv4 *p, ifindex_t /* , struct in_addr nexthop */); -extern struct in_addr ospf_get_ip_from_ifp(struct ospf_interface *); +extern struct in_addr ospf_get_ip_from_ifp(struct ospf_interface *oi); -extern struct ospf_lsa *ospf_external_lsa_originate(struct ospf *, - struct external_info *); +extern struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf, struct external_info *ei); extern struct ospf_lsa *ospf_nssa_lsa_originate(struct ospf_area *area, struct external_info *ei); extern struct ospf_lsa *ospf_nssa_lsa_refresh(struct ospf_area *area, struct ospf_lsa *lsa, struct external_info *ei); extern void ospf_external_lsa_rid_change(struct ospf *ospf); -extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *, - uint32_t, struct in_addr, - struct in_addr); -extern struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *, uint32_t, - struct in_addr); -extern struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *, - struct lsa_header *); -extern int ospf_lsa_more_recent(struct ospf_lsa *, struct ospf_lsa *); -extern int ospf_lsa_different(struct ospf_lsa *, struct ospf_lsa *, - bool ignore_rcvd_flag); -extern void ospf_flush_self_originated_lsas_now(struct ospf *); - -extern int ospf_lsa_is_self_originated(struct ospf *, struct ospf_lsa *); - -extern struct ospf_lsa *ospf_lsa_lookup_by_prefix(struct ospf_lsdb *, uint8_t, - struct prefix_ipv4 *, - struct in_addr); - -extern void ospf_lsa_maxage(struct ospf *, struct ospf_lsa *); -extern uint32_t get_metric(uint8_t *); - -extern void ospf_lsa_maxage_walker(struct event *thread); -extern struct ospf_lsa *ospf_lsa_refresh(struct ospf *, struct ospf_lsa *); - -extern void ospf_external_lsa_refresh_default(struct ospf *); - -extern void ospf_external_lsa_refresh_type(struct ospf *, uint8_t, - unsigned short, int); -extern struct ospf_lsa *ospf_external_lsa_refresh(struct ospf *, - struct ospf_lsa *, - struct external_info *, int, - bool aggr); +extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *area, uint32_t type, + struct in_addr id, struct in_addr adv_router); +extern struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *area, uint32_t type, + struct in_addr id); +extern struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *area, struct lsa_header *lsah); +extern int ospf_lsa_more_recent(struct ospf_lsa *l1, struct ospf_lsa *l2); +extern int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2, bool ignore_rcvd_flag); +extern void ospf_flush_self_originated_lsas_now(struct ospf *ospf); + +extern int ospf_lsa_is_self_originated(struct ospf *ospf, struct ospf_lsa *lsa); + +extern struct ospf_lsa *ospf_lsa_lookup_by_prefix(struct ospf_lsdb *lsdb, uint8_t type, + struct prefix_ipv4 *p, struct in_addr router_id); + +extern void ospf_lsa_maxage(struct ospf *ospf, struct ospf_lsa *lsa); +extern uint32_t get_metric(uint8_t *metric); + +extern void ospf_lsa_maxage_walker(struct event *event); +extern struct ospf_lsa *ospf_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa); + +extern void ospf_external_lsa_refresh_default(struct ospf *ospf); + +extern void ospf_external_lsa_refresh_type(struct ospf *ospf, uint8_t type, uint8_t instance, + int force); +extern struct ospf_lsa *ospf_external_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa, + struct external_info *ei, int force, bool aggr); extern enum lsid_status ospf_lsa_unique_id(struct ospf *ospf, struct ospf_lsdb *lsdb, uint8_t type, struct prefix_ipv4 *p, struct in_addr *addr); -extern void ospf_schedule_lsa_flood_area(struct ospf_area *, struct ospf_lsa *); -extern void ospf_schedule_lsa_flush_area(struct ospf_area *, struct ospf_lsa *); +extern void ospf_schedule_lsa_flood_area(struct ospf_area *area, struct ospf_lsa *lsa); +extern void ospf_schedule_lsa_flush_area(struct ospf_area *area, struct ospf_lsa *lsa); -extern void ospf_refresher_register_lsa(struct ospf *, struct ospf_lsa *); -extern void ospf_refresher_unregister_lsa(struct ospf *, struct ospf_lsa *); -extern void ospf_lsa_refresh_walker(struct event *thread); +extern void ospf_refresher_register_lsa(struct ospf *ospf, struct ospf_lsa *lsa); +extern void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa); +extern void ospf_lsa_refresh_walker(struct event *event); -extern void ospf_lsa_maxage_delete(struct ospf *, struct ospf_lsa *); +extern void ospf_lsa_maxage_delete(struct ospf *ospf, struct ospf_lsa *lsa); -extern void ospf_discard_from_db(struct ospf *, struct ospf_lsdb *, - struct ospf_lsa *); +extern void ospf_discard_from_db(struct ospf *ospf, struct ospf_lsdb *lsdb, struct ospf_lsa *lsa); -extern int metric_type(struct ospf *, uint8_t, unsigned short); -extern int metric_value(struct ospf *, uint8_t, unsigned short); +extern int metric_type(struct ospf *ospf, uint8_t src, unsigned short instance); +extern int metric_value(struct ospf *ospf, uint8_t src, unsigned short instance); extern char link_info_set(struct stream **s, struct in_addr id, struct in_addr data, uint8_t type, uint8_t tos, uint16_t cost); -extern struct in_addr ospf_get_nssa_ip(struct ospf_area *); -extern int ospf_translated_nssa_compare(struct ospf_lsa *, struct ospf_lsa *); +extern struct in_addr ospf_get_nssa_ip(struct ospf_area *area); extern struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, struct ospf_lsa *type7, struct ospf_lsa *type5); @@ -351,7 +340,7 @@ extern void ospf_check_and_gen_init_seq_lsa(struct ospf_interface *oi, struct ospf_lsa *lsa); extern void ospf_flush_lsa_from_area(struct ospf *ospf, struct in_addr area_id, int type); -extern void ospf_maxage_lsa_remover(struct event *thread); +extern void ospf_maxage_lsa_remover(struct event *event); extern bool ospf_check_dna_lsa(const struct ospf_lsa *lsa); extern void ospf_refresh_area_self_lsas(struct ospf_area *area); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index b7261da261..01cbfedc1c 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -718,7 +718,7 @@ DEFUN (ospf_area_range_not_advertise, DEFUN (no_ospf_area_range, no_ospf_area_range_cmd, - "no area <A.B.C.D|(0-4294967295)> range A.B.C.D/M [<cost (0-16777215)|advertise [cost (0-16777215)]|not-advertise>]", + "no area <A.B.C.D|(0-4294967295)> range A.B.C.D/M [<cost [(0-16777215)]|advertise [cost [(0-16777215)]]|not-advertise>]", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" @@ -781,6 +781,8 @@ DEFUN (no_ospf_area_range_substitute, ospf_area_range_substitute_unset(ospf, area, &p); + ospf_area_check_free(ospf, area_id); + return CMD_SUCCESS; } @@ -1353,12 +1355,13 @@ DEFUN (ospf_area_shortcut, DEFUN (no_ospf_area_shortcut, no_ospf_area_shortcut_cmd, - "no area <A.B.C.D|(0-4294967295)> shortcut <enable|disable>", + "no area <A.B.C.D|(0-4294967295)> shortcut <default|enable|disable>", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Deconfigure the area's shortcutting mode\n" + "Deconfigure default shortcutting through the area\n" "Deconfigure enabled shortcutting through the area\n" "Deconfigure disabled shortcutting through the area\n") { diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index a871837701..59cd9aea5f 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -468,6 +468,8 @@ static void gm_sg_update(struct gm_sg *sg, bool has_expired) static void gm_packet_free(struct gm_packet_state *pkt) { + assert(pkt->iface); + gm_packet_expires_del(pkt->iface->expires, pkt); gm_packets_del(pkt->subscriber->packets, pkt); gm_subscriber_drop(&pkt->subscriber); diff --git a/pimd/pim_autorp.c b/pimd/pim_autorp.c index 35347a2790..3fc30347a6 100644 --- a/pimd/pim_autorp.c +++ b/pimd/pim_autorp.c @@ -308,7 +308,7 @@ static bool pim_autorp_discovery(struct pim_autorp *autorp, uint8_t rpcnt, struct autorp_pkt_grp *grp; size_t offset = 0; pim_addr rp_addr; - struct prefix grppfix; + struct prefix grppfix = {}; char plname[32]; struct prefix_list *pl; struct prefix_list_entry *ple; diff --git a/pimd/pim_bsr_rpdb.c b/pimd/pim_bsr_rpdb.c index 3ec9f99cd1..6e93b65f4b 100644 --- a/pimd/pim_bsr_rpdb.c +++ b/pimd/pim_bsr_rpdb.c @@ -502,6 +502,9 @@ int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf, buf += sizeof(*crp_hdr); remain -= sizeof(*crp_hdr); + /* ignore trailing data */ + (void)buf; + size_t ngroups = crp_hdr->prefix_cnt; if (remain < ngroups * sizeof(struct pim_encoded_group_ipv4)) { diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index c19119fa47..5d344f1f66 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -193,7 +193,7 @@ static int zclient_read_nexthop(struct pim_instance *pim, distance = stream_getc(s); metric = stream_getl(s); - nexthop_num = stream_getc(s); + nexthop_num = stream_getw(s); if (nexthop_num < 1 || nexthop_num > router->multipath) { if (PIM_DEBUG_PIM_NHT_DETAIL) diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 420ed7903b..d76befc131 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -43,7 +43,7 @@ struct static_nht_data { vrf_id_t nh_vrf_id; uint32_t refcount; - uint8_t nh_num; + uint16_t nh_num; bool registered; }; diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz Binary files differindex 05e9f723a1..902b671b32 100644 --- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz +++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz diff --git a/tests/topotests/bfd_isis_topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/bfd_isis_topo1/rt1/step1/show_ipv6_route.ref index 68d3fe2c44..a760f1c249 100644 --- a/tests/topotests/bfd_isis_topo1/rt1/step1/show_ipv6_route.ref +++ b/tests/topotests/bfd_isis_topo1/rt1/step1/show_ipv6_route.ref @@ -1,7 +1,7 @@ { - "::ffff:202:202\/128":[ + "::ffff:2.2.2.2\/128":[ { - "prefix":"::ffff:202:202\/128", + "prefix":"::ffff:2.2.2.2\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -16,9 +16,9 @@ ] } ], - "::ffff:303:303\/128":[ + "::ffff:3.3.3.3\/128":[ { - "prefix":"::ffff:303:303\/128", + "prefix":"::ffff:3.3.3.3\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -33,9 +33,9 @@ ] } ], - "::ffff:404:404\/128":[ + "::ffff:4.4.4.4\/128":[ { - "prefix":"::ffff:404:404\/128", + "prefix":"::ffff:4.4.4.4\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -50,9 +50,9 @@ ] } ], - "::ffff:505:505\/128":[ + "::ffff:5.5.5.5\/128":[ { - "prefix":"::ffff:505:505\/128", + "prefix":"::ffff:5.5.5.5\/128", "protocol":"isis", "selected":true, "destSelected":true, diff --git a/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_healthy.ref b/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_healthy.ref index 68d3fe2c44..a760f1c249 100644 --- a/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_healthy.ref +++ b/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_healthy.ref @@ -1,7 +1,7 @@ { - "::ffff:202:202\/128":[ + "::ffff:2.2.2.2\/128":[ { - "prefix":"::ffff:202:202\/128", + "prefix":"::ffff:2.2.2.2\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -16,9 +16,9 @@ ] } ], - "::ffff:303:303\/128":[ + "::ffff:3.3.3.3\/128":[ { - "prefix":"::ffff:303:303\/128", + "prefix":"::ffff:3.3.3.3\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -33,9 +33,9 @@ ] } ], - "::ffff:404:404\/128":[ + "::ffff:4.4.4.4\/128":[ { - "prefix":"::ffff:404:404\/128", + "prefix":"::ffff:4.4.4.4\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -50,9 +50,9 @@ ] } ], - "::ffff:505:505\/128":[ + "::ffff:5.5.5.5\/128":[ { - "prefix":"::ffff:505:505\/128", + "prefix":"::ffff:5.5.5.5\/128", "protocol":"isis", "selected":true, "destSelected":true, diff --git a/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_rt2_down.ref b/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_rt2_down.ref index 200053c3e8..1168765457 100644 --- a/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_rt2_down.ref +++ b/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_rt2_down.ref @@ -1,7 +1,7 @@ { - "::ffff:202:202\/128":[ + "::ffff:2.2.2.2\/128":[ { - "prefix":"::ffff:202:202\/128", + "prefix":"::ffff:2.2.2.2\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -16,9 +16,9 @@ ] } ], - "::ffff:303:303\/128":[ + "::ffff:3.3.3.3\/128":[ { - "prefix":"::ffff:303:303\/128", + "prefix":"::ffff:3.3.3.3\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -33,9 +33,9 @@ ] } ], - "::ffff:404:404\/128":[ + "::ffff:4.4.4.4\/128":[ { - "prefix":"::ffff:404:404\/128", + "prefix":"::ffff:4.4.4.4\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -50,9 +50,9 @@ ] } ], - "::ffff:505:505\/128":[ + "::ffff:5.5.5.5\/128":[ { - "prefix":"::ffff:505:505\/128", + "prefix":"::ffff:5.5.5.5\/128", "protocol":"isis", "selected":true, "destSelected":true, diff --git a/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_rt3_down.ref b/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_rt3_down.ref index 4297f163b5..3e8505e79b 100644 --- a/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_rt3_down.ref +++ b/tests/topotests/bfd_isis_topo1/rt1/step3/show_ipv6_route_rt3_down.ref @@ -1,7 +1,7 @@ { - "::ffff:202:202\/128":[ + "::ffff:2.2.2.2\/128":[ { - "prefix":"::ffff:202:202\/128", + "prefix":"::ffff:2.2.2.2\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -16,9 +16,9 @@ ] } ], - "::ffff:303:303\/128":[ + "::ffff:3.3.3.3\/128":[ { - "prefix":"::ffff:303:303\/128", + "prefix":"::ffff:3.3.3.3\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -33,9 +33,9 @@ ] } ], - "::ffff:404:404\/128":[ + "::ffff:4.4.4.4\/128":[ { - "prefix":"::ffff:404:404\/128", + "prefix":"::ffff:4.4.4.4\/128", "protocol":"isis", "selected":true, "destSelected":true, @@ -50,9 +50,9 @@ ] } ], - "::ffff:505:505\/128":[ + "::ffff:5.5.5.5\/128":[ { - "prefix":"::ffff:505:505\/128", + "prefix":"::ffff:5.5.5.5\/128", "protocol":"isis", "selected":true, "destSelected":true, diff --git a/tests/topotests/bfd_isis_topo1/rt1/zebra.conf b/tests/topotests/bfd_isis_topo1/rt1/zebra.conf index 7e6f7881b4..bf2428e625 100644 --- a/tests/topotests/bfd_isis_topo1/rt1/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt1/zebra.conf @@ -10,7 +10,7 @@ hostname rt1 ! interface lo ip address 1.1.1.1/32 - ipv6 address ::ffff:0101:0101/128 + ipv6 address ::ffff:1.1.1.1/128 ! interface eth-rt2 ip address 10.0.1.1/24 diff --git a/tests/topotests/bfd_isis_topo1/rt2/zebra.conf b/tests/topotests/bfd_isis_topo1/rt2/zebra.conf index 5788e31f12..1670c20506 100644 --- a/tests/topotests/bfd_isis_topo1/rt2/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt2/zebra.conf @@ -7,7 +7,7 @@ hostname rt2 ! interface lo ip address 2.2.2.2/32 - ipv6 address ::ffff:0202:0202/128 + ipv6 address ::ffff:2.2.2.2/128 ! interface eth-rt1 ip address 10.0.1.2/24 diff --git a/tests/topotests/bfd_isis_topo1/rt3/zebra.conf b/tests/topotests/bfd_isis_topo1/rt3/zebra.conf index 78eac2e15a..d59085560f 100644 --- a/tests/topotests/bfd_isis_topo1/rt3/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt3/zebra.conf @@ -7,7 +7,7 @@ hostname rt3 ! interface lo ip address 3.3.3.3/32 - ipv6 address ::ffff:0303:0303/128 + ipv6 address ::ffff:3.3.3.3/128 ! interface eth-rt1 ip address 10.0.2.2/24 diff --git a/tests/topotests/bfd_isis_topo1/rt4/zebra.conf b/tests/topotests/bfd_isis_topo1/rt4/zebra.conf index a6cb573ed8..66121662dd 100644 --- a/tests/topotests/bfd_isis_topo1/rt4/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt4/zebra.conf @@ -7,7 +7,7 @@ hostname rt4 ! interface lo ip address 4.4.4.4/32 - ipv6 address ::ffff:0404:0404/128 + ipv6 address ::ffff:4.4.4.4/128 ! interface eth-rt3 ip address 10.0.4.2/24 diff --git a/tests/topotests/bfd_isis_topo1/rt5/zebra.conf b/tests/topotests/bfd_isis_topo1/rt5/zebra.conf index 33473c91a3..d3331b5b6c 100644 --- a/tests/topotests/bfd_isis_topo1/rt5/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt5/zebra.conf @@ -7,7 +7,7 @@ hostname rt5 ! interface lo ip address 5.5.5.5/32 - ipv6 address ::ffff:0505:0505/128 + ipv6 address ::ffff:5.5.5.5/128 ! interface eth-rt2 ip address 10.0.3.2/24 diff --git a/tests/topotests/bfd_ospf_topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/bfd_ospf_topo1/rt1/step1/show_ipv6_route.ref index 6465efb8b5..0526d8a6af 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/step1/show_ipv6_route.ref +++ b/tests/topotests/bfd_ospf_topo1/rt1/step1/show_ipv6_route.ref @@ -1,7 +1,7 @@ { - "::ffff:202:202\/128":[ + "::ffff:2.2.2.2\/128":[ { - "prefix":"::ffff:202:202\/128", + "prefix":"::ffff:2.2.2.2\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -16,9 +16,9 @@ ] } ], - "::ffff:303:303\/128":[ + "::ffff:3.3.3.3\/128":[ { - "prefix":"::ffff:303:303\/128", + "prefix":"::ffff:3.3.3.3\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -33,9 +33,9 @@ ] } ], - "::ffff:404:404\/128":[ + "::ffff:4.4.4.4\/128":[ { - "prefix":"::ffff:404:404\/128", + "prefix":"::ffff:4.4.4.4\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -50,9 +50,9 @@ ] } ], - "::ffff:505:505\/128":[ + "::ffff:5.5.5.5\/128":[ { - "prefix":"::ffff:505:505\/128", + "prefix":"::ffff:5.5.5.5\/128", "protocol":"ospf6", "selected":true, "destSelected":true, diff --git a/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_healthy.ref b/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_healthy.ref index 6465efb8b5..0526d8a6af 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_healthy.ref +++ b/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_healthy.ref @@ -1,7 +1,7 @@ { - "::ffff:202:202\/128":[ + "::ffff:2.2.2.2\/128":[ { - "prefix":"::ffff:202:202\/128", + "prefix":"::ffff:2.2.2.2\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -16,9 +16,9 @@ ] } ], - "::ffff:303:303\/128":[ + "::ffff:3.3.3.3\/128":[ { - "prefix":"::ffff:303:303\/128", + "prefix":"::ffff:3.3.3.3\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -33,9 +33,9 @@ ] } ], - "::ffff:404:404\/128":[ + "::ffff:4.4.4.4\/128":[ { - "prefix":"::ffff:404:404\/128", + "prefix":"::ffff:4.4.4.4\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -50,9 +50,9 @@ ] } ], - "::ffff:505:505\/128":[ + "::ffff:5.5.5.5\/128":[ { - "prefix":"::ffff:505:505\/128", + "prefix":"::ffff:5.5.5.5\/128", "protocol":"ospf6", "selected":true, "destSelected":true, diff --git a/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_rt2_down.ref b/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_rt2_down.ref index cfb1ef1bb6..8a8a0cd77d 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_rt2_down.ref +++ b/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_rt2_down.ref @@ -1,7 +1,7 @@ { - "::ffff:202:202\/128":[ + "::ffff:2.2.2.2\/128":[ { - "prefix":"::ffff:202:202\/128", + "prefix":"::ffff:2.2.2.2\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -16,9 +16,9 @@ ] } ], - "::ffff:303:303\/128":[ + "::ffff:3.3.3.3\/128":[ { - "prefix":"::ffff:303:303\/128", + "prefix":"::ffff:3.3.3.3\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -33,9 +33,9 @@ ] } ], - "::ffff:404:404\/128":[ + "::ffff:4.4.4.4\/128":[ { - "prefix":"::ffff:404:404\/128", + "prefix":"::ffff:4.4.4.4\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -50,9 +50,9 @@ ] } ], - "::ffff:505:505\/128":[ + "::ffff:5.5.5.5\/128":[ { - "prefix":"::ffff:505:505\/128", + "prefix":"::ffff:5.5.5.5\/128", "protocol":"ospf6", "selected":true, "destSelected":true, diff --git a/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_rt3_down.ref b/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_rt3_down.ref index 58b44da5c2..e4f056f7b5 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_rt3_down.ref +++ b/tests/topotests/bfd_ospf_topo1/rt1/step3/show_ipv6_route_rt3_down.ref @@ -1,7 +1,7 @@ { - "::ffff:202:202\/128":[ + "::ffff:2.2.2.2\/128":[ { - "prefix":"::ffff:202:202\/128", + "prefix":"::ffff:2.2.2.2\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -16,9 +16,9 @@ ] } ], - "::ffff:303:303\/128":[ + "::ffff:3.3.3.3\/128":[ { - "prefix":"::ffff:303:303\/128", + "prefix":"::ffff:3.3.3.3\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -33,9 +33,9 @@ ] } ], - "::ffff:404:404\/128":[ + "::ffff:4.4.4.4\/128":[ { - "prefix":"::ffff:404:404\/128", + "prefix":"::ffff:4.4.4.4\/128", "protocol":"ospf6", "selected":true, "destSelected":true, @@ -50,9 +50,9 @@ ] } ], - "::ffff:505:505\/128":[ + "::ffff:5.5.5.5\/128":[ { - "prefix":"::ffff:505:505\/128", + "prefix":"::ffff:5.5.5.5\/128", "protocol":"ospf6", "selected":true, "destSelected":true, diff --git a/tests/topotests/bfd_ospf_topo1/rt1/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt1/zebra.conf index 7e6f7881b4..bf2428e625 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt1/zebra.conf @@ -10,7 +10,7 @@ hostname rt1 ! interface lo ip address 1.1.1.1/32 - ipv6 address ::ffff:0101:0101/128 + ipv6 address ::ffff:1.1.1.1/128 ! interface eth-rt2 ip address 10.0.1.1/24 diff --git a/tests/topotests/bfd_ospf_topo1/rt2/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt2/zebra.conf index 5788e31f12..1670c20506 100644 --- a/tests/topotests/bfd_ospf_topo1/rt2/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt2/zebra.conf @@ -7,7 +7,7 @@ hostname rt2 ! interface lo ip address 2.2.2.2/32 - ipv6 address ::ffff:0202:0202/128 + ipv6 address ::ffff:2.2.2.2/128 ! interface eth-rt1 ip address 10.0.1.2/24 diff --git a/tests/topotests/bfd_ospf_topo1/rt3/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt3/zebra.conf index 78eac2e15a..d59085560f 100644 --- a/tests/topotests/bfd_ospf_topo1/rt3/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt3/zebra.conf @@ -7,7 +7,7 @@ hostname rt3 ! interface lo ip address 3.3.3.3/32 - ipv6 address ::ffff:0303:0303/128 + ipv6 address ::ffff:3.3.3.3/128 ! interface eth-rt1 ip address 10.0.2.2/24 diff --git a/tests/topotests/bfd_ospf_topo1/rt4/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt4/zebra.conf index a6cb573ed8..66121662dd 100644 --- a/tests/topotests/bfd_ospf_topo1/rt4/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt4/zebra.conf @@ -7,7 +7,7 @@ hostname rt4 ! interface lo ip address 4.4.4.4/32 - ipv6 address ::ffff:0404:0404/128 + ipv6 address ::ffff:4.4.4.4/128 ! interface eth-rt3 ip address 10.0.4.2/24 diff --git a/tests/topotests/bfd_ospf_topo1/rt5/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt5/zebra.conf index 33473c91a3..d3331b5b6c 100644 --- a/tests/topotests/bfd_ospf_topo1/rt5/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt5/zebra.conf @@ -7,7 +7,7 @@ hostname rt5 ! interface lo ip address 5.5.5.5/32 - ipv6 address ::ffff:0505:0505/128 + ipv6 address ::ffff:5.5.5.5/128 ! interface eth-rt2 ip address 10.0.3.2/24 diff --git a/tests/topotests/bgp_aigp/r1/bgpd.conf b/tests/topotests/bgp_aigp/r1/bgpd.conf index 74a0215bc4..15621999c5 100644 --- a/tests/topotests/bgp_aigp/r1/bgpd.conf +++ b/tests/topotests/bgp_aigp/r1/bgpd.conf @@ -9,4 +9,20 @@ router bgp 65001 neighbor 10.0.0.3 timers 1 3 neighbor 10.0.0.3 timers connect 1 neighbor 10.0.0.3 update-source lo + neighbor 192.168.18.8 remote-as external + neighbor 192.168.18.8 timers 1 3 + neighbor 192.168.18.8 timers connect 1 + address-family ipv4 + neighbor 192.168.18.8 route-map r8 out + exit-address-family ! +ip prefix-list p71 seq 5 permit 10.0.0.71/32 +ip prefix-list p72 seq 5 permit 10.0.0.72/32 +! +route-map r8 permit 10 + match ip address prefix-list p71 + set metric igp +route-map r8 permit 20 + match ip address prefix-list p72 + set metric aigp +exit diff --git a/tests/topotests/bgp_aigp/r1/ospfd.conf b/tests/topotests/bgp_aigp/r1/ospfd.conf index 38aa11d036..098bf57b03 100644 --- a/tests/topotests/bgp_aigp/r1/ospfd.conf +++ b/tests/topotests/bgp_aigp/r1/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r1-eth0 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r1/zebra.conf b/tests/topotests/bgp_aigp/r1/zebra.conf index 0ed22d37be..7ac4bb5de9 100644 --- a/tests/topotests/bgp_aigp/r1/zebra.conf +++ b/tests/topotests/bgp_aigp/r1/zebra.conf @@ -8,3 +8,6 @@ interface r1-eth0 interface r1-eth1 ip address 192.168.13.1/24 ! +interface r1-eth2 + ip address 192.168.18.1/24 +! diff --git a/tests/topotests/bgp_aigp/r2/bgpd.conf b/tests/topotests/bgp_aigp/r2/bgpd.conf index 4db4687536..4539016f91 100644 --- a/tests/topotests/bgp_aigp/r2/bgpd.conf +++ b/tests/topotests/bgp_aigp/r2/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 10.0.0.1 remote-as internal neighbor 10.0.0.1 timers 1 3 neighbor 10.0.0.1 timers connect 1 @@ -11,5 +12,6 @@ router bgp 65001 neighbor 192.168.24.4 aigp address-family ipv4 redistribute connected + neighbor 10.0.0.1 next-hop-self force exit-address-family ! diff --git a/tests/topotests/bgp_aigp/r2/ospfd.conf b/tests/topotests/bgp_aigp/r2/ospfd.conf index ed31941f65..106a46251d 100644 --- a/tests/topotests/bgp_aigp/r2/ospfd.conf +++ b/tests/topotests/bgp_aigp/r2/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r2-eth0 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r3/bgpd.conf b/tests/topotests/bgp_aigp/r3/bgpd.conf index 5ab712eaba..bdaa5cf55d 100644 --- a/tests/topotests/bgp_aigp/r3/bgpd.conf +++ b/tests/topotests/bgp_aigp/r3/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 10.0.0.1 remote-as internal neighbor 10.0.0.1 timers 1 3 neighbor 10.0.0.1 timers connect 1 @@ -11,5 +12,6 @@ router bgp 65001 neighbor 192.168.35.5 aigp address-family ipv4 redistribute connected + neighbor 10.0.0.1 next-hop-self force exit-address-family ! diff --git a/tests/topotests/bgp_aigp/r3/ospfd.conf b/tests/topotests/bgp_aigp/r3/ospfd.conf index f971ad6f89..9ede3a1fab 100644 --- a/tests/topotests/bgp_aigp/r3/ospfd.conf +++ b/tests/topotests/bgp_aigp/r3/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r3-eth0 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r4/bgpd.conf b/tests/topotests/bgp_aigp/r4/bgpd.conf index aa88bac913..2cdf84a1b3 100644 --- a/tests/topotests/bgp_aigp/r4/bgpd.conf +++ b/tests/topotests/bgp_aigp/r4/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 192.168.24.2 remote-as internal neighbor 192.168.24.2 timers 1 3 neighbor 192.168.24.2 timers connect 1 @@ -11,7 +12,25 @@ router bgp 65001 neighbor 10.0.0.6 timers connect 1 neighbor 10.0.0.6 update-source lo address-family ipv4 - redistribute connected - redistribute ospf + redistribute connected route-map connected-to-bgp + redistribute ospf route-map ospf-to-bgp + neighbor 192.168.24.2 route-map set-nexthop out exit-address-family ! +ip prefix-list p66 seq 5 permit 10.0.6.6/32 +! +route-map ospf-to-bgp permit 10 + match ip address prefix-list p66 + set aigp igp-metric +! +! Two OSPF domains should be isolated - otherwise the connected routes +! on r4 would be advertised to r3 (via r4 -> r6 -> r5 -> r3), and can +! mess up bgp bestpath calculation (igp metrics for the BGP nexthops). +! +route-map connected-to-bgp permit 10 + set community no-advertise +! +route-map set-nexthop permit 10 + set ip next-hop peer-address +exit +! diff --git a/tests/topotests/bgp_aigp/r4/ospfd.conf b/tests/topotests/bgp_aigp/r4/ospfd.conf index c9e6796f6e..237b5e18ab 100644 --- a/tests/topotests/bgp_aigp/r4/ospfd.conf +++ b/tests/topotests/bgp_aigp/r4/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r4-eth1 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r5/bgpd.conf b/tests/topotests/bgp_aigp/r5/bgpd.conf index 4fde262053..3d1f5e8572 100644 --- a/tests/topotests/bgp_aigp/r5/bgpd.conf +++ b/tests/topotests/bgp_aigp/r5/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 192.168.35.3 remote-as internal neighbor 192.168.35.3 timers 1 3 neighbor 192.168.35.3 timers connect 1 @@ -11,7 +12,18 @@ router bgp 65001 neighbor 10.0.0.6 timers connect 1 neighbor 10.0.0.6 update-source lo address-family ipv4 - redistribute connected - redistribute ospf + redistribute connected route-map connected-to-bgp + neighbor 192.168.35.3 route-map set-nexthop out exit-address-family ! +! Two OSPF domains should be isolated - otherwise the connected routes +! on r5 would be advertised to r2 (via r5 -> r6 -> r4 -> r2), and can +! mess up bgp bestpath calculation (igp metrics for the BGP nexthops). +! +route-map connected-to-bgp permit 10 + set community no-advertise +! +route-map set-nexthop permit 10 + set ip next-hop peer-address +exit +! diff --git a/tests/topotests/bgp_aigp/r5/ospfd.conf b/tests/topotests/bgp_aigp/r5/ospfd.conf index b853c74102..65a213df17 100644 --- a/tests/topotests/bgp_aigp/r5/ospfd.conf +++ b/tests/topotests/bgp_aigp/r5/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r5-eth1 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r6/bgpd.conf b/tests/topotests/bgp_aigp/r6/bgpd.conf index 2faae7720c..2d5f7a89ba 100644 --- a/tests/topotests/bgp_aigp/r6/bgpd.conf +++ b/tests/topotests/bgp_aigp/r6/bgpd.conf @@ -1,6 +1,7 @@ router bgp 65001 no bgp ebgp-requires-policy no bgp network import-check + bgp route-reflector allow-outbound-policy neighbor 10.0.0.4 remote-as internal neighbor 10.0.0.4 timers 1 3 neighbor 10.0.0.4 timers connect 1 @@ -15,6 +16,11 @@ router bgp 65001 neighbor 192.168.67.7 timers 1 3 neighbor 192.168.67.7 timers connect 1 address-family ipv4 - redistribute ospf + neighbor 10.0.0.4 route-map set-nexthop out + neighbor 10.0.0.5 route-map set-nexthop out exit-address-family ! +route-map set-nexthop permit 10 + set ip next-hop peer-address +exit +! diff --git a/tests/topotests/bgp_aigp/r6/ospfd.conf b/tests/topotests/bgp_aigp/r6/ospfd.conf index 46b2933178..89cbefa895 100644 --- a/tests/topotests/bgp_aigp/r6/ospfd.conf +++ b/tests/topotests/bgp_aigp/r6/ospfd.conf @@ -1,6 +1,6 @@ ! interface lo - ip ospf cost 10 + ip ospf passive ! interface r6-eth0 ip ospf dead-interval 4 diff --git a/tests/topotests/bgp_aigp/r6/zebra.conf b/tests/topotests/bgp_aigp/r6/zebra.conf index f8ca5f8b82..b6456cacc5 100644 --- a/tests/topotests/bgp_aigp/r6/zebra.conf +++ b/tests/topotests/bgp_aigp/r6/zebra.conf @@ -1,6 +1,7 @@ ! interface lo ip address 10.0.0.6/32 + ip address 10.0.6.6/32 ! interface r6-eth0 ip address 192.168.46.6/24 diff --git a/tests/topotests/bgp_aigp/r8/bgpd.conf b/tests/topotests/bgp_aigp/r8/bgpd.conf new file mode 100644 index 0000000000..c50c3ce91a --- /dev/null +++ b/tests/topotests/bgp_aigp/r8/bgpd.conf @@ -0,0 +1,4 @@ +router bgp 65008 + no bgp ebgp-requires-policy + neighbor 192.168.18.1 remote-as external +! diff --git a/tests/topotests/bgp_aigp/r8/zebra.conf b/tests/topotests/bgp_aigp/r8/zebra.conf new file mode 100644 index 0000000000..f7545270b2 --- /dev/null +++ b/tests/topotests/bgp_aigp/r8/zebra.conf @@ -0,0 +1,4 @@ +! +interface r8-eth0 + ip address 192.168.18.8/24 +! diff --git a/tests/topotests/bgp_aigp/test_bgp_aigp.py b/tests/topotests/bgp_aigp/test_bgp_aigp.py index b81c543297..f937f851a6 100644 --- a/tests/topotests/bgp_aigp/test_bgp_aigp.py +++ b/tests/topotests/bgp_aigp/test_bgp_aigp.py @@ -12,9 +12,13 @@ r7 sets aigp-metric for 10.0.0.71/32 to 71, and 72 for 10.0.0.72/32. r6 receives those routes with aigp-metric TLV. r2 and r3 receives those routes with aigp-metric TLV increased by 20, -and 30 appropriately. +and 10 appropriately. -r1 receives routes with aigp-metric TLV 111,131 and 112,132 appropriately. +r1 receives routes with aigp-metric TLV 81, 91 and 82, 92 respectively. + +r1 advertises MED from IGP protocol (set metric igp) to r8. + +r1 advertises MED from AIGP (set metric aigp) to r8. """ import os @@ -34,7 +38,7 @@ pytestmark = [pytest.mark.bgpd] def build_topo(tgen): - for routern in range(1, 8): + for routern in range(1, 9): tgen.add_router("r{}".format(routern)) switch = tgen.add_switch("s1") @@ -65,6 +69,10 @@ def build_topo(tgen): switch.add_link(tgen.gears["r6"]) switch.add_link(tgen.gears["r7"]) + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r8"]) + def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) @@ -102,21 +110,36 @@ def test_bgp_aigp(): r3 = tgen.gears["r3"] r4 = tgen.gears["r4"] r5 = tgen.gears["r5"] + r8 = tgen.gears["r8"] def _bgp_converge(): output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.0.0.71/32 json")) expected = { "paths": [ { - "aigpMetric": 111, + "aigpMetric": 81, "valid": True, - "nexthops": [{"hostname": "r3", "accessible": True}], + "nexthops": [ + { + "ip": "10.0.0.3", + "hostname": "r3", + "metric": 30, + "accessible": True, + } + ], }, { - "aigpMetric": 131, + "aigpMetric": 91, "valid": True, - "bestpath": {"selectionReason": "Neighbor IP"}, - "nexthops": [{"hostname": "r2", "accessible": True}], + "bestpath": {"selectionReason": "IGP Metric"}, + "nexthops": [ + { + "ip": "10.0.0.2", + "hostname": "r2", + "metric": 10, + "accessible": True, + } + ], }, ] } @@ -129,6 +152,18 @@ def test_bgp_aigp(): expected = {"paths": [{"aigpMetric": aigp, "valid": True}]} return topotest.json_cmp(output, expected) + def _bgp_check_received_med(): + output = json.loads( + r8.vtysh_cmd("show bgp ipv4 unicast 10.0.0.64/28 longer-prefixes json") + ) + expected = { + "routes": { + "10.0.0.71/32": [{"valid": True, "metric": 10}], + "10.0.0.72/32": [{"valid": True, "metric": 92}], + } + } + return topotest.json_cmp(output, expected) + def _bgp_check_aigp_metric_bestpath(): output = json.loads( r1.vtysh_cmd( @@ -140,30 +175,58 @@ def test_bgp_aigp(): "10.0.0.71/32": { "paths": [ { - "aigpMetric": 111, - "bestpath": {"selectionReason": "AIGP"}, + "aigpMetric": 81, "valid": True, - "nexthops": [{"hostname": "r3", "accessible": True}], + "nexthops": [ + { + "ip": "10.0.0.3", + "hostname": "r3", + "metric": 30, + "accessible": True, + } + ], }, { - "aigpMetric": 131, + "aigpMetric": 91, "valid": True, - "nexthops": [{"hostname": "r2", "accessible": True}], + "bestpath": {"selectionReason": "AIGP"}, + "nexthops": [ + { + "ip": "10.0.0.2", + "hostname": "r2", + "metric": 10, + "accessible": True, + } + ], }, ], }, "10.0.0.72/32": { "paths": [ { - "aigpMetric": 112, - "bestpath": {"selectionReason": "AIGP"}, + "aigpMetric": 82, "valid": True, - "nexthops": [{"hostname": "r3", "accessible": True}], + "nexthops": [ + { + "ip": "10.0.0.3", + "hostname": "r3", + "metric": 30, + "accessible": True, + } + ], }, { - "aigpMetric": 132, + "aigpMetric": 92, "valid": True, - "nexthops": [{"hostname": "r2", "accessible": True}], + "bestpath": {"selectionReason": "AIGP"}, + "nexthops": [ + { + "ip": "10.0.0.2", + "hostname": "r2", + "metric": 10, + "accessible": True, + } + ], }, ], }, @@ -185,6 +248,11 @@ def test_bgp_aigp(): """ ) + # r4, 10.0.6.6/32 with aigp-metric 20 + test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.6.6/32", 20) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assert result is None, "aigp-metric for 10.0.6.6/32 is not 20" + # r4, 10.0.0.71/32 with aigp-metric 71 test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.0.71/32", 71) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) @@ -195,21 +263,28 @@ def test_bgp_aigp(): _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assert result is None, "aigp-metric for 10.0.0.72/32 is not 72" - # r2, 10.0.0.71/32 with aigp-metric 101 (71 + 30) - test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.0.71/32", 101) + # r2, 10.0.0.71/32 with aigp-metric 101 (71 + 20) + test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.0.71/32", 91) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) - assert result is None, "aigp-metric for 10.0.0.71/32 is not 101" + assert result is None, "aigp-metric for 10.0.0.71/32 is not 91" - # r3, 10.0.0.72/32 with aigp-metric 92 (72 + 20) - test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.0.72/32", 92) + # r3, 10.0.0.72/32 with aigp-metric 92 (72 + 10) + test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.0.72/32", 82) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) - assert result is None, "aigp-metric for 10.0.0.72/32 is not 92" + assert result is None, "aigp-metric for 10.0.0.72/32 is not 82" - # r1, check if AIGP is considered in best-path selection (lowest wins) + # r1, check if AIGP is considered in best-path selection (lowest wins: aigp + nexthop-metric) test_func = functools.partial(_bgp_check_aigp_metric_bestpath) _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assert result is None, "AIGP attribute is not considered in best-path selection" + # r8, check if MED is set derived from `set metric igp`, and `set metric aigp` + test_func = functools.partial(_bgp_check_received_med) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "MED attribute values are not derived from `set metric [a]igp`" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py index 2d027081cb..9dfb7fc4d9 100644 --- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py +++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py @@ -210,7 +210,7 @@ def test_protocols_convergence(): "vrfName": "r1-vrf-101", "nexthops": [ { - "ip": "::ffff:c0a8:6429", + "ip": "::ffff:192.168.100.41", } ], } @@ -227,8 +227,8 @@ def test_protocols_convergence(): "192.168.100.41": { "nexthopIp": "192.168.100.41", }, - "::ffff:c0a8:6429": { - "nexthopIp": "::ffff:c0a8:6429", + "::ffff:192.168.100.41": { + "nexthopIp": "::ffff:192.168.100.41", }, } } diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py index 803b51c043..8382fea188 100644 --- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py +++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py @@ -670,7 +670,7 @@ def test_configure_gua_on_unnumbered_intf(request): { "nexthops": [ { - "ip": "::ffff:a00:501", + "ip": "::ffff:10.0.5.1", "hostname": "r1", "afi": "ipv6", "scope": "global", @@ -754,7 +754,7 @@ def test_configure_gua_on_unnumbered_intf(request): assert ( result is None ), "Testcase {} : Failed \n Error: Nexthop for prefix 11.0.20.1 \ - is not ::ffff:a00:501".format( + is not ::ffff:10.0.5.1".format( tc_name ) diff --git a/tests/topotests/bgp_match_peer/r1/frr.conf b/tests/topotests/bgp_match_peer/r1/frr.conf index f30da3b896..02fb8ae518 100644 --- a/tests/topotests/bgp_match_peer/r1/frr.conf +++ b/tests/topotests/bgp_match_peer/r1/frr.conf @@ -17,6 +17,7 @@ router bgp 65001 neighbor 192.168.1.2 route-map all in neighbor r3 route-map all in neighbor r4 route-map all in + neighbor r4 route-map r4 out exit-address-family ! route-map all permit 5 @@ -24,7 +25,7 @@ route-map all permit 5 set metric 1 ! route-map all permit 10 - match peer 192.168.1.2 + match src-peer 192.168.1.2 set metric 2 ! route-map all permit 15 @@ -35,3 +36,6 @@ route-map all permit 20 match peer r4 set metric 4 ! +route-map r4 permit 10 + match src-peer r3 +! diff --git a/tests/topotests/bgp_match_peer/test_bgp_match_peer.py b/tests/topotests/bgp_match_peer/test_bgp_match_peer.py index 4eb7473df0..180dbcd08a 100644 --- a/tests/topotests/bgp_match_peer/test_bgp_match_peer.py +++ b/tests/topotests/bgp_match_peer/test_bgp_match_peer.py @@ -82,6 +82,29 @@ def test_bgp_match_peer(): _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, "Can't converge" + def _bgp_show_advertised_routes(): + output = json.loads( + r1.vtysh_cmd("show bgp ipv4 unicast neighbors r4 advertised-routes json") + ) + expected = { + "advertisedRoutes": { + "10.0.0.3/32": { + "network": "10.0.0.3/32", + "nextHop": "192.168.1.3", + "path": "65003", + } + }, + "totalPrefixCounter": 1, + } + + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_show_advertised_routes, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't filter by source peer" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step2.json index 35a31e63f9..5506f07f29 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step2.json +++ b/tests/topotests/bgp_nexthop_ipv6/r4/show_bgp_ipv6_step2.json @@ -9,13 +9,7 @@ "ip": "fd00:0:2::1", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-sw", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -28,13 +22,7 @@ "ip": "fd00:0:2::2", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-sw", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -47,13 +35,7 @@ "ip": "fd00:0:2::3", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-sw", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -117,13 +99,7 @@ "ip": "fd00:0:2::1", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-sw", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -136,13 +112,7 @@ "ip": "fd00:0:2::2", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-sw", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -155,13 +125,7 @@ "ip": "fd00:0:2::3", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-sw", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] diff --git a/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step2.json b/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step2.json index d0875474ae..afcf7c3ffc 100644 --- a/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step2.json +++ b/tests/topotests/bgp_nexthop_ipv6/r5/show_bgp_ipv6_step2.json @@ -9,13 +9,7 @@ "ip": "fd00:0:3::9", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-r5", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -28,13 +22,7 @@ "ip": "fd00:0:3::9", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-r5", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -47,13 +35,7 @@ "ip": "fd00:0:3::9", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-r5", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -117,13 +99,7 @@ "ip": "fd00:0:3::9", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-r5", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -136,13 +112,7 @@ "ip": "fd00:0:3::9", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-r5", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] @@ -155,13 +125,7 @@ "ip": "fd00:0:3::9", "hostname": "rr", "afi": "ipv6", - "scope": "global" - }, - { - "ip": "link-local:rr:eth-r5", - "hostname": "rr", - "afi": "ipv6", - "scope": "link-local", + "scope": "global", "used": true } ] diff --git a/tests/topotests/bgp_set_metric_igp/__init__.py b/tests/topotests/bgp_set_metric_igp/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_set_metric_igp/__init__.py diff --git a/tests/topotests/bgp_set_metric_igp/r1/frr.conf b/tests/topotests/bgp_set_metric_igp/r1/frr.conf new file mode 100644 index 0000000000..018ea0269e --- /dev/null +++ b/tests/topotests/bgp_set_metric_igp/r1/frr.conf @@ -0,0 +1,13 @@ +! +int r1-eth0 + ip address 10.0.0.1/24 +! +int r1-eth1 + ip address 10.0.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.2 remote-as external + neighbor 10.0.1.2 remote-as external +! diff --git a/tests/topotests/bgp_set_metric_igp/r2/frr.conf b/tests/topotests/bgp_set_metric_igp/r2/frr.conf new file mode 100644 index 0000000000..bce06c47f0 --- /dev/null +++ b/tests/topotests/bgp_set_metric_igp/r2/frr.conf @@ -0,0 +1,36 @@ +! +int r2-eth0 + ip address 10.0.0.2/24 + ip router isis n2 + isis circuit-type level-2-only + isis fast-reroute lfa level-2 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +int r2-eth1 + ip address 10.0.2.1/24 + ip router isis n2 + isis circuit-type level-2-only + isis fast-reroute lfa level-2 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 10.0.0.1 remote-as external + neighbor 10.0.2.2 remote-as internal + address-family ipv4 unicast + neighbor 10.0.0.1 route-map igp out + exit-address-family +! +router isis n2 + is-type level-2-only + net 49.0001.0000.0000.0002.00 + lsp-mtu 1440 +exit +! +route-map igp permit 10 + set metric igp +exit diff --git a/tests/topotests/bgp_set_metric_igp/r3/frr.conf b/tests/topotests/bgp_set_metric_igp/r3/frr.conf new file mode 100644 index 0000000000..312f97d08a --- /dev/null +++ b/tests/topotests/bgp_set_metric_igp/r3/frr.conf @@ -0,0 +1,38 @@ +! +int r3-eth0 + ip address 10.0.1.2/24 + ip router isis n3 + isis circuit-type level-2-only + isis fast-reroute lfa level-2 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +int r3-eth1 + ip address 10.0.3.1/24 + ip router isis n3 + isis circuit-type level-2-only + isis fast-reroute lfa level-2 + isis metric level-1 10 + isis metric level-2 100 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 10.0.1.1 remote-as external + neighbor 10.0.3.2 remote-as internal + address-family ipv4 unicast + neighbor 10.0.1.1 route-map igp out + exit-address-family +! +router isis n3 + is-type level-2-only + net 49.0001.0000.0000.0003.00 + lsp-mtu 1440 +exit +! +route-map igp permit 10 + set metric igp +exit diff --git a/tests/topotests/bgp_set_metric_igp/r4/frr.conf b/tests/topotests/bgp_set_metric_igp/r4/frr.conf new file mode 100644 index 0000000000..04165b80b2 --- /dev/null +++ b/tests/topotests/bgp_set_metric_igp/r4/frr.conf @@ -0,0 +1,41 @@ +! +int r4-eth0 + ip address 10.0.2.2/24 + ip router isis n4 + isis circuit-type level-2-only + isis fast-reroute lfa level-2 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +int r4-eth1 + ip address 10.0.3.2/24 + ip router isis n4 + isis circuit-type level-2-only + isis fast-reroute lfa level-2 + isis metric level-1 10 + isis metric level-2 100 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +int r4-eth2 + ip address 10.0.4.1/24 + ip router isis n4 + isis circuit-type level-2-only + isis fast-reroute lfa level-2 + isis network point-to-point + isis hello-interval 1 + isis hello-multiplier 10 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 10.0.2.1 remote-as internal + neighbor 10.0.3.1 remote-as internal + neighbor 10.0.4.2 remote-as external +! +router isis n4 + is-type level-2-only + net 49.0001.0000.0000.0004.00 + lsp-mtu 1440 +exit diff --git a/tests/topotests/bgp_set_metric_igp/r5/frr.conf b/tests/topotests/bgp_set_metric_igp/r5/frr.conf new file mode 100644 index 0000000000..af23677b72 --- /dev/null +++ b/tests/topotests/bgp_set_metric_igp/r5/frr.conf @@ -0,0 +1,14 @@ +! +int r5-eth0 + ip address 10.0.4.2/24 +! +router bgp 65005 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.4.1 remote-as external + neighbor 10.0.4.1 timers 1 3 + neighbor 10.0.4.1 timers connect 1 + address-family ipv4 unicast + network 10.5.5.5/32 + exit-address-family +! diff --git a/tests/topotests/bgp_set_metric_igp/test_bgp_set_metric_igp.py b/tests/topotests/bgp_set_metric_igp/test_bgp_set_metric_igp.py new file mode 100644 index 0000000000..8fbe817689 --- /dev/null +++ b/tests/topotests/bgp_set_metric_igp/test_bgp_set_metric_igp.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = { + "s1": ("r1", "r2"), + "s2": ("r1", "r3"), + "s3": ("r2", "r4"), + "s4": ("r3", "r4"), + "s5": ("r4", "r5"), + } + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_set_metric_igp(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.5.5.5/32": [ + { + "valid": True, + "bestpath": True, + "selectionReason": "MED", + "metric": 20, + "nexthops": [ + { + "ip": "10.0.0.2", + "hostname": "r2", + } + ], + }, + { + "valid": True, + "bestpath": None, + "metric": 110, + "nexthops": [ + { + "ip": "10.0.1.2", + "hostname": "r3", + } + ], + }, + ] + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=5) + assert result is None, "10.5.5.5/32 best path is not via r2 (MED == 20)" + + r2.vtysh_cmd( + """ +configure terminal +interface r2-eth1 + isis metric level-2 6000 +""" + ) + + def _bgp_converge_after_isis_metric_changes(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.5.5.5/32": [ + { + "valid": True, + "bestpath": None, + "metric": 6010, + "nexthops": [ + { + "ip": "10.0.0.2", + "hostname": "r2", + } + ], + }, + { + "valid": True, + "bestpath": True, + "selectionReason": "MED", + "metric": 110, + "nexthops": [ + { + "ip": "10.0.1.2", + "hostname": "r3", + } + ], + }, + ] + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_after_isis_metric_changes, + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=5) + assert result is None, "10.5.5.5/32 best path is not via r3 (MED == 110)" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/lib/common_check.py b/tests/topotests/lib/common_check.py index 19f02dbadc..b04b9de44e 100644 --- a/tests/topotests/lib/common_check.py +++ b/tests/topotests/lib/common_check.py @@ -58,7 +58,7 @@ def iproute2_check_path_selection(router, ipaddr_str, expected, vrf_name=None): else: cmdstr = f"ip -json route show {ipaddr_str}" try: - output = json.loads(cmdstr) + output = json.loads(router.cmd(cmdstr)) except: output = [] diff --git a/tools/gcc-plugins/frr-format.c b/tools/gcc-plugins/frr-format.c index 963741e479..d9e38f62ca 100644 --- a/tools/gcc-plugins/frr-format.c +++ b/tools/gcc-plugins/frr-format.c @@ -2685,7 +2685,8 @@ tree type_normalize (tree type, tree *cousin, tree target = NULL) { while (1) { - if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == POINTER_TYPE) + if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == POINTER_TYPE + || TREE_CODE (type) == ARRAY_TYPE) return type; if (target) /* Strip off any "const" etc. */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 2d80feef6c..5a54c60c6b 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -280,9 +280,6 @@ static int vtysh_client_run(struct vtysh_client *vclient, const char *line, nread = vtysh_client_receive( vclient, bufvalid, buf + bufsz - bufvalid - 1, pass_fd); - if (nread < 0 && (errno == EINTR || errno == EAGAIN)) - continue; - if (nread <= 0) { if (vty->of) vty_out(vty, @@ -698,7 +695,7 @@ static char *trim(char *s) int vtysh_mark_file(const char *filename) { struct vty *vty; - FILE *confp = NULL; + FILE *confp = NULL, *closefp = NULL; int ret; vector vline; int tried = 0; @@ -711,7 +708,7 @@ int vtysh_mark_file(const char *filename) if (strncmp("-", filename, 1) == 0) confp = stdin; else - confp = fopen(filename, "r"); + confp = closefp = fopen(filename, "r"); if (confp == NULL) { fprintf(stderr, "%% Can't open config file %s due to '%s'.\n", @@ -851,9 +848,8 @@ int vtysh_mark_file(const char *filename) vty_close(vty); XFREE(MTYPE_VTYSH_CMD, vty_buf_copy); - if (confp != stdin) - fclose(confp); - + if (closefp) + fclose(closefp); return 0; } diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 64198132cc..297d87ec41 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -350,6 +350,7 @@ int main(int argc, char **argv, char **env) char pathspace[MAXPATHLEN] = ""; const char *histfile = NULL; const char *histfile_env = getenv("VTYSH_HISTFILE"); + const char *logpath = getenv("VTYSH_LOG"); /* SUID: drop down to calling user & go back up when needed */ elevuid = geteuid(); @@ -643,9 +644,7 @@ int main(int argc, char **argv, char **env) } } - if (getenv("VTYSH_LOG")) { - const char *logpath = getenv("VTYSH_LOG"); - + if (logpath != NULL) { logfile = fopen(logpath, "a"); if (!logfile) { fprintf(stderr, "Failed to open logfile (%s): %s\n", diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index 44058ab04e..4ed80d7d07 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -94,6 +94,12 @@ module frr-bgp-route-map { "Match peer address"; } + identity src-peer { + base frr-route-map:rmap-match-type; + description + "Match source peer address"; + } + identity mac-address-list { base frr-route-map:rmap-match-type; description @@ -688,6 +694,37 @@ identity set-extcommunity-color { } } + case src-peer { + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:src-peer')"; + choice peer { + description + "Value of the peer"; + case src-peer-ipv4-address { + description + "IP address of peer"; + leaf src-peer-ipv4-address { + type inet:ipv4-address; + } + } + + case src-peer-interface { + description + "Interface name of peer"; + leaf src-peer-interface { + type string; + } + } + + case src-peer-ipv6-address { + description + "IPv6 address of peer"; + leaf src-peer-ipv6-address { + type inet:ipv6-address; + } + } + } + } + case access-list-name { when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:mac-address-list') or " + "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:as-path-list') or " diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index c875a6ec7f..244c353a63 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -355,6 +355,22 @@ module frr-route-map { "Subtract round trip time to metric"; } } + + case use-igp { + leaf use-igp { + type boolean; + description + "Use metric from IGP procotol"; + } + } + + case use-aigp { + leaf use-aigp { + type boolean; + description + "Use metric from AIGP (Accumulated IGP)"; + } + } } } diff --git a/zebra/connected.c b/zebra/connected.c index 974a1c17a2..ce4f6919d5 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -176,6 +176,43 @@ static void connected_update(struct interface *ifp, struct connected *ifc) connected_announce(ifp, ifc); } +/* + * This function goes through and handles the deletion of a kernel route that happened + * to be the exact same as the connected route, so that the connected route wins. + * This can happen during processing if we happen to receive events in a slightly + * unexpected order. This is similiar to code in the other direction where if we + * have a kernel route don't install it if it perfectly matches a connected route. + */ +static void connected_remove_kernel_for_connected(afi_t afi, safi_t safi, struct zebra_vrf *zvrf, + struct prefix *p, struct nexthop *nh) +{ + struct route_node *rn; + struct route_entry *re; + rib_dest_t *dest; + struct route_table *table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf->vrf->vrf_id); + + if (!table) + return; + + rn = route_node_match(table, p); + if (!rn) + return; + + if (!prefix_same(&rn->p, p)) + return; + + dest = rib_dest_from_rnode(rn); + if (!dest || !dest->selected_fib) + return; + + re = dest->selected_fib; + if (re->type != ZEBRA_ROUTE_KERNEL) + return; + + rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_KERNEL, 0, 0, p, NULL, nh, 0, + zvrf->table_id, 0, 0, false); +} + /* Called from if_up(). */ void connected_up(struct interface *ifp, struct connected *ifc) { @@ -284,10 +321,13 @@ void connected_up(struct interface *ifp, struct connected *ifc) } if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_NOPREFIXROUTE)) { + connected_remove_kernel_for_connected(afi, SAFI_UNICAST, zvrf, &p, &nh); + rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, false); + connected_remove_kernel_for_connected(afi, SAFI_MULTICAST, zvrf, &p, &nh); rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0, flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0, false); diff --git a/zebra/dpdk/zebra_dplane_dpdk.c b/zebra/dpdk/zebra_dplane_dpdk.c index 411155167f..ae1a3743ce 100644 --- a/zebra/dpdk/zebra_dplane_dpdk.c +++ b/zebra/dpdk/zebra_dplane_dpdk.c @@ -400,6 +400,7 @@ static void zd_dpdk_rule_update(struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_INSTALL: case DPLANE_OP_INTF_UPDATE: case DPLANE_OP_INTF_DELETE: + case DPLANE_OP_VLAN_INSTALL, break; } } @@ -459,6 +460,7 @@ static void zd_dpdk_process_update(struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_INSTALL: case DPLANE_OP_INTF_UPDATE: case DPLANE_OP_INTF_DELETE: + case DPLANE_OP_VLAN_INSTALL, atomic_fetch_add_explicit(&dpdk_stat->ignored_updates, 1, memory_order_relaxed); diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 4fb57d84d9..8a967978cb 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -1058,6 +1058,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_NONE: case DPLANE_OP_STARTUP_STAGE: + case DPLANE_OP_VLAN_INSTALL: break; } diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8beae125d2..62b665682f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1610,68 +1610,18 @@ int netlink_tunneldump_read(struct zebra_ns *zns) return 0; } -static const char *port_state2str(uint8_t state) +static uint8_t netlink_get_dplane_vlan_state(uint8_t state) { - switch (state) { - case BR_STATE_DISABLED: - return "DISABLED"; - case BR_STATE_LISTENING: - return "LISTENING"; - case BR_STATE_LEARNING: - return "LEARNING"; - case BR_STATE_FORWARDING: - return "FORWARDING"; - case BR_STATE_BLOCKING: - return "BLOCKING"; - } - - return "UNKNOWN"; -} - -static void vxlan_vni_state_change(struct zebra_if *zif, uint16_t id, - uint8_t state) -{ - struct zebra_vxlan_vni *vnip; - - vnip = zebra_vxlan_if_vlanid_vni_find(zif, id); - - if (!vnip) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Cannot find VNI for VID (%u) IF %s for vlan state update", - id, zif->ifp->name); - - return; - } - - switch (state) { - case BR_STATE_FORWARDING: - zebra_vxlan_if_vni_up(zif->ifp, vnip); - break; - case BR_STATE_BLOCKING: - zebra_vxlan_if_vni_down(zif->ifp, vnip); - break; - case BR_STATE_DISABLED: - case BR_STATE_LISTENING: - case BR_STATE_LEARNING: - default: - /* Not used for anything at the moment */ - break; - } -} - -static void vlan_id_range_state_change(struct interface *ifp, uint16_t id_start, - uint16_t id_end, uint8_t state) -{ - struct zebra_if *zif; - - zif = (struct zebra_if *)ifp->info; - - if (!zif) - return; - - for (uint16_t i = id_start; i <= id_end; i++) - vxlan_vni_state_change(zif, i, state); + if (state == BR_STATE_LISTENING) + return ZEBRA_DPLANE_BR_STATE_LISTENING; + else if (state == BR_STATE_LEARNING) + return ZEBRA_DPLANE_BR_STATE_LEARNING; + else if (state == BR_STATE_FORWARDING) + return ZEBRA_DPLANE_BR_STATE_FORWARDING; + else if (state == BR_STATE_BLOCKING) + return ZEBRA_DPLANE_BR_STATE_BLOCKING; + + return ZEBRA_DPLANE_BR_STATE_DISABLED; } /** @@ -1686,7 +1636,6 @@ static void vlan_id_range_state_change(struct interface *ifp, uint16_t id_start, int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) { int len, rem; - struct interface *ifp; struct br_vlan_msg *bvm; struct bridge_vlan_info *vinfo; struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1] = {}; @@ -1694,6 +1643,9 @@ int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) uint8_t state; uint32_t vrange; int type; + uint32_t count = 0; + struct zebra_dplane_ctx *ctx = NULL; + struct zebra_vxlan_vlan_array *vlan_array = NULL; /* We only care about state changes for now */ if (!(h->nlmsg_type == RTM_NEWVLAN)) @@ -1713,25 +1665,10 @@ int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (bvm->family != AF_BRIDGE) return 0; - ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), bvm->ifindex); - if (!ifp) { - zlog_debug("Cannot find bridge-vlan IF (%u) for vlan update", - bvm->ifindex); - return 0; - } - - if (!IS_ZEBRA_IF_VXLAN(ifp)) { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Ignoring non-vxlan IF (%s) for vlan update", - ifp->name); - - return 0; - } - - if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("%s %s IF %s NS %u", - nl_msg_type_to_str(h->nlmsg_type), - nl_family_to_str(bvm->family), ifp->name, ns_id); + ctx = dplane_ctx_alloc(); + dplane_ctx_set_ns_id(ctx, ns_id); + dplane_ctx_set_op(ctx, DPLANE_OP_VLAN_INSTALL); + dplane_ctx_set_vlan_ifindex(ctx, bvm->ifindex); /* Loop over "ALL" BRIDGE_VLANDB_ENTRY */ rem = len; @@ -1762,26 +1699,39 @@ int netlink_vlan_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (!vtb[BRIDGE_VLANDB_ENTRY_STATE]) continue; + count++; + vlan_array = + XREALLOC(MTYPE_VLAN_CHANGE_ARR, vlan_array, + sizeof(struct zebra_vxlan_vlan_array) + + count * sizeof(struct zebra_vxlan_vlan)); + + memset(&vlan_array->vlans[count - 1], 0, + sizeof(struct zebra_vxlan_vlan)); + state = *(uint8_t *)RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_STATE]); if (vtb[BRIDGE_VLANDB_ENTRY_RANGE]) vrange = *(uint32_t *)RTA_DATA( vtb[BRIDGE_VLANDB_ENTRY_RANGE]); - if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN) { - if (vrange) - zlog_debug("VLANDB_ENTRY: VID (%u-%u) state=%s", - vinfo->vid, vrange, - port_state2str(state)); - else - zlog_debug("VLANDB_ENTRY: VID (%u) state=%s", - vinfo->vid, port_state2str(state)); - } - - vlan_id_range_state_change( - ifp, vinfo->vid, (vrange ? vrange : vinfo->vid), state); + vlan_array->vlans[count - 1].state = + netlink_get_dplane_vlan_state(state); + vlan_array->vlans[count - 1].vid = vinfo->vid; + vlan_array->vlans[count - 1].vrange = vrange; } + if (count) { + vlan_array->count = count; + dplane_ctx_set_vxlan_vlan_array(ctx, vlan_array); + if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("RTM_NEWVLAN for ifindex %u NS %u, enqueuing for zebra main", + bvm->ifindex, ns_id); + + dplane_provider_enqueue_to_zebra(ctx); + } else + dplane_ctx_fini(&ctx); + + return 0; } diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c index 08fbfede42..0eae221e1e 100644 --- a/zebra/ipforward_proc.c +++ b/zebra/ipforward_proc.c @@ -17,10 +17,15 @@ extern struct zebra_privs_t zserv_privs; static const char proc_net_snmp[] = "/proc/net/snmp"; -static void dropline(FILE *fp) +static bool dropline(FILE *fp) { - while (getc(fp) != '\n') - ; + int ch; + + do { + ch = getc(fp); + } while (ch != EOF && ch != '\n'); + + return ch != EOF; } int ipforward(void) @@ -36,7 +41,10 @@ int ipforward(void) return -1; /* We don't care about the first line. */ - dropline(fp); + if (!dropline(fp)) { + fclose(fp); + return 0; + } /* Get ip_statistics.IpForwarding : 1 => ip forwarding enabled diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 84aabc4254..3547314f84 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -430,10 +430,6 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_NEWTFILTER: case RTM_DELTFILTER: return netlink_tfilter_change(h, ns_id, startup); - case RTM_NEWVLAN: - return netlink_vlan_change(h, ns_id, startup); - case RTM_DELVLAN: - return netlink_vlan_change(h, ns_id, startup); /* Messages we may receive, but ignore */ case RTM_NEWCHAIN: @@ -449,6 +445,8 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_NEWTUNNEL: case RTM_DELTUNNEL: case RTM_GETTUNNEL: + case RTM_NEWVLAN: + case RTM_DELVLAN: return 0; default: /* @@ -492,6 +490,10 @@ static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, case RTM_DELLINK: return netlink_link_change(h, ns_id, startup); + case RTM_NEWVLAN: + case RTM_DELVLAN: + return netlink_vlan_change(h, ns_id, startup); + default: break; } @@ -1621,6 +1623,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_IPSET_ENTRY_ADD: case DPLANE_OP_IPSET_ENTRY_DELETE: case DPLANE_OP_STARTUP_STAGE: + case DPLANE_OP_VLAN_INSTALL: return FRR_NETLINK_ERROR; case DPLANE_OP_GRE_SET: @@ -1862,8 +1865,8 @@ void kernel_init(struct zebra_ns *zns) * setsockopt multicast group subscriptions that don't fit in nl_groups */ grp = RTNLGRP_BRVLAN; - ret = setsockopt(zns->netlink.sock, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, - &grp, sizeof(grp)); + ret = setsockopt(zns->netlink_dplane_in.sock, SOL_NETLINK, + NETLINK_ADD_MEMBERSHIP, &grp, sizeof(grp)); if (ret < 0) zlog_notice( diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 5cfbe7a896..4789cb62f2 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1627,6 +1627,7 @@ void kernel_update_multi(struct dplane_ctx_list_head *ctx_list) case DPLANE_OP_INTF_ADDR_DEL: case DPLANE_OP_STARTUP_STAGE: case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: + case DPLANE_OP_VLAN_INSTALL: zlog_err("Unhandled dplane data for %s", dplane_op2str(dplane_ctx_get_op(ctx))); res = ZEBRA_DPLANE_REQUEST_FAILURE; diff --git a/zebra/main.c b/zebra/main.c index 687da70cab..dd6249eff5 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -238,7 +238,7 @@ void zebra_finalize(struct event *dummy) zebra_ns_notify_close(); /* Final shutdown of ns resources */ - ns_walk_func(zebra_ns_final_shutdown, NULL, NULL); + ns_walk_func(zebra_ns_kernel_shutdown, NULL, NULL); zebra_rib_terminate(); zebra_router_terminate(); @@ -251,6 +251,8 @@ void zebra_finalize(struct event *dummy) label_manager_terminate(); + ns_walk_func(zebra_ns_final_shutdown, NULL, NULL); + ns_terminate(); frr_fini(); exit(0); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 7dae75bacc..10acee9be4 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -647,7 +647,7 @@ static int zsend_nexthop_lookup_mrib(struct zserv *client, struct ipaddr *addr, { struct stream *s; unsigned long nump; - uint8_t num; + uint16_t num; struct nexthop *nexthop; /* Get output stream. */ @@ -667,7 +667,7 @@ static int zsend_nexthop_lookup_mrib(struct zserv *client, struct ipaddr *addr, /* remember position for nexthop_num */ nump = stream_get_endp(s); /* reserve room for nexthop_num */ - stream_putc(s, 0); + stream_putw(s, 0); nhg = rib_get_fib_nhg(re); for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { if (rnh_nexthop_valid(re, nexthop)) @@ -675,11 +675,11 @@ static int zsend_nexthop_lookup_mrib(struct zserv *client, struct ipaddr *addr, } /* store nexthop_num */ - stream_putc_at(s, nump, num); + stream_putw_at(s, nump, num); } else { stream_putc(s, 0); /* distance */ stream_putl(s, 0); /* metric */ - stream_putc(s, 0); /* nexthop_num */ + stream_putw(s, 0); /* nexthop_num */ } stream_putw_at(s, 0, stream_get_endp(s)); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 00e990e856..88c1a04938 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -35,6 +35,8 @@ DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider"); DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object"); DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes"); +DEFINE_MTYPE(ZEBRA, VLAN_CHANGE_ARR, "Vlan Change Array"); + #ifndef AOK # define AOK 0 #endif @@ -371,6 +373,14 @@ struct dplane_srv6_encap_ctx { }; /* + * VLAN info for the dataplane + */ +struct dplane_vlan_info { + ifindex_t ifindex; + struct zebra_vxlan_vlan_array *vlan_array; +}; + +/* * The context block used to exchange info about route updates across * the boundary between the zebra main context (and pthread) and the * dataplane layer (and pthread). @@ -416,6 +426,7 @@ struct zebra_dplane_ctx { struct dplane_pw_info pw; struct dplane_br_port_info br_port; struct dplane_intf_info intf; + struct dplane_vlan_info vlan_info; struct dplane_mac_info macinfo; struct dplane_neigh_info neigh; struct dplane_rule_info rule; @@ -885,6 +896,11 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_STARTUP_STAGE: case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: break; + case DPLANE_OP_VLAN_INSTALL: + if (ctx->u.vlan_info.vlan_array) + XFREE(MTYPE_VLAN_CHANGE_ARR, + ctx->u.vlan_info.vlan_array); + break; } } @@ -1030,144 +1046,102 @@ enum dplane_op_e dplane_ctx_get_op(const struct zebra_dplane_ctx *ctx) const char *dplane_op2str(enum dplane_op_e op) { - const char *ret = "UNKNOWN"; - switch (op) { case DPLANE_OP_NONE: - ret = "NONE"; - break; + return "NONE"; /* Route update */ case DPLANE_OP_ROUTE_INSTALL: - ret = "ROUTE_INSTALL"; - break; + return "ROUTE_INSTALL"; case DPLANE_OP_ROUTE_UPDATE: - ret = "ROUTE_UPDATE"; - break; + return "ROUTE_UPDATE"; case DPLANE_OP_ROUTE_DELETE: - ret = "ROUTE_DELETE"; - break; + return "ROUTE_DELETE"; case DPLANE_OP_ROUTE_NOTIFY: - ret = "ROUTE_NOTIFY"; - break; + return "ROUTE_NOTIFY"; /* Nexthop update */ case DPLANE_OP_NH_INSTALL: - ret = "NH_INSTALL"; - break; + return "NH_INSTALL"; case DPLANE_OP_NH_UPDATE: - ret = "NH_UPDATE"; - break; + return "NH_UPDATE"; case DPLANE_OP_NH_DELETE: - ret = "NH_DELETE"; - break; + return "NH_DELETE"; case DPLANE_OP_LSP_INSTALL: - ret = "LSP_INSTALL"; - break; + return "LSP_INSTALL"; case DPLANE_OP_LSP_UPDATE: - ret = "LSP_UPDATE"; - break; + return "LSP_UPDATE"; case DPLANE_OP_LSP_DELETE: - ret = "LSP_DELETE"; - break; + return "LSP_DELETE"; case DPLANE_OP_LSP_NOTIFY: - ret = "LSP_NOTIFY"; - break; + return "LSP_NOTIFY"; case DPLANE_OP_PW_INSTALL: - ret = "PW_INSTALL"; - break; + return "PW_INSTALL"; case DPLANE_OP_PW_UNINSTALL: - ret = "PW_UNINSTALL"; - break; + return "PW_UNINSTALL"; case DPLANE_OP_SYS_ROUTE_ADD: - ret = "SYS_ROUTE_ADD"; - break; + return "SYS_ROUTE_ADD"; case DPLANE_OP_SYS_ROUTE_DELETE: - ret = "SYS_ROUTE_DEL"; - break; + return "SYS_ROUTE_DEL"; case DPLANE_OP_BR_PORT_UPDATE: - ret = "BR_PORT_UPDATE"; - break; + return "BR_PORT_UPDATE"; case DPLANE_OP_ADDR_INSTALL: - ret = "ADDR_INSTALL"; - break; + return "ADDR_INSTALL"; case DPLANE_OP_ADDR_UNINSTALL: - ret = "ADDR_UNINSTALL"; - break; + return "ADDR_UNINSTALL"; case DPLANE_OP_MAC_INSTALL: - ret = "MAC_INSTALL"; - break; + return "MAC_INSTALL"; case DPLANE_OP_MAC_DELETE: - ret = "MAC_DELETE"; - break; + return "MAC_DELETE"; case DPLANE_OP_NEIGH_INSTALL: - ret = "NEIGH_INSTALL"; - break; + return "NEIGH_INSTALL"; case DPLANE_OP_NEIGH_UPDATE: - ret = "NEIGH_UPDATE"; - break; + return "NEIGH_UPDATE"; case DPLANE_OP_NEIGH_DELETE: - ret = "NEIGH_DELETE"; - break; + return "NEIGH_DELETE"; case DPLANE_OP_VTEP_ADD: - ret = "VTEP_ADD"; - break; + return "VTEP_ADD"; case DPLANE_OP_VTEP_DELETE: - ret = "VTEP_DELETE"; - break; + return "VTEP_DELETE"; case DPLANE_OP_RULE_ADD: - ret = "RULE_ADD"; - break; + return "RULE_ADD"; case DPLANE_OP_RULE_DELETE: - ret = "RULE_DELETE"; - break; + return "RULE_DELETE"; case DPLANE_OP_RULE_UPDATE: - ret = "RULE_UPDATE"; - break; + return "RULE_UPDATE"; case DPLANE_OP_NEIGH_DISCOVER: - ret = "NEIGH_DISCOVER"; - break; + return "NEIGH_DISCOVER"; case DPLANE_OP_IPTABLE_ADD: - ret = "IPTABLE_ADD"; - break; + return "IPTABLE_ADD"; case DPLANE_OP_IPTABLE_DELETE: - ret = "IPTABLE_DELETE"; - break; + return "IPTABLE_DELETE"; case DPLANE_OP_IPSET_ADD: - ret = "IPSET_ADD"; - break; + return "IPSET_ADD"; case DPLANE_OP_IPSET_DELETE: - ret = "IPSET_DELETE"; - break; + return "IPSET_DELETE"; case DPLANE_OP_IPSET_ENTRY_ADD: - ret = "IPSET_ENTRY_ADD"; - break; + return "IPSET_ENTRY_ADD"; case DPLANE_OP_IPSET_ENTRY_DELETE: - ret = "IPSET_ENTRY_DELETE"; - break; + return "IPSET_ENTRY_DELETE"; case DPLANE_OP_NEIGH_IP_INSTALL: - ret = "NEIGH_IP_INSTALL"; - break; + return "NEIGH_IP_INSTALL"; case DPLANE_OP_NEIGH_IP_DELETE: - ret = "NEIGH_IP_DELETE"; - break; + return "NEIGH_IP_DELETE"; case DPLANE_OP_NEIGH_TABLE_UPDATE: - ret = "NEIGH_TABLE_UPDATE"; - break; + return "NEIGH_TABLE_UPDATE"; case DPLANE_OP_GRE_SET: - ret = "GRE_SET"; - break; + return "GRE_SET"; case DPLANE_OP_INTF_ADDR_ADD: return "INTF_ADDR_ADD"; @@ -1179,68 +1153,53 @@ const char *dplane_op2str(enum dplane_op_e op) return "INTF_NETCONFIG"; case DPLANE_OP_INTF_INSTALL: - ret = "INTF_INSTALL"; - break; + return "INTF_INSTALL"; case DPLANE_OP_INTF_UPDATE: - ret = "INTF_UPDATE"; - break; + return "INTF_UPDATE"; case DPLANE_OP_INTF_DELETE: - ret = "INTF_DELETE"; - break; + return "INTF_DELETE"; case DPLANE_OP_TC_QDISC_INSTALL: - ret = "TC_QDISC_INSTALL"; - break; + return "TC_QDISC_INSTALL"; case DPLANE_OP_TC_QDISC_UNINSTALL: - ret = "TC_QDISC_UNINSTALL"; - break; + return "TC_QDISC_UNINSTALL"; case DPLANE_OP_TC_CLASS_ADD: - ret = "TC_CLASS_ADD"; - break; + return "TC_CLASS_ADD"; case DPLANE_OP_TC_CLASS_DELETE: - ret = "TC_CLASS_DELETE"; - break; + return "TC_CLASS_DELETE"; case DPLANE_OP_TC_CLASS_UPDATE: - ret = "TC_CLASS_UPDATE"; - break; + return "TC_CLASS_UPDATE"; case DPLANE_OP_TC_FILTER_ADD: - ret = "TC_FILTER_ADD"; - break; + return "TC_FILTER_ADD"; case DPLANE_OP_TC_FILTER_DELETE: - ret = "TC_FILTER_DELETE"; - break; + return "TC_FILTER_DELETE"; case DPLANE_OP_TC_FILTER_UPDATE: - ret = "TC__FILTER_UPDATE"; - break; + return "TC__FILTER_UPDATE"; case DPLANE_OP_STARTUP_STAGE: - ret = "STARTUP_STAGE"; - break; + return "STARTUP_STAGE"; case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: - ret = "SRV6_ENCAP_SRCADDR_SET"; - break; + return "SRV6_ENCAP_SRCADDR_SET"; + + case DPLANE_OP_VLAN_INSTALL: + return "NEW_VLAN"; } - return ret; + return "UNKNOWN"; } const char *dplane_res2str(enum zebra_dplane_result res) { - const char *ret = "<Unknown>"; - switch (res) { case ZEBRA_DPLANE_REQUEST_FAILURE: - ret = "FAILURE"; - break; + return "FAILURE"; case ZEBRA_DPLANE_REQUEST_QUEUED: - ret = "QUEUED"; - break; + return "QUEUED"; case ZEBRA_DPLANE_REQUEST_SUCCESS: - ret = "SUCCESS"; - break; + return "SUCCESS"; } - return ret; + return "<Unknown>"; } void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx, @@ -3321,6 +3280,35 @@ uint32_t dplane_get_in_queue_len(void) memory_order_seq_cst); } +void dplane_ctx_set_vlan_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex) +{ + DPLANE_CTX_VALID(ctx); + ctx->u.vlan_info.ifindex = ifindex; +} + +ifindex_t dplane_ctx_get_vlan_ifindex(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.vlan_info.ifindex; +} + +void dplane_ctx_set_vxlan_vlan_array(struct zebra_dplane_ctx *ctx, + struct zebra_vxlan_vlan_array *vlan_array) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.vlan_info.vlan_array = vlan_array; +} + +const struct zebra_vxlan_vlan_array * +dplane_ctx_get_vxlan_vlan_array(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.vlan_info.vlan_array; +} + /* * Internal helper that copies information from a zebra ns object; this is * called in the zebra main pthread context as part of dplane ctx init. @@ -6720,6 +6708,12 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_op2str(dplane_ctx_get_op(ctx)), &ctx->u.srv6_encap.srcaddr); break; + + case DPLANE_OP_VLAN_INSTALL: + zlog_debug("Dplane %s on idx %u", + dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_vlan_ifindex(ctx)); + break; } } @@ -6888,6 +6882,7 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_ADDR_ADD: case DPLANE_OP_INTF_ADDR_DEL: case DPLANE_OP_INTF_NETCONFIG: + case DPLANE_OP_VLAN_INSTALL: break; case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index a3318bf5e9..285b00c9b7 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -24,6 +24,8 @@ extern "C" { #endif +DECLARE_MTYPE(VLAN_CHANGE_ARR); + /* Retrieve the dataplane API version number; see libfrr.h to decode major, * minor, sub version values. * Plugins should pay attention to the major version number, at least, to @@ -204,6 +206,9 @@ enum dplane_op_e { DPLANE_OP_TC_FILTER_DELETE, DPLANE_OP_TC_FILTER_UPDATE, + /* VLAN update */ + DPLANE_OP_VLAN_INSTALL, + /* Startup Control */ DPLANE_OP_STARTUP_STAGE, @@ -211,6 +216,13 @@ enum dplane_op_e { DPLANE_OP_SRV6_ENCAP_SRCADDR_SET, }; +/* Operational status of Bridge Ports */ +#define ZEBRA_DPLANE_BR_STATE_DISABLED 0x01 +#define ZEBRA_DPLANE_BR_STATE_LISTENING 0x02 +#define ZEBRA_DPLANE_BR_STATE_LEARNING 0x04 +#define ZEBRA_DPLANE_BR_STATE_FORWARDING 0x08 +#define ZEBRA_DPLANE_BR_STATE_BLOCKING 0x10 + /* * The vxlan/evpn neighbor management code needs some values to use * when programming neighbor changes. Offer some platform-neutral values @@ -1078,6 +1090,26 @@ void dplane_set_in_queue_limit(uint32_t limit, bool set); /* Retrieve the current queue depth of incoming, unprocessed updates */ uint32_t dplane_get_in_queue_len(void); +void dplane_ctx_set_vlan_ifindex(struct zebra_dplane_ctx *ctx, + ifindex_t ifindex); +ifindex_t dplane_ctx_get_vlan_ifindex(struct zebra_dplane_ctx *ctx); +struct zebra_vxlan_vlan_array; + +/* + * In netlink_vlan_change(), the memory allocated for vlan_array is freed + * in two cases + * 1) Inline free in netlink_vlan_change() when there are no new + * vlans to process i.e. nothing is enqueued to main thread. + * 2) Dplane-ctx takes over the vlan memory which gets freed in + * rib_process_dplane_results() after handling the vlan install + * + * Note: MTYPE of interest for this purpose is MTYPE_VLAN_CHANGE_ARR + */ +void dplane_ctx_set_vxlan_vlan_array(struct zebra_dplane_ctx *ctx, + struct zebra_vxlan_vlan_array *vlan_array); +const struct zebra_vxlan_vlan_array * +dplane_ctx_get_vxlan_vlan_array(struct zebra_dplane_ctx *ctx); + /* * Vty/cli apis */ diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 588917f4c0..ad5f5eeee0 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -146,6 +146,17 @@ union zebra_l2if_info { struct zebra_l2info_gre gre; }; +struct zebra_vxlan_vlan { + uint8_t state; + uint32_t vrange; + vlanid_t vid; +}; + +struct zebra_vxlan_vlan_array { + uint16_t count; + struct zebra_vxlan_vlan vlans[0]; +}; + /* NOTE: These macros are to be invoked only in the "correct" context. * IOW, the macro VNI_FROM_ZEBRA_IF() will assume the interface is * of type ZEBRA_IF_VXLAN. diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c index 63ac7877d0..6ed11f75f1 100644 --- a/zebra/zebra_nb_state.c +++ b/zebra/zebra_nb_state.c @@ -900,6 +900,7 @@ lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_nexthop_bh_type_get_elem( if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) return NULL; + (void)type_str; /* clang-SA */ switch (nexthop->bh_type) { case BLACKHOLE_NULL: type_str = "null"; diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c index 4cee3b89f1..3da79e249e 100644 --- a/zebra/zebra_netns_id.c +++ b/zebra/zebra_netns_id.c @@ -159,6 +159,7 @@ ns_id_t zebra_ns_id_get(const char *netnspath, int fd_param) int fd = -1, sock, ret; unsigned int seq; ns_id_t return_nsid = NS_UNKNOWN; + int nl_errno; /* netns path check */ if (!netnspath && fd_param == -1) @@ -231,32 +232,31 @@ ns_id_t zebra_ns_id_get(const char *netnspath, int fd_param) ret = -1; if (err->error < 0) - errno = -err->error; + nl_errno = -err->error; else - errno = err->error; - if (errno == 0) { + nl_errno = err->error; + if (nl_errno == 0) { /* request NEWNSID was successfull * return EEXIST error to get GETNSID */ - errno = EEXIST; + nl_errno = EEXIST; } } else { /* other errors ignored * attempt to get nsid */ ret = -1; - errno = EEXIST; + nl_errno = EEXIST; } } - if (errno != EEXIST && ret != 0) { - flog_err(EC_LIB_SOCKET, - "netlink( %u) recvfrom() error 2 when reading: %s", fd, - safe_strerror(errno)); + if (ret != 0 && nl_errno != EEXIST) { + flog_err(EC_LIB_SOCKET, "netlink( %u) recvfrom() error 2 when reading: %s", fd, + safe_strerror(nl_errno)); close(sock); if (netnspath) close(fd); - if (errno == ENOTSUP) { + if (nl_errno == ENOTSUP) { zlog_debug("NEWNSID locally generated"); return zebra_ns_id_get_fallback(netnspath); } diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index 3ac4fdd737..52b94e0405 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -378,19 +378,28 @@ void zebra_ns_notify_parse(void) { struct dirent *dent; DIR *srcdir = opendir(NS_RUN_DIR); + int srcdirfd; if (srcdir == NULL) { flog_err_sys(EC_LIB_SYSTEM_CALL, "NS parsing init: failed to parse %s", NS_RUN_DIR); return; } + + srcdirfd = dirfd(srcdir); + if (srcdirfd < 0) { + closedir(srcdir); + flog_err_sys(EC_LIB_SYSTEM_CALL, "NS parsing init: failed to parse %s", NS_RUN_DIR); + return; + } + while ((dent = readdir(srcdir)) != NULL) { struct stat st; if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; - if (fstatat(dirfd(srcdir), dent->d_name, &st, 0) < 0) { + if (fstatat(srcdirfd, dent->d_name, &st, 0) < 0) { flog_err_sys( EC_LIB_SYSTEM_CALL, "NS parsing init: failed to parse entry %s", diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 803d8f0034..ffd749fcf1 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -175,6 +175,22 @@ int zebra_ns_early_shutdown(struct ns *ns, return NS_WALK_CONTINUE; } +/* During zebra shutdown, do kernel cleanup + * netlink sockets, .. + */ +int zebra_ns_kernel_shutdown(struct ns *ns, void *param_in __attribute__((unused)), + void **param_out __attribute__((unused))) +{ + struct zebra_ns *zns = ns->info; + + if (zns == NULL) + return NS_WALK_CONTINUE; + + kernel_terminate(zns, true); + + return NS_WALK_CONTINUE; +} + /* During zebra shutdown, do final cleanup * after all dataplane work is complete. */ @@ -185,9 +201,7 @@ int zebra_ns_final_shutdown(struct ns *ns, struct zebra_ns *zns = ns->info; if (zns == NULL) - return 0; - - kernel_terminate(zns, true); + return NS_WALK_CONTINUE; zebra_ns_delete(ns); diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 8d988c3f82..d5fd5869bc 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -70,6 +70,8 @@ int zebra_ns_early_shutdown(struct ns *ns, int zebra_ns_final_shutdown(struct ns *ns, void *param_in __attribute__((unused)), void **param_out __attribute__((unused))); +int zebra_ns_kernel_shutdown(struct ns *ns, void *param_in __attribute__((unused)), + void **param_out __attribute__((unused))); void zebra_ns_startup_continue(struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 8ebc193fba..72421dc8ee 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -795,13 +795,77 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, struct rnh *rnh; /* - * We are storing the rnh's associated withb - * the tracked nexthop as a list of the rn's. + * We are storing the rnh's associated with + * the tracked nexthop as a list of the rnh's + * on the rn that we have matched to. As an + * example if you have these rnh's: + * rnh 1.1.1.1 + * rnh 1.1.1.2 + * rnh 1.1.3.4 + * rnh 4.5.6.7 + * Now imagine that you have in the tree these + * prefix's: + * 1.1.1.1/32 + * 1.1.1.0/24 + * 1.1.0.0/16 + * 0.0.0.0/0 + * + * The 1.1.1.1 rnh would be stored on 1.1.1.1/32 + * The 1.1.1.2 rnh would be stored on 1.1.1.0/24 + * The 1.1.3.4 rnh would be stored on the 1.1.0.0/16 + * and finally the 4.5.6.7 would be stored on the 0.0.0.0/0 + * prefix. + * * Unresolved rnh's are placed at the top * of the tree list.( 0.0.0.0/0 for v4 and 0::0/0 for v6 ) * As such for each rn we need to walk up the tree * and see if any rnh's need to see if they * would match a more specific route + * + * Now if a 1.1.1.2/32 prefix was added to the tree + * this function would start at this new node and + * see that the 1.1.1.2/32 node has no rnh's and + * there is nothing to do on this node currently, + * so the function would walk the parent pointers, until the + * 1.1.1.0/24 node is hit with the 1.1.1.2 rnh. This function + * would then call zebra_evaluate_rnh() which would then + * do a LPM and match on the 1.1.1.2/32 node. This function + * would then pull the 1.1.1.2 rnh off the 1.1.1.0/24 node + * and place it on the 1.1.1.1/32 node and notify the upper + * level protocols interested about the change( as necessary ). + * At this point in time a sequence number is added to note + * that the rnh has been moved. + * The function would also continue to walk up the tree + * looking at the list of rnh's and moving them around + * as necessary. Since in this example nothing else + * would change no further actions are made. + * + * Another case to consider is a node being deleted + * suppose the 1.1.1.2/32 route is being deleted. + * This function would start at the 1.1.1.1/32 node, + * perform a LPM and settle on the 1.1.1.0/24 node + * as where it belongs. The code would update appropriate + * interested parties and additionally also mark the sequence + * number and walk up the tree. Eventually it would get to + * the 1.1.1.0/24 node and since the seqno matches we would + * know that it is not necessary to reconsider this node + * as it was already moved to this spot. + * + * This all works because each node's parent pointer points + * to a node that has a prefix that contains this node. Eventually + * the parent traversal will hit the 0.0.0.0/0 node and we know + * we are done. We know this is pretty efficient because when + * a more specific is added as we walk the tree we can + * find the rnh's that matched to a less specific very easily + * and move them to a more specific node. Also vice-versa as a + * more specific node is removed. + * + * Long term the rnh code might be improved some as the rnh's + * are stored as a list. This might be transformed to a better + * data structure. This has not proven to be necessary yet as + * that we have not seen any particular case where a rn is + * storing more than a couple rnh's. If we find a case + * where this matters something might need to be done. */ while (rn) { if (IS_ZEBRA_DEBUG_NHT_DETAILED) @@ -5020,6 +5084,9 @@ static void rib_process_dplane_results(struct event *thread) zebra_ns_startup_continue(ctx); break; + case DPLANE_OP_VLAN_INSTALL: + zebra_vlan_dplane_result(ctx); + break; } /* Dispatch by op code */ dplane_ctx_fini(&ctx); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 89317be74d..35486a4cd0 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -220,10 +220,9 @@ void zebra_free_rnh(struct rnh *rnh) if (rern) { rib_dest_t *dest; - route_unlock_node(rern); - dest = rib_dest_from_rnode(rern); rnh_list_del(&dest->nht, rnh); + route_unlock_node(rern); } } free_state(rnh->vrf_id, rnh->state, rnh->node); @@ -1141,7 +1140,7 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, struct stream *s = NULL; struct route_entry *re; unsigned long nump; - uint8_t num; + uint16_t num; struct nexthop *nh; struct route_node *rn; int ret; @@ -1212,7 +1211,7 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, stream_putl(s, re->metric); num = 0; nump = stream_get_endp(s); - stream_putc(s, 0); + stream_putw(s, 0); nhg = rib_get_fib_nhg(re); for (ALL_NEXTHOPS_PTR(nhg, nh)) @@ -1240,13 +1239,13 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, } } - stream_putc_at(s, nump, num); + stream_putw_at(s, nump, num); } else { stream_putc(s, 0); // type stream_putw(s, 0); // instance stream_putc(s, 0); // distance stream_putl(s, 0); // metric - stream_putc(s, 0); // nexthops + stream_putw(s, 0); // nexthops } stream_putw_at(s, 0, stream_get_endp(s)); diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c index 6c34d12c64..a0d5e2054c 100644 --- a/zebra/zebra_script.c +++ b/zebra/zebra_script.c @@ -418,6 +418,7 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) case DPLANE_OP_SRV6_ENCAP_SRCADDR_SET: case DPLANE_OP_NONE: case DPLANE_OP_STARTUP_STAGE: + case DPLANE_OP_VLAN_INSTALL: break; } /* Dispatch by op code */ } diff --git a/zebra/zebra_srte.c b/zebra/zebra_srte.c index c0b83382c4..bb8d4b3b40 100644 --- a/zebra/zebra_srte.c +++ b/zebra/zebra_srte.c @@ -145,7 +145,7 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy, stream_putc(s, nhlfe->distance); stream_putl(s, 0); /* metric - not available */ nump = stream_get_endp(s); - stream_putc(s, 0); + stream_putw(s, 0); } zapi_nexthop_from_nexthop(&znh, nhlfe->nexthop); @@ -155,7 +155,7 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy, num++; } - stream_putc_at(s, nump, num); + stream_putw_at(s, nump, num); stream_putw_at(s, 0, stream_get_endp(s)); client->nh_last_upd_time = monotime(NULL); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index f1ae42e320..0f72259951 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -6246,3 +6246,114 @@ extern void zebra_evpn_init(void) { hook_register(zserv_client_close, zebra_evpn_cfg_clean_up); } + +static const char *port_state2str(uint8_t state) +{ + switch (state) { + case ZEBRA_DPLANE_BR_STATE_DISABLED: + return "DISABLED"; + case ZEBRA_DPLANE_BR_STATE_LISTENING: + return "LISTENING"; + case ZEBRA_DPLANE_BR_STATE_LEARNING: + return "LEARNING"; + case ZEBRA_DPLANE_BR_STATE_FORWARDING: + return "FORWARDING"; + case ZEBRA_DPLANE_BR_STATE_BLOCKING: + return "BLOCKING"; + } + + return "UNKNOWN"; +} + +static void vxlan_vni_state_change(struct zebra_if *zif, uint16_t id, + uint8_t state) +{ + struct zebra_vxlan_vni *vnip; + + vnip = zebra_vxlan_if_vlanid_vni_find(zif, id); + + if (!vnip) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Cannot find VNI for VID (%u) IF %s for vlan state update", + id, zif->ifp->name); + + return; + } + + switch (state) { + case ZEBRA_DPLANE_BR_STATE_FORWARDING: + zebra_vxlan_if_vni_up(zif->ifp, vnip); + break; + case ZEBRA_DPLANE_BR_STATE_BLOCKING: + zebra_vxlan_if_vni_down(zif->ifp, vnip); + break; + case ZEBRA_DPLANE_BR_STATE_DISABLED: + case ZEBRA_DPLANE_BR_STATE_LISTENING: + case ZEBRA_DPLANE_BR_STATE_LEARNING: + default: + /* Not used for anything at the moment */ + break; + } +} + +static void vlan_id_range_state_change(struct interface *ifp, uint16_t id_start, + uint16_t id_end, uint8_t state) +{ + struct zebra_if *zif; + + zif = (struct zebra_if *)ifp->info; + + if (!zif) + return; + + for (uint16_t i = id_start; i <= id_end; i++) + vxlan_vni_state_change(zif, i, state); +} + +void zebra_vlan_dplane_result(struct zebra_dplane_ctx *ctx) +{ + int i; + struct interface *ifp = NULL; + ns_id_t ns_id = dplane_ctx_get_ns_id(ctx); + enum dplane_op_e op = dplane_ctx_get_op(ctx); + const struct zebra_vxlan_vlan_array *vlan_array = + dplane_ctx_get_vxlan_vlan_array(ctx); + ifindex_t ifindex = dplane_ctx_get_vlan_ifindex(ctx); + + ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), ifindex); + if (!ifp) { + zlog_debug("Cannot find bridge-vlan IF (%u) for vlan update", + ifindex); + return; + } + + if (!IS_ZEBRA_IF_VXLAN(ifp)) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Ignoring non-vxlan IF (%s) for vlan update", + ifp->name); + + return; + } + + if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Dequeuing in zebra main..%s IF %s ifindex %u NS %u", + dplane_op2str(op), ifp->name, ifindex, ns_id); + + for (i = 0; i < vlan_array->count; i++) { + vlanid_t vid = vlan_array->vlans[i].vid; + uint8_t state = vlan_array->vlans[i].state; + uint32_t vrange = vlan_array->vlans[i].vrange; + + if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_VXLAN) { + if (vrange) + zlog_debug("VLANDB_ENTRY: VID (%u-%u) state=%s", + vid, vrange, port_state2str(state)); + else + zlog_debug("VLANDB_ENTRY: VID (%u) state=%s", + vid, port_state2str(state)); + } + + vlan_id_range_state_change(ifp, vid, (vrange ? vrange : vid), + state); + } +} diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index eb02de6f7b..ef4c39c060 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -221,7 +221,7 @@ extern int zebra_vxlan_dp_network_mac_del(struct interface *ifp, extern void zebra_vxlan_set_accept_bgp_seq(bool set); extern bool zebra_vxlan_get_accept_bgp_seq(void); - +extern void zebra_vlan_dplane_result(struct zebra_dplane_ctx *ctx); #ifdef __cplusplus } #endif |
