diff options
218 files changed, 10339 insertions, 3698 deletions
diff --git a/.clang-format b/.clang-format index 7aefafa58f..72018d5a82 100644 --- a/.clang-format +++ b/.clang-format @@ -55,7 +55,7 @@ BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false -ColumnLimit: 80 +ColumnLimit: 100 # Linux: CommentPragmas: '^ IWYU pragma:' CommentPragmas: '\$(FRR|clippy)' CompactNamespaces: false diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 75034d220c..2e213a2237 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -338,11 +338,12 @@ void bfd_cli_show_minimum_ttl(struct vty *vty, const struct lyd_node *dnode, DEFPY_YANG( bfd_peer_mult, bfd_peer_mult_cmd, - "detect-multiplier (2-255)$multiplier", + "[no] detect-multiplier ![(2-255)$multiplier]", + NO_STR "Configure peer detection multiplier\n" "Configure peer detection multiplier value\n") { - nb_cli_enqueue_change(vty, "./detection-multiplier", NB_OP_MODIFY, + nb_cli_enqueue_change(vty, "./detection-multiplier", no ? NB_OP_DESTROY : NB_OP_MODIFY, multiplier_str); return nb_cli_apply_changes(vty, NULL); } @@ -356,14 +357,15 @@ void bfd_cli_show_mult(struct vty *vty, const struct lyd_node *dnode, DEFPY_YANG( bfd_peer_rx, bfd_peer_rx_cmd, - "receive-interval (10-60000)$interval", + "[no] receive-interval ![(10-60000)$interval]", + NO_STR "Configure peer receive interval\n" "Configure peer receive interval value in milliseconds\n") { char value[32]; snprintf(value, sizeof(value), "%ld", interval * 1000); - nb_cli_enqueue_change(vty, "./required-receive-interval", NB_OP_MODIFY, + nb_cli_enqueue_change(vty, "./required-receive-interval", no ? NB_OP_DESTROY : NB_OP_MODIFY, value); return nb_cli_apply_changes(vty, NULL); @@ -379,7 +381,8 @@ void bfd_cli_show_rx(struct vty *vty, const struct lyd_node *dnode, DEFPY_YANG( bfd_peer_tx, bfd_peer_tx_cmd, - "transmit-interval (10-60000)$interval", + "[no] transmit-interval ![(10-60000)$interval]", + NO_STR "Configure peer transmit interval\n" "Configure peer transmit interval value in milliseconds\n") { @@ -387,7 +390,7 @@ DEFPY_YANG( snprintf(value, sizeof(value), "%ld", interval * 1000); nb_cli_enqueue_change(vty, "./desired-transmission-interval", - NB_OP_MODIFY, value); + no ? NB_OP_DESTROY : NB_OP_MODIFY, value); return nb_cli_apply_changes(vty, NULL); } @@ -436,7 +439,8 @@ void bfd_cli_show_echo(struct vty *vty, const struct lyd_node *dnode, DEFPY_YANG( bfd_peer_echo_interval, bfd_peer_echo_interval_cmd, - "echo-interval (10-60000)$interval", + "[no] echo-interval ![(10-60000)$interval]", + NO_STR "Configure peer echo intervals\n" "Configure peer echo rx/tx intervals value in milliseconds\n") { @@ -449,16 +453,17 @@ DEFPY_YANG( snprintf(value, sizeof(value), "%ld", interval * 1000); nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval", - NB_OP_MODIFY, value); + no ? NB_OP_DESTROY : NB_OP_MODIFY, value); nb_cli_enqueue_change(vty, "./required-echo-receive-interval", - NB_OP_MODIFY, value); + no ? NB_OP_DESTROY : NB_OP_MODIFY, value); return nb_cli_apply_changes(vty, NULL); } DEFPY_YANG( bfd_peer_echo_transmit_interval, bfd_peer_echo_transmit_interval_cmd, - "echo transmit-interval (10-60000)$interval", + "[no] echo transmit-interval ![(10-60000)$interval]", + NO_STR "Configure peer echo intervals\n" "Configure desired transmit interval\n" "Configure interval value in milliseconds\n") @@ -472,7 +477,7 @@ DEFPY_YANG( snprintf(value, sizeof(value), "%ld", interval * 1000); nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval", - NB_OP_MODIFY, value); + no ? NB_OP_DESTROY : NB_OP_MODIFY, value); return nb_cli_apply_changes(vty, NULL); } @@ -487,7 +492,8 @@ void bfd_cli_show_desired_echo_transmission_interval( DEFPY_YANG( bfd_peer_echo_receive_interval, bfd_peer_echo_receive_interval_cmd, - "echo receive-interval <disabled$disabled|(10-60000)$interval>", + "[no] echo receive-interval ![<disabled$disabled|(10-60000)$interval>]", + NO_STR "Configure peer echo intervals\n" "Configure required receive interval\n" "Disable echo packets receive\n" @@ -504,9 +510,9 @@ DEFPY_YANG( snprintf(value, sizeof(value), "0"); else snprintf(value, sizeof(value), "%ld", interval * 1000); - + nb_cli_enqueue_change(vty, "./required-echo-receive-interval", - NB_OP_MODIFY, value); + no ? NB_OP_DESTROY : NB_OP_MODIFY, value); return nb_cli_apply_changes(vty, NULL); } @@ -571,17 +577,20 @@ void bfd_cli_show_profile(struct vty *vty, const struct lyd_node *dnode, } ALIAS_YANG(bfd_peer_mult, bfd_profile_mult_cmd, - "detect-multiplier (2-255)$multiplier", + "[no] detect-multiplier ![(2-255)$multiplier]", + NO_STR "Configure peer detection multiplier\n" "Configure peer detection multiplier value\n") ALIAS_YANG(bfd_peer_tx, bfd_profile_tx_cmd, - "transmit-interval (10-60000)$interval", + "[no] transmit-interval ![(10-60000)$interval]", + NO_STR "Configure peer transmit interval\n" "Configure peer transmit interval value in milliseconds\n") ALIAS_YANG(bfd_peer_rx, bfd_profile_rx_cmd, - "receive-interval (10-60000)$interval", + "[no] receive-interval ![(10-60000)$interval]", + NO_STR "Configure peer receive interval\n" "Configure peer receive interval value in milliseconds\n") @@ -612,20 +621,23 @@ ALIAS_YANG(bfd_peer_echo, bfd_profile_echo_cmd, "Configure echo mode\n") ALIAS_YANG(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd, - "echo-interval (10-60000)$interval", + "[no] echo-interval ![(10-60000)$interval]", + NO_STR "Configure peer echo interval\n" "Configure peer echo interval value in milliseconds\n") ALIAS_YANG( bfd_peer_echo_transmit_interval, bfd_profile_echo_transmit_interval_cmd, - "echo transmit-interval (10-60000)$interval", + "[no] echo transmit-interval ![(10-60000)$interval]", + NO_STR "Configure peer echo intervals\n" "Configure desired transmit interval\n" "Configure interval value in milliseconds\n") ALIAS_YANG( bfd_peer_echo_receive_interval, bfd_profile_echo_receive_interval_cmd, - "echo receive-interval <disabled$disabled|(10-60000)$interval>", + "[no] echo receive-interval ![<disabled$disabled|(10-60000)$interval>]", + NO_STR "Configure peer echo intervals\n" "Configure required receive interval\n" "Disable echo packets receive\n" diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 213de45c55..a8ca8c1fa6 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -353,7 +353,7 @@ struct transit { __builtin_choose_expr((X) >= 1 && (X) <= 64, 1ULL << ((X)-1), (void)0) #define BGP_CLUSTER_LIST_LENGTH(attr) \ - (((attr)->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) \ + (CHECK_FLAG((attr)->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) \ ? bgp_attr_get_cluster((attr))->length \ : 0) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index fc7548d9bf..a3ffe61eb8 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -218,7 +218,8 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr) continue; flags = *pnt++; - if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) + if (CHECK_FLAG(flags, + ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)) SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); else UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); @@ -258,11 +259,12 @@ void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy) sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) { val = *pnt++; - if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) + if (CHECK_FLAG(val, + ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)) SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER); - if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG) + if (CHECK_FLAG(val, ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG)) *proxy = true; break; diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 44a4c0f00b..9d99c2c7fd 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -1047,7 +1047,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) { - uint8_t bpi_num_labels; + uint8_t bpi_num_labels, adjin_num_labels; afi_t afi; safi_t safi; @@ -1241,11 +1241,12 @@ afibreak: bpi_num_labels ? bpi->extra->labels->label : NULL, bpi_num_labels); - if (adjin) - /* TODO: set label here when adjin supports labels */ - bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, - bn_p, prd, adjin->attr, afi, safi, adjin->uptime, - NULL, 0); + if (adjin) { + adjin_num_labels = adjin->labels ? adjin->labels->num_labels : 0; + bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd, + adjin->attr, afi, safi, adjin->uptime, + adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels); + } if (bn) bgp_dest_unlock_node(bn); @@ -1382,7 +1383,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) struct peer *peer; struct bgp_dest *bn = NULL; bool written = false; - uint8_t bpi_num_labels; + uint8_t bpi_num_labels, adjin_num_labels; bqe = bmp_pull(bmp); if (!bqe) @@ -1453,10 +1454,11 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) if (adjin->peer == peer) break; } - /* TODO: set label here when adjin supports labels */ - bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, - &bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi, - adjin ? adjin->uptime : monotime(NULL), NULL, 0); + adjin_num_labels = adjin && adjin->labels ? adjin->labels->num_labels : 0; + bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd, + adjin ? adjin->attr : NULL, afi, safi, + adjin ? adjin->uptime : monotime(NULL), + adjin_num_labels ? &adjin->labels->label[0] : NULL, adjin_num_labels); written = true; } @@ -2543,9 +2545,9 @@ DEFPY(bmp_monitor_cfg, bmp_monitor_cmd, prev = bt->afimon[afi][safi]; if (no) - bt->afimon[afi][safi] &= ~flag; + UNSET_FLAG(bt->afimon[afi][safi], flag); else - bt->afimon[afi][safi] |= flag; + SET_FLAG(bt->afimon[afi][safi], flag); if (prev == bt->afimon[afi][safi]) return CMD_SUCCESS; diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index 1d5034efd2..32823cc376 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -69,7 +69,7 @@ static void attr_parse(struct stream *s, uint16_t len) flag = stream_getc(s); type = stream_getc(s); - if (flag & BGP_ATTR_FLAG_EXTLEN) + if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN)) length = stream_getw(s); else length = stream_getc(s); diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 339bfae56d..93f5a19902 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -779,7 +779,8 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); bgp = bgp_get_default(); - if (bgp == NULL) { + + if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) { vty_out(vty, "No BGP process is configured\n"); return CMD_WARNING; } diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 1beb0307d2..547dcdf7f3 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -515,7 +515,7 @@ static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type, /* Fill in the values. */ eval->val[0] = type; if (!trans) - eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; + SET_FLAG(eval->val[0], ECOMMUNITY_FLAG_NON_TRANSITIVE); eval->val[1] = sub_type; if (type == ECOMMUNITY_ENCODE_AS) { encode_route_target_as(as, val, eval, trans); @@ -1293,11 +1293,12 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) == ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL) { uint8_t flags = *++pnt; - snprintf(encbuf, - sizeof(encbuf), "ESI-label-Rt:%s", - (flags & - ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG) ? - "SA":"AA"); + snprintf(encbuf, sizeof(encbuf), + "ESI-label-Rt:%s", + CHECK_FLAG(flags, + ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG) + ? "SA" + : "AA"); } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION) { uint8_t alg; @@ -1337,38 +1338,37 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) char buf[ECOMMUNITY_STRLEN]; memset(buf, 0, sizeof(buf)); - ecommunity_rt_soo_str_internal(buf, sizeof(buf), - (const uint8_t *)pnt, - type & - ~ECOMMUNITY_ENCODE_TRANS_EXP, - ECOMMUNITY_ROUTE_TARGET, - format, - ecom->unit_size); + ecommunity_rt_soo_str_internal( + buf, sizeof(buf), (const uint8_t *)pnt, + CHECK_FLAG(type, + ~ECOMMUNITY_ENCODE_TRANS_EXP), + ECOMMUNITY_ROUTE_TARGET, format, + ecom->unit_size); snprintf(encbuf, sizeof(encbuf), "%s", buf); } else if (sub_type == ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) { char buf[64]; memset(buf, 0, sizeof(buf)); - ecommunity_rt_soo_str_internal(buf, sizeof(buf), - (const uint8_t *)pnt, - type & - ~ECOMMUNITY_ENCODE_TRANS_EXP, - ECOMMUNITY_ROUTE_TARGET, - ECOMMUNITY_FORMAT_DISPLAY, - ecom->unit_size); + ecommunity_rt_soo_str_internal( + buf, sizeof(buf), (const uint8_t *)pnt, + CHECK_FLAG(type, + ~ECOMMUNITY_ENCODE_TRANS_EXP), + ECOMMUNITY_ROUTE_TARGET, + ECOMMUNITY_FORMAT_DISPLAY, + ecom->unit_size); snprintf(encbuf, sizeof(encbuf), "FS:redirect VRF %s", buf); } else if (sub_type == ECOMMUNITY_REDIRECT_VRF) { char buf[16]; memset(buf, 0, sizeof(buf)); - ecommunity_rt_soo_str(buf, sizeof(buf), - (const uint8_t *)pnt, - type & - ~ECOMMUNITY_ENCODE_TRANS_EXP, - ECOMMUNITY_ROUTE_TARGET, - ECOMMUNITY_FORMAT_DISPLAY); + ecommunity_rt_soo_str( + buf, sizeof(buf), (const uint8_t *)pnt, + CHECK_FLAG(type, + ~ECOMMUNITY_ENCODE_TRANS_EXP), + ECOMMUNITY_ROUTE_TARGET, + ECOMMUNITY_FORMAT_DISPLAY); snprintf(encbuf, sizeof(encbuf), "FS:redirect VRF %s", buf); snprintf(encbuf, sizeof(encbuf), @@ -1640,12 +1640,13 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_ACTION) { api->action = ACTION_TRAFFIC_ACTION; /* else distribute code is set by default */ - if (ecom_eval->val[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL)) - api->u.za.filter |= TRAFFIC_ACTION_TERMINATE; + if (CHECK_FLAG(ecom_eval->val[5], + (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL))) + SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_TERMINATE); else - api->u.za.filter |= TRAFFIC_ACTION_DISTRIBUTE; + SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_DISTRIBUTE); if (ecom_eval->val[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE) - api->u.za.filter |= TRAFFIC_ACTION_SAMPLE; + SET_FLAG(api->u.za.filter, TRAFFIC_ACTION_SAMPLE); } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_MARKING) { api->action = ACTION_MARKING; @@ -1940,7 +1941,7 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, return new; type = *eval; - if (type & ECOMMUNITY_FLAG_NON_TRANSITIVE) + if (CHECK_FLAG(type, ECOMMUNITY_FLAG_NON_TRANSITIVE)) return new; /* Transitive link-bandwidth exists, replace with the passed diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 929e4e60be..67c16aeb9e 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -155,12 +155,12 @@ struct ecommunity_ip6 { /* Extended community value is eight octet. */ struct ecommunity_val { - char val[ECOMMUNITY_SIZE]; + uint8_t val[ECOMMUNITY_SIZE]; }; /* IPv6 Extended community value is eight octet. */ struct ecommunity_val_ipv6 { - char val[IPV6_ECOMMUNITY_SIZE]; + uint8_t val[IPV6_ECOMMUNITY_SIZE]; }; #define ecom_length_size(X, Y) ((X)->size * (Y)) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index db93640635..fb7d2f47fb 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -117,7 +117,7 @@ int vni_list_cmp(void *p1, void *p2) static unsigned int vrf_import_rt_hash_key_make(const void *p) { const struct vrf_irt_node *irt = p; - const char *pnt = irt->rt.val; + const uint8_t *pnt = irt->rt.val; return jhash(pnt, 8, 0x5abc1234); } @@ -229,7 +229,7 @@ static int is_vrf_present_in_irt_vrfs(struct list *vrfs, struct bgp *bgp_vrf) static unsigned int import_rt_hash_key_make(const void *p) { const struct irt_node *irt = p; - const char *pnt = irt->rt.val; + const uint8_t *pnt = irt->rt.val; return jhash(pnt, 8, 0xdeadbeef); } @@ -621,7 +621,7 @@ static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl, struct listnode *node; if (bgp->advertise_autort_rfc8365) - vni |= EVPN_AUTORT_VXLAN; + SET_FLAG(vni, EVPN_AUTORT_VXLAN); encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true); ecomadd = ecommunity_new(); @@ -1314,12 +1314,11 @@ enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn * flag set install the local entry as a router entry */ if (is_evpn_prefix_ipaddr_v6(p) && - (pi->attr->es_flags & - ATTR_ES_PEER_ROUTER)) + CHECK_FLAG(pi->attr->es_flags, ATTR_ES_PEER_ROUTER)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); - if (!(pi->attr->es_flags & ATTR_ES_PEER_ACTIVE)) + if (!CHECK_FLAG(pi->attr->es_flags, ATTR_ES_PEER_ACTIVE)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT); } @@ -1611,12 +1610,16 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, struct bgp_labels bgp_labels = {}; struct bgp_path_info *local_pi = NULL; struct bgp_path_info *tmp_pi = NULL; + struct aspath *new_aspath; + struct attr static_attr = { 0 }; *route_changed = 0; /* See if this is an update of an existing route, or a new add. */ local_pi = bgp_evpn_route_get_local_path(bgp_evpn, dest); + static_attr = *attr; + /* * create a new route entry if one doesn't exist. * Otherwise see if route attr has changed @@ -1626,8 +1629,19 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, /* route has changed as this is the first entry */ *route_changed = 1; + /* + * if the asn values are different, copy the as of + * source vrf to the target entry + */ + if (bgp_vrf->as != bgp_evpn->as) { + new_aspath = aspath_dup(static_attr.aspath); + new_aspath = aspath_add_seq(new_aspath, bgp_vrf->as); + static_attr.aspath = new_aspath; + } + /* Add (or update) attribute to hash. */ - attr_new = bgp_attr_intern(attr); + attr_new = bgp_attr_intern(&static_attr); + bgp_attr_flush(&static_attr); /* create the route info from attribute */ pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0, @@ -1897,42 +1911,44 @@ static void update_evpn_route_entry_sync_info(struct bgp *bgp, mac); attr->mm_sync_seqnum = max_sync_seq; if (active_on_peer) - attr->es_flags |= ATTR_ES_PEER_ACTIVE; + SET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE); else - attr->es_flags &= ~ATTR_ES_PEER_ACTIVE; + UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE); if (proxy_from_peer) - attr->es_flags |= ATTR_ES_PEER_PROXY; + SET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY); else - attr->es_flags &= ~ATTR_ES_PEER_PROXY; + UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY); if (peer_router) - attr->es_flags |= ATTR_ES_PEER_ROUTER; + SET_FLAG(attr->es_flags, ATTR_ES_PEER_ROUTER); else - attr->es_flags &= ~ATTR_ES_PEER_ROUTER; + UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ROUTER); if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) { char esi_buf[ESI_STR_LEN]; - zlog_debug( - "setup sync info for %pFX es %s max_seq %d %s%s%s", - evp, - esi_to_str(esi, esi_buf, - sizeof(esi_buf)), - max_sync_seq, - (attr->es_flags & ATTR_ES_PEER_ACTIVE) - ? "peer-active " - : "", - (attr->es_flags & ATTR_ES_PEER_PROXY) - ? "peer-proxy " - : "", - (attr->es_flags & ATTR_ES_PEER_ROUTER) - ? "peer-router " - : ""); + zlog_debug("setup sync info for %pFX es %s max_seq %d %s%s%s", + evp, + esi_to_str(esi, esi_buf, + sizeof(esi_buf)), + max_sync_seq, + CHECK_FLAG(attr->es_flags, + ATTR_ES_PEER_ACTIVE) + ? "peer-active " + : "", + CHECK_FLAG(attr->es_flags, + ATTR_ES_PEER_PROXY) + ? "peer-proxy " + : "", + CHECK_FLAG(attr->es_flags, + ATTR_ES_PEER_ROUTER) + ? "peer-router " + : ""); } } } else { attr->mm_sync_seqnum = 0; - attr->es_flags &= ~ATTR_ES_PEER_ACTIVE; - attr->es_flags &= ~ATTR_ES_PEER_PROXY; + UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_ACTIVE); + UNSET_FLAG(attr->es_flags, ATTR_ES_PEER_PROXY); } } @@ -2217,16 +2233,16 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) - attr.es_flags |= ATTR_ES_PROXY_ADVERT; + SET_FLAG(attr.es_flags, ATTR_ES_PROXY_ADVERT); if (esi && bgp_evpn_is_esi_valid(esi)) { memcpy(&attr.esi, esi, sizeof(esi_t)); - attr.es_flags |= ATTR_ES_IS_LOCAL; + SET_FLAG(attr.es_flags, ATTR_ES_IS_LOCAL); } /* PMSI is only needed for type-3 routes */ if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) { - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); + SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)); bgp_attr_set_pmsi_tnl_type(&attr, PMSI_TNLTYPE_INGR_REPL); } @@ -2258,8 +2274,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * IPv4 or IPv6 global addresses and we're advertising L3VNI with * these routes. */ - add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok( - vpn, p, (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL); + add_l3_ecomm = + bgp_evpn_route_add_l3_ecomm_ok(vpn, p, + CHECK_FLAG(attr.es_flags, + ATTR_ES_IS_LOCAL) + ? &attr.esi + : NULL); if (bgp->evpn_info) macvrf_soo = bgp->evpn_info->soo; @@ -2531,9 +2551,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* Add L3 VNI RTs and RMAC for non IPv6 link-local if * using L3 VNI for type-2 routes also. */ - add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok( - vpn, &evp, - (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL); + add_l3_ecomm = + bgp_evpn_route_add_l3_ecomm_ok(vpn, &evp, + CHECK_FLAG(attr.es_flags, + ATTR_ES_IS_LOCAL) + ? &attr.esi + : NULL); if (bgp->evpn_info) macvrf_soo = bgp->evpn_info->soo; @@ -3091,23 +3114,23 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, attr.mp_nexthop_len = IPV6_MAX_BYTELEN; } else { attr.nexthop = bre->gw_ip.ipaddr_v4; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); + SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)); } } else { if (afi == AFI_IP6) evpn_convert_nexthop_to_ipv6(&attr); else { attr.nexthop = attr.mp_nexthop_global_in; - attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); + SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)); } } bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg, &is_l3nhg_active, NULL); if (use_l3nhg) - attr.es_flags |= ATTR_ES_L3_NHG_USE; + SET_FLAG(attr.es_flags, ATTR_ES_L3_NHG_USE); if (is_l3nhg_active) - attr.es_flags |= ATTR_ES_L3_NHG_ACTIVE; + SET_FLAG(attr.es_flags, ATTR_ES_L3_NHG_ACTIVE); /* Check if route entry is already present. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) @@ -3271,8 +3294,7 @@ static int install_evpn_route_entry_in_vni_common( if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) zlog_debug("VNI %d path %pFX chg to %s es", vpn->vni, &pi->net->rn->p, - new_local_es ? "local" - : "non-local"); + new_local_es ? "local" : "non-local"); bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED); } @@ -3635,7 +3657,7 @@ static int is_route_matching_for_vrf(struct bgp *bgp_vrf, assert(attr); /* Route should have valid RT to be even considered. */ - if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) + if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) return 0; ecom = bgp_attr_get_ecommunity(attr); @@ -3702,7 +3724,7 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn, assert(attr); /* Route should have valid RT to be even considered. */ - if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) + if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) return 0; ecom = bgp_attr_get_ecommunity(attr); @@ -4204,7 +4226,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi, return 0; /* If we don't have Route Target, nothing much to do. */ - if (!(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) + if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) return 0; /* EAD prefix in the global table doesn't include the VTEP-IP so @@ -4734,9 +4756,9 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, STREAM_GET(&attr->esi, pkt, sizeof(esi_t)); if (bgp_evpn_is_esi_local_and_non_bypass(&attr->esi)) - attr->es_flags |= ATTR_ES_IS_LOCAL; + SET_FLAG(attr->es_flags, ATTR_ES_IS_LOCAL); else - attr->es_flags &= ~ATTR_ES_IS_LOCAL; + UNSET_FLAG(attr->es_flags, ATTR_ES_IS_LOCAL); } else { STREAM_FORWARD_GETP(pkt, sizeof(esi_t)); } @@ -4838,8 +4860,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi, * Note: We just simply ignore the values as it is not clear if * doing anything else is better. */ - if (attr && - (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) { + if (attr && CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) { enum pta_type pmsi_tnl_type = bgp_attr_get_pmsi_tnl_type(attr); if (pmsi_tnl_type != PMSI_TNLTYPE_INGR_REPL @@ -5441,7 +5462,7 @@ void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl, struct ecommunity_val eval; if (bgp->advertise_autort_rfc8365) - vni |= EVPN_AUTORT_VXLAN; + SET_FLAG(vni, EVPN_AUTORT_VXLAN); encode_route_target_as((bgp->as & 0xFFFF), vni, &eval, true); @@ -7719,18 +7740,18 @@ static void bgp_evpn_remote_ip_process_nexthops(struct bgpevpn *vpn, * MAC/IP route or SVI or tenant vrf being added to EVI. * Set nexthop as valid only if it is already L3 reachable */ - if (resolve && bnc->flags & BGP_NEXTHOP_EVPN_INCOMPLETE) { - bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; - bnc->flags |= BGP_NEXTHOP_VALID; - bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED; + if (resolve && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) { + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE); + SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + SET_FLAG(bnc->change_flags, BGP_NEXTHOP_MACIP_CHANGED); evaluate_paths(bnc); } /* MAC/IP route or SVI or tenant vrf being deleted from EVI */ - if (!resolve && bnc->flags & BGP_NEXTHOP_VALID) { - bnc->flags &= ~BGP_NEXTHOP_VALID; - bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE; - bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED; + if (!resolve && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) { + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + SET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE); + SET_FLAG(bnc->change_flags, BGP_NEXTHOP_MACIP_CHANGED); evaluate_paths(bnc); } } diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index f4528defc2..1fb6594557 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -1404,8 +1404,8 @@ bgp_zebra_send_remote_es_vtep(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, return ZCLIENT_SEND_SUCCESS; } - if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) - flags |= ZAPI_ES_VTEP_FLAG_ESR_RXED; + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR)) + SET_FLAG(flags, ZAPI_ES_VTEP_FLAG_ESR_RXED); s = zclient->obuf; stream_reset(s); @@ -1964,9 +1964,9 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi) */ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller) { - if ((es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) - || listcount(es->macip_evi_path_list) - || listcount(es->macip_global_path_list)) + if (CHECK_FLAG(es->flags, (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) || + listcount(es->macip_evi_path_list) || + listcount(es->macip_global_path_list)) return; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) @@ -1991,8 +1991,8 @@ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller) static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es *es) { - return (es->flags & BGP_EVPNES_LOCAL) - && !(es->flags & BGP_EVPNES_BYPASS); + return CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL) && + !CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS); } /* init local info associated with the ES */ @@ -2074,8 +2074,8 @@ bool bgp_evpn_es_add_l3_ecomm_ok(esi_t *esi) es = bgp_evpn_es_find(esi); - return (!es || !(es->flags & BGP_EVPNES_LOCAL) - || bgp_evpn_local_es_is_active(es)); + return (!es || !CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL) || + bgp_evpn_local_es_is_active(es)); } static bool bgp_evpn_is_valid_local_path(struct bgp_path_info *pi) @@ -2175,9 +2175,9 @@ static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es *es, attr_tmp = *pi->attr; if (is_local) - attr_tmp.es_flags |= ATTR_ES_IS_LOCAL; + SET_FLAG(attr_tmp.es_flags, ATTR_ES_IS_LOCAL); else - attr_tmp.es_flags &= ~ATTR_ES_IS_LOCAL; + UNSET_FLAG(attr_tmp.es_flags, ATTR_ES_IS_LOCAL); attr_new = bgp_attr_intern(&attr_tmp); bgp_attr_unintern(&pi->attr); pi->attr = attr_new; @@ -2471,9 +2471,9 @@ static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es, for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { vtep_flag_str[0] = '\0'; - if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR)) strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str)); - if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE) + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE)) strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str)); if (!strlen(vtep_flag_str)) @@ -2505,15 +2505,15 @@ static void bgp_evpn_es_json_vtep_fill(json_object *json_vteps, json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4", &es_vtep->vtep_ip); - if (es_vtep->flags & (BGP_EVPNES_VTEP_ESR | - BGP_EVPNES_VTEP_ACTIVE)) { + if (CHECK_FLAG(es_vtep->flags, + (BGP_EVPNES_VTEP_ESR | BGP_EVPNES_VTEP_ACTIVE))) { json_flags = json_object_new_array(); - if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR)) json_array_string_add(json_flags, "esr"); - if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE) + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE)) json_array_string_add(json_flags, "active"); json_object_object_add(json_vtep_entry, "flags", json_flags); - if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) { + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR)) { json_object_int_add(json_vtep_entry, "dfPreference", es_vtep->df_pref); json_object_string_add( @@ -2537,9 +2537,9 @@ static void bgp_evpn_es_vteps_show_detail(struct vty *vty, for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { vtep_flag_str[0] = '\0'; - if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR)) strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str)); - if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE) + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE)) strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str)); if (!strlen(vtep_flag_str)) @@ -2548,7 +2548,7 @@ static void bgp_evpn_es_vteps_show_detail(struct vty *vty, vty_out(vty, " %pI4 flags: %s", &es_vtep->vtep_ip, vtep_flag_str); - if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) + if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR)) vty_out(vty, " df_alg: %s df_pref: %u\n", evpn_es_df_alg2str(es_vtep->df_alg, alg_buf, sizeof(alg_buf)), @@ -2573,11 +2573,12 @@ static void bgp_evpn_es_show_entry(struct vty *vty, json_object_string_addf(json, "rd", "%pRDP", &es->es_base_frag->prd); - if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) { + if (CHECK_FLAG(es->flags, + (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))) { json_types = json_object_new_array(); - if (es->flags & BGP_EVPNES_LOCAL) + if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL)) json_array_string_add(json_types, "local"); - if (es->flags & BGP_EVPNES_REMOTE) + if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE)) json_array_string_add(json_types, "remote"); json_object_object_add(json, "type", json_types); } @@ -2597,11 +2598,11 @@ static void bgp_evpn_es_show_entry(struct vty *vty, char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ]; type_str[0] = '\0'; - if (es->flags & BGP_EVPNES_BYPASS) + if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS)) strlcat(type_str, "B", sizeof(type_str)); - if (es->flags & BGP_EVPNES_LOCAL) + if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL)) strlcat(type_str, "L", sizeof(type_str)); - if (es->flags & BGP_EVPNES_REMOTE) + if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE)) strlcat(type_str, "R", sizeof(type_str)); if (es->inconsistencies) strlcat(type_str, "I", sizeof(type_str)); @@ -2628,16 +2629,16 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, /* Add the "brief" info first */ bgp_evpn_es_show_entry(vty, es, json); - if (es->flags - & (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI - | BGP_EVPNES_BYPASS)) { + if (CHECK_FLAG(es->flags, + (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI | + BGP_EVPNES_BYPASS))) { json_flags = json_object_new_array(); - if (es->flags & BGP_EVPNES_OPER_UP) + if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) json_array_string_add(json_flags, "up"); - if (es->flags & BGP_EVPNES_ADV_EVI) + if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) json_array_string_add(json_flags, "advertiseEVI"); - if (es->flags & BGP_EVPNES_BYPASS) + if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS)) json_array_string_add(json_flags, "bypass"); json_object_object_add(json, "flags", json_flags); } @@ -2653,7 +2654,7 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, listcount(es->macip_global_path_list)); json_object_int_add(json, "inconsistentVniVtepCount", es->incons_evi_vtep_cnt); - if (es->flags & BGP_EVPNES_LOCAL) + if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL)) json_object_int_add(json, "localEsDfPreference", es->df_pref); if (listcount(es->es_vtep_list)) { @@ -2671,7 +2672,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, } if (es->inconsistencies) { json_incons = json_object_new_array(); - if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST) + if (CHECK_FLAG(es->inconsistencies, + BGP_EVPNES_INCONS_VTEP_LIST)) json_array_string_add(json_incons, "vni-vtep-mismatch"); json_object_object_add(json, "inconsistencies", @@ -2682,9 +2684,9 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, char type_str[4]; type_str[0] = '\0'; - if (es->flags & BGP_EVPNES_LOCAL) + if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL)) strlcat(type_str, "L", sizeof(type_str)); - if (es->flags & BGP_EVPNES_REMOTE) + if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE)) strlcat(type_str, "R", sizeof(type_str)); vty_out(vty, "ESI: %s\n", es->esi_str); @@ -2692,10 +2694,10 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, vty_out(vty, " RD: %pRDP\n", es->es_base_frag ? &es->es_base_frag->prd : NULL); vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip); - if (es->flags & BGP_EVPNES_LOCAL) + if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL)) vty_out(vty, " Local ES DF preference: %u\n", es->df_pref); - if (es->flags & BGP_EVPNES_BYPASS) + if (CHECK_FLAG(es->flags, BGP_EVPNES_BYPASS)) vty_out(vty, " LACP bypass: on\n"); vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list)); vty_out(vty, " Remote VNI Count: %d\n", @@ -2709,7 +2711,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, es->incons_evi_vtep_cnt); if (es->inconsistencies) { incons_str[0] = '\0'; - if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST) + if (CHECK_FLAG(es->inconsistencies, + BGP_EVPNES_INCONS_VTEP_LIST)) strlcat(incons_str, "vni-vtep-mismatch", sizeof(incons_str)); } else { @@ -2933,7 +2936,7 @@ static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf *es_vrf) static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf) { - if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)) + if (!CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE)) return; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) @@ -2941,7 +2944,7 @@ static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf) es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id, es_vrf->nhg_id); bgp_evpn_l3nhg_zebra_del(es_vrf); - es_vrf->flags &= ~BGP_EVPNES_VRF_NHG_ACTIVE; + UNSET_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE); /* MAC-IPs can now be installed via the L3NHG */ bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg-deactivate"); } @@ -2953,7 +2956,7 @@ static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update) return; } - if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) { + if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE)) { if (!update) return; } else { @@ -2961,7 +2964,7 @@ static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update) zlog_debug("es %s vrf %u nhg %u activate", es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id, es_vrf->nhg_id); - es_vrf->flags |= BGP_EVPNES_VRF_NHG_ACTIVE; + SET_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE); /* MAC-IPs can now be installed via the L3NHG */ bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg_activate"); } @@ -3182,7 +3185,7 @@ void bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi, bool *use_l3nhg, return; *use_l3nhg = true; - if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) + if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE)) *is_l3nhg_active = true; if (es_vrf_p) *es_vrf_p = es_vrf; @@ -3274,9 +3277,9 @@ static void bgp_evpn_es_vrf_show_entry(struct vty *vty, json_object_string_add(json, "esi", es->esi_str); json_object_string_add(json, "vrf", bgp_vrf->name_pretty); - if (es_vrf->flags & (BGP_EVPNES_VRF_NHG_ACTIVE)) { + if (CHECK_FLAG(es_vrf->flags, (BGP_EVPNES_VRF_NHG_ACTIVE))) { json_types = json_object_new_array(); - if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) + if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE)) json_array_string_add(json_types, "active"); json_object_object_add(json, "flags", json_types); } @@ -3288,7 +3291,7 @@ static void bgp_evpn_es_vrf_show_entry(struct vty *vty, char flags_str[4]; flags_str[0] = '\0'; - if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) + if (CHECK_FLAG(es_vrf->flags, BGP_EVPNES_VRF_NHG_ACTIVE)) strlcat(flags_str, "A", sizeof(flags_str)); vty_out(vty, "%-30s %-15s %-5s %-8u %-8u %u\n", es->esi_str, @@ -3398,7 +3401,7 @@ static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep *evi_vtep) { struct bgp_evpn_es_evi *es_evi = evi_vtep->es_evi; - if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD)) + if (CHECK_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD))) /* as long as there is some reference we can't free it */ return; @@ -3443,7 +3446,8 @@ bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, /* EAD-per-ES is sufficent to activate the PE */ ead_activity_flags = BGP_EVPN_EVI_VTEP_EAD_PER_ES; - if ((evi_vtep->flags & ead_activity_flags) == ead_activity_flags) + if (CHECK_FLAG(evi_vtep->flags, ead_activity_flags) == + ead_activity_flags) SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); else UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); @@ -3600,7 +3604,8 @@ bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi) /* cannot free the element as long as there is a local or remote * reference */ - if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE)) + if (CHECK_FLAG(es_evi->flags, + (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE))) return es_evi; bgp_evpn_es_frag_evi_del(es_evi, false); bgp_evpn_es_vrf_deref(es_evi); @@ -3922,8 +3927,8 @@ static void bgp_evpn_remote_es_evi_flush(struct bgp_evpn_es_evi *es_evi) /* delete all VTEPs */ for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list, node, nnode, evi_vtep)) { - evi_vtep->flags &= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES - | BGP_EVPN_EVI_VTEP_EAD_PER_EVI); + UNSET_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD_PER_ES | + BGP_EVPN_EVI_VTEP_EAD_PER_EVI)); bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); bgp_evpn_es_evi_vtep_free(evi_vtep); } @@ -3971,9 +3976,9 @@ static char *bgp_evpn_es_evi_vteps_str(char *vtep_str, vtep_str[0] = '\0'; for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) { vtep_flag_str[0] = '\0'; - if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES) + if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES)) strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str)); - if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI) + if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) strlcat(vtep_flag_str, "V", sizeof(vtep_flag_str)); if (!strnlen(vtep_flag_str, sizeof(vtep_flag_str))) @@ -4004,12 +4009,12 @@ static void bgp_evpn_es_evi_json_vtep_fill(json_object *json_vteps, json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4", &evi_vtep->vtep_ip); - if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD_PER_ES | - BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) { + if (CHECK_FLAG(evi_vtep->flags, (BGP_EVPN_EVI_VTEP_EAD_PER_ES | + BGP_EVPN_EVI_VTEP_EAD_PER_EVI))) { json_flags = json_object_new_array(); - if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES) + if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES)) json_array_string_add(json_flags, "ead-per-es"); - if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI) + if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) json_array_string_add(json_flags, "ead-per-evi"); json_object_object_add(json_vtep_entry, "flags", json_flags); @@ -4033,12 +4038,12 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty, if (es_evi->vpn) json_object_int_add(json, "vni", es_evi->vpn->vni); - if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | - BGP_EVPNES_EVI_REMOTE)) { + if (CHECK_FLAG(es_evi->flags, (BGP_EVPNES_EVI_LOCAL | + BGP_EVPNES_EVI_REMOTE))) { json_types = json_object_new_array(); - if (es_evi->flags & BGP_EVPNES_EVI_LOCAL) + if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL)) json_array_string_add(json_types, "local"); - if (es_evi->flags & BGP_EVPNES_EVI_REMOTE) + if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) json_array_string_add(json_types, "remote"); json_object_object_add(json, "type", json_types); } @@ -4057,11 +4062,11 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty, char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ]; type_str[0] = '\0'; - if (es_evi->flags & BGP_EVPNES_EVI_LOCAL) + if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL)) strlcat(type_str, "L", sizeof(type_str)); - if (es_evi->flags & BGP_EVPNES_EVI_REMOTE) + if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) strlcat(type_str, "R", sizeof(type_str)); - if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) + if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST)) strlcat(type_str, "I", sizeof(type_str)); bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str)); @@ -4088,7 +4093,7 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty, json_object_string_addf(json, "esFragmentRd", BGP_RD_AS_FORMAT(mode), &es_evi->es_frag->prd); - if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) { + if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST)) { json_flags = json_object_new_array(); json_array_string_add(json_flags, "es-vtep-mismatch"); json_object_object_add(json, "flags", json_flags); @@ -4098,9 +4103,9 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty, char type_str[4]; type_str[0] = '\0'; - if (es_evi->flags & BGP_EVPNES_EVI_LOCAL) + if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL)) strlcat(type_str, "L", sizeof(type_str)); - if (es_evi->flags & BGP_EVPNES_EVI_REMOTE) + if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) strlcat(type_str, "R", sizeof(type_str)); bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str)); @@ -4117,8 +4122,10 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty, vty_out(vty, "\n"); } vty_out(vty, " Inconsistencies: %s\n", - (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ? - "es-vtep-mismatch":"-"); + CHECK_FLAG(es_evi->flags, + BGP_EVPNES_EVI_INCONS_VTEP_LIST) + ? "es-vtep-mismatch" + : "-"); vty_out(vty, " VTEPs: %s\n", vtep_str); vty_out(vty, "\n"); } @@ -4512,12 +4519,12 @@ static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add) static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh *nh, bool add) { if (add && !is_zero_mac(&nh->rmac)) { - nh->flags |= BGP_EVPN_NH_READY_FOR_ZEBRA; + SET_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA); bgp_evpn_nh_zebra_update_send(nh, true); } else { - if (!(nh->flags & BGP_EVPN_NH_READY_FOR_ZEBRA)) + if (!CHECK_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA)) return; - nh->flags &= ~BGP_EVPN_NH_READY_FOR_ZEBRA; + UNSET_FLAG(nh->flags, BGP_EVPN_NH_READY_FOR_ZEBRA); bgp_evpn_nh_zebra_update_send(nh, false); } } @@ -4809,7 +4816,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) /* if NHG is not being used for this path we don't need to manage the * nexthops in bgp (they are managed by zebra instead) */ - if (!(pi->attr->es_flags & ATTR_ES_L3_NHG_USE)) { + if (!CHECK_FLAG(pi->attr->es_flags, ATTR_ES_L3_NHG_USE)) { if (nh_info) bgp_evpn_path_nh_unlink(nh_info); return; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 0a5e6a773b..958a9c6492 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2820,9 +2820,9 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, path_cnt++; } - if (json && path_cnt) { + if (json) { if (path_cnt) - json_object_object_addf(json, json_paths, "%pFX", &p); + json_object_object_add(json, "paths", json_paths); json_object_int_add(json, "numPaths", path_cnt); } else { vty_out(vty, "\nDisplayed %u paths for requested prefix\n", diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c index 66426ab32f..31e14d41f7 100644 --- a/bgpd/bgp_flowspec_util.c +++ b/bgpd/bgp_flowspec_util.c @@ -305,14 +305,14 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type, break; mval->value = value; if (op[5] == 1) - mval->compare_operator |= - OPERATOR_COMPARE_LESS_THAN; + SET_FLAG(mval->compare_operator, + OPERATOR_COMPARE_LESS_THAN); if (op[6] == 1) - mval->compare_operator |= - OPERATOR_COMPARE_GREATER_THAN; + SET_FLAG(mval->compare_operator, + OPERATOR_COMPARE_GREATER_THAN); if (op[7] == 1) - mval->compare_operator |= - OPERATOR_COMPARE_EQUAL_TO; + SET_FLAG(mval->compare_operator, + OPERATOR_COMPARE_EQUAL_TO); if (op[1] == 1) mval->unary_operator = OPERATOR_UNARY_AND; else @@ -413,16 +413,16 @@ int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type, mval->value = value; if (op[6] == 1) { /* different from */ - mval->compare_operator |= - OPERATOR_COMPARE_LESS_THAN; - mval->compare_operator |= - OPERATOR_COMPARE_GREATER_THAN; + SET_FLAG(mval->compare_operator, + OPERATOR_COMPARE_LESS_THAN); + SET_FLAG(mval->compare_operator, + OPERATOR_COMPARE_GREATER_THAN); } else - mval->compare_operator |= - OPERATOR_COMPARE_EQUAL_TO; + SET_FLAG(mval->compare_operator, + OPERATOR_COMPARE_EQUAL_TO); if (op[7] == 1) - mval->compare_operator |= - OPERATOR_COMPARE_EXACT_MATCH; + SET_FLAG(mval->compare_operator, + OPERATOR_COMPARE_EXACT_MATCH); if (op[1] == 1) mval->unary_operator = OPERATOR_UNARY_AND; @@ -467,11 +467,11 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, case FLOWSPEC_SRC_PREFIX: bitmask = 0; if (type == FLOWSPEC_DEST_PREFIX) { - bitmask |= PREFIX_DST_PRESENT; + SET_FLAG(bitmask, PREFIX_DST_PRESENT); prefix = &bpem->dst_prefix; prefix_offset = &bpem->dst_prefix_offset; } else { - bitmask |= PREFIX_SRC_PRESENT; + SET_FLAG(bitmask, PREFIX_SRC_PRESENT); prefix = &bpem->src_prefix; prefix_offset = &bpem->src_prefix_offset; } @@ -491,14 +491,16 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, */ if (prefix->family == AF_INET && prefix->u.prefix4.s_addr == INADDR_ANY) - bpem->match_bitmask_iprule |= bitmask; + SET_FLAG(bpem->match_bitmask_iprule, + bitmask); else if (prefix->family == AF_INET6 && !memcmp(&prefix->u.prefix6, &in6addr_any, sizeof(struct in6_addr))) - bpem->match_bitmask_iprule |= bitmask; + SET_FLAG(bpem->match_bitmask_iprule, + bitmask); else - bpem->match_bitmask |= bitmask; + SET_FLAG(bpem->match_bitmask, bitmask); } offset += ret; break; @@ -640,8 +642,8 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, || bpem->match_dst_port_num || bpem->match_protocol_num || bpem->match_bitmask || bpem->match_flowlabel_num) bpem->type = BGP_PBR_IPSET; - else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) || - (bpem->match_bitmask_iprule & PREFIX_DST_PRESENT)) + else if (CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_SRC_PRESENT) || + CHECK_FLAG(bpem->match_bitmask_iprule, PREFIX_DST_PRESENT)) /* the extracted policy rule may not need an * iptables/ipset filtering. check this may not be * a standard ip rule : permit any to any ( eg) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 74ad65f1ec..cdd9b7ae4d 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1799,18 +1799,14 @@ bgp_connect_fail(struct peer_connection *connection) */ static void bgp_connect_in_progress_update_connection(struct peer *peer) { - if (bgp_getsockname(peer) < 0) { - if (!peer->su_remote && - !BGP_CONNECTION_SU_UNSPEC(peer->connection)) { - /* if connect initiated, then dest port and dest addresses are well known */ - peer->su_remote = sockunion_dup(&peer->connection->su); - if (sockunion_family(peer->su_remote) == AF_INET) - peer->su_remote->sin.sin_port = - htons(peer->port); - else if (sockunion_family(peer->su_remote) == AF_INET6) - peer->su_remote->sin6.sin6_port = - htons(peer->port); - } + bgp_updatesockname(peer); + if (!peer->su_remote && !BGP_CONNECTION_SU_UNSPEC(peer->connection)) { + /* if connect initiated, then dest port and dest addresses are well known */ + peer->su_remote = sockunion_dup(&peer->connection->su); + if (sockunion_family(peer->su_remote) == AF_INET) + peer->su_remote->sin.sin_port = htons(peer->port); + else if (sockunion_family(peer->su_remote) == AF_INET6) + peer->su_remote->sin6.sin6_port = htons(peer->port); } } diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 5e6a62c9b9..535d2fc5f4 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -63,18 +63,16 @@ DEFINE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled), (vrf, enabled)); /* bgpd options, we use GNU getopt library. */ -static const struct option longopts[] = { - { "bgp_port", required_argument, NULL, 'p' }, - { "listenon", required_argument, NULL, 'l' }, - { "no_kernel", no_argument, NULL, 'n' }, - { "skip_runas", no_argument, NULL, 'S' }, - { "ecmp", required_argument, NULL, 'e' }, - { "int_num", required_argument, NULL, 'I' }, - { "no_zebra", no_argument, NULL, 'Z' }, - { "socket_size", required_argument, NULL, 's' }, - { "v6-with-v4-nexthops", no_argument, NULL, 'v' }, - { 0 } -}; +static const struct option longopts[] = { { "bgp_port", required_argument, NULL, 'p' }, + { "listenon", required_argument, NULL, 'l' }, + { "no_kernel", no_argument, NULL, 'n' }, + { "skip_runas", no_argument, NULL, 'S' }, + { "ecmp", required_argument, NULL, 'e' }, + { "int_num", required_argument, NULL, 'I' }, + { "no_zebra", no_argument, NULL, 'Z' }, + { "socket_size", required_argument, NULL, 's' }, + { "v6-with-v4-nexthops", no_argument, NULL, 'x' }, + { 0 } }; /* signal definitions */ void sighup(void); @@ -424,11 +422,12 @@ int main(int argc, char **argv) int buffer_size = BGP_SOCKET_SNDBUF_SIZE; char *address; struct listnode *node; + bool v6_with_v4_nexthops = false; addresses->cmp = (int (*)(void *, void *))strcmp; frr_preinit(&bgpd_di, argc, argv); - frr_opt_add("p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts, + frr_opt_add("p:l:SnZe:I:s:x" DEPRECATED_OPTIONS, longopts, " -p, --bgp_port Set BGP listen port number (0 means do not listen).\n" " -l, --listenon Listen on specified address (implies -n)\n" " -n, --no_kernel Do not install route to kernel.\n" @@ -437,7 +436,7 @@ int main(int argc, char **argv) " -e, --ecmp Specify ECMP to use.\n" " -I, --int_num Set instance number (label-manager)\n" " -s, --socket_size Set BGP peer socket send buffer size\n" - " , --v6-with-v4-nexthop Allow BGP to form v6 neighbors using v4 nexthops\n"); + " -x, --v6-with-v4-nexthop Allow BGP to form v6 neighbors using v4 nexthops\n"); /* Command line argument treatment. */ while (1) { @@ -499,8 +498,8 @@ int main(int argc, char **argv) case 's': buffer_size = atoi(optarg); break; - case 'v': - bm->v6_with_v4_nexthops = true; + case 'x': + v6_with_v4_nexthops = true; break; default: frr_help_exit(1); @@ -513,6 +512,7 @@ int main(int argc, char **argv) bgp_master_init(frr_init(), buffer_size, addresses); bm->startup_time = monotime(NULL); bm->port = bgp_port; + bm->v6_with_v4_nexthops = v6_with_v4_nexthops; if (bgp_port == 0) bgp_option_set(BGP_OPT_NO_LISTEN); if (no_fib_flag || no_zebra_flag) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index eadd52b8e0..609afa4245 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -2,8 +2,10 @@ /* * BGP Multipath * Copyright (C) 2010 Google Inc. + * 2024 Nvidia Corporation + * Donald Sharp * - * This file is part of Quagga + * This file is part of FRR */ #include <zebra.h> @@ -191,78 +193,6 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, } /* - * bgp_path_info_mpath_cmp - * - * This function determines our multipath list ordering. By ordering - * the list we can deterministically select which paths are included - * in the multipath set. The ordering also helps in detecting changes - * in the multipath selection so we can detect whether to send an - * update to zebra. - * - * The order of paths is determined first by received nexthop, and then - * by peer address if the nexthops are the same. - */ -static int bgp_path_info_mpath_cmp(void *val1, void *val2) -{ - struct bgp_path_info *bpi1, *bpi2; - int compare; - - bpi1 = val1; - bpi2 = val2; - - compare = bgp_path_info_nexthop_cmp(bpi1, bpi2); - - if (!compare) { - if (!bpi1->peer->su_remote && !bpi2->peer->su_remote) - compare = 0; - else if (!bpi1->peer->su_remote) - compare = 1; - else if (!bpi2->peer->su_remote) - compare = -1; - else - compare = sockunion_cmp(bpi1->peer->su_remote, - bpi2->peer->su_remote); - } - - return compare; -} - -/* - * bgp_mp_list_init - * - * Initialize the mp_list, which holds the list of multipaths - * selected by bgp_best_selection - */ -void bgp_mp_list_init(struct list *mp_list) -{ - assert(mp_list); - memset(mp_list, 0, sizeof(struct list)); - mp_list->cmp = bgp_path_info_mpath_cmp; -} - -/* - * bgp_mp_list_clear - * - * Clears all entries out of the mp_list - */ -void bgp_mp_list_clear(struct list *mp_list) -{ - assert(mp_list); - list_delete_all_node(mp_list); -} - -/* - * bgp_mp_list_add - * - * Adds a multipath entry to the mp_list - */ -void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo) -{ - assert(mp_list && mpinfo); - listnode_add_sort(mp_list, mpinfo); -} - -/* * bgp_path_info_mpath_new * * Allocate and zero memory for a new bgp_path_info_mpath element @@ -274,6 +204,7 @@ static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void) new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO, sizeof(struct bgp_path_info_mpath)); + new_mpath->mp_count = 1; return new_mpath; } @@ -287,6 +218,8 @@ void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath) if (mpath && *mpath) { if ((*mpath)->mp_attr) bgp_attr_unintern(&(*mpath)->mp_attr); + (*mpath)->mp_attr = NULL; + XFREE(MTYPE_BGP_MPATH_INFO, *mpath); } } @@ -314,58 +247,22 @@ bgp_path_info_mpath_get(struct bgp_path_info *path) } /* - * bgp_path_info_mpath_enqueue - * - * Enqueue a path onto the multipath list given the previous multipath - * list entry - */ -static void bgp_path_info_mpath_enqueue(struct bgp_path_info *prev_info, - struct bgp_path_info *path) -{ - struct bgp_path_info_mpath *prev, *mpath; - - prev = bgp_path_info_mpath_get(prev_info); - mpath = bgp_path_info_mpath_get(path); - if (!prev || !mpath) - return; - - mpath->mp_next = prev->mp_next; - mpath->mp_prev = prev; - if (prev->mp_next) - prev->mp_next->mp_prev = mpath; - prev->mp_next = mpath; - - SET_FLAG(path->flags, BGP_PATH_MULTIPATH); -} - -/* - * bgp_path_info_mpath_dequeue - * - * Remove a path from the multipath list - */ -void bgp_path_info_mpath_dequeue(struct bgp_path_info *path) -{ - struct bgp_path_info_mpath *mpath = path->mpath; - if (!mpath) - return; - if (mpath->mp_prev) - mpath->mp_prev->mp_next = mpath->mp_next; - if (mpath->mp_next) - mpath->mp_next->mp_prev = mpath->mp_prev; - mpath->mp_next = mpath->mp_prev = NULL; - UNSET_FLAG(path->flags, BGP_PATH_MULTIPATH); -} - -/* * bgp_path_info_mpath_next * * Given a bgp_path_info, return the next multipath entry */ struct bgp_path_info *bgp_path_info_mpath_next(struct bgp_path_info *path) { - if (!path->mpath || !path->mpath->mp_next) - return NULL; - return path->mpath->mp_next->mp_info; + path = path->next; + + while (path) { + if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH)) + return path; + + path = path->next; + } + + return NULL; } /* @@ -386,7 +283,8 @@ struct bgp_path_info *bgp_path_info_mpath_first(struct bgp_path_info *path) uint32_t bgp_path_info_mpath_count(struct bgp_path_info *path) { if (!path->mpath) - return 0; + return 1; + return path->mpath->mp_count; } @@ -411,6 +309,10 @@ static void bgp_path_info_mpath_count_set(struct bgp_path_info *path, * bgp_path_info_mpath_lb_update * * Update cumulative info related to link-bandwidth + * + * This is only set on the first mpath of the list + * as such we should UNSET the flags when removing + * to ensure nothing accidently happens */ static void bgp_path_info_mpath_lb_update(struct bgp_path_info *path, bool set, bool all_paths_lb, uint64_t cum_bw) @@ -472,10 +374,10 @@ bool bgp_path_info_mpath_chkwtd(struct bgp *bgp, struct bgp_path_info *path) */ if (bgp->lb_handling != BGP_LINK_BW_SKIP_MISSING && bgp->lb_handling != BGP_LINK_BW_DEFWT_4_MISSING) - return (path->mpath->mp_flags & BGP_MP_LB_ALL); + return CHECK_FLAG(path->mpath->mp_flags, BGP_MP_LB_ALL); /* At least one path should have bandwidth. */ - return (path->mpath->mp_flags & BGP_MP_LB_PRESENT); + return CHECK_FLAG(path->mpath->mp_flags, BGP_MP_LB_PRESENT); } /* @@ -511,58 +413,51 @@ static void bgp_path_info_mpath_attr_set(struct bgp_path_info *path, /* * bgp_path_info_mpath_update * - * Compare and sync up the multipath list with the mp_list generated by - * bgp_best_selection + * Compare and sync up the multipath flags with what was choosen + * in best selection */ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, - struct bgp_path_info *new_best, - struct bgp_path_info *old_best, - struct list *mp_list, - struct bgp_maxpaths_cfg *mpath_cfg) + struct bgp_path_info *new_best, struct bgp_path_info *old_best, + uint32_t num_candidates, struct bgp_maxpaths_cfg *mpath_cfg) { uint16_t maxpaths, mpath_count, old_mpath_count; uint64_t bwval; uint64_t cum_bw, old_cum_bw; - struct listnode *mp_node, *mp_next_node; - struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; - int mpath_changed, debug; + struct bgp_path_info *cur_iterator = NULL; + bool mpath_changed, debug; bool all_paths_lb; char path_buf[PATH_ADDPATH_STR_BUFFER]; + bool old_mpath, new_mpath; - mpath_changed = 0; + mpath_changed = false; maxpaths = multipath_num; mpath_count = 0; - cur_mpath = NULL; old_mpath_count = 0; old_cum_bw = cum_bw = 0; - prev_mpath = new_best; - mp_node = listhead(mp_list); debug = bgp_debug_bestpath(dest); - if (new_best) { - mpath_count++; - if (new_best != old_best) - bgp_path_info_mpath_dequeue(new_best); - maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) - ? mpath_cfg->maxpaths_ibgp - : mpath_cfg->maxpaths_ebgp; - } - if (old_best) { - cur_mpath = bgp_path_info_mpath_first(old_best); old_mpath_count = bgp_path_info_mpath_count(old_best); + if (old_mpath_count == 1) + SET_FLAG(old_best->flags, BGP_PATH_MULTIPATH); old_cum_bw = bgp_path_info_mpath_cumbw(old_best); bgp_path_info_mpath_count_set(old_best, 0); bgp_path_info_mpath_lb_update(old_best, false, false, 0); - bgp_path_info_mpath_dequeue(old_best); + bgp_path_info_mpath_free(&old_best->mpath); + old_best->mpath = NULL; + } + + if (new_best) { + maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ? mpath_cfg->maxpaths_ibgp + : mpath_cfg->maxpaths_ebgp; + cur_iterator = new_best; } if (debug) - zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64, - dest, bgp->name_pretty, - new_best ? new_best->peer->host : "NONE", - mp_list ? listcount(mp_list) : 0, old_mpath_count, - old_cum_bw); + zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64 + " maxpaths set %u", + dest, bgp->name_pretty, new_best ? new_best->peer->host : "NONE", + num_candidates, old_mpath_count, old_cum_bw, maxpaths); /* * We perform an ordered walk through both lists in parallel. @@ -576,240 +471,106 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, * to skip over it */ all_paths_lb = true; /* We'll reset if any path doesn't have LB. */ - while (mp_node || cur_mpath) { - struct bgp_path_info *tmp_info; + while (cur_iterator) { + old_mpath = CHECK_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH); + new_mpath = CHECK_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW); + + UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW); /* - * We can bail out of this loop if all existing paths on the - * multipath list have been visited (for cleanup purposes) and - * the maxpath requirement is fulfulled + * If the current mpath count is equal to the number of + * maxpaths that can be used then we can bail, after + * we clean up the flags associated with the rest of the + * bestpaths */ - if (!cur_mpath && (mpath_count >= maxpaths)) - break; + if (mpath_count >= maxpaths) { + while (cur_iterator) { + UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH); + UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH_NEW); + + cur_iterator = cur_iterator->next; + } - mp_next_node = mp_node ? listnextnode(mp_node) : NULL; - next_mpath = - cur_mpath ? bgp_path_info_mpath_next(cur_mpath) : NULL; - tmp_info = mp_node ? listgetdata(mp_node) : NULL; + if (debug) + zlog_debug("%pBD(%s): Mpath count %u is equal to maximum paths allowed, finished comparision for MPATHS", + dest, bgp->name_pretty, mpath_count); - if (debug) - zlog_debug("%pBD(%s): comparing candidate %s with existing mpath %s", - dest, bgp->name_pretty, - tmp_info ? tmp_info->peer->host : "NONE", - cur_mpath ? cur_mpath->peer->host : "NONE"); + break; + } + if (debug) + zlog_debug("%pBD(%s): Candidate %s old_mpath: %u new_mpath: %u, Nexthop %pI4 current mpath count: %u", + dest, bgp->name_pretty, cur_iterator->peer->host, old_mpath, + new_mpath, &cur_iterator->attr->nexthop, mpath_count); /* - * If equal, the path was a multipath and is still a multipath. - * Insert onto new multipath list if maxpaths allows. + * There is nothing to do if the cur_iterator is neither a old path + * or a new path */ - if (mp_node && (listgetdata(mp_node) == cur_mpath)) { - list_delete_node(mp_list, mp_node); - bgp_path_info_mpath_dequeue(cur_mpath); - if ((mpath_count < maxpaths) && prev_mpath) { - mpath_count++; - if (bgp_path_info_nexthop_cmp(prev_mpath, - cur_mpath)) { - if (ecommunity_linkbw_present( - bgp_attr_get_ecommunity( - cur_mpath->attr), - &bwval) || - ecommunity_linkbw_present( - bgp_attr_get_ipv6_ecommunity( - cur_mpath->attr), - &bwval)) - cum_bw += bwval; - else - all_paths_lb = false; - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf, - sizeof(path_buf)); - zlog_debug("%pBD: %s is still multipath, cur count %d", - dest, path_buf, - mpath_count); - } - } else { - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf, - sizeof(path_buf)); - zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d", - dest, path_buf, - &cur_mpath->attr->nexthop, - mpath_count); - } - } - bgp_path_info_mpath_enqueue(prev_mpath, - cur_mpath); - prev_mpath = cur_mpath; - } else { - mpath_changed = 1; - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf, - sizeof(path_buf)); - zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d", - dest, path_buf, - &cur_mpath->attr->nexthop, - mpath_count); - } - } - mp_node = mp_next_node; - cur_mpath = next_mpath; + if (!old_mpath && !new_mpath) { + UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH); + cur_iterator = cur_iterator->next; continue; } - if (cur_mpath - && (!mp_node - || (bgp_path_info_mpath_cmp(cur_mpath, - listgetdata(mp_node)) - < 0))) { - /* - * If here, we have an old multipath and either the - * mp_list - * is finished or the next mp_node points to a later - * multipath, so we need to purge this path from the - * multipath list - */ - bgp_path_info_mpath_dequeue(cur_mpath); - mpath_changed = 1; + if (new_mpath) { + mpath_count++; + + if (cur_iterator != new_best) + SET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH); + + if (!old_mpath) + mpath_changed = true; + + if (ecommunity_linkbw_present(bgp_attr_get_ecommunity(cur_iterator->attr), + &bwval) || + ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity( + cur_iterator->attr), + &bwval)) + cum_bw += bwval; + else + all_paths_lb = false; + if (debug) { - bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf, sizeof(path_buf)); - zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d", - dest, path_buf, - &cur_mpath->attr->nexthop, - mpath_count); + bgp_path_info_path_with_addpath_rx_str(cur_iterator, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d cum_bw: %" PRIu64 + " all_paths_lb: %u", + dest, path_buf, &cur_iterator->attr->nexthop, + mpath_count, cum_bw, all_paths_lb); } - cur_mpath = next_mpath; } else { /* - * If here, we have a path on the mp_list that was not - * previously - * a multipath (due to non-equivalance or maxpaths - * exceeded), - * or the matching multipath is sorted later in the - * multipath - * list. Before we enqueue the path on the new multipath - * list, - * make sure its not on the old_best multipath list or - * referenced - * via next_mpath: - * - If next_mpath points to this new path, update - * next_mpath to - * point to the multipath after this one - * - Dequeue the path from the multipath list just to - * make sure + * We know that old_mpath is true and new_mpath is false in this path */ - new_mpath = listgetdata(mp_node); - list_delete_node(mp_list, mp_node); - assert(new_mpath); - assert(prev_mpath); - if ((mpath_count < maxpaths) && (new_mpath != new_best)) { - /* keep duplicate nexthop */ - bgp_path_info_mpath_dequeue(new_mpath); - - bgp_path_info_mpath_enqueue(prev_mpath, - new_mpath); - mpath_changed = 1; - mpath_count++; - if (bgp_path_info_nexthop_cmp(prev_mpath, - new_mpath)) { - if (ecommunity_linkbw_present( - bgp_attr_get_ecommunity( - new_mpath->attr), - &bwval) || - ecommunity_linkbw_present( - bgp_attr_get_ipv6_ecommunity( - new_mpath->attr), - &bwval)) - cum_bw += bwval; - else - all_paths_lb = false; - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - new_mpath, path_buf, - sizeof(path_buf)); - zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d", - dest, path_buf, - &new_mpath->attr - ->nexthop, - mpath_count); - } - } else { - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - new_mpath, path_buf, - sizeof(path_buf)); - zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d", - dest, path_buf, - &new_mpath->attr - ->nexthop, - mpath_count); - } - } - prev_mpath = new_mpath; - } - mp_node = mp_next_node; + mpath_changed = true; + UNSET_FLAG(cur_iterator->flags, BGP_PATH_MULTIPATH); } + + cur_iterator = cur_iterator->next; } if (new_best) { - bgp_path_info_mpath_count_set(new_best, mpath_count - 1); - if (mpath_count <= 1 || - (!ecommunity_linkbw_present(bgp_attr_get_ecommunity( - new_best->attr), - &bwval) && - !ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity( - new_best->attr), - &bwval))) - all_paths_lb = false; - else - cum_bw += bwval; - bgp_path_info_mpath_lb_update(new_best, true, - all_paths_lb, cum_bw); - + if (mpath_count > 1 || new_best->mpath) { + bgp_path_info_mpath_count_set(new_best, mpath_count); + bgp_path_info_mpath_lb_update(new_best, true, all_paths_lb, cum_bw); + } if (debug) zlog_debug("%pBD(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64, dest, bgp->name_pretty, mpath_count, mpath_changed ? "YES" : "NO", all_paths_lb, cum_bw); + if (mpath_count == 1) + UNSET_FLAG(new_best->flags, BGP_PATH_MULTIPATH); if (mpath_changed || (bgp_path_info_mpath_count(new_best) != old_mpath_count)) SET_FLAG(new_best->flags, BGP_PATH_MULTIPATH_CHG); - if ((mpath_count - 1) != old_mpath_count || - old_cum_bw != cum_bw) + if ((mpath_count) != old_mpath_count || old_cum_bw != cum_bw) SET_FLAG(new_best->flags, BGP_PATH_LINK_BW_CHG); } } /* - * bgp_mp_dmed_deselect - * - * Clean up multipath information for BGP_PATH_DMED_SELECTED path that - * is not selected as best path - */ -void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best) -{ - struct bgp_path_info *mpinfo, *mpnext; - - if (!dmed_best) - return; - - for (mpinfo = bgp_path_info_mpath_first(dmed_best); mpinfo; - mpinfo = mpnext) { - mpnext = bgp_path_info_mpath_next(mpinfo); - bgp_path_info_mpath_dequeue(mpinfo); - } - - bgp_path_info_mpath_count_set(dmed_best, 0); - UNSET_FLAG(dmed_best->flags, BGP_PATH_MULTIPATH_CHG); - UNSET_FLAG(dmed_best->flags, BGP_PATH_LINK_BW_CHG); - assert(bgp_path_info_mpath_first(dmed_best) == NULL); -} - -/* * bgp_path_info_mpath_aggregate_update * * Set the multipath aggregate attribute. We need to see if the @@ -843,7 +604,7 @@ void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best, if (!new_best) return; - if (!bgp_path_info_mpath_count(new_best)) { + if (bgp_path_info_mpath_count(new_best) == 1) { if ((new_attr = bgp_path_info_mpath_attr(new_best))) { bgp_attr_unintern(&new_attr); bgp_path_info_mpath_attr_set(new_best, NULL); diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h index 129682d1dc..c5a009a4c8 100644 --- a/bgpd/bgp_mpath.h +++ b/bgpd/bgp_mpath.h @@ -2,8 +2,9 @@ /* * BGP Multipath * Copyright (C) 2010 Google Inc. + * 2024 Nvidia Corporation * - * This file is part of Quagga + * This file is part of FRR */ #ifndef _FRR_BGP_MPATH_H @@ -13,27 +14,24 @@ * multipath selections, lazily allocated to save memory */ struct bgp_path_info_mpath { - /* Points to the first multipath (on bestpath) or the next multipath */ - struct bgp_path_info_mpath *mp_next; - - /* Points to the previous multipath or NULL on bestpath */ - struct bgp_path_info_mpath *mp_prev; - /* Points to bgp_path_info associated with this multipath info */ struct bgp_path_info *mp_info; /* When attached to best path, the number of selected multipaths */ uint16_t mp_count; - /* Flags - relevant as noted. */ + /* Flags - relevant as noted, attached to bestpath. */ uint16_t mp_flags; #define BGP_MP_LB_PRESENT 0x1 /* Link-bandwidth present for >= 1 path */ #define BGP_MP_LB_ALL 0x2 /* Link-bandwidth present for all multipaths */ - /* Aggregated attribute for advertising multipath route */ + /* + * Aggregated attribute for advertising multipath route, + * attached to bestpath + */ struct attr *mp_attr; - /* Cumulative bandiwdth of all multipaths - attached to best path. */ + /* Cumulative bandiwdth of all multipaths - attached to bestpath. */ uint64_t cum_bw; }; @@ -47,23 +45,16 @@ extern int bgp_maximum_paths_unset(struct bgp *bgp, afi_t afi, safi_t safi, /* Functions used by bgp_best_selection to record current * multipath selections */ -extern int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, - struct bgp_path_info *bpi2); -extern void bgp_mp_list_init(struct list *mp_list); -extern void bgp_mp_list_clear(struct list *mp_list); -extern void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo); -extern void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best); +extern int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, struct bgp_path_info *bpi2); extern void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *new_best, - struct bgp_path_info *old_best, - struct list *mp_list, + struct bgp_path_info *old_best, uint32_t num_candidates, struct bgp_maxpaths_cfg *mpath_cfg); extern void bgp_path_info_mpath_aggregate_update(struct bgp_path_info *new_best, struct bgp_path_info *old_best); /* Unlink and free multipath information associated with a bgp_path_info */ -extern void bgp_path_info_mpath_dequeue(struct bgp_path_info *path); extern void bgp_path_info_mpath_free(struct bgp_path_info_mpath **mpath); /* Walk list of multipaths associated with a best path */ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 432ead7936..13da55ffb7 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -34,6 +34,7 @@ #include "bgpd/bgp_nht.h" #include "bgpd/bgp_evpn.h" #include "bgpd/bgp_memory.h" +#include "bgpd/bgp_aspath.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -385,6 +386,18 @@ void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi) if (!vrf) return; + if (bgp->vpn_policy[afi].tovpn_sid_locator) { + ctx.block_len = + bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length; + ctx.node_len = + bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length; + ctx.function_len = + bgp->vpn_policy[afi] + .tovpn_sid_locator->function_bits_length; + ctx.argument_len = + bgp->vpn_policy[afi] + .tovpn_sid_locator->argument_bits_length; + } ctx.table = vrf->data.l.table_id; act = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4 : ZEBRA_SEG6_LOCAL_ACTION_END_DT6; @@ -436,6 +449,12 @@ void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp) if (!vrf) return; + if (bgp->tovpn_sid_locator) { + ctx.block_len = bgp->tovpn_sid_locator->block_bits_length; + ctx.node_len = bgp->tovpn_sid_locator->node_bits_length; + ctx.function_len = bgp->tovpn_sid_locator->function_bits_length; + ctx.argument_len = bgp->tovpn_sid_locator->argument_bits_length; + } ctx.table = vrf->data.l.table_id; act = ZEBRA_SEG6_LOCAL_ACTION_END_DT46; zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx); @@ -475,6 +494,7 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi) { int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); struct srv6_sid_ctx ctx = {}; + struct seg6local_context seg6localctx = {}; if (bgp->vrf_id == VRF_UNKNOWN) { if (debug) @@ -487,9 +507,22 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi) zlog_debug("%s: deleting sid for vrf %s afi (id=%d)", __func__, bgp->name_pretty, bgp->vrf_id); + if (bgp->vpn_policy[afi].tovpn_sid_locator) { + seg6localctx.block_len = + bgp->vpn_policy[afi].tovpn_sid_locator->block_bits_length; + seg6localctx.node_len = + bgp->vpn_policy[afi].tovpn_sid_locator->node_bits_length; + seg6localctx.function_len = + bgp->vpn_policy[afi] + .tovpn_sid_locator->function_bits_length; + seg6localctx.argument_len = + bgp->vpn_policy[afi] + .tovpn_sid_locator->argument_bits_length; + } zclient_send_localsid(zclient, - bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent, - bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL); + bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent, + bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, + &seg6localctx); XFREE(MTYPE_BGP_SRV6_SID, bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent); bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = NULL; @@ -508,6 +541,7 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp) { int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); struct srv6_sid_ctx ctx = {}; + struct seg6local_context seg6localctx = {}; if (bgp->vrf_id == VRF_UNKNOWN) { if (debug) @@ -521,9 +555,18 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp) zlog_debug("%s: deleting sid for vrf %s (id=%d)", __func__, bgp->name_pretty, bgp->vrf_id); + if (bgp->tovpn_sid_locator) { + seg6localctx.block_len = + bgp->tovpn_sid_locator->block_bits_length; + seg6localctx.node_len = bgp->tovpn_sid_locator->node_bits_length; + seg6localctx.function_len = + bgp->tovpn_sid_locator->function_bits_length; + seg6localctx.argument_len = + bgp->tovpn_sid_locator->argument_bits_length; + } zclient_send_localsid(zclient, bgp->tovpn_zebra_vrf_sid_last_sent, bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, - NULL); + &seg6localctx); XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent); bgp->tovpn_zebra_vrf_sid_last_sent = NULL; @@ -2114,6 +2157,7 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ struct bgp *src_vrf; struct interface *ifp = NULL; char rd_buf[RD_ADDRSTRLEN]; + struct aspath *new_aspath; int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); @@ -2171,6 +2215,32 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ return; } + bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); + + /* Check if leaked route has our asn. If so, don't import it. */ + if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as)) { + for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; + bpi = bpi->next) { + if (bpi->extra && bpi->extra->vrfleak && + (struct bgp_path_info *)bpi->extra->vrfleak->parent == + path_vpn) { + break; + } + } + + if (bpi) { + if (debug) + zlog_debug("%s: blocking import of %p, as-path match", + __func__, bpi); + bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi); + bgp_path_info_delete(bn, bpi); + bgp_process(to_bgp, bn, bpi, afi, safi); + } + bgp_dest_unlock_node(bn); + + return; + } + if (debug) zlog_debug("%s: updating RD %s, %pFX to %s", __func__, rd_buf, p, to_bgp->name_pretty); @@ -2323,6 +2393,21 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ nexthop_self_flag = 0; } + /* + * if the asn values are different, copy the asn of the source vrf + * into the entry before importing. This helps with as-path loop + * detection + */ + if (path_vpn->extra && path_vpn->extra->vrfleak && + path_vpn->extra->vrfleak->bgp_orig && + (to_bgp->as != path_vpn->extra->vrfleak->bgp_orig->as)) { + new_aspath = aspath_dup(static_attr.aspath); + new_aspath = + aspath_add_seq(new_aspath, + path_vpn->extra->vrfleak->bgp_orig->as); + static_attr.aspath = new_aspath; + } + new_attr = bgp_attr_intern(&static_attr); bgp_attr_flush(&static_attr); @@ -3824,7 +3909,8 @@ void bgp_vpn_leak_unimport(struct bgp *from_bgp) bool is_vrf_leak_bind; int debug; - if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) + if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF && + from_bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) return; debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index e09dbc22af..de57d91806 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -861,8 +861,7 @@ int bgp_connect(struct peer_connection *connection) htons(peer->port), ifindex); } -/* After TCP connection is established. Get local address and port. */ -int bgp_getsockname(struct peer *peer) +void bgp_updatesockname(struct peer *peer) { if (peer->su_local) { sockunion_free(peer->su_local); @@ -876,6 +875,12 @@ int bgp_getsockname(struct peer *peer) peer->su_local = sockunion_getsockname(peer->connection->fd); peer->su_remote = sockunion_getpeername(peer->connection->fd); +} + +/* After TCP connection is established. Get local address and port. */ +int bgp_getsockname(struct peer *peer) +{ + bgp_updatesockname(peer); if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote, &peer->nexthop, peer)) { diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index 7a0b3cc67d..ceb6b6f002 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -23,6 +23,7 @@ extern void bgp_close_vrf_socket(struct bgp *bgp); extern void bgp_close(void); extern int bgp_connect(struct peer_connection *connection); extern int bgp_getsockname(struct peer *peer); +extern void bgp_updatesockname(struct peer *peer); extern int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p, const char *password); diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index c89ccc9792..8719af56b3 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -607,10 +607,10 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, } if (nhr->metric != bnc->metric) - bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED; + SET_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED); if (nhr->nexthop_num != bnc->nexthop_num) - bnc->change_flags |= BGP_NEXTHOP_CHANGED; + SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); if (import_check && (nhr->type == ZEBRA_ROUTE_BGP || !prefix_same(&bnc->prefix, &nhr->prefix))) { @@ -636,11 +636,12 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); if (!bnc->is_evpn_gwip_nexthop) - bnc->flags |= BGP_NEXTHOP_VALID; + SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); bnc->metric = nhr->metric; bnc->nexthop_num = nhr->nexthop_num; - bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */ + UNSET_FLAG(bnc->flags, + BGP_NEXTHOP_LABELED_VALID); /* check below */ for (i = 0; i < nhr->nexthop_num; i++) { int num_labels = 0; @@ -670,8 +671,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, /* There is at least one label-switched path */ if (nexthop->nh_label && nexthop->nh_label->num_labels) { - - bnc->flags |= BGP_NEXTHOP_LABELED_VALID; + SET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID); num_labels = nexthop->nh_label->num_labels; } @@ -695,7 +695,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, * determined * that there has been a change. */ - if (bnc->change_flags & BGP_NEXTHOP_CHANGED) + if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) continue; for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next) @@ -703,7 +703,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, break; if (!oldnh) - bnc->change_flags |= BGP_NEXTHOP_CHANGED; + SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); } bnc_nexthop_free(bnc); bnc->nexthop = nhlist_head; @@ -727,19 +727,22 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, : "failed")); if (evpn_resolved) { - bnc->flags |= BGP_NEXTHOP_VALID; - bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; - bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED; + SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + UNSET_FLAG(bnc->flags, + BGP_NEXTHOP_EVPN_INCOMPLETE); + SET_FLAG(bnc->change_flags, + BGP_NEXTHOP_MACIP_CHANGED); } else { - bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE; - bnc->flags &= ~BGP_NEXTHOP_VALID; + SET_FLAG(bnc->flags, + BGP_NEXTHOP_EVPN_INCOMPLETE); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); } } } else { memset(&bnc->resolved_prefix, 0, sizeof(bnc->resolved_prefix)); - bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; - bnc->flags &= ~BGP_NEXTHOP_VALID; - bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID); bnc->nexthop_num = nhr->nexthop_num; /* notify bgp fsm if nbr ip goes from valid->invalid */ @@ -1181,7 +1184,7 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) static void register_zebra_rnh(struct bgp_nexthop_cache *bnc) { /* Check if we have already registered */ - if (bnc->flags & BGP_NEXTHOP_REGISTERED) + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) return; if (bnc->ifindex_ipv6_ll) { diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index fa03f1d21d..62be7ffbf7 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -2702,6 +2702,19 @@ static int bgp_notify_receive(struct peer_connection *connection, inner.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM) UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + /* Resend the next OPEN message with a global AS number if we received + * a `Bad Peer AS` notification. This is only valid if `dual-as` is + * configured. + */ + if (inner.code == BGP_NOTIFY_OPEN_ERR && + inner.subcode == BGP_NOTIFY_OPEN_BAD_PEER_AS && + CHECK_FLAG(peer->flags, PEER_FLAG_DUAL_AS)) { + if (peer->change_local_as != peer->bgp->as) + peer->change_local_as = peer->bgp->as; + else + peer->change_local_as = peer->local_as; + } + /* If Graceful-Restart N-bit (Notification) is exchanged, * and it's not a Hard Reset, let's retain the routes. */ diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 43682de413..2d61c0f00a 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -173,33 +173,33 @@ static int snprintf_bgp_pbr_match_val(char *str, int len, ptr += delta; len -= delta; } else { - if (mval->unary_operator & OPERATOR_UNARY_OR) { + if (CHECK_FLAG(mval->unary_operator, OPERATOR_UNARY_OR)) { delta = snprintf(ptr, len, ", or "); ptr += delta; len -= delta; } - if (mval->unary_operator & OPERATOR_UNARY_AND) { + if (CHECK_FLAG(mval->unary_operator, OPERATOR_UNARY_AND)) { delta = snprintf(ptr, len, ", and "); ptr += delta; len -= delta; } } - if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN) { + if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_LESS_THAN)) { delta = snprintf(ptr, len, "<"); ptr += delta; len -= delta; } - if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN) { + if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_GREATER_THAN)) { delta = snprintf(ptr, len, ">"); ptr += delta; len -= delta; } - if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO) { + if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_EQUAL_TO)) { delta = snprintf(ptr, len, "="); ptr += delta; len -= delta; } - if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH) { + if (CHECK_FLAG(mval->compare_operator, OPERATOR_COMPARE_EXACT_MATCH)) { delta = snprintf(ptr, len, "match"); ptr += delta; len -= delta; @@ -287,9 +287,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite( { if (unary_operator == OPERATOR_UNARY_AND && and_valmask) { if (type_entry == FLOWSPEC_TCP_FLAGS) { - and_valmask->mask |= - TCP_HEADER_ALL_FLAGS & - ~(value); + SET_FLAG(and_valmask->mask, CHECK_FLAG(TCP_HEADER_ALL_FLAGS, ~(value))); } else if (type_entry == FLOWSPEC_DSCP || type_entry == FLOWSPEC_FLOW_LABEL || type_entry == FLOWSPEC_PKT_LEN || @@ -302,9 +300,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite( sizeof(struct bgp_pbr_val_mask)); if (type_entry == FLOWSPEC_TCP_FLAGS) { and_valmask->val = TCP_HEADER_ALL_FLAGS; - and_valmask->mask |= - TCP_HEADER_ALL_FLAGS & - ~(value); + SET_FLAG(and_valmask->mask, CHECK_FLAG(TCP_HEADER_ALL_FLAGS, ~(value))); } else if (type_entry == FLOWSPEC_DSCP || type_entry == FLOWSPEC_FLOW_LABEL || type_entry == FLOWSPEC_FRAGMENT || @@ -346,14 +342,10 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[], if (i != 0 && list[i].unary_operator != unary_operator) return false; - if (!(list[i].compare_operator & - OPERATOR_COMPARE_EQUAL_TO) && - !(list[i].compare_operator & - OPERATOR_COMPARE_EXACT_MATCH)) { - if ((list[i].compare_operator & - OPERATOR_COMPARE_LESS_THAN) && - (list[i].compare_operator & - OPERATOR_COMPARE_GREATER_THAN)) { + if (!CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_EQUAL_TO) && + !CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_EXACT_MATCH)) { + if (CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_LESS_THAN) && + CHECK_FLAG(list[i].compare_operator, OPERATOR_COMPARE_GREATER_THAN)) { ret = bgp_pbr_extract_enumerate_unary_opposite( unary_operator, and_valmask, or_valmask, list[i].value, @@ -366,15 +358,15 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[], } if (unary_operator == OPERATOR_UNARY_AND && and_valmask) { if (type_entry == FLOWSPEC_TCP_FLAGS) - and_valmask->mask |= - TCP_HEADER_ALL_FLAGS & list[i].value; + SET_FLAG(and_valmask->mask, + CHECK_FLAG(TCP_HEADER_ALL_FLAGS, list[i].value)); } else if (unary_operator == OPERATOR_UNARY_OR && or_valmask) { and_valmask = XCALLOC(MTYPE_PBR_VALMASK, sizeof(struct bgp_pbr_val_mask)); if (type_entry == FLOWSPEC_TCP_FLAGS) { and_valmask->val = TCP_HEADER_ALL_FLAGS; - and_valmask->mask |= - TCP_HEADER_ALL_FLAGS & list[i].value; + SET_FLAG(and_valmask->mask, + CHECK_FLAG(TCP_HEADER_ALL_FLAGS, list[i].value)); } else if (type_entry == FLOWSPEC_DSCP || type_entry == FLOWSPEC_FLOW_LABEL || type_entry == FLOWSPEC_ICMP_TYPE || @@ -402,8 +394,8 @@ static bool bgp_pbr_extract_enumerate(struct bgp_pbr_match_val list[], uint8_t unary_operator_val; bool double_check = false; - if ((unary_operator & OPERATOR_UNARY_OR) && - (unary_operator & OPERATOR_UNARY_AND)) { + if (CHECK_FLAG(unary_operator, OPERATOR_UNARY_OR) && + CHECK_FLAG(unary_operator, OPERATOR_UNARY_AND)) { unary_operator_val = OPERATOR_UNARY_AND; double_check = true; } else @@ -431,12 +423,12 @@ static uint8_t bgp_pbr_match_val_get_operator(struct bgp_pbr_match_val list[], for (i = 0; i < num; i++) { if (i == 0) continue; - if (list[i].unary_operator & OPERATOR_UNARY_OR) + if (CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_OR)) unary_operator = OPERATOR_UNARY_OR; - if ((list[i].unary_operator & OPERATOR_UNARY_AND - && unary_operator == OPERATOR_UNARY_OR) || - (list[i].unary_operator & OPERATOR_UNARY_OR - && unary_operator == OPERATOR_UNARY_AND)) + if ((CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_AND) && + unary_operator == OPERATOR_UNARY_OR) || + (CHECK_FLAG(list[i].unary_operator, OPERATOR_UNARY_OR) && + unary_operator == OPERATOR_UNARY_AND)) return 0; } return unary_operator; @@ -723,8 +715,8 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api) } } - } else if (!(api->match_bitmask & PREFIX_SRC_PRESENT) && - !(api->match_bitmask & PREFIX_DST_PRESENT)) { + } else if (!CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT) && + !CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) { if (BGP_DEBUG(pbr, PBR)) { bgp_pbr_print_policy_route(api); zlog_debug("BGP: match actions without src or dst address can not operate. ignoring."); @@ -775,21 +767,18 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, } api_action = &api->actions[action_count - 1]; - if ((ecom_eval->val[1] == - (char)ECOMMUNITY_REDIRECT_VRF) && - (ecom_eval->val[0] == - (char)ECOMMUNITY_ENCODE_TRANS_EXP || + if ((ecom_eval->val[1] == ECOMMUNITY_REDIRECT_VRF) && + (ecom_eval->val[0] == ECOMMUNITY_ENCODE_TRANS_EXP || ecom_eval->val[0] == - (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 || + ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 || ecom_eval->val[0] == - (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) { + ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) { struct ecommunity *eckey = ecommunity_new(); struct ecommunity_val ecom_copy; memcpy(&ecom_copy, ecom_eval, sizeof(struct ecommunity_val)); - ecom_copy.val[0] &= - ~ECOMMUNITY_ENCODE_TRANS_EXP; + UNSET_FLAG(ecom_copy.val[0], ECOMMUNITY_ENCODE_TRANS_EXP); ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET; ecommunity_add_val(eckey, &ecom_copy, false, false); @@ -800,9 +789,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, eckey); ecommunity_free(&eckey); } else if ((ecom_eval->val[0] == - (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH) && + ECOMMUNITY_ENCODE_REDIRECT_IP_NH) && (ecom_eval->val[1] == - (char)ECOMMUNITY_REDIRECT_IP_NH)) { + ECOMMUNITY_REDIRECT_IP_NH)) { /* in case the 2 ecom present, * do not overwrite * draft-ietf-idr-flowspec-redirect @@ -861,10 +850,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, = ecom_eval->val[7]; api_action_redirect_ip = api_action; } - } else if ((ecom_eval->val[0] == - (char)ECOMMUNITY_ENCODE_IP) && + } else if ((ecom_eval->val[0] == ECOMMUNITY_ENCODE_IP) && (ecom_eval->val[1] == - (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) { + ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4)) { /* in case the 2 ecom present, * overwrite simpson draft * update redirect ip fields @@ -888,7 +876,7 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, } } else { if (ecom_eval->val[0] != - (char)ECOMMUNITY_ENCODE_TRANS_EXP) + ECOMMUNITY_ENCODE_TRANS_EXP) continue; ret = ecommunity_fill_pbr_action(ecom_eval, api_action, @@ -920,9 +908,9 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, } api_action = &api->actions[action_count - 1]; if ((ipv6_ecom_eval->val[1] == - (char)ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) && + ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) && (ipv6_ecom_eval->val[0] == - (char)ECOMMUNITY_ENCODE_TRANS_EXP)) { + ECOMMUNITY_ENCODE_TRANS_EXP)) { struct ecommunity *eckey = ecommunity_new(); struct ecommunity_val_ipv6 ecom_copy; @@ -958,12 +946,12 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, return -1; /* check inconsistency in the match rule */ - if (api->match_bitmask & PREFIX_SRC_PRESENT) { + if (CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT)) { src = &api->src_prefix; afi = family2afi(src->family); valid_prefix = 1; } - if (api->match_bitmask & PREFIX_DST_PRESENT) { + if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) { dst = &api->dst_prefix; if (valid_prefix && afi != family2afi(dst->family)) { if (BGP_DEBUG(pbr, PBR)) { @@ -1207,12 +1195,10 @@ bool bgp_pbr_rule_hash_equal(const void *arg1, const void *arg2) if (r1->action != r2->action) return false; - if ((r1->flags & MATCH_IP_SRC_SET) && - !prefix_same(&r1->src, &r2->src)) + if (CHECK_FLAG(r1->flags, MATCH_IP_SRC_SET) && !prefix_same(&r1->src, &r2->src)) return false; - if ((r1->flags & MATCH_IP_DST_SET) && - !prefix_same(&r1->dst, &r2->dst)) + if (CHECK_FLAG(r1->flags, MATCH_IP_DST_SET) && !prefix_same(&r1->dst, &r2->dst)) return false; return true; @@ -1429,7 +1415,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api) delta = snprintf(ptr, sizeof(return_string), "MATCH : "); len -= delta; ptr += delta; - if (api->match_bitmask & PREFIX_SRC_PRESENT) { + if (CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT)) { struct prefix *p = &(api->src_prefix); if (api->src_prefix_offset) @@ -1441,7 +1427,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api) ptr += delta; INCREMENT_DISPLAY(ptr, nb_items, len); } - if (api->match_bitmask & PREFIX_DST_PRESENT) { + if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT)) { struct prefix *p = &(api->dst_prefix); INCREMENT_DISPLAY(ptr, nb_items, len); @@ -1584,21 +1570,18 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api) delta = snprintf(ptr, len, "@action "); len -= delta; ptr += delta; - if (api->actions[i].u.za.filter - & TRAFFIC_ACTION_TERMINATE) { + if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_TERMINATE)) { delta = snprintf(ptr, len, " terminate (apply filter(s))"); len -= delta; ptr += delta; } - if (api->actions[i].u.za.filter - & TRAFFIC_ACTION_DISTRIBUTE) { + if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_DISTRIBUTE)) { delta = snprintf(ptr, len, " distribute"); len -= delta; ptr += delta; } - if (api->actions[i].u.za.filter - & TRAFFIC_ACTION_SAMPLE) { + if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_SAMPLE)) { delta = snprintf(ptr, len, " sample"); len -= delta; ptr += delta; @@ -1749,12 +1732,10 @@ static int bgp_pbr_get_same_rule(struct hash_bucket *bucket, void *arg) if (r1->flags != r2->flags) return HASHWALK_CONTINUE; - if ((r1->flags & MATCH_IP_SRC_SET) && - !prefix_same(&r1->src, &r2->src)) + if (CHECK_FLAG(r1->flags, MATCH_IP_SRC_SET) && !prefix_same(&r1->src, &r2->src)) return HASHWALK_CONTINUE; - if ((r1->flags & MATCH_IP_DST_SET) && - !prefix_same(&r1->dst, &r2->dst)) + if (CHECK_FLAG(r1->flags, MATCH_IP_DST_SET) && !prefix_same(&r1->dst, &r2->dst)) return HASHWALK_CONTINUE; /* this function is used for two cases: @@ -1843,11 +1824,11 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit( pbr_rule.vrf_id = bpf->vrf_id; if (bpf->src) { prefix_copy(&pbr_rule.src, bpf->src); - pbr_rule.flags |= MATCH_IP_SRC_SET; + SET_FLAG(pbr_rule.flags, MATCH_IP_SRC_SET); } if (bpf->dst) { prefix_copy(&pbr_rule.dst, bpf->dst); - pbr_rule.flags |= MATCH_IP_DST_SET; + SET_FLAG(pbr_rule.flags, MATCH_IP_DST_SET); } bpr = &pbr_rule; /* A previous entry may already exist @@ -1870,32 +1851,32 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit( temp.family = bpf->family; if (bpf->src) { - temp.flags |= MATCH_IP_SRC_SET; + SET_FLAG(temp.flags, MATCH_IP_SRC_SET); prefix_copy(&temp2.src, bpf->src); } else temp2.src.family = bpf->family; if (bpf->dst) { - temp.flags |= MATCH_IP_DST_SET; + SET_FLAG(temp.flags, MATCH_IP_DST_SET); prefix_copy(&temp2.dst, bpf->dst); } else temp2.dst.family = bpf->family; if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) { if (bpf->protocol == IPPROTO_ICMP) - temp.flags |= MATCH_ICMP_SET; - temp.flags |= MATCH_PORT_SRC_SET; + SET_FLAG(temp.flags, MATCH_ICMP_SET); + SET_FLAG(temp.flags, MATCH_PORT_SRC_SET); temp2.src_port_min = src_port->min_port; if (src_port->max_port) { - temp.flags |= MATCH_PORT_SRC_RANGE_SET; + SET_FLAG(temp.flags, MATCH_PORT_SRC_RANGE_SET); temp2.src_port_max = src_port->max_port; } } if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) { if (bpf->protocol == IPPROTO_ICMP) - temp.flags |= MATCH_ICMP_SET; - temp.flags |= MATCH_PORT_DST_SET; + SET_FLAG(temp.flags, MATCH_ICMP_SET); + SET_FLAG(temp.flags, MATCH_PORT_DST_SET); temp2.dst_port_min = dst_port->min_port; if (dst_port->max_port) { - temp.flags |= MATCH_PORT_DST_RANGE_SET; + SET_FLAG(temp.flags, MATCH_PORT_DST_RANGE_SET); temp2.dst_port_max = dst_port->max_port; } } @@ -1907,7 +1888,7 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit( temp.pkt_len_max = pkt_len->max_port; } else if (bpf->pkt_len_val) { if (bpf->pkt_len_val->mask) - temp.flags |= MATCH_PKT_LEN_INVERSE_SET; + SET_FLAG(temp.flags, MATCH_PKT_LEN_INVERSE_SET); temp.pkt_len_min = bpf->pkt_len_val->val; } if (bpf->tcp_flags) { @@ -1916,32 +1897,32 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit( } if (bpf->dscp) { if (bpf->dscp->mask) - temp.flags |= MATCH_DSCP_INVERSE_SET; + SET_FLAG(temp.flags, MATCH_DSCP_INVERSE_SET); else - temp.flags |= MATCH_DSCP_SET; + SET_FLAG(temp.flags, MATCH_DSCP_SET); temp.dscp_value = bpf->dscp->val; } if (bpf->flow_label) { if (bpf->flow_label->mask) - temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET; + SET_FLAG(temp.flags, MATCH_FLOW_LABEL_INVERSE_SET); else - temp.flags |= MATCH_FLOW_LABEL_SET; + SET_FLAG(temp.flags, MATCH_FLOW_LABEL_SET); temp.flow_label = bpf->flow_label->val; } if (bpf->fragment) { if (bpf->fragment->mask) - temp.flags |= MATCH_FRAGMENT_INVERSE_SET; + SET_FLAG(temp.flags, MATCH_FRAGMENT_INVERSE_SET); temp.fragment = bpf->fragment->val; } if (bpf->src == NULL || bpf->dst == NULL) { - if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)) + if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))) temp.type = IPSET_NET_PORT; else temp.type = IPSET_NET; } else { - if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)) + if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))) temp.type = IPSET_NET_PORT_NET; else temp.type = IPSET_NET_NET; @@ -2319,11 +2300,11 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, pbr_rule.vrf_id = bpf->vrf_id; pbr_rule.priority = 20; if (bpf->src) { - pbr_rule.flags |= MATCH_IP_SRC_SET; + SET_FLAG(pbr_rule.flags, MATCH_IP_SRC_SET); prefix_copy(&pbr_rule.src, bpf->src); } if (bpf->dst) { - pbr_rule.flags |= MATCH_IP_DST_SET; + SET_FLAG(pbr_rule.flags, MATCH_IP_DST_SET); prefix_copy(&pbr_rule.dst, bpf->dst); } pbr_rule.action = bpa; @@ -2380,32 +2361,32 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, temp.vrf_id = bpf->vrf_id; temp.family = bpf->family; if (bpf->src) - temp.flags |= MATCH_IP_SRC_SET; + SET_FLAG(temp.flags, MATCH_IP_SRC_SET); if (bpf->dst) - temp.flags |= MATCH_IP_DST_SET; + SET_FLAG(temp.flags, MATCH_IP_DST_SET); if (src_port && (src_port->min_port || bpf->protocol == IPPROTO_ICMP)) { if (bpf->protocol == IPPROTO_ICMP) - temp.flags |= MATCH_ICMP_SET; - temp.flags |= MATCH_PORT_SRC_SET; + SET_FLAG(temp.flags, MATCH_ICMP_SET); + SET_FLAG(temp.flags, MATCH_PORT_SRC_SET); } if (dst_port && (dst_port->min_port || bpf->protocol == IPPROTO_ICMP)) { if (bpf->protocol == IPPROTO_ICMP) - temp.flags |= MATCH_ICMP_SET; - temp.flags |= MATCH_PORT_DST_SET; + SET_FLAG(temp.flags, MATCH_ICMP_SET); + SET_FLAG(temp.flags, MATCH_PORT_DST_SET); } if (src_port && src_port->max_port) - temp.flags |= MATCH_PORT_SRC_RANGE_SET; + SET_FLAG(temp.flags, MATCH_PORT_SRC_RANGE_SET); if (dst_port && dst_port->max_port) - temp.flags |= MATCH_PORT_DST_RANGE_SET; + SET_FLAG(temp.flags, MATCH_PORT_DST_RANGE_SET); if (bpf->src == NULL || bpf->dst == NULL) { - if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)) + if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))) temp.type = IPSET_NET_PORT; else temp.type = IPSET_NET; } else { - if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)) + if (CHECK_FLAG(temp.flags, (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET))) temp.type = IPSET_NET_PORT_NET; else temp.type = IPSET_NET_NET; @@ -2416,7 +2397,7 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, temp.pkt_len_max = pkt_len->max_port; } else if (bpf->pkt_len_val) { if (bpf->pkt_len_val->mask) - temp.flags |= MATCH_PKT_LEN_INVERSE_SET; + SET_FLAG(temp.flags, MATCH_PKT_LEN_INVERSE_SET); temp.pkt_len_min = bpf->pkt_len_val->val; } if (bpf->tcp_flags) { @@ -2425,26 +2406,26 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, } if (bpf->dscp) { if (bpf->dscp->mask) - temp.flags |= MATCH_DSCP_INVERSE_SET; + SET_FLAG(temp.flags, MATCH_DSCP_INVERSE_SET); else - temp.flags |= MATCH_DSCP_SET; + SET_FLAG(temp.flags, MATCH_DSCP_SET); temp.dscp_value = bpf->dscp->val; } if (bpf->flow_label) { if (bpf->flow_label->mask) - temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET; + SET_FLAG(temp.flags, MATCH_FLOW_LABEL_INVERSE_SET); else - temp.flags |= MATCH_FLOW_LABEL_SET; + SET_FLAG(temp.flags, MATCH_FLOW_LABEL_SET); temp.flow_label = bpf->flow_label->val; } if (bpf->fragment) { if (bpf->fragment->mask) - temp.flags |= MATCH_FRAGMENT_INVERSE_SET; + SET_FLAG(temp.flags, MATCH_FRAGMENT_INVERSE_SET); temp.fragment = bpf->fragment->val; } if (bpf->protocol) { temp.protocol = bpf->protocol; - temp.flags |= MATCH_PROTOCOL_SET; + SET_FLAG(temp.flags, MATCH_PROTOCOL_SET); } temp.action = bpa; bpm = hash_get(bgp->pbr_match_hash, &temp, @@ -2661,13 +2642,13 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path, memset(&nh, 0, sizeof(nh)); memset(&bpf, 0, sizeof(bpf)); memset(&bpof, 0, sizeof(bpof)); - if (api->match_bitmask & PREFIX_SRC_PRESENT || + if (CHECK_FLAG(api->match_bitmask, PREFIX_SRC_PRESENT) || (api->type == BGP_PBR_IPRULE && - api->match_bitmask_iprule & PREFIX_SRC_PRESENT)) + CHECK_FLAG(api->match_bitmask_iprule, PREFIX_SRC_PRESENT))) src = &api->src_prefix; - if (api->match_bitmask & PREFIX_DST_PRESENT || + if (CHECK_FLAG(api->match_bitmask, PREFIX_DST_PRESENT) || (api->type == BGP_PBR_IPRULE && - api->match_bitmask_iprule & PREFIX_DST_PRESENT)) + CHECK_FLAG(api->match_bitmask_iprule, PREFIX_DST_PRESENT))) dst = &api->dst_prefix; if (api->type == BGP_PBR_IPRULE) bpf.type = api->type; @@ -2812,8 +2793,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path, } break; case ACTION_TRAFFIC_ACTION: - if (api->actions[i].u.za.filter - & TRAFFIC_ACTION_SAMPLE) { + if (CHECK_FLAG(api->actions[i].u.za.filter, TRAFFIC_ACTION_SAMPLE)) { if (BGP_DEBUG(pbr, PBR)) { bgp_pbr_print_policy_route(api); zlog_warn("PBR: Sample action Ignored"); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3c0f0c8b53..8dbb4e3b04 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -525,8 +525,6 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest, else bgp_dest_set_bgp_path_info(dest, pi->next); - bgp_path_info_mpath_dequeue(pi); - pi->next = NULL; pi->prev = NULL; @@ -541,8 +539,6 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest, static struct bgp_dest *bgp_path_info_reap_unsorted(struct bgp_dest *dest, struct bgp_path_info *pi) { - bgp_path_info_mpath_dequeue(pi); - pi->next = NULL; pi->prev = NULL; @@ -2173,8 +2169,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, from = pi->peer; filter = &peer->filter[afi][safi]; bgp = SUBGRP_INST(subgrp); - piattr = bgp_path_info_mpath_count(pi) ? bgp_path_info_mpath_attr(pi) - : pi->attr; + piattr = bgp_path_info_mpath_count(pi) > 1 ? bgp_path_info_mpath_attr(pi) : pi->attr; if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT) && peer->pmax_out[afi][safi] != 0 && @@ -2472,13 +2467,16 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, if (NEXTHOP_IS_V6) { attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; if ((CHECK_FLAG(peer->af_flags[afi][safi], - PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) - && IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) - || (!reflect && !transparent - && IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) - && peer->shared_network - && (from == bgp->peer_self - || peer->sort == BGP_PEER_EBGP))) { + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) && + IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) || + (!reflect && !transparent && + IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) && + peer->shared_network && + ((from == bgp->peer_self && peer->sort == BGP_PEER_EBGP) || + (from == bgp->peer_self && peer->sort != BGP_PEER_EBGP) || + (from != bgp->peer_self && + IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local) && + peer->sort == BGP_PEER_EBGP)))) { if (safi == SAFI_MPLS_VPN) attr->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL; @@ -2851,13 +2849,12 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *pi2; int paths_eq, do_mpath; bool debug, any_comparisons; - struct list mp_list; char pfx_buf[PREFIX2STR_BUFFER] = {}; char path_buf[PATH_ADDPATH_STR_BUFFER]; enum bgp_path_selection_reason reason = bgp_path_selection_none; bool unsorted_items = true; + uint32_t num_candidates = 0; - bgp_mp_list_init(&mp_list); do_mpath = (mpath_cfg->maxpaths_ebgp > 1 || mpath_cfg->maxpaths_ibgp > 1); @@ -3232,7 +3229,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, "%pBD(%s): %s is the bestpath, add to the multipath list", dest, bgp->name_pretty, path_buf); - bgp_mp_list_add(&mp_list, pi); + SET_FLAG(pi->flags, BGP_PATH_MULTIPATH_NEW); + num_candidates++; continue; } @@ -3255,15 +3253,14 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, "%pBD(%s): %s is equivalent to the bestpath, add to the multipath list", dest, bgp->name_pretty, path_buf); - bgp_mp_list_add(&mp_list, pi); + SET_FLAG(pi->flags, BGP_PATH_MULTIPATH_NEW); + num_candidates++; } } } - bgp_path_info_mpath_update(bgp, dest, new_select, old_select, &mp_list, - mpath_cfg); + bgp_path_info_mpath_update(bgp, dest, new_select, old_select, num_candidates, mpath_cfg); bgp_path_info_mpath_aggregate_update(new_select, old_select); - bgp_mp_list_clear(&mp_list); bgp_addpath_update_ids(bgp, dest, afi, safi); @@ -3618,7 +3615,16 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info_pair old_and_new; int debug = 0; - if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) { + /* + * For default bgp instance, which is deleted i.e. marked hidden + * we are skipping SAFI_MPLS_VPN route table deletion + * in bgp_cleanup_routes. + * So, we need to delete routes from VPNV4 table. + * Here for !IS_BGP_INSTANCE_HIDDEN, + * !(SAFI_MPLS_VPN && AF_IP/AF_IP6), + * we ignore the event for the prefix. + */ + if (BGP_INSTANCE_HIDDEN_DELETE_IN_PROGRESS(bgp, afi, safi)) { if (dest) debug = bgp_debug_bestpath(dest); if (debug) @@ -3757,7 +3763,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, if (old_select || new_select) { bgp_bump_version(dest); - if (!bgp->t_rmap_def_originate_eval) + if (!bgp->t_rmap_def_originate_eval && + bgp->rmap_def_originate_eval_timer) event_add_timer( bm->master, update_group_refresh_default_originate_route_map, @@ -4011,8 +4018,9 @@ static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp) return pqnode; } -void bgp_process(struct bgp *bgp, struct bgp_dest *dest, - struct bgp_path_info *pi, afi_t afi, safi_t safi) +static void bgp_process_internal(struct bgp *bgp, struct bgp_dest *dest, + struct bgp_path_info *pi, afi_t afi, + safi_t safi, bool early_process) { #define ARBITRARY_PROCESS_QLEN 10000 struct work_queue *wq = bgp->process_queue; @@ -4075,9 +4083,8 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest, struct work_queue_item *item = work_queue_last_item(wq); pqnode = item->data; - if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) - || pqnode->bgp != bgp - || pqnode->queued >= ARBITRARY_PROCESS_QLEN) + if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) || + (pqnode->queued >= ARBITRARY_PROCESS_QLEN && !early_process)) pqnode = bgp_processq_alloc(bgp); else pqnode_reuse = 1; @@ -4091,7 +4098,10 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest, /* can't be enqueued twice */ assert(STAILQ_NEXT(dest, pq) == NULL); - STAILQ_INSERT_TAIL(&pqnode->pqueue, dest, pq); + if (early_process) + STAILQ_INSERT_HEAD(&pqnode->pqueue, dest, pq); + else + STAILQ_INSERT_TAIL(&pqnode->pqueue, dest, pq); pqnode->queued++; if (!pqnode_reuse) @@ -4100,6 +4110,18 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest, return; } +void bgp_process(struct bgp *bgp, struct bgp_dest *dest, + struct bgp_path_info *pi, afi_t afi, safi_t safi) +{ + bgp_process_internal(bgp, dest, pi, afi, safi, false); +} + +void bgp_process_early(struct bgp *bgp, struct bgp_dest *dest, + struct bgp_path_info *pi, afi_t afi, safi_t safi) +{ + bgp_process_internal(bgp, dest, pi, afi, safi, true); +} + void bgp_add_eoiu_mark(struct bgp *bgp) { struct bgp_process_queue *pqnode; @@ -6428,16 +6450,21 @@ void bgp_cleanup_routes(struct bgp *bgp) if (afi != AFI_L2VPN) { safi_t safi; safi = SAFI_MPLS_VPN; - for (dest = bgp_table_top(bgp->rib[afi][safi]); dest; - dest = bgp_route_next(dest)) { - table = bgp_dest_get_bgp_table_info(dest); - if (table != NULL) { - bgp_cleanup_table(bgp, table, afi, safi); - bgp_table_finish(&table); - bgp_dest_set_bgp_table_info(dest, NULL); - dest = bgp_dest_unlock_node(dest); - - assert(dest); + if (!IS_BGP_INSTANCE_HIDDEN(bgp)) { + for (dest = bgp_table_top(bgp->rib[afi][safi]); + dest; dest = bgp_route_next(dest)) { + table = bgp_dest_get_bgp_table_info( + dest); + if (table != NULL) { + bgp_cleanup_table(bgp, table, + afi, safi); + bgp_table_finish(&table); + bgp_dest_set_bgp_table_info(dest, + NULL); + dest = bgp_dest_unlock_node( + dest); + assert(dest); + } } } safi = SAFI_ENCAP; @@ -11156,9 +11183,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, ", otc %u", attr->otc); } - if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH) - || (CHECK_FLAG(path->flags, BGP_PATH_SELECTED) - && bgp_path_info_mpath_count(path))) { + if (CHECK_FLAG(path->flags, BGP_PATH_MULTIPATH) || + (CHECK_FLAG(path->flags, BGP_PATH_SELECTED) && bgp_path_info_mpath_count(path) > 1)) { if (json_paths) json_object_boolean_true_add(json_path, "multipath"); else @@ -12141,7 +12167,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, bgp = bgp_get_default(); } - if (bgp == NULL) { + if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) { if (!use_json) vty_out(vty, "No BGP process is configured\n"); else @@ -12187,6 +12213,8 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi, vty_out(vty, "{\n"); for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (IS_BGP_INSTANCE_HIDDEN(bgp)) + continue; route_output = true; if (use_json) { if (!is_first) @@ -12705,7 +12733,7 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, { if (!bgp) { bgp = bgp_get_default(); - if (!bgp) { + if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) { if (!use_json) vty_out(vty, "No BGP process is configured\n"); else @@ -13657,6 +13685,8 @@ enum bgp_stats { BGP_STATS_ASPATH_MAXSIZE, BGP_STATS_ASPATH_TOTSIZE, BGP_STATS_ASN_HIGHEST, + BGP_STATS_REDISTRIBUTED, + BGP_STATS_LOCAL_AGGREGATES, BGP_STATS_MAX, }; @@ -13686,6 +13716,8 @@ static const char *table_stats_strs[][2] = { [BGP_STATS_ASPATH_TOTSIZE] = {"Average AS-Path size (bytes)", "averageAsPathSizeBytes"}, [BGP_STATS_ASN_HIGHEST] = {"Highest public ASN", "highestPublicAsn"}, + [BGP_STATS_REDISTRIBUTED] = {"Redistributed routes", "totalRedistributed"}, + [BGP_STATS_LOCAL_AGGREGATES] = {"Local aggregates", "totalLocalAggregates"}, [BGP_STATS_MAX] = {NULL, NULL} }; @@ -13735,6 +13767,15 @@ static void bgp_table_stats_rn(struct bgp_dest *dest, struct bgp_dest *top, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE))) ts->counts[BGP_STATS_AGGREGATES]++; + if (pi->peer == ts->table->bgp->peer_self) { + if (pi->sub_type == BGP_ROUTE_REDISTRIBUTE) + ts->counts[BGP_STATS_REDISTRIBUTED]++; + + if ((pi->type == ZEBRA_ROUTE_BGP) && + (pi->sub_type == BGP_ROUTE_AGGREGATE)) + ts->counts[BGP_STATS_LOCAL_AGGREGATES]++; + } + /* as-path stats */ if (pi->attr->aspath) { unsigned int hops = aspath_count_hops(pi->attr->aspath); @@ -14350,7 +14391,7 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix, int idx = 0; char *network = NULL; struct bgp *bgp = bgp_get_default(); - if (!bgp) { + if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) { vty_out(vty, "Can't find default instance\n"); return CMD_WARNING; } @@ -15852,7 +15893,7 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, /* BGP structure lookup. */ if (view_name) { bgp = bgp_lookup_by_name(view_name); - if (bgp == NULL) { + if (bgp == NULL || IS_BGP_INSTANCE_HIDDEN(bgp)) { vty_out(vty, "%% Can't find BGP instance %s\n", view_name); return CMD_WARNING; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index bc3ca4b2f8..d71bfd3ebc 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -313,6 +313,11 @@ struct bgp_path_info { #define BGP_PATH_STALE (1 << 8) #define BGP_PATH_REMOVED (1 << 9) #define BGP_PATH_COUNTED (1 << 10) +/* + * A BGP_PATH_MULTIPATH flag is not set on the best path + * it is set on every other node that is part of ECMP + * for that particular dest + */ #define BGP_PATH_MULTIPATH (1 << 11) #define BGP_PATH_MULTIPATH_CHG (1 << 12) #define BGP_PATH_RIB_ATTR_CHG (1 << 13) @@ -322,6 +327,15 @@ struct bgp_path_info { #define BGP_PATH_MPLSVPN_LABEL_NH (1 << 17) #define BGP_PATH_MPLSVPN_NH_LABEL_BIND (1 << 18) #define BGP_PATH_UNSORTED (1 << 19) +/* + * BGP_PATH_MULTIPATH_NEW is set on those bgp_path_info + * nodes that we have decided should possibly be in the + * ecmp path for a particular dest. This flag is + * removed when the bgp_path_info's are looked at to + * decide on whether or not a bgp_path_info is on + * the actual ecmp path. + */ +#define BGP_PATH_MULTIPATH_NEW (1 << 20) /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ uint8_t type; @@ -804,10 +818,20 @@ extern void bgp_withdraw(struct peer *peer, const struct prefix *p, int sub_type, struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels); -/* for bgp_nexthop and bgp_damp */ +/* + * Add a route to be processed for bgp bestpath through the bgp + * workqueue. This route is added to the end of all other routes + * queued for processing + * + * bgp_process_early adds the route for processing at the beginning + * of the current queue for processing. + */ extern void bgp_process(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *pi, afi_t afi, safi_t safi); +extern void bgp_process_early(struct bgp *bgp, struct bgp_dest *dest, + struct bgp_path_info *pi, afi_t afi, safi_t safi); + /* * Add an end-of-initial-update marker to the process queue. This is just a * queue element with NULL bgp node. diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index d37b171063..583b9e7980 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -251,7 +251,7 @@ route_match_peer(void *rule, const struct prefix *prefix, void *object) peer = ((struct bgp_path_info *)object)->peer; if (pc->interface) { - if (!peer->conf_if || !peer->group) + if (!peer->conf_if && !peer->group) return RMAP_NOMATCH; if (peer->conf_if && strcmp(peer->conf_if, pc->interface) == 0) @@ -2357,7 +2357,7 @@ static void route_aspath_exclude_free(void *rule) if (ase->exclude_aspath_acl) { acl = ase->exclude_aspath_acl; as_list_list_del(&acl->exclude_rule, ase); - } else { + } else if (ase->exclude_aspath_acl_name) { /* no ref to acl, this aspath exclude is orphan */ as_exclude_remove_orphan(ase); } @@ -3220,7 +3220,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) return RMAP_OKAY; bw_bytes = (peer->bgp->lb_ref_bw * 1000 * 1000) / 8; - mpath_count = bgp_path_info_mpath_count(path) + 1; + mpath_count = bgp_path_info_mpath_count(path); bw_bytes *= mpath_count; } diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index f9cbf24031..347c5d02a1 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -1920,81 +1920,6 @@ DEFUN (no_rpki_retry_interval, return CMD_SUCCESS; } -#if CONFDATE > 20240916 -CPP_NOTICE("Remove rpki_cache_cmd") -#endif -DEFPY(rpki_cache, rpki_cache_cmd, - "rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH]> [source <A.B.C.D>$bindaddr] preference (1-255)", - RPKI_OUTPUT_STRING - "Install a cache server to current group\n" - "IP address of cache server\n" - "Hostname of cache server\n" - "TCP port number\n" - "SSH port number\n" - "SSH user name\n" - "Path to own SSH private key\n" - "Path to the known hosts file\n" - "Configure source IP address of RPKI connection\n" - "Define a Source IP Address\n" - "Preference of the cache server\n" - "Preference value\n") -{ - int return_value; - struct listnode *cache_node; - struct cache *current_cache; - struct rpki_vrf *rpki_vrf; - bool init; - - if (vty->node == RPKI_VRF_NODE) - rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); - else - rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); - - if (!rpki_vrf) - return CMD_WARNING_CONFIG_FAILED; - - if (!rpki_vrf || !rpki_vrf->cache_list) - return CMD_WARNING; - - init = !!list_isempty(rpki_vrf->cache_list); - - for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, - current_cache)) { - if (current_cache->preference == preference) { - vty_out(vty, - "Cache with preference %ld is already configured\n", - preference); - return CMD_WARNING; - } - } - - // use ssh connection - if (ssh_uname) { -#if defined(FOUND_SSH) - return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname, - ssh_privkey, known_hosts_path, - preference, bindaddr_str); -#else - return_value = SUCCESS; - vty_out(vty, - "ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n"); -#endif - } else { // use tcp connection - return_value = add_tcp_cache(rpki_vrf, cache, tcpport, - preference, bindaddr_str); - } - - if (return_value == ERROR) { - vty_out(vty, "Could not create new rpki cache\n"); - return CMD_WARNING; - } - - if (init) - start(rpki_vrf); - - return CMD_SUCCESS; -} - DEFPY(rpki_cache_tcp, rpki_cache_tcp_cmd, "rpki cache tcp <A.B.C.D|WORD>$cache TCPPORT [source <A.B.C.D>$bindaddr] preference (1-255)", RPKI_OUTPUT_STRING @@ -2820,7 +2745,6 @@ static void install_cli_commands(void) /* Install rpki cache commands */ install_element(RPKI_NODE, &rpki_cache_tcp_cmd); install_element(RPKI_NODE, &rpki_cache_ssh_cmd); - install_element(RPKI_NODE, &rpki_cache_cmd); install_element(RPKI_NODE, &no_rpki_cache_cmd); /* RPKI_VRF_NODE commands */ @@ -2844,7 +2768,6 @@ static void install_cli_commands(void) /* Install rpki cache commands */ install_element(RPKI_VRF_NODE, &rpki_cache_tcp_cmd); install_element(RPKI_VRF_NODE, &rpki_cache_ssh_cmd); - install_element(RPKI_VRF_NODE, &rpki_cache_cmd); install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd); /* Install show commands */ diff --git a/bgpd/bgp_script.h b/bgpd/bgp_script.h index f2f47e940d..9feb550135 100644 --- a/bgpd/bgp_script.h +++ b/bgpd/bgp_script.h @@ -7,7 +7,6 @@ #define __BGP_SCRIPT__ #include <zebra.h> -#include "bgpd.h" #ifdef HAVE_SCRIPTING @@ -18,6 +17,10 @@ */ void bgp_script_init(void); +/* Forward references */ +struct peer; +struct attr; + void lua_pushpeer(lua_State *L, const struct peer *peer); void lua_pushattr(lua_State *L, const struct attr *attr); diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 115bc35cdc..90c43b938f 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -783,8 +783,11 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) json_updgrp, "replaceLocalAs", CHECK_FLAG(updgrp->conf->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)); + json_object_boolean_add(json_updgrp, "dualAs", + CHECK_FLAG(updgrp->conf->flags, + PEER_FLAG_DUAL_AS)); } else { - vty_out(vty, " Local AS %u%s%s\n", + vty_out(vty, " Local AS %u%s%s%s\n", updgrp->conf->change_local_as, CHECK_FLAG(updgrp->conf->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) @@ -793,6 +796,10 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) CHECK_FLAG(updgrp->conf->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ? " replace-as" + : "", + CHECK_FLAG(updgrp->conf->flags, + PEER_FLAG_DUAL_AS) + ? " dual-as" : ""); } } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index f669564bb8..e7be2a33d2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -879,6 +879,7 @@ int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret) switch (ret) { case BGP_SUCCESS: case BGP_CREATED: + case BGP_INSTANCE_EXISTS: case BGP_GR_NO_OPERATION: break; case BGP_ERR_INVALID_VALUE: @@ -1418,7 +1419,7 @@ DEFUN_HIDDEN (bgp_local_mac, seq = strtoul(argv[7]->arg, NULL, 10); bgp = bgp_get_default(); - if (!bgp) { + if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) { vty_out(vty, "Default BGP instance is not there\n"); return CMD_WARNING; } @@ -1458,7 +1459,7 @@ DEFUN_HIDDEN (no_bgp_local_mac, memset(&ip, 0, sizeof(ip)); bgp = bgp_get_default(); - if (!bgp) { + if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) { vty_out(vty, "Default BGP instance is not there\n"); return CMD_WARNING; } @@ -1601,8 +1602,12 @@ DEFUN_NOSH (router_bgp, if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT) vpn_leak_postchange_all(); - if (inst_type == BGP_INSTANCE_TYPE_VRF) + if (inst_type == BGP_INSTANCE_TYPE_VRF || + IS_BGP_INSTANCE_HIDDEN(bgp)) { bgp_vpn_leak_export(bgp); + UNSET_FLAG(bgp->flags, BGP_FLAG_INSTANCE_HIDDEN); + UNSET_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS); + } /* Pending: handle when user tries to change a view to vrf n vv. */ /* for pre-existing bgp instance, @@ -1674,7 +1679,7 @@ DEFUN (no_router_bgp, argv[idx_asn]->arg); return CMD_WARNING_CONFIG_FAILED; } - if (argc > 4) { + if (argc > 4 && strncmp(argv[4]->arg, "vrf", 3) == 0) { name = argv[idx_vrf]->arg; if (strmatch(argv[idx_vrf - 1]->text, "vrf") && strmatch(name, VRF_DEFAULT_NAME)) @@ -5451,7 +5456,7 @@ DEFUN (neighbor_local_as, return CMD_WARNING_CONFIG_FAILED; } - ret = peer_local_as_set(peer, as, 0, 0, argv[idx_number]->arg); + ret = peer_local_as_set(peer, as, 0, 0, 0, argv[idx_number]->arg); return bgp_vty_return(vty, ret); } @@ -5480,19 +5485,20 @@ DEFUN (neighbor_local_as_no_prepend, return CMD_WARNING_CONFIG_FAILED; } - ret = peer_local_as_set(peer, as, 1, 0, argv[idx_number]->arg); + ret = peer_local_as_set(peer, as, 1, 0, 0, argv[idx_number]->arg); return bgp_vty_return(vty, ret); } -DEFUN (neighbor_local_as_no_prepend_replace_as, +DEFPY (neighbor_local_as_no_prepend_replace_as, neighbor_local_as_no_prepend_replace_as_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend replace-as", + "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend replace-as [dual-as$dual_as]", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a local-as number\n" "AS number expressed in dotted or plain format used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n" - "Do not prepend local-as to updates from ibgp peers\n") + "Do not prepend local-as to updates from ibgp peers\n" + "Allow peering with a global AS number or local-as number\n") { int idx_peer = 1; int idx_number = 3; @@ -5510,20 +5516,21 @@ DEFUN (neighbor_local_as_no_prepend_replace_as, return CMD_WARNING_CONFIG_FAILED; } - ret = peer_local_as_set(peer, as, 1, 1, argv[idx_number]->arg); + ret = peer_local_as_set(peer, as, 1, 1, dual_as, argv[idx_number]->arg); return bgp_vty_return(vty, ret); } DEFUN (no_neighbor_local_as, no_neighbor_local_as_cmd, - "no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [ASNUM [no-prepend [replace-as]]]", + "no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [ASNUM [no-prepend [replace-as] [dual-as]]]", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a local-as number\n" "AS number expressed in dotted or plain format used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n" - "Do not prepend local-as to updates from ibgp peers\n") + "Do not prepend local-as to updates from ibgp peers\n" + "Allow peering with a global AS number or local-as number\n") { int idx_peer = 2; struct peer *peer; @@ -8417,7 +8424,7 @@ DEFPY (bgp_condadv_period, DEFPY (bgp_def_originate_eval, bgp_def_originate_eval_cmd, - "[no$no] bgp default-originate timer (0-3600)$timer", + "[no$no] bgp default-originate timer (0-65535)$timer", NO_STR BGP_STR "Control default-originate\n" @@ -8426,8 +8433,7 @@ DEFPY (bgp_def_originate_eval, { VTY_DECLVAR_CONTEXT(bgp, bgp); - bgp->rmap_def_originate_eval_timer = - no ? RMAP_DEFAULT_ORIGINATE_EVAL_TIMER : timer; + bgp->rmap_def_originate_eval_timer = no ? 0 : timer; if (bgp->t_rmap_def_originate_eval) EVENT_OFF(bgp->t_rmap_def_originate_eval); @@ -10445,9 +10451,9 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd, bgp_default = bgp_get_default(); if (!bgp_default) { int32_t ret; - as_t as = bgp->as; + as_t as = AS_UNSPECIFIED; - /* Auto-create assuming the same AS */ + /* Auto-create with AS_UNSPECIFIED, to be filled in later */ ret = bgp_get_vty(&bgp_default, &as, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL, ASNOTATION_UNDEFINED); @@ -10457,6 +10463,8 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd, "VRF default is not configured as a bgp instance\n"); return CMD_WARNING; } + + SET_FLAG(bgp_default->flags, BGP_FLAG_INSTANCE_HIDDEN); } vpn_leak_prechange(dir, afi, bgp_get_default(), bgp); @@ -10560,7 +10568,9 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, bgp_default = bgp_get_default(); if (!bgp_default) { - /* Auto-create assuming the same AS */ + as = AS_UNSPECIFIED; + + /* Auto-create with AS_UNSPECIFIED, to be filled in later */ ret = bgp_get_vty(&bgp_default, &as, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL, ASNOTATION_UNDEFINED); @@ -10570,6 +10580,8 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, "VRF default is not configured as a bgp instance\n"); return CMD_WARNING; } + + SET_FLAG(bgp_default->flags, BGP_FLAG_INSTANCE_HIDDEN); } vrf_bgp = bgp_lookup_by_name(import_name); @@ -10577,9 +10589,19 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) { vrf_bgp = bgp_default; } else { - /* Auto-create assuming the same AS */ + as = AS_UNSPECIFIED; + + /* Auto-create with AS_UNSPECIFIED, fill in later */ ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type, NULL, ASNOTATION_UNDEFINED); + if (ret) { + vty_out(vty, + "VRF %s is not configured as a bgp instance\n", + import_name); + return CMD_WARNING; + } + + SET_FLAG(vrf_bgp->flags, BGP_FLAG_INSTANCE_HIDDEN); /* Auto created VRF instances should be marked * properly, otherwise we have a state after bgpd @@ -10587,13 +10609,6 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, */ SET_FLAG(vrf_bgp->vrf_flags, BGP_VRF_AUTO); } - - if (ret) { - vty_out(vty, - "VRF %s is not configured as a bgp instance\n", - import_name); - return CMD_WARNING; - } } if (remove) { @@ -11550,7 +11565,7 @@ DEFUN(show_bgp_martian_nexthop_db, show_bgp_martian_nexthop_db_cmd, else bgp = bgp_get_default(); - if (!bgp) { + if (!bgp || IS_BGP_INSTANCE_HIDDEN(bgp)) { vty_out(vty, "%% No BGP process is configured\n"); return CMD_WARNING; } @@ -12782,6 +12797,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) continue; + if (IS_BGP_INSTANCE_HIDDEN(bgp)) + continue; + nbr_output = true; if (use_json) { if (!is_first) @@ -14052,6 +14070,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, if (CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)) json_object_boolean_true_add(json_neigh, "localAsReplaceAs"); + + json_object_boolean_add(json_neigh, "localAsReplaceAsDualAs", + !!CHECK_FLAG(p->flags, + PEER_FLAG_DUAL_AS)); } else { if (p->as_type == AS_SPECIFIED || CHECK_FLAG(p->as_type, AS_AUTO) || @@ -14066,13 +14088,15 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, ASN_FORMAT(bgp->asnotation), p->change_local_as ? &p->change_local_as : &p->local_as); - vty_out(vty, "%s%s, ", + vty_out(vty, "%s%s%s, ", CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? " no-prepend" : "", CHECK_FLAG(p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ? " replace-as" - : ""); + : "", + CHECK_FLAG(p->flags, PEER_FLAG_DUAL_AS) ? " dual-as" + : ""); } /* peer type internal or confed-internal */ if ((p->as == p->local_as) || (CHECK_FLAG(p->as_type, AS_INTERNAL))) { @@ -16170,6 +16194,9 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) continue; + if (IS_BGP_INSTANCE_HIDDEN(bgp)) + continue; + nbr_output = true; if (use_json) { if (!(json = json_object_new_object())) { @@ -16825,6 +16852,9 @@ static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi, if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) continue; + if (IS_BGP_INSTANCE_HIDDEN(bgp)) + continue; + if (!uj) vty_out(vty, "\nInstance %s:\n", (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) @@ -16947,7 +16977,7 @@ DEFUN (show_bgp_updgrps_stats, struct bgp *bgp; bgp = bgp_get_default(); - if (bgp) + if (bgp && !IS_BGP_INSTANCE_HIDDEN(bgp)) update_group_show_stats(bgp, vty); return CMD_SUCCESS; @@ -18664,6 +18694,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " no-prepend"); if (peergroup_flag_check(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS)) vty_out(vty, " replace-as"); + if (peergroup_flag_check(peer, PEER_FLAG_DUAL_AS)) + vty_out(vty, " dual-as"); vty_out(vty, "\n"); } @@ -18942,6 +18974,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, char *addr; bool flag_scomm, flag_secomm, flag_slcomm; + /* skip hidden default vrf bgp instance */ + if (IS_BGP_INSTANCE_HIDDEN(bgp)) + return; + /* Skip dynamic neighbors. */ if (peer_dynamic_neighbor(peer)) return; @@ -19247,6 +19283,9 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, struct peer_group *group; struct listnode *node, *nnode; + /* skip hidden default vrf bgp instance */ + if (IS_BGP_INSTANCE_HIDDEN(bgp)) + return; vty_frame(vty, " !\n address-family "); if (afi == AFI_IP) { @@ -19429,6 +19468,10 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) continue; + /* skip hidden default vrf bgp instance */ + if (IS_BGP_INSTANCE_HIDDEN(bgp)) + continue; + /* Router bgp ASN */ vty_out(vty, "router bgp %s", bgp->as_pretty); @@ -19792,8 +19835,9 @@ int bgp_config_write(struct vty *vty) bgp->condition_check_period); /* default-originate timer configuration */ - if (bgp->rmap_def_originate_eval_timer != - RMAP_DEFAULT_ORIGINATE_EVAL_TIMER) + if (bgp->rmap_def_originate_eval_timer && + bgp->rmap_def_originate_eval_timer != + RMAP_DEFAULT_ORIGINATE_EVAL_TIMER) vty_out(vty, " bgp default-originate timer %u\n", bgp->rmap_def_originate_eval_timer); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 19f26e9c75..bffa5a0e6b 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -542,7 +542,7 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) /* Now perform the add/update. */ bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex, - nhtype, bhtype, api.distance, api.metric, + nhtype, api.distance, bhtype, api.metric, api.type, api.instance, api.tag); } else { bgp_redistribute_delete(bgp, &api.prefix, api.type, diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 9d36ed9008..80b1ae39d4 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1255,7 +1255,6 @@ static void peer_free(struct peer *peer) EVENT_OFF(peer->t_revalidate_all[afi][safi]); assert(!peer->connection->t_write); assert(!peer->connection->t_read); - event_cancel_event_ready(bm->master, peer->connection); /* Free connected nexthop, if present */ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) @@ -3421,12 +3420,18 @@ static void bgp_vrf_string_name_delete(void *data) static struct bgp *bgp_create(as_t *as, const char *name, enum bgp_instance_type inst_type, const char *as_pretty, - enum asnotation_mode asnotation) + enum asnotation_mode asnotation, + struct bgp *bgp_old, bool hidden) { struct bgp *bgp; afi_t afi; safi_t safi; + if (hidden) { + bgp = bgp_old; + goto peer_init; + } + bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp)); bgp->as = *as; if (as_pretty) @@ -3480,18 +3485,24 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->peer_self->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, cmd_domainname_get()); bgp->peer = list_new(); + +peer_init: bgp->peer->cmp = (int (*)(void *, void *))peer_cmp; bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, "BGP Peer Hash"); bgp->peerhash->max_size = BGP_PEER_MAX_HASH_SIZE; - bgp->group = list_new(); + if (!hidden) + bgp->group = list_new(); bgp->group->cmp = (int (*)(void *, void *))peer_group_cmp; FOREACH_AFI_SAFI (afi, safi) { - bgp->route[afi][safi] = bgp_table_init(bgp, afi, safi); - bgp->aggregate[afi][safi] = bgp_table_init(bgp, afi, safi); - bgp->rib[afi][safi] = bgp_table_init(bgp, afi, safi); + if (!hidden) { + bgp->route[afi][safi] = bgp_table_init(bgp, afi, safi); + bgp->aggregate[afi][safi] = bgp_table_init(bgp, afi, + safi); + bgp->rib[afi][safi] = bgp_table_init(bgp, afi, safi); + } /* Enable maximum-paths */ bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_EBGP, @@ -3512,7 +3523,8 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->default_subgroup_pkt_queue_max = BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX; bgp_tcp_keepalive_unset(bgp); - bgp_timers_unset(bgp); + if (!hidden) + bgp_timers_unset(bgp); bgp->default_min_holdtime = 0; bgp->restart_time = BGP_DEFAULT_RESTART_TIME; bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; @@ -3527,10 +3539,10 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp_addpath_init_bgp_data(&bgp->tx_addpath); bgp->fast_convergence = false; bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME; - bgp->rmap_def_originate_eval_timer = RMAP_DEFAULT_ORIGINATE_EVAL_TIMER; + bgp->rmap_def_originate_eval_timer = 0; #ifdef ENABLE_BGP_VNC - if (inst_type != BGP_INSTANCE_TYPE_VRF) { + if (inst_type != BGP_INSTANCE_TYPE_VRF && !hidden) { bgp->rfapi = bgp_rfapi_new(bgp); assert(bgp->rfapi); assert(bgp->rfapi_cfg); @@ -3547,9 +3559,11 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->vpn_policy[afi].import_vrf = list_new(); bgp->vpn_policy[afi].import_vrf->del = bgp_vrf_string_name_delete; - bgp->vpn_policy[afi].export_vrf = list_new(); - bgp->vpn_policy[afi].export_vrf->del = - bgp_vrf_string_name_delete; + if (!hidden) { + bgp->vpn_policy[afi].export_vrf = list_new(); + bgp->vpn_policy[afi].export_vrf->del = + bgp_vrf_string_name_delete; + } SET_FLAG(bgp->af_flags[afi][SAFI_MPLS_VPN], BGP_VPNVX_RETAIN_ROUTE_TARGET_ALL); } @@ -3567,7 +3581,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->restart_time, &bgp->t_startup); /* printable name we can use in debug messages */ - if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) { + if (inst_type == BGP_INSTANCE_TYPE_DEFAULT && !hidden) { bgp->name_pretty = XSTRDUP(MTYPE_BGP_NAME, "VRF default"); } else { const char *n; @@ -3595,17 +3609,20 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME; bgp->default_af[AFI_IP][SAFI_UNICAST] = true; - QOBJ_REG(bgp, bgp); + if (!hidden) + QOBJ_REG(bgp, bgp); update_bgp_group_init(bgp); - /* assign a unique rd id for auto derivation of vrf's RD */ - bf_assign_index(bm->rd_idspace, bgp->vrf_rd_id); + if (!hidden) { + /* assign a unique rd id for auto derivation of vrf's RD */ + bf_assign_index(bm->rd_idspace, bgp->vrf_rd_id); - bgp_evpn_init(bgp); - bgp_evpn_vrf_es_init(bgp); - bgp_pbr_init(bgp); - bgp_srv6_init(bgp); + bgp_evpn_init(bgp); + bgp_evpn_vrf_es_init(bgp); + bgp_pbr_init(bgp); + bgp_srv6_init(bgp); + } /*initilize global GR FSM */ bgp_global_gr_init(bgp); @@ -3743,10 +3760,15 @@ int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id, return bgp_check_main_socket(create, bgp); } -int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name, +int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, + const char *as_pretty, + enum asnotation_mode asnotation, const char *name, enum bgp_instance_type inst_type) { struct bgp *bgp; + struct peer *peer = NULL; + struct listnode *node, *nnode; + bool hidden = false; /* Multiple instance check. */ if (name) @@ -3755,14 +3777,41 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name, bgp = bgp_get_default(); if (bgp) { - *bgp_val = bgp; + if (IS_BGP_INSTANCE_HIDDEN(bgp) && *as != AS_UNSPECIFIED) + hidden = true; + /* Handle AS number change */ if (bgp->as != *as) { + if (hidden || CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) { + if (hidden) { + bgp_create(as, name, inst_type, + as_pretty, asnotation, bgp, + hidden); + UNSET_FLAG(bgp->flags, + BGP_FLAG_INSTANCE_HIDDEN); + } else { + bgp->as = *as; + UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO); + } + + /* Set all peer's local AS with this ASN */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, + peer)) + peer->local_as = *as; + *bgp_val = bgp; + return BGP_INSTANCE_EXISTS; + } + *as = bgp->as; - return BGP_ERR_AS_MISMATCH; + *bgp_val = bgp; + return BGP_ERR_INSTANCE_MISMATCH; } if (bgp->inst_type != inst_type) return BGP_ERR_INSTANCE_MISMATCH; - return BGP_SUCCESS; + if (hidden) + bgp_create(as, name, inst_type, as_pretty, asnotation, + bgp, hidden); + *bgp_val = bgp; + return BGP_INSTANCE_EXISTS; } *bgp_val = NULL; @@ -3778,11 +3827,13 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name, struct vrf *vrf = NULL; int ret = 0; - ret = bgp_lookup_by_as_name_type(bgp_val, as, name, inst_type); + ret = bgp_lookup_by_as_name_type(bgp_val, as, as_pretty, asnotation, + name, inst_type); if (ret || *bgp_val) return ret; - bgp = bgp_create(as, name, inst_type, as_pretty, asnotation); + bgp = bgp_create(as, name, inst_type, as_pretty, asnotation, NULL, + false); /* * view instances will never work inside of a vrf @@ -4022,6 +4073,15 @@ int bgp_delete(struct bgp *bgp) bgp_damp_disable(bgp, afi, safi); } + if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT && + (bgp_table_top(bgp->rib[AFI_IP][SAFI_MPLS_VPN]) || + bgp_table_top(bgp->rib[AFI_IP6][SAFI_MPLS_VPN]))) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug( + "Marking the deleting default bgp instance as hidden"); + SET_FLAG(bgp->flags, BGP_FLAG_INSTANCE_HIDDEN); + } + if (BGP_DEBUG(zebra, ZEBRA)) { if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) zlog_debug("Deleting Default VRF"); @@ -4034,7 +4094,8 @@ int bgp_delete(struct bgp *bgp) } /* unmap from RT list */ - bgp_evpn_vrf_delete(bgp); + if (!IS_BGP_INSTANCE_HIDDEN(bgp)) + bgp_evpn_vrf_delete(bgp); /* unmap bgp vrf label */ vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); @@ -4066,7 +4127,7 @@ int bgp_delete(struct bgp *bgp) peer_delete(peer); } - if (bgp->peer_self) { + if (bgp->peer_self && !IS_BGP_INSTANCE_HIDDEN(bgp)) { peer_delete(bgp->peer_self); bgp->peer_self = NULL; } @@ -4076,7 +4137,8 @@ int bgp_delete(struct bgp *bgp) /* TODO - Other memory may need to be freed - e.g., NHT */ #ifdef ENABLE_BGP_VNC - rfapi_delete(bgp); + if (!IS_BGP_INSTANCE_HIDDEN(bgp)) + rfapi_delete(bgp); #endif /* Free memory allocated with aggregate address configuration. */ @@ -4118,7 +4180,7 @@ int bgp_delete(struct bgp *bgp) } /* Deregister from Zebra, if needed */ - if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { + if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp) && !IS_BGP_INSTANCE_HIDDEN(bgp)) { if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug( "%s: deregistering this bgp %s instance from zebra", @@ -4126,17 +4188,19 @@ int bgp_delete(struct bgp *bgp) bgp_zebra_instance_deregister(bgp); } - /* Remove visibility via the master list - there may however still be - * routes to be processed still referencing the struct bgp. - */ - listnode_delete(bm->bgp, bgp); - - /* Free interfaces in this instance. */ - bgp_if_finish(bgp); + if (!IS_BGP_INSTANCE_HIDDEN(bgp)) { + /* Remove visibility via the master list - + * there may however still be routes to be processed + * still referencing the struct bgp. + */ + listnode_delete(bm->bgp, bgp); + /* Free interfaces in this instance. */ + bgp_if_finish(bgp); + } vrf = bgp_vrf_lookup_by_instance_type(bgp); bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, false); - if (vrf) + if (vrf && !IS_BGP_INSTANCE_HIDDEN(bgp)) bgp_vrf_unlink(bgp, vrf); /* Update EVPN VRF pointer */ @@ -4151,7 +4215,22 @@ int bgp_delete(struct bgp *bgp) work_queue_free_and_null(&bgp->process_queue); event_master_free_unused(bm->master); - bgp_unlock(bgp); /* initial reference */ + + if (!IS_BGP_INSTANCE_HIDDEN(bgp)) + bgp_unlock(bgp); /* initial reference */ + else { + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + enum vpn_policy_direction dir; + + if (bgp->vpn_policy[afi].import_vrf) + list_delete(&bgp->vpn_policy[afi].import_vrf); + + dir = BGP_VPN_POLICY_DIR_FROMVPN; + if (bgp->vpn_policy[afi].rtlist[dir]) + ecommunity_free( + &bgp->vpn_policy[afi].rtlist[dir]); + } + } return 0; } @@ -4696,6 +4775,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_LOCAL_AS, 0, peer_change_reset}, {PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_reset}, {PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_reset}, + {PEER_FLAG_DUAL_AS, 0, peer_change_reset}, {PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none}, {PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE, 0, peer_change_none}, {PEER_FLAG_EXTENDED_OPT_PARAMS, 0, peer_change_reset}, @@ -5791,6 +5871,10 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, subgrp = peer_subgroup(peer, afi, safi); if (rmap) { + if (!peer->bgp->rmap_def_originate_eval_timer) + peer->bgp->rmap_def_originate_eval_timer = + RMAP_DEFAULT_ORIGINATE_EVAL_TIMER; + if (!peer->default_rmap[afi][safi].name || strcmp(rmap, peer->default_rmap[afi][safi].name) != 0) { struct route_map *map = NULL; @@ -5873,6 +5957,10 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, if (rmap) { struct route_map *map = NULL; + if (!member->bgp->rmap_def_originate_eval_timer) + member->bgp->rmap_def_originate_eval_timer = + RMAP_DEFAULT_ORIGINATE_EVAL_TIMER; + if (member->default_rmap[afi][safi].name) { map = route_map_lookup_by_name( member->default_rmap[afi][safi].name); @@ -6638,9 +6726,9 @@ int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi) } int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, - bool replace_as, const char *as_str) + bool replace_as, bool dual_as, const char *as_str) { - bool old_no_prepend, old_replace_as; + bool old_no_prepend, old_replace_as, old_dual_as; struct bgp *bgp = peer->bgp; struct peer *member; struct listnode *node, *nnode; @@ -6653,14 +6741,16 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, !!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); old_replace_as = !!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); + old_dual_as = !!CHECK_FLAG(peer->flags, PEER_FLAG_DUAL_AS); /* Set flag and configuration on peer. */ peer_flag_set(peer, PEER_FLAG_LOCAL_AS); peer_flag_modify(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND, no_prepend); peer_flag_modify(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS, replace_as); + peer_flag_modify(peer, PEER_FLAG_DUAL_AS, dual_as); - if (peer->change_local_as == as && old_no_prepend == no_prepend - && old_replace_as == replace_as) + if (peer->change_local_as == as && old_no_prepend == no_prepend && + old_replace_as == replace_as && old_dual_as == dual_as) return 0; peer->change_local_as = as; if (as_str) { @@ -6689,10 +6779,11 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, PEER_FLAG_LOCAL_AS_NO_PREPEND); old_replace_as = CHECK_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); - if (member->change_local_as == as - && CHECK_FLAG(member->flags, PEER_FLAG_LOCAL_AS) - && old_no_prepend == no_prepend - && old_replace_as == replace_as) + old_dual_as = !!CHECK_FLAG(member->flags, PEER_FLAG_DUAL_AS); + if (member->change_local_as == as && + CHECK_FLAG(member->flags, PEER_FLAG_LOCAL_AS) && + old_no_prepend == no_prepend && + old_replace_as == replace_as && old_dual_as == dual_as) continue; /* Set flag and configuration on peer-group member. */ @@ -6701,6 +6792,7 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, no_prepend); COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS, replace_as); + COND_FLAG(member->flags, PEER_FLAG_DUAL_AS, dual_as); member->change_local_as = as; if (as_str) member->change_local_as_pretty = XSTRDUP(MTYPE_BGP_NAME, @@ -6723,12 +6815,14 @@ int peer_local_as_unset(struct peer *peer) peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS); peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND); peer_flag_inherit(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS); + peer_flag_inherit(peer, PEER_FLAG_DUAL_AS); PEER_ATTR_INHERIT(peer, peer->group, change_local_as); } else { /* Otherwise remove flag and configuration from peer. */ peer_flag_unset(peer, PEER_FLAG_LOCAL_AS); peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND); peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS); + peer_flag_unset(peer, PEER_FLAG_DUAL_AS); peer->change_local_as = 0; XFREE(MTYPE_BGP_NAME, peer->change_local_as_pretty); } @@ -6760,6 +6854,7 @@ int peer_local_as_unset(struct peer *peer) UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS); UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); + UNSET_FLAG(member->flags, PEER_FLAG_DUAL_AS); member->change_local_as = 0; XFREE(MTYPE_BGP_NAME, member->change_local_as_pretty); member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; @@ -8806,6 +8901,12 @@ static ssize_t printfrr_bp(struct fbuf *buf, struct printfrr_eargs *ea, if (!peer) return bputs(buf, "(null)"); + if (!peer->host) { + if (peer->conf_if) + return bprintfrr(buf, "%s", peer->conf_if); + return bprintfrr(buf, "%pSU", &peer->connection->su); + } + return bprintfrr(buf, "%s(%s)", peer->host, peer->hostname ? peer->hostname : "Unknown"); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index def12ee642..3c3655f0a5 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -550,6 +550,7 @@ struct bgp { #define BGP_FLAG_ENFORCE_FIRST_AS (1ULL << 36) #define BGP_FLAG_DYNAMIC_CAPABILITY (1ULL << 37) #define BGP_FLAG_VNI_DOWN (1ULL << 38) +#define BGP_FLAG_INSTANCE_HIDDEN (1ULL << 39) /* BGP default address-families. * New peers inherit enabled afi/safis from bgp instance. @@ -1507,6 +1508,7 @@ struct peer { #define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */ #define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */ #define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39) +#define PEER_FLAG_DUAL_AS (1ULL << 40) /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART @@ -2152,6 +2154,7 @@ enum bgp_clear_type { enum bgp_create_error_code { BGP_SUCCESS = 0, BGP_CREATED = 1, + BGP_INSTANCE_EXISTS = 2, BGP_ERR_INVALID_VALUE = -1, BGP_ERR_INVALID_FLAG = -2, BGP_ERR_INVALID_AS = -3, @@ -2443,7 +2446,7 @@ extern int peer_allowas_in_set(struct peer *, afi_t, safi_t, int, int); extern int peer_allowas_in_unset(struct peer *, afi_t, safi_t); extern int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, - bool replace_as, const char *as_str); + bool replace_as, bool dual_as, const char *as_str); extern int peer_local_as_unset(struct peer *); extern int peer_prefix_list_set(struct peer *, afi_t, safi_t, int, @@ -2822,6 +2825,8 @@ extern struct peer *peer_new(struct bgp *bgp); extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, const char *ip_str, bool use_json); extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, + const char *as_pretty, + enum asnotation_mode asnotation, const char *name, enum bgp_instance_type inst_type); @@ -2863,4 +2868,17 @@ extern void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode); /* clang-format on */ #endif +/* Macro to check if default bgp instance is hidden */ +#define IS_BGP_INSTANCE_HIDDEN(_bgp) \ + (CHECK_FLAG(_bgp->flags, BGP_FLAG_INSTANCE_HIDDEN) && \ + (_bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT || \ + _bgp->inst_type == BGP_INSTANCE_TYPE_VRF)) + +/* Macro to check if bgp instance delete in-progress and !hidden */ +#define BGP_INSTANCE_HIDDEN_DELETE_IN_PROGRESS(_bgp, _afi, _safi) \ + (CHECK_FLAG(_bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) && \ + !IS_BGP_INSTANCE_HIDDEN(_bgp) && \ + !(_afi == AFI_IP && _safi == SAFI_MPLS_VPN) && \ + !(_afi == AFI_IP6 && _safi == SAFI_MPLS_VPN)) + #endif /* _QUAGGA_BGPD_H */ diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index b6d289fac9..4632c70d53 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -83,7 +83,7 @@ be specified (:ref:`common-invocation-options`). be done to see if this is helping or not at the scale you are running at. -.. option:: --v6-with-v4-nexthops +.. option:: -x, --v6-with-v4-nexthops Allow BGP to peer in the V6 afi, when the interface only has v4 addresses. This allows bgp to install the v6 routes with a v6 nexthop that has the @@ -1818,7 +1818,7 @@ Configuring Peers Since sent prefix count is managed by update-groups, this option creates a separate update-group for outgoing updates. -.. clicmd:: neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as] +.. clicmd:: neighbor PEER local-as AS-NUMBER [no-prepend [replace-as [dual-as]]] Specify an alternate AS for this BGP process when interacting with the specified peer. With no modifiers, the specified local-as is prepended to @@ -1834,6 +1834,10 @@ Configuring Peers Note that replace-as can only be specified if no-prepend is. + The ``dual-as`` keyword is used to configure the neighbor to establish a peering + session using the real autonomous-system number (``router bgp ASN``) or by using + the autonomous system number configured with the ``local-as``. + This command is only allowed for eBGP peers. .. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> as-override @@ -1972,12 +1976,14 @@ Configuring Peers and will not be displayed as part of a `show run`. The no form of the command turns off this ability. -.. clicmd:: bgp default-originate timer (0-3600) +.. clicmd:: bgp default-originate timer (0-65535) Set the period to rerun the default-originate route-map scanner process. The default is 5 seconds. With a full routing table, it might be useful to increase this setting to avoid scanning the whole BGP table aggressively. + Setting to 0 turns off the scanning at all. + .. clicmd:: bgp default ipv4-unicast This command allows the user to specify that the IPv4 Unicast address diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 5701560bd6..0fe53247b0 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -71,6 +71,31 @@ PIM Routers prefix of group ranges covered. This command is vrf aware, to configure for a vrf, specify the vrf in the router pim block. +.. clicmd:: no autorp discovery + + In order to use pim, it is necessary to configure a RP for join messages to + be sent to. FRR supports learning RP information dynamically via the AutoRP + protocol and performs discovery by default. This command will disable the + AutoRP discovery protocol. + All routers in the pim network must agree on the network RP information, so + all routers in the network should have AutoRP either enabled or disabled. + This command is vrf aware, to configure for a vrf, specify the vrf in the + router pim block. + +.. clicmd:: autorp announce A.B.C.D [A.B.C.D/M | group-list PREFIX_LIST] + + Configure the router to advertise itself as a candidate PIM-SM RP via AutoRP. + The supported groups can be defined as a single group range, or multiple + group ranges can be defined via a prefix list. + +.. clicmd:: autorp announce {scope (1-255) | interval (1-65535) | holdtime (0-65535)} + + Configure the AutoRP advertise messages. The scope defines the TTL value in the + messages to limit the scope, defaults to 31. Interval defines the number of + seconds elapsed between advertise messages sent, defaults to 60. Hold time defines + how long the AutoRP mapping agent will consider the information valid, setting to + 0 will disable expiration of the candidate RP information, defaults to 3 * interval. + .. clicmd:: rp keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds at RP. @@ -83,6 +108,41 @@ PIM Routers cannot see data flowing in better than 30 second chunks. This command is vrf aware, to configure for a vrf, specify the vrf in the router pim block. +.. clicmd:: bsr candidate-bsr [priority (0-255)] [source [address A.B.C.D] | [interface INTERFACE] | [loopback] | [any]] + + Configure the router to advertise itself as a candidate PIM-SM BSR. The candidate + with the highest priority becomes the BSR for the domain (high wins). When priority is the + same for more than one candidate BSR, the candidate with the highest IP address + becomes the BSR of the domain. The address can be configured explicitly + via ``address``, or be selecting an interface name using ``interface``. + If ``any`` is configured the highest address from any interface will be selected. + By default, the highest loopback address is selected, which can also be + configured via ``loopback`` + +.. clicmd:: bsr candidate-rp [interval] + + Configure the router to advertise itself as a candidate PIM-SM RP at the + specified ``interval`` in seconds. + + +.. clicmd:: bsr candidate-rp group A.B.C.D/M + + Configure the multicast group prefix that this candidate RP advertises itself for. + This command can be repeated for all desired groups that need to be added to the + candidate RP advertisement. + +.. clicmd:: bsr candidate-rp [priority (0-255)] [source [address A.B.C.D] | [interface INTERFACE] | [loopback] | [any]] + + Configure the router to advertise itself as a candidate PIM-SM RP. ``interval`` + can be used to configure the interval in seconds to send these advertisements. + The candidate with the lowest priority becomes the RP for the domain (low wins). + When priority is the same for more than one candidate RP, the candidate with + the highest IP address becomes the BSR of the domain. The address can be + configured explicitly via ``address``, or be selecting an interface name + using ``interface``. If ``any`` is configured the highest address from any + interface will be selected.By default, the highest loopback address is + selected, which can also be configured via ``loopback``. + .. clicmd:: register-accept-list PLIST When pim receives a register packet the source of the packet will be compared @@ -267,6 +327,12 @@ is in a vrf, enter the interface command with the vrf keyword at the end. Add a static multicast group or source-group on an interface. This will behave as if there is a receiver on this interface without any IGMP reports. +.. clicmd:: ip igmp proxy + + Tell pim to send proxy IGMP reports for joins occuring on all other + interfaces on this interface. Join-groups on other interfaces will + also be proxied. The default version is v3. + .. clicmd:: ip igmp query-interval (1-65535) Set the IGMP query interval that PIM will use. @@ -440,6 +506,10 @@ cause great confusion. Display IGMP group retransmission information. +.. clicmd:: show ip igmp [vrf NAME] proxy [json] + + Display IGMP proxy join information. + .. clicmd:: show ip igmp [vrf NAME] sources [json] Display IGMP sources information. @@ -571,6 +641,11 @@ cause great confusion. 192.168.10.123 239.0.0.0/8 eth2 yes Static ASM 192.168.10.123 239.4.0.0/24 eth2 yes Static SSM +.. clicmd:: show ip pim [vrf NAME] autorp [json] + + Display information about AutoRP. Including state of AutoRP Discovery parsing + and configured AutoRP candidate RP information. + .. clicmd:: show ip pim rpf Display information about currently being used S,G's and their RPF lookup @@ -611,11 +686,28 @@ cause great confusion. Display PIM MLAG (multi-chassis link aggregation) session status and control message statistics. -.. clicmd:: show ip pim bsr +.. clicmd:: show ip pim bsr [vrf NAME] [json] Display current bsr, its uptime and last received bsm age. -.. clicmd:: show ip pim bsrp-info [vrf NAME] [json] +.. clicmd:: show ip pim bsr candidate-bsr [vrf NAME] [json] + + Display information about the candidate BSR state on this router. + +.. clicmd:: show ip pim bsr candidate-rp [vrf NAME] [json] + + Display information about the candidate RP state on this router. + +.. clicmd:: show ip pim bsr candidate-rp-database [vrf NAME] [json] + + Display the current list of candidate RPs received by this router. + +.. clicmd:: show ip pim bsr groups [vrf NAME] [json] + + Display the current list of multicast group mapping received by + this router from candidate RPs. + +.. clicmd:: show ip pim bsr rp-info [vrf NAME] [json] Display group-to-rp mappings received from E-BSR. @@ -699,6 +791,10 @@ the config was written out. This gathers data about events from zebra that come up through the ZAPI. +.. clicmd:: debug pim autorp + + This turns on debugging for PIM AutoRP protocol events. + PIM Clear Commands ================== Clear commands reset various variables. diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst index edf7a82015..e4e28d71ab 100644 --- a/doc/user/pimv6.rst +++ b/doc/user/pimv6.rst @@ -80,6 +80,29 @@ PIMv6 Router cannot see data flowing in better than 30 second chunks. This command is vrf aware, to configure for a vrf, specify the vrf in the router pim6 block. +.. clicmd:: bsr candidate-bsr [priority (0-255)] [source [address X:X::X:X] | [interface INTERFACE] | [loopback] | [any]] + + Configure the router to advertise itself as a candidate PIM-SM BSR. The candidate + with the highest priority becomes the BSR for the domain (high wins). When priority is the + same for more than one candidate BSR, the candidate with the highest IP address + becomes the BSR of the domain. The address can be configured explicitly + via ``address``, or be selecting an interface name using ``interface``. + If ``any`` is configured the highest address from any interface will be selected. + By default, the highest loopback address is selected, which can also be + configured via ``loopback`` + +.. clicmd:: bsr candidate-rp [interval (1-4294967295) ] [priority (0-255)] [source [address X:X::X:X] | [interface INTERFACE] | [loopback] | [any]] + + Configure the router to advertise itself as a candidate PIM-SM RP. ``interval`` + can be used to configure the interval in seconds to send these advertisements. + The candidate with the lowest priority becomes the RP for the domain (low wins). + When priority is the same for more than one candidate RP, the candidate with + the highest IP address becomes the BSR of the domain. The address can be + configured explicitly via ``address``, or be selecting an interface name + using ``interface``. If ``any`` is configured the highest address from any + interface will be selected.By default, the highest loopback address is + selected, which can also be configured via ``loopback``. + .. clicmd:: spt-switchover infinity-and-beyond [prefix-list PLIST] On the last hop router if it is desired to not switch over to the SPT tree @@ -391,11 +414,28 @@ General multicast routing state Display total number of S,G mroutes and number of S,G mroutes installed into the kernel for all vrfs. -.. clicmd:: show ipv6 pim bsr +.. clicmd:: show ipv6 pim bsr [vrf NAME] [json] Display current bsr, its uptime and last received bsm age. -.. clicmd:: show ipv6 pim bsrp-info [vrf NAME] [json] +.. clicmd:: show ipv6 pim bsr candidate-bsr [vrf NAME] [json] + + Display information about the candidate BSR state on this router. + +.. clicmd:: show ipv6 pim bsr candidate-rp [vrf NAME] [json] + + Display information about the candidate RP state on this router. + +.. clicmd:: show ipv6 pim bsr candidate-rp-database [vrf NAME] [json] + + Display the current list of candidate RPs received by this router. + +.. clicmd:: show ipv6 pim bsr groups [vrf NAME] [json] + + Display the current list of multicast group mapping received by + this router from candidate RPs. + +.. clicmd:: show ipv6 pim bsr rp-info [vrf NAME] [json] Display group-to-rp mappings received from E-BSR. diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 391d42fba1..d588af314c 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -711,10 +711,6 @@ void lsp_print_common(struct isis_lsp *lsp, struct vty *vty, struct json_object } } -#if CONFDATE > 20240916 -CPP_NOTICE("Remove JSON in '-' format") -#endif - void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, char dynhost, struct isis *isis) { @@ -728,19 +724,11 @@ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, own_json = json_object_new_object(); json_object_object_add(json, "lsp", own_json); json_object_string_add(own_json, "id", LSPid); -#if CONFDATE > 20240916 - CPP_NOTICE("remove own key") -#endif json_object_string_add(own_json, "own", lsp->own_lsp ? "*" : " "); if (lsp->own_lsp) json_object_boolean_add(own_json, "ownLSP", true); - json_object_int_add(json, "pdu-len", lsp->hdr.pdu_len); json_object_int_add(json, "pduLen", lsp->hdr.pdu_len); snprintfrr(buf, sizeof(buf), "0x%08x", lsp->hdr.seqno); -#if CONFDATE > 20240916 - CPP_NOTICE("remove seq-number key") -#endif - json_object_string_add(json, "seq-number", buf); json_object_string_add(json, "seqNumber", buf); snprintfrr(buf, sizeof(buf), "0x%04hx", lsp->hdr.checksum); json_object_string_add(json, "chksum", buf); @@ -751,11 +739,6 @@ void lsp_print_json(struct isis_lsp *lsp, struct json_object *json, } else { json_object_int_add(json, "holdtime", lsp->hdr.rem_lifetime); } -#if CONFDATE > 20240916 - CPP_NOTICE("remove att-p-ol key") -#endif - json_object_string_add( - json, "att-p-ol", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); json_object_string_add(json, "attPOl", lsp_bits2string(lsp->hdr.lsp_bits, b, sizeof(b))); } diff --git a/isisd/isis_nb_state.c b/isisd/isis_nb_state.c index b7c33ed27b..da61bcced3 100644 --- a/isisd/isis_nb_state.c +++ b/isisd/isis_nb_state.c @@ -98,6 +98,8 @@ const void *lib_interface_state_isis_adjacencies_adjacency_get_next( * adjacencies list. */ list = circuit->u.bc.adjdb[ISIS_LEVEL2 - 1]; + if (!list) + break; adj_next = listnode_head(list); } break; diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 0f37ed012a..8fc0f144b2 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1469,14 +1469,13 @@ static void spf_adj_list_parse_tlv(struct isis_spftree *spftree, sadj->metric = metric; if (oldmetric) SET_FLAG(flags, F_ISIS_SPF_ADJ_OLDMETRIC); + if ((oldmetric && sadj->metric == ISIS_NARROW_METRIC_INFINITY) || + (!oldmetric && sadj->metric == ISIS_WIDE_METRIC_INFINITY)) + SET_FLAG(flags, F_ISIS_SPF_ADJ_METRIC_INFINITY); sadj->lsp = lsp; sadj->subtlvs = subtlvs; sadj->flags = flags; - if ((oldmetric && metric == ISIS_NARROW_METRIC_INFINITY) - || (!oldmetric && metric == ISIS_WIDE_METRIC_INFINITY)) - SET_FLAG(flags, F_ISIS_SPF_ADJ_METRIC_INFINITY); - /* Set real adjacency. */ if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES) && !LSP_PSEUDO_ID(id)) { diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index 71e0f56e03..95ea36c3a8 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -627,6 +627,50 @@ static int sr_local_block_release_label(struct sr_local_block *srlb, return 0; } +static bool sr_adj_same_subnet_ipv4(struct in_addr ipv4, + struct isis_circuit *circuit) +{ + struct listnode *node; + struct prefix ipv4_adj; + struct prefix_ipv4 *ipv4_circuit; + + ipv4_adj.family = AF_INET; + ipv4_adj.u.prefix4 = ipv4; + + for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ipv4_circuit)) { + ipv4_adj.prefixlen = ipv4_circuit->prefixlen; + if (!prefix_cmp(&ipv4_adj, (struct prefix *)ipv4_circuit)) + return true; + } + + return false; +} + +static bool sr_adj_same_subnet_ipv6(struct in6_addr *ipv6, + struct isis_circuit *circuit) +{ + struct listnode *node; + struct prefix ipv6_adj; + struct prefix_ipv6 *ipv6_circuit; + + ipv6_adj.family = AF_INET6; + IPV6_ADDR_COPY(&ipv6_adj.u.prefix6, ipv6); + + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ipv6_circuit)) { + ipv6_adj.prefixlen = ipv6_circuit->prefixlen; + if (!prefix_cmp(&ipv6_adj, (struct prefix *)ipv6_circuit)) + return true; + } + + for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ipv6_circuit)) { + ipv6_adj.prefixlen = ipv6_circuit->prefixlen; + if (!prefix_cmp(&ipv6_adj, (struct prefix *)ipv6_circuit)) + return true; + } + + return false; +} + /* --- Segment Routing Adjacency-SID management functions ------------------- */ /** @@ -658,12 +702,18 @@ void sr_adj_sid_add_single(struct isis_adjacency *adj, int family, bool backup, if (!circuit->ip_router || !adj->ipv4_address_count) return; + if (!sr_adj_same_subnet_ipv4(adj->ipv4_addresses[0], circuit)) + return; + nexthop.ipv4 = adj->ipv4_addresses[0]; break; case AF_INET6: if (!circuit->ipv6_router || !adj->ll_ipv6_count) return; + if (!sr_adj_same_subnet_ipv6(&adj->ll_ipv6_addrs[0], circuit)) + return; + nexthop.ipv6 = adj->ll_ipv6_addrs[0]; break; default: diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index d2dacdc113..b5caf396c1 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -565,10 +565,6 @@ static void format_item_asla_subtlvs(struct isis_asla_subtlvs *asla, asla->use_bw); } -#if CONFDATE > 20240916 -CPP_NOTICE("Remove JSON in '-' format") -#endif - /* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct sbuf *buf, struct json_object *json, @@ -585,10 +581,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "0x%x", exts->adm_group); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "adm-group", aux_buf); json_object_string_add(json, "admGroup", aux_buf); } else { sbuf_push(buf, indent, "Admin Group: 0x%08x\n", @@ -639,13 +631,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } if (IS_SUBTLV(exts, EXT_LLRI)) { if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_int_add(json, "link-local-id", - exts->local_llri); - json_object_int_add(json, "link-remote-id", - exts->remote_llri); json_object_int_add(json, "linkLocalId", exts->local_llri); json_object_int_add(json, "linkRemoteId", @@ -661,10 +646,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET, &exts->local_addr, aux_buf, sizeof(aux_buf)); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "local-iface-ip", aux_buf); json_object_string_add(json, "localIfaceIp", aux_buf); } else sbuf_push(buf, indent, @@ -675,11 +656,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET, &exts->neigh_addr, aux_buf, sizeof(aux_buf)); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "remote-iface-ip", - aux_buf); json_object_string_add(json, "remoteIfaceIp", aux_buf); } else sbuf_push(buf, indent, @@ -690,11 +666,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET6, &exts->local_addr6, aux_buf, sizeof(aux_buf)); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "local-iface-ipv6", - aux_buf); json_object_string_add(json, "localIfaceIpv6", aux_buf); } else sbuf_push(buf, indent, @@ -705,11 +676,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET6, &exts->neigh_addr6, aux_buf, sizeof(aux_buf)); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "remote-iface-ipv6", - aux_buf); json_object_string_add(json, "remoteIfaceIpv6", aux_buf); } else sbuf_push(buf, indent, @@ -720,11 +686,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", exts->max_bw); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "max-bandwith-bytes-sec", - aux_buf); json_object_string_add(json, "maxBandwithBytesSec", aux_buf); } else @@ -736,11 +697,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", exts->max_rsv_bw); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add( - json, "max-res-bandwith-bytes-sec", aux_buf); json_object_string_add(json, "maxResBandwithBytesSec", aux_buf); } else @@ -763,22 +719,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, json_object_string_add(unrsv_json, cnt_buf, aux_buf); } - -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - unrsv_json = json_object_new_object(); - json_object_object_add(json, "unrsv-bandwith-bytes-sec", - unrsv_json); - for (int j = 0; j < MAX_CLASS_TYPE; j += 1) { - snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", j); - snprintfrr(aux_buf, sizeof(aux_buf), "%g", - exts->unrsv_bw[j]); - json_object_string_add(unrsv_json, cnt_buf, - aux_buf); - } - /* end old deprecated key format */ } else { sbuf_push(buf, indent, "Unreserved Bandwidth:\n"); for (int j = 0; j < MAX_CLASS_TYPE; j += 2) { @@ -791,27 +731,18 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, } } if (IS_SUBTLV(exts, EXT_TE_METRIC)) { - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_int_add(json, "te-metric", exts->te_metric); + if (json) json_object_int_add(json, "teMetric", exts->te_metric); - } else + else sbuf_push(buf, indent, "Traffic Engineering Metric: %u\n", exts->te_metric); } if (IS_SUBTLV(exts, EXT_RMT_AS)) { - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_int_add(json, "inter-as-te-remote-as", - exts->remote_as); + if (json) json_object_int_add(json, "interAsTeRemoteAs", exts->remote_as); - } else + else sbuf_push(buf, indent, "Inter-AS TE Remote AS number: %u\n", exts->remote_as); @@ -820,11 +751,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { inet_ntop(AF_INET6, &exts->remote_ip, aux_buf, sizeof(aux_buf)); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add( - json, "inter-as-te-remote-asbr-ip", aux_buf); json_object_string_add(json, "interAsTeRemoteAsbrIp", aux_buf); } else @@ -836,16 +762,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_DELAY)) { if (json) { struct json_object *avg_json; - avg_json = json_object_new_object(); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_object_add(json, "avg-delay", avg_json); - json_object_string_add(avg_json, "delay", - IS_ANORMAL(exts->delay) - ? "Anomalous" - : "Normal"); - json_object_int_add(avg_json, "micro-sec", exts->delay); avg_json = json_object_new_object(); json_object_object_add(json, "avgDelay", avg_json); @@ -864,19 +780,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_MM_DELAY)) { if (json) { struct json_object *avg_json; - avg_json = json_object_new_object(); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_object_add(json, "max-min-delay", avg_json); - json_object_string_add(avg_json, "delay", - IS_ANORMAL(exts->min_delay) - ? "Anomalous" - : "Normal"); - snprintfrr(aux_buf, sizeof(aux_buf), "%u / %u", - exts->min_delay & TE_EXT_MASK, - exts->max_delay & TE_EXT_MASK); - json_object_string_add(avg_json, "micro-sec", aux_buf); avg_json = json_object_new_object(); json_object_object_add(json, "maxMinDelay", avg_json); @@ -899,15 +802,10 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, exts->max_delay & TE_EXT_MASK); } if (IS_SUBTLV(exts, EXT_DELAY_VAR)) { - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_int_add(json, "delay-variation-micro-sec", - exts->delay_var & TE_EXT_MASK); + if (json) json_object_int_add(json, "delayVariationMicroSec", exts->delay_var & TE_EXT_MASK); - } else + else sbuf_push(buf, indent, "Delay Variation: %u (micro-sec)\n", exts->delay_var & TE_EXT_MASK); @@ -919,20 +817,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, LOSS_PRECISION)); struct json_object *link_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - link_json = json_object_new_object(); - json_object_object_add(json, "link-packet-loss", - link_json); - json_object_string_add(link_json, "loss", - IS_ANORMAL(exts->pkt_loss) - ? "Anomalous" - : "Normal"); - /* typo */ - json_object_string_add(link_json, "percentaje", - aux_buf); - link_json = json_object_new_object(); json_object_object_add(json, "linkPacketLoss", link_json); @@ -952,12 +836,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", (exts->res_bw)); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, - "unidir-residual-band-bytes-sec", - aux_buf); json_object_string_add(json, "unidirResidualBandBytesSec", aux_buf); @@ -971,12 +849,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { snprintfrr(aux_buf, sizeof(aux_buf), "%g", (exts->ava_bw)); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add( - json, "unidir-available-band-bytes-sec", - aux_buf); json_object_string_add(json, "unidirAvailableBandBytesSec", aux_buf); @@ -991,12 +863,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, snprintfrr(aux_buf, sizeof(aux_buf), "%g", (exts->use_bw)); json_object_string_add(json, - "unidir-utilized-band-bytes-sec", - aux_buf); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "unidirUtilizedBandBytesSec", aux_buf); } else @@ -1012,50 +878,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { struct json_object *arr_adj_json, *adj_sid_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - arr_adj_json = json_object_new_array(); - json_object_object_add(json, "adj-sid", arr_adj_json); - for (adj = (struct isis_adj_sid *)exts->adj_sid.head; - adj; adj = adj->next) { - snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", - adj->sid); - adj_sid_json = json_object_new_object(); - json_object_int_add(adj_sid_json, "sid", - adj->sid); - json_object_int_add(adj_sid_json, "weight", - adj->weight); - json_object_string_add(adj_sid_json, "flag-f", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add(adj_sid_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add(adj_sid_json, "flag-v", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add(adj_sid_json, "flag-l", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add(adj_sid_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add(adj_sid_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, - adj_sid_json); - } - /* end old deprecated key format */ - arr_adj_json = json_object_new_array(); json_object_object_add(json, "adjSid", arr_adj_json); for (adj = (struct isis_adj_sid *)exts->adj_sid.head; @@ -1127,57 +949,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { struct json_object *arr_adj_json, *lan_adj_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - arr_adj_json = json_object_new_array(); - json_object_object_add(json, "lan-adj-sid", - arr_adj_json); - for (lan = (struct isis_lan_adj_sid *) - exts->adj_sid.head; - lan; lan = lan->next) { - if (((mtid == ISIS_MT_IPV4_UNICAST) && - (lan->family != AF_INET)) || - ((mtid == ISIS_MT_IPV6_UNICAST) && - (lan->family != AF_INET6))) - continue; - snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", - lan->sid); - lan_adj_json = json_object_new_object(); - json_object_int_add(lan_adj_json, "sid", - lan->sid); - json_object_int_add(lan_adj_json, "weight", - lan->weight); - json_object_string_add(lan_adj_json, "flag-f", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add(lan_adj_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add(lan_adj_json, "flag-v", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add(lan_adj_json, "flag-l", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add(lan_adj_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add(lan_adj_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, - lan_adj_json); - } - /* end old deprecated key format */ - arr_adj_json = json_object_new_array(); json_object_object_add(json, "lanAdjSid", arr_adj_json); for (lan = (struct isis_lan_adj_sid *)exts->adj_sid.head; @@ -1264,57 +1035,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (json) { struct json_object *arr_adj_json, *srv6_endx_sid_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - arr_adj_json = json_object_new_array(); - json_object_object_add(json, "srv6-endx-sid", - arr_adj_json); - for (adj = (struct isis_srv6_endx_sid_subtlv *) - exts->srv6_endx_sid.head; - adj; adj = adj->next) { - snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", - &adj->sid); - srv6_endx_sid_json = json_object_new_object(); - json_object_string_addf(srv6_endx_sid_json, - "sid", "%pI6", - &adj->sid); - json_object_string_add(srv6_endx_sid_json, - "algorithm", - sr_algorithm_string( - adj->algorithm)); - json_object_int_add(srv6_endx_sid_json, - "weight", adj->weight); - json_object_string_add(srv6_endx_sid_json, - "behavior", - seg6local_action2str( - adj->behavior)); - json_object_string_add(srv6_endx_sid_json, - "flag-b", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add(srv6_endx_sid_json, - "flag-s", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add(srv6_endx_sid_json, - "flag-p", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, - srv6_endx_sid_json); - if (adj->subsubtlvs) - isis_format_subsubtlvs(adj->subsubtlvs, - NULL, - srv6_endx_sid_json, - indent + 4); - } - /* end old deprecated key format */ - arr_adj_json = json_object_new_array(); json_object_object_add(json, "srv6EndXSID", arr_adj_json); @@ -1390,63 +1110,6 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct json_object *arr_adj_json, *srv6_lan_endx_sid_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - arr_adj_json = json_object_new_array(); - json_object_object_add(json, "srv6-lan-endx-sid", - arr_adj_json); - for (lan = (struct isis_srv6_lan_endx_sid_subtlv *) - exts->srv6_lan_endx_sid.head; - lan; lan = lan->next) { - snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", - &lan->sid); - srv6_lan_endx_sid_json = - json_object_new_object(); - json_object_string_addf(srv6_lan_endx_sid_json, - "sid", "%pI6", - &lan->sid); - json_object_int_add(srv6_lan_endx_sid_json, - "weight", lan->weight); - json_object_string_add(srv6_lan_endx_sid_json, - "algorithm", - sr_algorithm_string( - lan->algorithm)); - json_object_int_add(srv6_lan_endx_sid_json, - "weight", lan->weight); - json_object_string_add(srv6_lan_endx_sid_json, - "behavior", - seg6local_action2str( - lan->behavior)); - json_object_string_add(srv6_lan_endx_sid_json, - "flag-b", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add(srv6_lan_endx_sid_json, - "flag-s", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add(srv6_lan_endx_sid_json, - "flag-p", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_string_addf(srv6_lan_endx_sid_json, - "neighbor-id", "%pSY", - lan->neighbor_id); - json_object_array_add(arr_adj_json, - srv6_lan_endx_sid_json); - if (lan->subsubtlvs) - isis_format_subsubtlvs(lan->subsubtlvs, - NULL, - srv6_lan_endx_sid_json, - indent + 4); - } - /* end old deprecated key format */ - arr_adj_json = json_object_new_array(); json_object_object_add(json, "srv6LanEndxSID", arr_adj_json); @@ -2613,33 +2276,6 @@ static void format_item_prefix_sid(uint16_t mtid, struct isis_item *i, } json_object_int_add(sr_json, "alg", sid->algorithm); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated non boolean json") -#endif - /* old deprecated keys (no booleans) */ - json_object_string_add( - sr_json, "readvertised", - ((sid->flags & ISIS_PREFIX_SID_READVERTISED) ? "yes" - : "")); - json_object_string_add( - sr_json, "node", - ((sid->flags & ISIS_PREFIX_SID_NODE) ? "yes" : "")); - json_object_string_add(sr_json, "php", - ((sid->flags & ISIS_PREFIX_SID_NO_PHP) - ? "no-php" - : "php")); - json_object_string_add( - sr_json, "explicit-null", - ((sid->flags & ISIS_PREFIX_SID_EXPLICIT_NULL) ? "yes" - : "")); - json_object_string_add( - sr_json, "value", - ((sid->flags & ISIS_PREFIX_SID_VALUE) ? "yes" : "")); - json_object_string_add( - sr_json, "local", - ((sid->flags & ISIS_PREFIX_SID_LOCAL) ? "yes" : "")); - /* end deprecated keys (no booleans) */ - struct json_object *flags_json; flags_json = json_object_new_object(); @@ -2788,10 +2424,6 @@ static void format_subtlv_ipv6_source_prefix(struct prefix_ipv6 *p, char prefixbuf[PREFIX2STR_BUFFER]; if (json) { prefix2str(p, prefixbuf, sizeof(prefixbuf)); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "ipv6-src-prefix", prefixbuf); json_object_string_add(json, "ipv6SrcPrefix", prefixbuf); } else { sbuf_push(buf, indent, "IPv6 Source Prefix: %s\n", @@ -2895,23 +2527,6 @@ static void format_subsubtlv_srv6_sid_structure( if (json) { struct json_object *sid_struct_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - sid_struct_json = json_object_new_object(); - json_object_object_add(json, "srv6-sid-structure", - sid_struct_json); - json_object_int_add(sid_struct_json, "loc-block-len", - sid_struct->loc_block_len); - json_object_int_add(sid_struct_json, "loc-node-len", - sid_struct->loc_node_len); - json_object_int_add(sid_struct_json, "func-len", - sid_struct->func_len); - json_object_int_add(sid_struct_json, "arg-len", - sid_struct->arg_len); - /* end old deprecated key format */ - sid_struct_json = json_object_new_object(); json_object_object_add(json, "srv6SidStructure", sid_struct_json); @@ -3205,26 +2820,6 @@ static void format_item_srv6_end_sid(uint16_t mtid, struct isis_item *i, if (json) { struct json_object *sid_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - sid_json = json_object_new_object(); - json_object_object_add(json, "srv6-end-sid", sid_json); - json_object_string_add(sid_json, "endpoint-behavior", - seg6local_action2str(sid->behavior)); - json_object_string_addf(sid_json, "sid-value", "%pI6", - &sid->sid); - if (sid->subsubtlvs) { - struct json_object *subtlvs_json; - subtlvs_json = json_object_new_object(); - json_object_object_add(sid_json, "subsubtlvs", - subtlvs_json); - isis_format_subsubtlvs(sid->subsubtlvs, NULL, - subtlvs_json, 0); - } - /* end old deprecated key format */ - sid_json = json_object_new_object(); json_object_object_add(json, "srv6EndSid", sid_json); json_object_string_add(sid_json, "endpointBehavior", @@ -3385,13 +2980,9 @@ static void format_item_area_address(uint16_t mtid, struct isis_item *i, memcpy(iso_addr.area_addr, addr->addr, ISO_ADDR_SIZE); iso_addr.addr_len = addr->len; - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_addf(json, "area-addr", "%pIS", &iso_addr); + if (json) json_object_string_addf(json, "areaAddr", "%pIS", &iso_addr); - } else + else sbuf_push(buf, indent, "Area Address: %pIS\n", &iso_addr); } @@ -3479,22 +3070,6 @@ static void format_item_oldstyle_reach(uint16_t mtid, struct isis_item *i, if (json) { struct json_object *old_json, *array_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - old_json = json_object_new_object(); - json_object_object_get_ex(json, "old-reach-style", &array_json); - if (!array_json) { - array_json = json_object_new_array(); - json_object_object_add(json, "old-reach-style", - array_json); - } - json_object_array_add(array_json, old_json); - json_object_string_add(old_json, "is-reach", sys_id); - json_object_int_add(old_json, "metric", r->metric); - /* end old deprecated key format */ - old_json = json_object_new_object(); json_object_object_get_ex(json, "oldReachStyle", &array_json); if (!array_json) { @@ -3582,13 +3157,9 @@ static void format_item_lan_neighbor(uint16_t mtid, struct isis_item *i, char sys_id[ISO_SYSID_STRLEN]; snprintfrr(sys_id, ISO_SYSID_STRLEN, "%pSY", n->mac); - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "lan-neighbor", sys_id); + if (json) json_object_string_add(json, "lanNeighbor", sys_id); - } else + else sbuf_push(buf, indent, "LAN Neighbor: %s\n", sys_id); } @@ -3660,17 +3231,6 @@ static void format_item_lsp_entry(uint16_t mtid, struct isis_item *i, if (json) { char buf[255]; struct json_object *lsp_json; - lsp_json = json_object_new_object(); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_object_add(json, "lsp-entry", lsp_json); - json_object_string_add(lsp_json, "id", sys_id); - snprintfrr(buf,sizeof(buf),"0x%08x",e->seqno); - json_object_string_add(lsp_json, "seq", buf); - snprintfrr(buf,sizeof(buf),"0x%04hx",e->checksum); - json_object_string_add(lsp_json, "chksum", buf); - json_object_int_add(lsp_json, "lifetime", e->checksum); lsp_json = json_object_new_object(); json_object_object_add(json, "lspEntry", lsp_json); @@ -3762,31 +3322,6 @@ static void format_item_extended_reach(uint16_t mtid, struct isis_item *i, if (json) { struct json_object *reach_json, *array_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - reach_json = json_object_new_object(); - json_object_object_get_ex(json, "ext-reach", &array_json); - if (!array_json) { - array_json = json_object_new_array(); - json_object_object_add(json, "ext-reach", array_json); - } - json_object_array_add(array_json, reach_json); - json_object_string_add( - reach_json, "mt-id", - (mtid == ISIS_MT_IPV4_UNICAST) ? "Extended" : "MT"); - json_object_string_add(reach_json, "id", sys_id); - json_object_int_add(reach_json, "metric", r->metric); - if (mtid != ISIS_MT_IPV4_UNICAST) - json_object_string_add(reach_json, "mt-name", - isis_mtid2str(mtid)); - - if (r->subtlvs) - format_item_ext_subtlvs(r->subtlvs, NULL, reach_json, - indent + 2, mtid); - /* end old deprecated key format */ - reach_json = json_object_new_object(); json_object_object_get_ex(json, "extReach", &array_json); if (!array_json) { @@ -3935,24 +3470,6 @@ static void format_item_oldstyle_ip_reach(uint16_t mtid, struct isis_item *i, if (json) { struct json_object *old_json, *array_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - old_json = json_object_new_object(); - json_object_object_get_ex(json, "old-ip-reach-style", - &array_json); - if (!array_json) { - array_json = json_object_new_array(); - json_object_object_add(json, "old-ip-reach-style", - old_json); - } - json_object_array_add(array_json, old_json); - json_object_string_add(old_json, "prefix", - prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); - json_object_int_add(old_json, "metric", r->metric); - /* end old deprecated key format */ - old_json = json_object_new_object(); json_object_object_get_ex(json, "oldIpReachStyle", &array_json); if (!array_json) { @@ -4058,19 +3575,6 @@ static void format_tlv_protocols_supported(struct isis_protocols_supported *p, struct json_object *protocol_json; char buf[255]; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - protocol_json = json_object_new_object(); - json_object_object_add(json, "protocols-supported", - protocol_json); - for (uint8_t i = 0; i < p->count; i++) { - snprintfrr(buf, sizeof(buf), "%d", i); - json_object_string_add(protocol_json, buf, - nlpid2str(p->protocols[i])); - } - protocol_json = json_object_new_object(); json_object_object_add(json, "supportedProtocols", protocol_json); @@ -4079,7 +3583,6 @@ static void format_tlv_protocols_supported(struct isis_protocols_supported *p, json_object_string_add(protocol_json, buf, nlpid2str(p->protocols[i])); } - /* end old deprecated key format */ } else { sbuf_push(buf, indent, "Protocols Supported: "); for (uint8_t i = 0; i < p->count; i++) { @@ -4295,13 +3798,9 @@ static void format_item_global_ipv6_address(uint16_t mtid, struct isis_item *i, char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &a->addr, addrbuf, sizeof(addrbuf)); - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "global-ipv6", addrbuf); + if (json) json_object_string_add(json, "globalIpv6", addrbuf); - } else + else sbuf_push(buf, indent, "Global IPv6 Interface Address: %s\n", addrbuf); } @@ -4383,12 +3882,6 @@ static void format_item_mt_router_info(uint16_t mtid, struct isis_item *i, json_object_string_add(mt_json, "mtDescription", isis_mtid2str(mtid)); -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated non boolean format") -#endif - json_object_string_add(mt_json, "overload", info->overload?"true":"false"); - json_object_string_add(mt_json, "attached", info->attached?"true":"false"); - json_object_boolean_add(mt_json, "overloadBit", !!info->overload); json_object_boolean_add(mt_json, "attachedbit", @@ -4475,13 +3968,9 @@ static void format_tlv_te_router_id(const struct in_addr *id, struct sbuf *buf, char addrbuf[INET_ADDRSTRLEN]; inet_ntop(AF_INET, id, addrbuf, sizeof(addrbuf)); - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "te-router-id", addrbuf); + if (json) json_object_string_add(json, "teRouterId", addrbuf); - } else + else sbuf_push(buf, indent, "TE Router ID: %s\n", addrbuf); } @@ -4556,37 +4045,6 @@ static void format_item_extended_ip_reach(uint16_t mtid, struct isis_item *i, char prefixbuf[PREFIX2STR_BUFFER]; if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - ext_json = json_object_new_object(); - json_object_object_get_ex(json, "ext-ip-reach", &array_json); - if (!array_json) { - array_json = json_object_new_array(); - json_object_object_add(json, "ext-ip-reach", array_json); - } - json_object_array_add(array_json, ext_json); - json_object_string_add(ext_json, "mt-id", - (mtid == ISIS_MT_IPV4_UNICAST) - ? "Extended" - : "MT"); - json_object_string_add(ext_json, "ip-reach", - prefix2str(&r->prefix, prefixbuf, - sizeof(prefixbuf))); - json_object_int_add(ext_json, "ip-reach-metric", r->metric); - json_object_string_add(ext_json, "down", r->down ? "yes" : ""); - if (mtid != ISIS_MT_IPV4_UNICAST) - json_object_string_add(ext_json, "mt-name", - isis_mtid2str(mtid)); - if (r->subtlvs) { - struct json_object *subtlv_json; - subtlv_json = json_object_new_object(); - json_object_object_add(ext_json, "subtlvs", subtlv_json); - format_subtlvs(r->subtlvs, NULL, subtlv_json, 0); - } - /* end old deprecated key format */ - ext_json = json_object_new_object(); json_object_object_get_ex(json, "extIpReach", &array_json); if (!array_json) { @@ -4869,13 +4327,9 @@ static void format_tlv_te_router_id_ipv6(const struct in6_addr *id, char addrbuf[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, id, addrbuf, sizeof(addrbuf)); - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "ipv6-te-router-id", addrbuf); + if (json) json_object_string_add(json, "ipv6TeRouterId", addrbuf); - } else + else sbuf_push(buf, indent, "IPv6 TE Router ID: %s\n", addrbuf); } @@ -4953,30 +4407,6 @@ static void format_tlv_spine_leaf(const struct isis_spine_leaf *spine_leaf, if (json) { struct json_object *spine_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated format */ - spine_json = json_object_new_object(); - json_object_object_add(json, "spine-leaf-extension", - spine_json); - if (spine_leaf->has_tier) { - snprintfrr(aux_buf, sizeof(aux_buf), "%hhu", - spine_leaf->tier); - json_object_string_add( - spine_json, "tier", - (spine_leaf->tier == ISIS_TIER_UNDEFINED) - ? "undefined" - : aux_buf); - } - json_object_string_add(spine_json, "flag-leaf", - spine_leaf->is_leaf ? "yes" : ""); - json_object_string_add(spine_json, "flag-spine", - spine_leaf->is_spine ? "yes" : ""); - json_object_string_add(spine_json, "flag-backup", - spine_leaf->is_backup ? "yes" : ""); - /* end old deprecated format */ - spine_json = json_object_new_object(); json_object_object_add(json, "spineLeafExtension", spine_json); if (spine_leaf->has_tier) { @@ -5136,26 +4566,6 @@ format_tlv_threeway_adj(const struct isis_threeway_adj *threeway_adj, if (json) { struct json_object *three_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - three_json = json_object_new_object(); - json_object_object_add(json, "p2p-three-way-adj", three_json); - json_object_string_add( - three_json, "state-name", - isis_threeway_state_name(threeway_adj->state)); - json_object_int_add(three_json, "state", threeway_adj->state); - json_object_int_add(three_json, "ext-local-circuit-id", - threeway_adj->local_circuit_id); - if (threeway_adj->neighbor_set) { - json_object_string_add(three_json, "neigh-system-id", - sys_id); - json_object_int_add(three_json, "neigh-ext-circuit-id", - threeway_adj->neighbor_circuit_id); - } - /* end old deprecated key format */ - three_json = json_object_new_object(); json_object_object_add(json, "p2pThreeWayAdj", three_json); json_object_string_add(three_json, "stateName", @@ -5306,40 +4716,6 @@ static void format_item_ipv6_reach(uint16_t mtid, struct isis_item *i, subtlvs_json); format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0); } - -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated JSON key format */ - reach_json = json_object_new_object(); - json_object_object_get_ex(json, "ipv6-reach", &array_json); - if (!array_json) { - array_json = json_object_new_array(); - json_object_object_add(json, "ipv6-reach", array_json); - } - json_object_array_add(array_json, reach_json); - json_object_string_add(reach_json, "mt-id", - (mtid == ISIS_MT_IPV4_UNICAST) ? "" - : "mt"); - json_object_string_add( - reach_json, "prefix", - prefix2str(&r->prefix, prefixbuf, sizeof(prefixbuf))); - json_object_int_add(reach_json, "metric", r->metric); - json_object_string_add(reach_json, "down", - r->down ? "yes" : ""); - json_object_string_add(reach_json, "external", - r->external ? "yes" : ""); - if (mtid != ISIS_MT_IPV4_UNICAST) - json_object_string_add(reach_json, "mt-name", - isis_mtid2str(mtid)); - if (r->subtlvs) { - struct json_object *subtlvs_json; - subtlvs_json = json_object_new_object(); - json_object_object_add(reach_json, "subtlvs", - subtlvs_json); - format_subtlvs(r->subtlvs, NULL, subtlvs_json, 0); - } - /* end deprecated key format */ } else { sbuf_push(buf, indent, "%sIPv6 Reachability: %s (Metric: %u)%s%s", @@ -5552,22 +4928,6 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, /* Router ID and Flags */ struct json_object *cap_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* deprecated JSON key format */ - cap_json = json_object_new_object(); - json_object_object_add(json, "router-capability", cap_json); - inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); - json_object_string_add(cap_json, "id", addrbuf); - json_object_string_add( - cap_json, "flag-d", - router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? "1" : "0"); - json_object_string_add( - cap_json, "flag-s", - router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? "1" : "0"); - /* end deprecated JSON key format */ - cap_json = json_object_new_object(); json_object_object_add(json, "routerCapability", cap_json); inet_ntop(AF_INET, &router_cap->router_id, addrbuf, sizeof(addrbuf)); @@ -5582,23 +4942,6 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, if (router_cap->srgb.range_size != 0) { struct json_object *gb_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* deprecated old key format */ - gb_json = json_object_new_object(); - json_object_object_add(json, "segment-routing-gb", gb_json); - json_object_string_add(gb_json, "ipv4", - IS_SR_IPV4(&router_cap->srgb) ? "1" - : "0"); - json_object_string_add(gb_json, "ipv6", - IS_SR_IPV6(&router_cap->srgb) ? "1" - : "0"); - json_object_int_add(gb_json, "global-block-base", - router_cap->srgb.lower_bound); - json_object_int_add(gb_json, "global-block-range", - router_cap->srgb.range_size); - gb_json = json_object_new_object(); json_object_object_add(json, "segmentRoutingGb", gb_json); json_object_boolean_add(gb_json, "ipv4", @@ -5615,18 +4958,6 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, if (router_cap->srlb.range_size != 0) { struct json_object *lb_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - lb_json = json_object_new_object(); - json_object_object_add(json, "segment-routing-lb", lb_json); - json_object_int_add(lb_json, "global-block-base", - router_cap->srlb.lower_bound); - json_object_int_add(lb_json, "global-block-range", - router_cap->srlb.range_size); - /* end old deprecated key format */ - lb_json = json_object_new_object(); json_object_object_add(json, "segmentRoutingLb", lb_json); json_object_int_add(lb_json, "globalBlockBase", @@ -5640,23 +4971,6 @@ static void format_tlv_router_cap_json(const struct isis_router_cap *router_cap, char buf[255]; struct json_object *alg_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - alg_json = json_object_new_object(); - json_object_object_add(json, "segment-routing-algorithm", - alg_json); - for (int i = 0; i < SR_ALGORITHM_COUNT; i++) - if (router_cap->algo[i] != SR_ALGORITHM_UNSET) { - snprintfrr(buf, sizeof(buf), "%d", i); - json_object_string_add(alg_json, buf, - router_cap->algo[i] == 0 - ? "SPF" - : "Strict SPF"); - } - /* end old deprecated key format */ - alg_json = json_object_new_object(); json_object_object_add(json, "segmentRoutingAlgorithm", alg_json); @@ -6147,16 +5461,17 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, return 0; } - if (tlvs->router_cap) - /* Multiple Router Capability found */ - rcap = tlvs->router_cap; - else { - /* Allocate router cap structure and initialize SR Algorithms */ - rcap = XCALLOC(MTYPE_ISIS_TLV, sizeof(struct isis_router_cap)); + if (!tlvs->router_cap) { + /* First Router Capability TLV. + * Allocate router cap structure and initialize SR Algorithms */ + tlvs->router_cap = XCALLOC(MTYPE_ISIS_TLV, + sizeof(struct isis_router_cap)); for (int i = 0; i < SR_ALGORITHM_COUNT; i++) - rcap->algo[i] = SR_ALGORITHM_UNSET; + tlvs->router_cap->algo[i] = SR_ALGORITHM_UNSET; } + rcap = tlvs->router_cap; + /* Get Router ID and Flags */ rcap->router_id.s_addr = stream_get_ipv4(s); rcap->flags = stream_getc(s); @@ -6178,7 +5493,6 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, log, indent, "WARNING: Router Capability subTLV length too large compared to expected size\n"); stream_forward_getp(s, STREAM_READABLE(s)); - XFREE(MTYPE_ISIS_TLV, rcap); return 0; } @@ -6489,7 +5803,6 @@ static int unpack_tlv_router_cap(enum isis_tlv_context context, } subtlv_len = subtlv_len - length - 2; } - tlvs->router_cap = rcap; return 0; } @@ -6512,24 +5825,16 @@ static void format_item_auth(uint16_t mtid, struct isis_item *i, struct isis_auth *auth = (struct isis_auth *)i; char obuf[768]; - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "test-auth", "ok"); + if (json) json_object_string_add(json, "testAuth", "ok"); - } else + else sbuf_push(buf, indent, "Authentication:\n"); switch (auth->type) { case ISIS_PASSWD_TYPE_CLEARTXT: zlog_sanitize(obuf, sizeof(obuf), auth->value, auth->length); - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "auth-pass", obuf); + if (json) json_object_string_add(json, "authPass", obuf); - } else + else sbuf_push(buf, indent, " Password: %s\n", obuf); break; case ISIS_PASSWD_TYPE_HMAC_MD5: @@ -6537,23 +5842,15 @@ static void format_item_auth(uint16_t mtid, struct isis_item *i, snprintf(obuf + 2 * j, sizeof(obuf) - 2 * j, "%02hhx", auth->value[j]); } - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "auth-hmac-md5", obuf); + if (json) json_object_string_add(json, "authHmacMd5", obuf); - } else + else sbuf_push(buf, indent, " HMAC-MD5: %s\n", obuf); break; default: - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_int_add(json, "auth-unknown", auth->type); + if (json) json_object_int_add(json, "authUnknown", auth->type); - } else + else sbuf_push(buf, indent, " Unknown (%hhu)\n", auth->type); break; @@ -6669,18 +5966,6 @@ static void format_tlv_purge_originator(struct isis_purge_originator *poi, if (json) { struct json_object *purge_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old deprecated key format */ - purge_json = json_object_new_object(); - json_object_object_add(json, "purge_originator", purge_json); - - json_object_string_add(purge_json, "id", gen_id); - if (poi->sender_set) - json_object_string_add(purge_json, "rec-from", sen_id); - /* end old deprecated key format */ - purge_json = json_object_new_object(); json_object_object_add(json, "purgeOriginator", purge_json); @@ -7230,33 +6515,6 @@ static void format_item_srv6_locator(uint16_t mtid, struct isis_item *i, if (json) { struct json_object *loc_json; -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - /* old json key format */ - loc_json = json_object_new_object(); - json_object_object_add(json, "srv6-locator", loc_json); - json_object_int_add(loc_json, "mt-id", mtid); - json_object_string_addf(loc_json, "prefix", "%pFX", - &loc->prefix); - json_object_int_add(loc_json, "metric", loc->metric); - json_object_string_add( - loc_json, "d-flag", - CHECK_FLAG(loc->flags, ISIS_TLV_SRV6_LOCATOR_FLAG_D) - ? "yes" - : ""); - json_object_int_add(loc_json, "algorithm", loc->algorithm); - json_object_string_add(loc_json, "mt-name", - isis_mtid2str(mtid)); - if (loc->subtlvs) { - struct json_object *subtlvs_json; - subtlvs_json = json_object_new_object(); - json_object_object_add(loc_json, "subtlvs", - subtlvs_json); - format_subtlvs(loc->subtlvs, NULL, subtlvs_json, 0); - } - /* old deprecated key format */ - loc_json = json_object_new_object(); json_object_object_add(json, "srv6Locator", loc_json); json_object_int_add(loc_json, "mtId", mtid); @@ -7558,13 +6816,9 @@ static void format_tlvs(struct isis_tlvs *tlvs, struct sbuf *buf, struct json_ob &tlvs->area_addresses, buf, json, indent); if (tlvs->mt_router_info_empty) { - if (json) { -#if CONFDATE > 20240916 - CPP_NOTICE("remove deprecated key format with -") -#endif - json_object_string_add(json, "mt-router-info", "none"); + if (json) json_object_object_add(json, "mtRouterInfo", NULL); - } else + else sbuf_push(buf, indent, "MT Router Info: None\n"); } else { format_items(ISIS_CONTEXT_LSP, ISIS_TLV_MT_ROUTER_INFO, @@ -16,14 +16,8 @@ extern "C" { #endif #define BFD_DEF_MIN_RX 300 -#define BFD_MIN_MIN_RX 50 -#define BFD_MAX_MIN_RX 60000 #define BFD_DEF_MIN_TX 300 -#define BFD_MIN_MIN_TX 50 -#define BFD_MAX_MIN_TX 60000 #define BFD_DEF_DETECT_MULT 3 -#define BFD_MIN_DETECT_MULT 2 -#define BFD_MAX_DETECT_MULT 255 #define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */ #define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */ diff --git a/lib/command.c b/lib/command.c index ac8d60118e..25c9ee9a73 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1454,7 +1454,7 @@ DEFUN (config_help, "Description of the interactive help system\n") { vty_out(vty, - "Quagga VTY provides advanced help feature. When you need help,\n\ + "FRR VTY provides advanced help feature. When you need help,\n\ anytime at the command line please press '?'.\n\ \n\ If nothing matches, the help list will be empty and you must backup\n\ diff --git a/lib/command.h b/lib/command.h index 61d09973fd..f369a35243 100644 --- a/lib/command.h +++ b/lib/command.h @@ -100,7 +100,6 @@ enum node_type { INTERFACE_NODE, /* Interface mode node. */ NH_GROUP_NODE, /* Nexthop-Group mode node. */ ZEBRA_NODE, /* zebra connection node. */ - TABLE_NODE, /* rtm_table selection node. */ RIP_NODE, /* RIP protocol mode node. */ RIPNG_NODE, /* RIPng protocol mode node. */ BABEL_NODE, /* BABEL protocol mode node. */ @@ -118,7 +117,6 @@ enum node_type { BGP_VNC_DEFAULTS_NODE, /* BGP VNC nve defaults */ BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */ BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */ - RFP_DEFAULTS_NODE, /* RFP defaults node */ BGP_EVPN_NODE, /* BGP EVPN node. */ BGP_SRV6_NODE, /* BGP SRv6 node. */ OSPF_NODE, /* OSPF protocol mode */ diff --git a/lib/elf_py.c b/lib/elf_py.c index 2b4fea373f..6c63d1f892 100644 --- a/lib/elf_py.c +++ b/lib/elf_py.c @@ -1307,7 +1307,7 @@ static PyObject *elffile_load(PyTypeObject *type, PyObject *args, } #endif - w->sects = calloc(sizeof(PyObject *), w->ehdr->e_shnum); + w->sects = calloc(w->ehdr->e_shnum, sizeof(PyObject *)); w->n_sect = w->ehdr->e_shnum; return (PyObject *)w; diff --git a/lib/frrscript.c b/lib/frrscript.c index acdd1df67b..dbae31b666 100644 --- a/lib/frrscript.c +++ b/lib/frrscript.c @@ -348,6 +348,9 @@ int frrscript_load(struct frrscript *fs, const char *function_name, /* Set up the Lua script */ lua_State *L = luaL_newstate(); + /* Load basic built-in Lua functions, e.g. ipairs, string, etc. */ + luaL_openlibs(L); + frrlua_export_logging(L); char script_name[MAXPATHLEN]; diff --git a/lib/libfrr.c b/lib/libfrr.c index 0a575abac6..a1982841d3 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -1125,9 +1125,12 @@ static void frr_terminal_close(int isexit) * don't redirect when stdout is set with --log stdout */ for (fd = 2; fd >= 0; fd--) - if (isatty(fd) && - (fd != STDOUT_FILENO || !logging_to_stdout)) + if (logging_to_stdout && isatty(fd) && + fd == STDOUT_FILENO) { + /* Do nothing. */ + } else { dup2(nullfd, fd); + } close(nullfd); } } @@ -1213,9 +1216,12 @@ void frr_run(struct event_loop *master) * stdout */ for (fd = 2; fd >= 0; fd--) - if (isatty(fd) && - (fd != STDOUT_FILENO || !logging_to_stdout)) + if (logging_to_stdout && isatty(fd) && + fd == STDOUT_FILENO) { + /* Do nothing. */ + } else { dup2(nullfd, fd); + } close(nullfd); } diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index 76a52658cd..ef03b66edc 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -383,11 +383,18 @@ _Static_assert(sizeof(struct mgmt_msg_edit) == /** * struct mgmt_msg_edit_reply - frontend edit reply. * - * @data: the xpath of the data node that was created. + * @changed: If true then changes in datastore resulted. + * @created: If true then object was newly created (non-existing before) + * @data: @vsplit values, second value may be zero len. + * @data: [0] the xpath of the data node that was created. + * @data: [1] Possible structured data to pass back to client (e.g., non-"error" + * yang modeled error data). */ struct mgmt_msg_edit_reply { struct mgmt_msg_header; - uint8_t resv2[8]; + uint8_t changed; + uint8_t created; + uint8_t resv2[6]; alignas(8) char data[]; }; diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 3f408e0a71..cb1ebb5d09 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -70,10 +70,10 @@ static struct nexthop *nexthop_group_tail(const struct nexthop_group *nhg) return nexthop; } -uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg) +uint16_t nexthop_group_nexthop_num(const struct nexthop_group *nhg) { struct nexthop *nhop; - uint8_t num = 0; + uint16_t num = 0; for (ALL_NEXTHOPS_PTR(nhg, nhop)) num++; @@ -81,11 +81,10 @@ uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg) return num; } -static uint8_t -nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg) +static uint16_t nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg) { struct nexthop *nhop; - uint8_t num = 0; + uint16_t num = 0; for (nhop = nhg->nexthop; nhop; nhop = nhop->next) num++; @@ -93,10 +92,10 @@ nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg) return num; } -uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg) +uint16_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg) { struct nexthop *nhop; - uint8_t num = 0; + uint16_t num = 0; for (ALL_NEXTHOPS_PTR(nhg, nhop)) { if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE)) @@ -184,11 +183,9 @@ static struct nexthop *nhg_nh_find(const struct nexthop_group *nhg, return NULL; } -static bool -nexthop_group_equal_common(const struct nexthop_group *nhg1, - const struct nexthop_group *nhg2, - uint8_t (*nexthop_group_nexthop_num_func)( - const struct nexthop_group *nhg)) +static bool nexthop_group_equal_common( + const struct nexthop_group *nhg1, const struct nexthop_group *nhg2, + uint16_t (*nexthop_group_nexthop_num_func)(const struct nexthop_group *nhg)) { if (nhg1 && !nhg2) return false; diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 822a35439c..9103299418 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -149,9 +149,8 @@ extern void nexthop_group_json_nexthop(json_object *j, const struct nexthop *nh); /* Return the number of nexthops in this nhg */ -extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg); -extern uint8_t -nexthop_group_active_nexthop_num(const struct nexthop_group *nhg); +extern uint16_t nexthop_group_nexthop_num(const struct nexthop_group *nhg); +extern uint16_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg); extern bool nexthop_group_has_label(const struct nexthop_group *nhg); diff --git a/lib/northbound.c b/lib/northbound.c index 0bc79d0277..2dae21341e 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -178,7 +178,7 @@ struct nb_node *nb_node_find(const char *path) struct nb_node **nb_nodes_find(const char *xpath) { - struct lysc_node **snodes = NULL; + const struct lysc_node **snodes = NULL; struct nb_node **nb_nodes = NULL; bool simple; LY_ERR err; @@ -816,8 +816,9 @@ int nb_candidate_edit(struct nb_config *candidate, const struct nb_node *nb_node static int nb_candidate_edit_tree_add(struct nb_config *candidate, enum nb_operation operation, LYD_FORMAT format, const char *xpath, - const char *data, char *xpath_created, - char *errmsg, size_t errmsg_len) + const char *data, bool *created, + char *xpath_created, char *errmsg, + size_t errmsg_len) { struct lyd_node *tree = NULL; struct lyd_node *parent = NULL; @@ -897,10 +898,18 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate, } /* check if the node already exists in candidate */ - if (operation == NB_OP_CREATE_EXCL || operation == NB_OP_REPLACE) { + if (operation == NB_OP_CREATE || operation == NB_OP_MODIFY) + existing = yang_dnode_get(candidate->dnode, xpath_created); + else if (operation == NB_OP_CREATE_EXCL || operation == NB_OP_REPLACE) { existing = yang_dnode_get(candidate->dnode, xpath_created); /* if the existing node is implicit default, ignore */ + /* Q: Is this correct for CREATE_EXCL which is supposed to error + * if the resouurce already exists? This is used by RESTCONF + * when processing the POST command, for example. RFC8040 + * doesn't say POST fails if resource exists "unless it was a + * default". + */ if (existing && (existing->flags & LYD_DEFAULT)) existing = NULL; @@ -908,7 +917,7 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate, if (operation == NB_OP_CREATE_EXCL) { snprintf(errmsg, errmsg_len, "Data already exists"); - ret = NB_ERR; + ret = NB_ERR_EXISTS; goto done; } @@ -930,7 +939,7 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate, LYD_MERGE_DESTRUCT | LYD_MERGE_WITH_FLAGS); if (err) { /* if replace failed, restore the original node */ - if (existing) { + if (existing && operation == NB_OP_REPLACE) { if (root) { /* Restoring the whole config. */ candidate->dnode = existing; @@ -954,6 +963,8 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate, ret = NB_ERR; goto done; } else { + if (!existing) + *created = true; /* * Free existing node after replace. * We're using `lyd_free_siblings` here to free the whole @@ -961,7 +972,7 @@ static int nb_candidate_edit_tree_add(struct nb_config *candidate, * siblings if it wasn't root, because the existing node * was unlinked from the tree. */ - if (existing) + if (existing && operation == NB_OP_REPLACE) lyd_free_siblings(existing); tree = NULL; /* LYD_MERGE_DESTRUCT deleted the tree */ @@ -995,7 +1006,7 @@ static int nb_candidate_edit_tree_del(struct nb_config *candidate, if (!dnode || (dnode->flags & LYD_DEFAULT)) { if (operation == NB_OP_DELETE) { snprintf(errmsg, errmsg_len, "Data missing"); - return NB_ERR; + return NB_ERR_NOT_FOUND; } else return NB_OK; } @@ -1011,7 +1022,7 @@ static int nb_candidate_edit_tree_del(struct nb_config *candidate, int nb_candidate_edit_tree(struct nb_config *candidate, enum nb_operation operation, LYD_FORMAT format, - const char *xpath, const char *data, + const char *xpath, const char *data, bool *created, char *xpath_created, char *errmsg, size_t errmsg_len) { int ret = NB_ERR; @@ -1022,8 +1033,9 @@ int nb_candidate_edit_tree(struct nb_config *candidate, case NB_OP_MODIFY: case NB_OP_REPLACE: ret = nb_candidate_edit_tree_add(candidate, operation, format, - xpath, data, xpath_created, - errmsg, errmsg_len); + xpath, data, created, + xpath_created, errmsg, + errmsg_len); break; case NB_OP_DESTROY: case NB_OP_DELETE: @@ -2605,6 +2617,8 @@ const char *nb_err_name(enum nb_error error) return "no changes"; case NB_ERR_NOT_FOUND: return "element not found"; + case NB_ERR_EXISTS: + return "element already exists"; case NB_ERR_LOCKED: return "resource is locked"; case NB_ERR_VALIDATION: diff --git a/lib/northbound.h b/lib/northbound.h index da5f5be1ee..dd3fbf8f73 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -678,6 +678,7 @@ enum nb_error { NB_ERR, NB_ERR_NO_CHANGES, NB_ERR_NOT_FOUND, + NB_ERR_EXISTS, NB_ERR_LOCKED, NB_ERR_VALIDATION, NB_ERR_RESOURCE, @@ -1015,6 +1016,9 @@ extern int nb_candidate_edit(struct nb_config *candidate, * data * New data tree for the node. * + * created + * OUT param set accordingly if a node was created or just updated + * * xpath_created * XPath of the created node if operation is "create". * @@ -1029,9 +1033,9 @@ extern int nb_candidate_edit(struct nb_config *candidate, * - NB_ERR for other errors. */ extern int nb_candidate_edit_tree(struct nb_config *candidate, - enum nb_operation operation, - LYD_FORMAT format, const char *xpath, - const char *data, char *xpath_created, + enum nb_operation operation, LYD_FORMAT format, + const char *xpath, const char *data, + bool *created, char *xpath_created, char *errmsg, size_t errmsg_len); /* @@ -1712,6 +1716,7 @@ extern void nb_terminate(void); extern void nb_oper_init(struct event_loop *loop); extern void nb_oper_terminate(void); +extern bool nb_oper_is_yang_lib_query(const char *xpath); #ifdef __cplusplus } diff --git a/lib/northbound_oper.c b/lib/northbound_oper.c index e95f99a2bd..a3ff360780 100644 --- a/lib/northbound_oper.c +++ b/lib/northbound_oper.c @@ -1741,6 +1741,16 @@ static enum nb_error nb_op_walk_start(struct nb_op_yield_state *ys) return __walk(ys, false); } +bool nb_oper_is_yang_lib_query(const char *xpath) +{ + const char *libstr = "/ietf-yang-library:"; + const unsigned long liblen = strlen(libstr); + + if (strncmp(libstr, xpath, liblen)) + return false; + + return strlen(xpath) > liblen; +} void *nb_oper_walk(const char *xpath, struct yang_translator *translator, uint32_t flags, bool should_batch, nb_oper_data_cb cb, diff --git a/lib/srv6.h b/lib/srv6.h index f25c5cfcaa..9a041e3d85 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -106,6 +106,10 @@ struct seg6local_context { struct in6_addr nh6; uint32_t table; struct seg6local_flavors_info flv; + uint8_t block_len; + uint8_t node_len; + uint8_t function_len; + uint8_t argument_len; }; struct srv6_locator { diff --git a/lib/yang.c b/lib/yang.c index 6c1aed00cc..14d5b118c6 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -286,7 +286,7 @@ void yang_snode_get_path(const struct lysc_node *snode, } LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath, - struct lysc_node ***snodes, bool *simple) + const struct lysc_node ***snodes, bool *simple) { struct lysc_node *snode; struct ly_set *set; diff --git a/lib/yang.h b/lib/yang.h index 57131f478b..c4fc78b8ae 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -827,7 +827,8 @@ extern int yang_xpath_pop_node(char *xpath); * Return: a libyang error or LY_SUCCESS. */ extern LY_ERR yang_resolve_snode_xpath(struct ly_ctx *ly_ctx, const char *xpath, - struct lysc_node ***snodes, bool *simple); + const struct lysc_node ***snodes, + bool *simple); /* * Libyang future functions diff --git a/mgmtd/mgmt.c b/mgmtd/mgmt.c index cfadad4829..02c54b9215 100644 --- a/mgmtd/mgmt.c +++ b/mgmtd/mgmt.c @@ -57,6 +57,9 @@ void mgmt_init(void) /* Initialize MGMTD Transaction module */ mgmt_txn_init(mm, mm->master); + /* Add yang-library module */ + yang_module_load("ietf-yang-library", NULL); + /* Initialize the MGMTD Frontend Adapter Module */ mgmt_fe_adapter_init(mm->master); diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c index 09d1910cee..32f28a5774 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -1164,7 +1164,9 @@ done: } static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session, - uint64_t req_id, const char *xpath) + uint64_t req_id, bool changed, + bool created, const char *xpath, + const char *data) { struct mgmt_msg_edit_reply *msg; int ret; @@ -1173,14 +1175,19 @@ static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session, MTYPE_MSG_NATIVE_EDIT_REPLY); msg->refer_id = session->session_id; msg->req_id = req_id; + msg->changed = changed; + msg->created = created; msg->code = MGMT_MSG_CODE_EDIT_REPLY; mgmt_msg_native_xpath_encode(msg, xpath); + if (data) + mgmt_msg_native_append(msg, data, strlen(data) + 1); + __dbg("Sending edit-reply from adapter %s to session-id %" PRIu64 - " req-id %" PRIu64 " len %u", - session->adapter->name, session->session_id, req_id, - mgmt_msg_native_get_msg_len(msg)); + " req-id %" PRIu64 " changed %u created %u len %u", + session->adapter->name, session->session_id, req_id, changed, + created, mgmt_msg_native_get_msg_len(msg)); ret = fe_adapter_send_native_msg(session->adapter, msg, mgmt_msg_native_get_msg_len(msg), @@ -1282,8 +1289,7 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session, void *__msg, size_t msg_len) { struct mgmt_msg_get_data *msg = __msg; - struct lysc_node **snodes = NULL; - char *xpath_resolved = NULL; + const struct lysc_node **snodes = NULL; uint64_t req_id = msg->req_id; Mgmtd__DatastoreId ds_id; uint64_t clients; @@ -1331,6 +1337,31 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session, goto done; } + /* Check for yang-library shortcut */ + if (nb_oper_is_yang_lib_query(msg->xpath)) { + struct lyd_node *ylib = NULL; + LY_ERR err; + + err = ly_ctx_get_yanglib_data(ly_native_ctx, &ylib, "%u", + ly_ctx_get_change_count( + ly_native_ctx)); + if (err) { + fe_adapter_send_error(session, req_id, false, err, + "Error getting yang-library data, session-id: %" PRIu64 + " error: %s", + session->session_id, + ly_last_errmsg()); + } else { + yang_lyd_trim_xpath(&ylib, msg->xpath); + (void)fe_adapter_send_tree_data(session, req_id, false, + msg->result_type, + wd_options, ylib, 0); + } + if (ylib) + lyd_free_all(ylib); + goto done; + } + switch (msg->datastore) { case MGMT_MSG_DATASTORE_CANDIDATE: ds_id = MGMTD_DS_CANDIDATE; @@ -1395,7 +1426,6 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session, } done: darr_free(snodes); - darr_free(xpath_resolved); } static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session, @@ -1408,7 +1438,12 @@ static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session, bool lock, commit; int ret; - if (msg->datastore != MGMT_MSG_DATASTORE_CANDIDATE) { + lock = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_LOCK); + commit = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_COMMIT); + + if (lock && commit && msg->datastore == MGMT_MSG_DATASTORE_RUNNING) + ; + else if (msg->datastore != MGMT_MSG_DATASTORE_CANDIDATE) { fe_adapter_send_error(session, msg->req_id, false, -EINVAL, "Unsupported datastore"); return; @@ -1429,9 +1464,6 @@ static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session, rds_ctx = mgmt_ds_get_ctx_by_id(mm, rds_id); assert(rds_ctx); - lock = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_LOCK); - commit = CHECK_FLAG(msg->flags, EDIT_FLAG_IMPLICIT_COMMIT); - if (lock) { if (mgmt_fe_session_write_lock_ds(ds_id, ds_ctx, session)) { fe_adapter_send_error(session, msg->req_id, false, @@ -1977,8 +2009,8 @@ int mgmt_fe_adapter_send_rpc_reply(uint64_t session_id, uint64_t txn_id, int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id, uint64_t req_id, bool unlock, bool commit, - const char *xpath, int16_t error, - const char *errstr) + bool created, const char *xpath, + int16_t error, const char *errstr) { struct mgmt_fe_session_ctx *session; Mgmtd__DatastoreId ds_id, rds_id; @@ -2009,11 +2041,12 @@ int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id, } } - if (error) + if (error != 0 && error != -EALREADY) ret = fe_adapter_send_error(session, req_id, false, error, "%s", errstr); else - ret = fe_adapter_send_edit_reply(session, req_id, xpath); + ret = fe_adapter_send_edit_reply(session, req_id, created, + !error, xpath, errstr); if (session->cfg_txn_id != MGMTD_TXN_ID_NONE && !commit) mgmt_destroy_txn(&session->cfg_txn_id); diff --git a/mgmtd/mgmt_fe_adapter.h b/mgmtd/mgmt_fe_adapter.h index 61d6cfae13..4d94e7604f 100644 --- a/mgmtd/mgmt_fe_adapter.h +++ b/mgmtd/mgmt_fe_adapter.h @@ -193,14 +193,16 @@ extern int mgmt_fe_adapter_send_rpc_reply(uint64_t session_id, uint64_t txn_id, * req_id: the req id for the edit message * unlock: implicit-lock flag was set in the request * commit: implicit-commit flag was set in the request - * xpath: the xpath of the data node that was created - * error: the error code, zero for successful request + * created: true if the node was just created + * xpath: the xpath of the data node that was created/updated + * error: >0 LY_ERR, < 0 -errno * errstr: the error string, if error is non-zero */ extern int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id, uint64_t req_id, bool unlock, - bool commit, const char *xpath, - int16_t error, const char *errstr); + bool commit, bool created, + const char *xpath, int16_t error, + const char *errstr); /** * Send an error back to the FE client using native messaging. @@ -210,7 +212,7 @@ extern int mgmt_fe_adapter_send_edit_reply(uint64_t session_id, uint64_t txn_id, * Args: * txn_id: the txn_id this error pertains to. * short_circuit_ok: True if OK to short-circuit the call. - * error: An integer error value. + * error: >0 LY_ERR, < 0 -errno * errfmt: An error format string (i.e., printfrr) * ...: args for use by the `errfmt` format string. * diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c index ed133243a1..ccfdd7539f 100644 --- a/mgmtd/mgmt_txn.c +++ b/mgmtd/mgmt_txn.c @@ -94,6 +94,7 @@ DECLARE_LIST(mgmt_txn_batches, struct mgmt_txn_be_cfg_batch, list_linkage); struct mgmt_edit_req { char xpath_created[XPATH_MAXLEN]; + bool created; bool unlock; }; @@ -742,6 +743,8 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn, .edit->unlock, true, txn->commit_cfg_req->req.commit_cfg + .edit->created, + txn->commit_cfg_req->req.commit_cfg .edit->xpath_created, success ? 0 : -1, error_if_any) != 0) { @@ -1335,7 +1338,8 @@ static int txn_get_tree_data_done(struct mgmt_txn_ctx *txn, " req_id %" PRIu64 " to requested type %u", txn->txn_id, req_id, get_tree->result_type); - (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, ret, + (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, + errno_from_nb_error(ret), "Error converting results of GETTREE"); } @@ -1351,7 +1355,7 @@ static int txn_rpc_done(struct mgmt_txn_ctx *txn, struct mgmt_txn_req *txn_req) EVENT_OFF(txn->rpc_timeout); if (rpc->errstr) - mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, -1, + mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, -EINVAL, rpc->errstr); else if (mgmt_fe_adapter_send_rpc_reply(txn->session_id, txn->txn_id, req_id, rpc->result_type, @@ -1360,7 +1364,8 @@ static int txn_rpc_done(struct mgmt_txn_ctx *txn, struct mgmt_txn_req *txn_req) " req_id %" PRIu64 " to requested type %u", txn->txn_id, req_id, rpc->result_type); - (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, -1, + (void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, + -EINVAL, "Error converting results of RPC"); } @@ -2564,8 +2569,8 @@ int mgmt_txn_send_edit(uint64_t txn_id, uint64_t req_id, assert(nb_config); ret = nb_candidate_edit_tree(nb_config, operation, request_type, xpath, - data, edit->xpath_created, errstr, - sizeof(errstr)); + data, &edit->created, edit->xpath_created, + errstr, sizeof(errstr)); if (ret) goto reply; @@ -2579,8 +2584,9 @@ int mgmt_txn_send_edit(uint64_t txn_id, uint64_t req_id, } reply: mgmt_fe_adapter_send_edit_reply(txn->session_id, txn->txn_id, req_id, - unlock, commit, edit->xpath_created, - ret ? -1 : 0, errstr); + unlock, commit, edit->created, + edit->xpath_created, + errno_from_nb_error(ret), errstr); XFREE(MTYPE_MGMTD_TXN_REQ, edit); diff --git a/mgmtd/mgmt_txn.h b/mgmtd/mgmt_txn.h index b6ca288675..37dadc0171 100644 --- a/mgmtd/mgmt_txn.h +++ b/mgmtd/mgmt_txn.h @@ -69,6 +69,34 @@ static inline const char *mgmt_txn_type2str(enum mgmt_txn_type type) return "Unknown"; } + +static inline int16_t errno_from_nb_error(enum nb_error ret) +{ + switch (ret) { + case NB_OK: + return 0; + case NB_ERR_NO_CHANGES: + return -EALREADY; + case NB_ERR_NOT_FOUND: + return -ENOENT; + case NB_ERR_EXISTS: + return -EEXIST; + case NB_ERR_LOCKED: + return -EWOULDBLOCK; + case NB_ERR_VALIDATION: + return -EINVAL; + case NB_ERR_RESOURCE: + return -ENOMEM; + case NB_ERR: + case NB_ERR_INCONSISTENCY: + return -EINVAL; + case NB_YIELD: + default: + return -EINVAL; + } +} + + /* Initialise transaction module. */ extern int mgmt_txn_init(struct mgmt_master *cm, struct event_loop *tm); diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 3495317d4c..d2c1a8c401 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -597,6 +597,12 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) nhrp_ext_complete(zb, ext); } break; + case NHRP_EXTENSION_AUTHENTICATION: + /* Extensions can be copied from original packet except + * authentication extension which must be regenerated + * hop by hop. + */ + break; default: if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0) goto err; diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index 9b47d974c3..55d61a90b8 100644 --- a/nhrpd/nhrp_shortcut.c +++ b/nhrpd/nhrp_shortcut.c @@ -21,14 +21,16 @@ static struct route_table *shortcut_rib[AFI_MAX]; static void nhrp_shortcut_do_purge(struct event *t); static void nhrp_shortcut_delete(struct nhrp_shortcut *s, void *arg __attribute__((__unused__))); -static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s); +static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s, + bool retry); +static void nhrp_shortcut_retry_resolution_req(struct event *t); static void nhrp_shortcut_check_use(struct nhrp_shortcut *s) { if (s->expiring && s->cache && s->cache->used) { debugf(NHRP_DEBUG_ROUTE, "Shortcut %pFX used and expiring", s->p); - nhrp_shortcut_send_resolution_req(s); + nhrp_shortcut_send_resolution_req(s, false); } } @@ -37,7 +39,7 @@ static void nhrp_shortcut_do_expire(struct event *t) struct nhrp_shortcut *s = EVENT_ARG(t); event_add_timer(master, nhrp_shortcut_do_purge, s, s->holding_time / 3, - &s->t_timer); + &s->t_shortcut_purge); s->expiring = 1; nhrp_shortcut_check_use(s); } @@ -124,12 +126,12 @@ static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s, s->route_installed = 0; } - EVENT_OFF(s->t_timer); + EVENT_OFF(s->t_shortcut_purge); if (holding_time) { s->expiring = 0; s->holding_time = holding_time; event_add_timer(master, nhrp_shortcut_do_expire, s, - 2 * holding_time / 3, &s->t_timer); + 2 * holding_time / 3, &s->t_shortcut_purge); } } @@ -139,7 +141,8 @@ static void nhrp_shortcut_delete(struct nhrp_shortcut *s, struct route_node *rn; afi_t afi = family2afi(PREFIX_FAMILY(s->p)); - EVENT_OFF(s->t_timer); + EVENT_OFF(s->t_shortcut_purge); + EVENT_OFF(s->t_retry_resolution); nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); debugf(NHRP_DEBUG_ROUTE, "Shortcut %pFX purged", s->p); @@ -159,7 +162,8 @@ static void nhrp_shortcut_delete(struct nhrp_shortcut *s, static void nhrp_shortcut_do_purge(struct event *t) { struct nhrp_shortcut *s = EVENT_ARG(t); - s->t_timer = NULL; + s->t_shortcut_purge = NULL; + EVENT_OFF(s->t_retry_resolution); nhrp_shortcut_delete(s, NULL); } @@ -206,8 +210,10 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, int holding_time = pp->if_ad->holdtime; nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); - EVENT_OFF(s->t_timer); - event_add_timer(master, nhrp_shortcut_do_purge, s, 1, &s->t_timer); + EVENT_OFF(s->t_shortcut_purge); + EVENT_OFF(s->t_retry_resolution); + event_add_timer(master, nhrp_shortcut_do_purge, s, 1, + &s->t_shortcut_purge); if (pp->hdr->type != NHRP_PACKET_RESOLUTION_REPLY) { if (pp->hdr->type == NHRP_PACKET_ERROR_INDICATION @@ -374,7 +380,8 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution reply handled"); } -static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) +static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s, + bool retry) { struct zbuf *zb; struct nhrp_packet_header *hdr; @@ -389,6 +396,22 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) != NHRP_ROUTE_NBMA_NEXTHOP) return; + /*Retry interval for NHRP resolution request + * will start at 1 second and will be doubled every time + * another resolution request is sent, until it is + * eventually upper-bounded by the purge time of + * the shortcut. + */ + if (!retry) + s->retry_interval = 1; + event_add_timer(master, nhrp_shortcut_retry_resolution_req, s, + s->retry_interval, &s->t_retry_resolution); + if (s->retry_interval != (NHRPD_DEFAULT_PURGE_TIME / 4)) + s->retry_interval = ((s->retry_interval * 2) < + (NHRPD_DEFAULT_PURGE_TIME / 4)) + ? (s->retry_interval * 2) + : (NHRPD_DEFAULT_PURGE_TIME / 4); + if (s->type == NHRP_CACHE_INVALID || s->type == NHRP_CACHE_NEGATIVE) s->type = NHRP_CACHE_INCOMPLETE; @@ -401,9 +424,23 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) zb, NHRP_PACKET_RESOLUTION_REQUEST, &nifp->nbma, &nifp->afi[family2afi(sockunion_family(&s->addr))].addr, &s->addr); - hdr->u.request_id = - htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid, - nhrp_shortcut_recv_resolution_rep)); + + /* RFC2332 - The value is taken from a 32 bit counter that is incremented + * each time a new "request" is transmitted. The same value MUST + * be used when resending a "request", i.e., when a "reply" has not been + * received for a "request" and a retry is sent after an + * appropriate interval + */ + if (!retry) + hdr->u.request_id = htonl( + nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid, + nhrp_shortcut_recv_resolution_rep)); + else + /* Just pull request_id from existing incomplete + * shortcut in the case of a retry + */ + hdr->u.request_id = htonl(s->reqid.request_id); + hdr->flags = htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER | NHRP_FLAG_RESOLUTION_AUTHORATIVE | NHRP_FLAG_RESOLUTION_SOURCE_STABLE); @@ -412,7 +449,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) * - Prefix length: widest acceptable prefix we accept (if U set, 0xff) * - MTU: MTU of the source station * - Holding Time: Max time to cache the source information - * */ + */ /* FIXME: push CIE for each local protocol address */ cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL); if_ad = &nifp->afi[family2afi(sockunion_family(&s->addr))]; @@ -456,13 +493,25 @@ void nhrp_shortcut_initiate(union sockunion *addr) s = nhrp_shortcut_get(&p); if (s && s->type != NHRP_CACHE_INCOMPLETE) { s->addr = *addr; - EVENT_OFF(s->t_timer); - event_add_timer(master, nhrp_shortcut_do_purge, s, 30, - &s->t_timer); - nhrp_shortcut_send_resolution_req(s); + EVENT_OFF(s->t_shortcut_purge); + EVENT_OFF(s->t_retry_resolution); + + event_add_timer(master, nhrp_shortcut_do_purge, s, + NHRPD_DEFAULT_PURGE_TIME, &s->t_shortcut_purge); + nhrp_shortcut_send_resolution_req(s, false); } } +static void nhrp_shortcut_retry_resolution_req(struct event *t) +{ + struct nhrp_shortcut *s = EVENT_ARG(t); + + EVENT_OFF(s->t_retry_resolution); + debugf(NHRP_DEBUG_COMMON, "Shortcut: Retrying Resolution Request"); + nhrp_shortcut_send_resolution_req(s, true); +} + + void nhrp_shortcut_init(void) { shortcut_rib[AFI_IP] = route_table_init(); @@ -503,13 +552,14 @@ struct purge_ctx { void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force) { - EVENT_OFF(s->t_timer); + EVENT_OFF(s->t_shortcut_purge); + EVENT_OFF(s->t_retry_resolution); nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); if (force) { /* Immediate purge on route with draw or pending shortcut */ event_add_timer_msec(master, nhrp_shortcut_do_purge, s, 5, - &s->t_timer); + &s->t_shortcut_purge); } else { /* Soft expire - force immediate renewal, but purge * in few seconds to make sure stale route is not @@ -518,8 +568,8 @@ void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force) * This allows to keep nhrp route up, and to not * cause temporary rerouting via hubs causing latency * jitter. */ - event_add_timer_msec(master, nhrp_shortcut_do_purge, s, 3000, - &s->t_timer); + event_add_timer_msec(master, nhrp_shortcut_do_purge, s, + NHRPD_PURGE_EXPIRE, &s->t_shortcut_purge); s->expiring = 1; nhrp_shortcut_check_use(s); } diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index 344e1d5178..6cab7b3a1d 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -15,7 +15,8 @@ DECLARE_MGROUP(NHRPD); #define NHRPD_DEFAULT_HOLDTIME 7200 - +#define NHRPD_DEFAULT_PURGE_TIME 30 +#define NHRPD_PURGE_EXPIRE 3000 #define NHRP_DEFAULT_CONFIG "nhrpd.conf" extern struct event_loop *master; @@ -250,10 +251,12 @@ struct nhrp_shortcut { union sockunion addr; struct nhrp_reqid reqid; - struct event *t_timer; + struct event *t_shortcut_purge; + struct event *t_retry_resolution; enum nhrp_cache_type type; unsigned int holding_time; + unsigned int retry_interval; unsigned route_installed : 1; unsigned expiring : 1; diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index 0c5be29ff8..343dfefcec 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -553,8 +553,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, lsa_header = (struct ospf6_lsa_header *)buffer; if (route->type == OSPF6_DEST_TYPE_ROUTER) { - router_lsa = (struct ospf6_inter_router_lsa *) - ospf6_lsa_header_end(lsa_header); + router_lsa = lsa_after_header(lsa_header); p = (caddr_t)router_lsa + sizeof(struct ospf6_inter_router_lsa); /* Fill Inter-Area-Router-LSA */ @@ -565,8 +564,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, router_lsa->router_id = ADV_ROUTER_IN_PREFIX(&route->prefix); type = htons(OSPF6_LSTYPE_INTER_ROUTER); } else { - prefix_lsa = (struct ospf6_inter_prefix_lsa *) - ospf6_lsa_header_end(lsa_header); + prefix_lsa = lsa_after_header(lsa_header); p = (caddr_t)prefix_lsa + sizeof(struct ospf6_inter_prefix_lsa); /* Fill Inter-Area-Prefix-LSA */ @@ -1016,8 +1014,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) oa->name); } - prefix_lsa = (struct ospf6_inter_prefix_lsa *) - ospf6_lsa_header_end(lsa->header); + prefix_lsa = lsa_after_header(lsa->header); prefix.family = AF_INET6; prefix.prefixlen = prefix_lsa->prefix.prefix_length; ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa, @@ -1036,8 +1033,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) oa->name); } - router_lsa = (struct ospf6_inter_router_lsa *) - ospf6_lsa_header_end(lsa->header); + router_lsa = lsa_after_header(lsa->header); ospf6_linkstate_prefix(router_lsa->router_id, htonl(0), &prefix); if (is_debug) inet_ntop(AF_INET, &router_lsa->router_id, buf, @@ -1429,8 +1425,7 @@ static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, char tbuf[16]; if (lsa != NULL) { - prefix_lsa = (struct ospf6_inter_prefix_lsa *) - ospf6_lsa_header_end(lsa->header); + prefix_lsa = lsa_after_header(lsa->header); ospf6_prefix_in6_addr(&in6, prefix_lsa, &prefix_lsa->prefix); if (buf) { @@ -1452,8 +1447,7 @@ static int ospf6_inter_area_prefix_lsa_show(struct vty *vty, struct ospf6_inter_prefix_lsa *prefix_lsa; char buf[INET6_ADDRSTRLEN]; - prefix_lsa = (struct ospf6_inter_prefix_lsa *)ospf6_lsa_header_end( - lsa->header); + prefix_lsa = lsa_after_header(lsa->header); if (use_json) { json_object_int_add( @@ -1489,9 +1483,7 @@ static char *ospf6_inter_area_router_lsa_get_prefix_str(struct ospf6_lsa *lsa, struct ospf6_inter_router_lsa *router_lsa; if (lsa != NULL) { - router_lsa = (struct ospf6_inter_router_lsa *) - ospf6_lsa_header_end(lsa->header); - + router_lsa = lsa_after_header(lsa->header); if (buf) inet_ntop(AF_INET, &router_lsa->router_id, buf, buflen); @@ -1508,8 +1500,7 @@ static int ospf6_inter_area_router_lsa_show(struct vty *vty, struct ospf6_inter_router_lsa *router_lsa; char buf[64]; - router_lsa = (struct ospf6_inter_router_lsa *)ospf6_lsa_header_end( - lsa->header); + router_lsa = lsa_after_header(lsa->header); ospf6_options_printbuf(router_lsa->options, buf, sizeof(buf)); if (use_json) { diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h index 52686ed49f..ab9e000d43 100644 --- a/ospf6d/ospf6_abr.h +++ b/ospf6d/ospf6_abr.h @@ -17,22 +17,6 @@ extern unsigned char conf_debug_ospf6_abr; #define OSPF6_DEBUG_ABR_OFF() (conf_debug_ospf6_abr = 0) #define IS_OSPF6_DEBUG_ABR (conf_debug_ospf6_abr) -/* Inter-Area-Prefix-LSA */ -#define OSPF6_INTER_PREFIX_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ -struct ospf6_inter_prefix_lsa { - uint32_t metric; - struct ospf6_prefix prefix; -}; - -/* Inter-Area-Router-LSA */ -#define OSPF6_INTER_ROUTER_LSA_FIX_SIZE 12U -struct ospf6_inter_router_lsa { - uint8_t mbz; - uint8_t options[3]; - uint32_t metric; - uint32_t router_id; -}; - #define OSPF6_ABR_SUMMARY_METRIC(E) \ (ntohl((E)->metric & htonl(OSPF6_EXT_PATH_METRIC_MAX))) #define OSPF6_ABR_SUMMARY_METRIC_SET(E, C) \ diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 2065527c93..8fa85badbe 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -39,6 +39,7 @@ #include "ospf6d.h" #include "ospf6_spf.h" #include "ospf6_nssa.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" #include "lib/json.h" @@ -102,8 +103,7 @@ struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route, /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - as_external_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa_header); + as_external_lsa = lsa_after_header(lsa_header); p = (caddr_t)((caddr_t)as_external_lsa + sizeof(struct ospf6_as_external_lsa)); @@ -216,8 +216,7 @@ static route_tag_t ospf6_as_external_lsa_get_tag(struct ospf6_lsa *lsa) if (!lsa) return 0; - external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa->header); + external = lsa_after_header(lsa->header); if (!CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_T)) return 0; @@ -520,8 +519,7 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) type = ntohs(lsa->header->type); oa = lsa->lsdb->data; - external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa->header); + external = lsa_after_header(lsa->header); if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) zlog_debug("Calculate AS-External route for %s", lsa->name); @@ -725,8 +723,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, int type; bool debug = false; - external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa->header); + external = lsa_after_header(lsa->header); if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || (IS_OSPF6_DEBUG_NSSA)) debug = true; @@ -2424,8 +2421,7 @@ static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa, char tbuf[16]; if (lsa) { - external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa->header); + external = lsa_after_header(lsa->header); if (pos == 0) { ospf6_prefix_in6_addr(&in6, external, @@ -2459,8 +2455,7 @@ static int ospf6_as_external_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, char buf[64]; assert(lsa->header); - external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa->header); + external = lsa_after_header(lsa->header); /* bits */ snprintf(buf, sizeof(buf), "%c%c%c", @@ -3027,8 +3022,7 @@ ospf6_originate_summary_lsa(struct ospf6 *ospf6, return; } - external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - aggr_lsa->header); + external = lsa_after_header(aggr_lsa->header); metric = (unsigned long)OSPF6_ASBR_METRIC(external); tag = ospf6_as_external_lsa_get_tag(aggr_lsa); mtype = CHECK_FLAG(external->bits_metric, @@ -3176,7 +3170,7 @@ ospf6_handle_external_aggr_modify(struct ospf6 *ospf6, return OSPF6_FAILURE; } - asel = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end(lsa->header); + asel = lsa_after_header(lsa->header); metric = (unsigned long)OSPF6_ASBR_METRIC(asel); tag = ospf6_as_external_lsa_get_tag(lsa); mtype = CHECK_FLAG(asel->bits_metric, @@ -3365,8 +3359,7 @@ static void ospf6_handle_aggregated_exnl_rt(struct ospf6 *ospf6, lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), htonl(info->id), ospf6->router_id, ospf6->lsdb); if (lsa) { - ext_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa->header); + ext_lsa = lsa_after_header(lsa->header); if (rt->prefix.prefixlen != ext_lsa->prefix.prefix_length) return; diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 21e6d898e8..ace3ba8488 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -79,17 +79,6 @@ struct ospf6_external_aggr_rt { struct hash *match_extnl_hash; }; -/* AS-External-LSA */ -#define OSPF6_AS_EXTERNAL_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ -struct ospf6_as_external_lsa { - uint32_t bits_metric; - - struct ospf6_prefix prefix; - /* followed by none or one forwarding address */ - /* followed by none or one external route tag */ - /* followed by none or one referenced LS-ID */ -}; - #define OSPF6_ASBR_BIT_T ntohl (0x01000000) #define OSPF6_ASBR_BIT_F ntohl (0x02000000) #define OSPF6_ASBR_BIT_E ntohl (0x04000000) diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index b87aa2ffe1..04ff35083f 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -26,6 +26,7 @@ #include "ospf6_flood.h" #include "ospf6_nssa.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" unsigned char conf_debug_ospf6_flooding; diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c index ab119a4ea4..64eb90d5f2 100644 --- a/ospf6d/ospf6_gr.c +++ b/ospf6d/ospf6_gr.c @@ -16,6 +16,7 @@ #include "printfrr.h" #include "lib_errors.h" +#include "ospf6_proto.h" #include "ospf6d/ospf6_lsa.h" #include "ospf6d/ospf6_lsdb.h" #include "ospf6d/ospf6_route.h" @@ -30,6 +31,7 @@ #include "ospf6d/ospf6_flood.h" #include "ospf6d/ospf6_intra.h" #include "ospf6d/ospf6_spf.h" +#include "ospf6d/ospf6_tlv.h" #include "ospf6d/ospf6_gr.h" #include "ospf6d/ospf6_gr_clippy.c" @@ -54,16 +56,17 @@ static int ospf6_gr_lsa_originate(struct ospf6_interface *oi, /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - grace_lsa = (struct ospf6_grace_lsa *)ospf6_lsa_header_end(lsa_header); + grace_lsa = lsa_after_header(lsa_header); /* Put grace period. */ - grace_lsa->tlv_period.header.type = htons(GRACE_PERIOD_TYPE); - grace_lsa->tlv_period.header.length = htons(GRACE_PERIOD_LENGTH); + grace_lsa->tlv_period.header.type = htons(TLV_GRACE_PERIOD_TYPE); + grace_lsa->tlv_period.header.length = htons(TLV_GRACE_PERIOD_LENGTH); grace_lsa->tlv_period.interval = htonl(gr_info->grace_period); /* Put restart reason. */ - grace_lsa->tlv_reason.header.type = htons(RESTART_REASON_TYPE); - grace_lsa->tlv_reason.header.length = htons(RESTART_REASON_LENGTH); + grace_lsa->tlv_reason.header.type = htons(TLV_GRACE_RESTART_REASON_TYPE); + grace_lsa->tlv_reason.header.length = + htons(TLV_GRACE_RESTART_REASON_LENGTH); grace_lsa->tlv_reason.reason = reason; /* Fill LSA Header */ diff --git a/ospf6d/ospf6_gr.h b/ospf6d/ospf6_gr.h index 84ef3aeb8a..e10d20680b 100644 --- a/ospf6d/ospf6_gr.h +++ b/ospf6d/ospf6_gr.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * OSPF6 Graceful Retsart helper functions. + * OSPF6 Graceful Restart helper functions. + * Ref RFC 5187 * * Copyright (C) 2021-22 Vmware, Inc. * Rajesh Kumar Girada @@ -60,58 +61,16 @@ enum ospf6_gr_helper_rejected_reason { OSPF6_HELPER_RESTARTING, }; -#ifdef roundup -#define ROUNDUP(val, gran) roundup(val, gran) -#else /* roundup */ -#define ROUNDUP(val, gran) (((val)-1 | (gran)-1) + 1) -#endif /* roundup */ -/* - * Generic TLV (type, length, value) macros - */ -struct tlv_header { - uint16_t type; /* Type of Value */ - uint16_t length; /* Length of Value portion only, in bytes */ -}; - -#define TLV_HDR_SIZE (sizeof(struct tlv_header)) - -#define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(uint32_t))) - -#define TLV_SIZE(tlvh) (uint32_t)(TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) - -#define TLV_HDR_TOP(lsah) \ - (struct tlv_header *)((char *)(lsah) + OSPF6_LSA_HEADER_SIZE) - -#define TLV_HDR_NEXT(tlvh) \ - (struct tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) - -/* Ref RFC5187 appendix-A */ -/* Grace period TLV */ -#define GRACE_PERIOD_TYPE 1 -#define GRACE_PERIOD_LENGTH 4 -struct grace_tlv_graceperiod { - struct tlv_header header; - uint32_t interval; -}; -#define GRACE_PERIOD_TLV_SIZE sizeof(struct grace_tlv_graceperiod) - -/* Restart reason TLV */ -#define RESTART_REASON_TYPE 2 -#define RESTART_REASON_LENGTH 1 -struct grace_tlv_restart_reason { - struct tlv_header header; - uint8_t reason; - uint8_t reserved[3]; -}; -#define GRACE_RESTART_REASON_TLV_SIZE sizeof(struct grace_tlv_restart_reason) +#define GRACE_PERIOD_TLV_SIZE sizeof(struct tlv_grace_period) +#define GRACE_RESTART_REASON_TLV_SIZE sizeof(struct tlv_grace_restart_reason) #define OSPF6_GRACE_LSA_MIN_SIZE \ GRACE_PERIOD_TLV_SIZE + GRACE_RESTART_REASON_TLV_SIZE struct ospf6_grace_lsa { - struct grace_tlv_graceperiod tlv_period; - struct grace_tlv_restart_reason tlv_reason; + struct tlv_grace_period tlv_period; + struct tlv_grace_restart_reason tlv_reason; }; struct advRtr { diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index f0e5d3a15c..da8b829cf1 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -32,6 +32,7 @@ #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6d.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" #include "lib/json.h" #include "ospf6d/ospf6_gr_helper_clippy.c" @@ -129,8 +130,8 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, { struct ospf6_lsa_header *lsah = NULL; struct tlv_header *tlvh = NULL; - struct grace_tlv_graceperiod *gracePeriod; - struct grace_tlv_restart_reason *grReason; + struct tlv_grace_period *gracePeriod; + struct tlv_grace_restart_reason *grReason; uint16_t length = 0; int sum = 0; @@ -144,9 +145,8 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; + for (tlvh = lsdesc_start(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { - /* Check TLV len against overall LSA */ if (sum + TLV_SIZE(tlvh) > length) { if (IS_DEBUG_OSPF6_GR) @@ -157,8 +157,8 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, } switch (ntohs(tlvh->type)) { - case GRACE_PERIOD_TYPE: - gracePeriod = (struct grace_tlv_graceperiod *)tlvh; + case TLV_GRACE_PERIOD_TYPE: + gracePeriod = (struct tlv_grace_period *)tlvh; *interval = ntohl(gracePeriod->interval); sum += TLV_SIZE(tlvh); @@ -167,8 +167,8 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, || *interval < OSPF6_MIN_GRACE_INTERVAL) return OSPF6_FAILURE; break; - case RESTART_REASON_TYPE: - grReason = (struct grace_tlv_restart_reason *)tlvh; + case TLV_GRACE_RESTART_REASON_TYPE: + grReason = (struct tlv_grace_restart_reason *)tlvh; *reason = grReason->reason; sum += TLV_SIZE(tlvh); @@ -1218,8 +1218,8 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, { struct ospf6_lsa_header *lsah = NULL; struct tlv_header *tlvh = NULL; - struct grace_tlv_graceperiod *gracePeriod; - struct grace_tlv_restart_reason *grReason; + struct tlv_grace_period *gracePeriod; + struct tlv_grace_restart_reason *grReason; uint16_t length = 0; int sum = 0; @@ -1240,9 +1240,8 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, zlog_debug(" TLV info:"); } - for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; + for (tlvh = lsdesc_start(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { - /* Check TLV len */ if (sum + TLV_SIZE(tlvh) > length) { if (vty) @@ -1255,8 +1254,8 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, } switch (ntohs(tlvh->type)) { - case GRACE_PERIOD_TYPE: - gracePeriod = (struct grace_tlv_graceperiod *)tlvh; + case TLV_GRACE_PERIOD_TYPE: + gracePeriod = (struct tlv_grace_period *)tlvh; sum += TLV_SIZE(tlvh); if (vty) { @@ -1272,8 +1271,8 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, ntohl(gracePeriod->interval)); } break; - case RESTART_REASON_TYPE: - grReason = (struct grace_tlv_restart_reason *)tlvh; + case TLV_GRACE_RESTART_REASON_TYPE: + grReason = (struct tlv_grace_restart_reason *)tlvh; sum += TLV_SIZE(tlvh); if (vty) { if (use_json) diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 7f813ce3cc..60f92385dd 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -14,6 +14,7 @@ #include "plist.h" #include "zclient.h" +#include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_top.h" @@ -30,9 +31,9 @@ #include "ospf6d.h" #include "ospf6_bfd.h" #include "ospf6_zebra.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" #include "lib/json.h" -#include "ospf6_proto.h" #include "lib/keychain.h" #include "ospf6_auth_trailer.h" #include "ospf6d/ospf6_interface_clippy.c" diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index b06796ada0..324cd7abe8 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -32,6 +32,7 @@ #include "ospf6_flood.h" #include "ospf6d.h" #include "ospf6_spf.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" unsigned char conf_debug_ospf6_brouter = 0; @@ -43,41 +44,20 @@ uint32_t conf_debug_ospf6_brouter_specific_area_id; /* RFC2740 3.4.3.1 Router-LSA */ /******************************/ +/* OSPF6_LSTYPE_ROUTER */ static char *ospf6_router_lsa_get_nbr_id(struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { - struct ospf6_router_lsa *router_lsa; - struct ospf6_router_lsdesc *lsdesc; - char *start, *end; char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN]; + struct ospf6_router_lsdesc *lsdesc = nth_lsdesc(lsa->header, pos); - if (lsa) { - router_lsa = (struct ospf6_router_lsa - *)((char *)lsa->header - + sizeof(struct ospf6_lsa_header)); - start = (char *)router_lsa + sizeof(struct ospf6_router_lsa); - end = (char *)lsa->header + ntohs(lsa->header->length); - - lsdesc = (struct ospf6_router_lsdesc - *)(start - + pos * (sizeof(struct - ospf6_router_lsdesc))); - if ((char *)lsdesc + sizeof(struct ospf6_router_lsdesc) - <= end) { - if (buf && (buflen > INET_ADDRSTRLEN * 2)) { - inet_ntop(AF_INET, - &lsdesc->neighbor_interface_id, buf1, - sizeof(buf1)); - inet_ntop(AF_INET, &lsdesc->neighbor_router_id, - buf2, sizeof(buf2)); - snprintf(buf, buflen, "%s/%s", buf2, buf1); - - return buf; - } - } - } + if (!lsdesc || !buf || buflen < (2 + 2 * INET_ADDRSTRLEN)) + return NULL; - return NULL; + inet_ntop(AF_INET, &lsdesc->neighbor_interface_id, buf1, sizeof(buf1)); + inet_ntop(AF_INET, &lsdesc->neighbor_router_id, buf2, sizeof(buf2)); + snprintf(buf, buflen, "%s/%s", buf2, buf1); + return buf; } static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, @@ -195,9 +175,7 @@ int ospf6_router_is_stub_router(struct ospf6_lsa *lsa) struct ospf6_router_lsa *rtr_lsa; if (lsa != NULL && OSPF6_LSA_IS_TYPE(ROUTER, lsa)) { - rtr_lsa = (struct ospf6_router_lsa - *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); + rtr_lsa = lsa_after_header(lsa->header); if (!OSPF6_OPT_ISSET(rtr_lsa->options, OSPF6_OPT_R)) { return OSPF6_IS_STUB_ROUTER; @@ -242,14 +220,12 @@ void ospf6_router_lsa_originate(struct event *thread) memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - router_lsa = (struct ospf6_router_lsa *)ospf6_lsa_header_end(lsa_header); + router_lsa = lsa_after_header(lsa_header); ospf6_router_lsa_options_set(oa, router_lsa); /* describe links for each interfaces */ - lsdesc = (struct ospf6_router_lsdesc - *)((caddr_t)router_lsa - + sizeof(struct ospf6_router_lsa)); + lsdesc = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_ROUTER); for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) { /* Interfaces in state Down or Loopback are not described */ @@ -272,9 +248,9 @@ void ospf6_router_lsa_originate(struct event *thread) && ((size_t)((char *)lsdesc - buffer) + sizeof(struct ospf6_router_lsdesc) > oa->router_lsa_size_limit)) { - if ((caddr_t)lsdesc - == (caddr_t)router_lsa - + sizeof(struct ospf6_router_lsa)) { + if (lsdesc == + lsdesc_start_lsa_type(lsa_header, + OSPF6_LSTYPE_ROUTER)) { zlog_warn( "Size limit setting for Router-LSA too short"); return; @@ -303,15 +279,13 @@ void ospf6_router_lsa_originate(struct event *thread) /* Reset Buffer to fill next Router LSA */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - router_lsa = (struct ospf6_router_lsa *) - ospf6_lsa_header_end(lsa_header); + router_lsa = lsa_after_header(lsa_header); ospf6_router_lsa_options_set(oa, router_lsa); /* describe links for each interfaces */ - lsdesc = (struct ospf6_router_lsdesc - *)((caddr_t)router_lsa - + sizeof(struct ospf6_router_lsa)); + lsdesc = lsdesc_start_lsa_type(lsa_header, + OSPF6_LSTYPE_ROUTER); link_state_id++; } @@ -424,30 +398,13 @@ void ospf6_router_lsa_originate(struct event *thread) static char *ospf6_network_lsa_get_ar_id(struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { - char *start, *end, *current; - struct ospf6_network_lsa *network_lsa; - struct ospf6_network_lsdesc *lsdesc; + struct ospf6_network_lsdesc *lsdesc = nth_lsdesc(lsa->header, pos); - if (lsa) { - network_lsa = (struct ospf6_network_lsa - *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); - - start = (char *)network_lsa + sizeof(struct ospf6_network_lsa); - end = (char *)lsa->header + ntohs(lsa->header->length); - current = start + pos * (sizeof(struct ospf6_network_lsdesc)); - - if ((current + sizeof(struct ospf6_network_lsdesc)) <= end) { - lsdesc = (struct ospf6_network_lsdesc *)current; - if (buf) { - inet_ntop(AF_INET, &lsdesc->router_id, buf, - buflen); - return buf; - } - } - } + if (!lsdesc || !buf || buflen < (1 + INET_ADDRSTRLEN)) + return NULL; - return NULL; + inet_ntop(AF_INET, &lsdesc->router_id, buf, buflen); + return buf; } static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, @@ -459,9 +416,7 @@ static int ospf6_network_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, char buf[128], options[32]; json_object *json_arr = NULL; - network_lsa = - (struct ospf6_network_lsa *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); + network_lsa = lsa_after_header(lsa->header); ospf6_options_printbuf(network_lsa->options, options, sizeof(options)); if (use_json) @@ -563,23 +518,19 @@ void ospf6_network_lsa_originate(struct event *thread) /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - network_lsa = - (struct ospf6_network_lsa *)ospf6_lsa_header_end(lsa_header); + network_lsa = lsa_after_header(lsa_header); /* Collect the interface's Link-LSAs to describe network's optional capabilities */ type = htons(OSPF6_LSTYPE_LINK); for (ALL_LSDB_TYPED(oi->lsdb, type, lsa)) { - link_lsa = (struct ospf6_link_lsa *)ospf6_lsa_header_end( - lsa->header); + link_lsa = lsa_after_header(lsa->header); network_lsa->options[0] |= link_lsa->options[0]; network_lsa->options[1] |= link_lsa->options[1]; network_lsa->options[2] |= link_lsa->options[2]; } - lsdesc = (struct ospf6_network_lsdesc - *)((caddr_t)network_lsa - + sizeof(struct ospf6_network_lsa)); + lsdesc = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_NETWORK); /* set Link Description to the router itself */ lsdesc->router_id = oi->area->ospf6->router_id; @@ -623,52 +574,24 @@ void ospf6_network_lsa_originate(struct event *thread) static char *ospf6_link_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { - char *start, *end, *current; - struct ospf6_link_lsa *link_lsa; - struct in6_addr in6; - struct ospf6_prefix *prefix; - int cnt = 0, prefixnum; + struct ospf6_link_lsa *link_lsa = lsa_after_header(lsa->header); + struct ospf6_prefix *prefix = nth_prefix(lsa->header, pos); + struct in6_addr in6 = { 0 }; - if (lsa) { - link_lsa = (struct ospf6_link_lsa - *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); - - if (pos == 0) { - inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, - buflen); - return (buf); - } + if (!lsa || !prefix || !buf || buflen < (1 + INET6_ADDRSTRLEN)) + return NULL; - prefixnum = ntohl(link_lsa->prefix_num); - if (pos > prefixnum) - return NULL; + /* position zero is used for the lladdr in the body of the LSA */ + if (pos == 0) { + inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, buflen); + return buf; + } - start = (char *)link_lsa + sizeof(struct ospf6_link_lsa); - end = (char *)lsa->header + ntohs(lsa->header->length); - current = start; - - while (current + sizeof(struct ospf6_prefix) <= end) { - prefix = (struct ospf6_prefix *)current; - if (prefix->prefix_length == 0 - || current + OSPF6_PREFIX_SIZE(prefix) > end) { - return NULL; - } + memcpy(&in6, OSPF6_PREFIX_BODY(prefix), + OSPF6_PREFIX_SPACE(prefix->prefix_length)); + inet_ntop(AF_INET6, &in6, buf, buflen); - if (cnt < (pos - 1)) { - current += OSPF6_PREFIX_SIZE(prefix); - cnt++; - } else { - memset(&in6, 0, sizeof(in6)); - memcpy(&in6, OSPF6_PREFIX_BODY(prefix), - OSPF6_PREFIX_SPACE( - prefix->prefix_length)); - inet_ntop(AF_INET6, &in6, buf, buflen); - return (buf); - } - } - } - return NULL; + return buf; } static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, @@ -684,8 +607,7 @@ static int ospf6_link_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, json_object *json_arr = NULL; char prefix_string[133]; - link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); + link_lsa = lsa_after_header(lsa->header); ospf6_options_printbuf(link_lsa->options, options, sizeof(options)); inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, sizeof(buf)); @@ -795,7 +717,7 @@ void ospf6_link_lsa_originate(struct event *thread) /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - link_lsa = (struct ospf6_link_lsa *)ospf6_lsa_header_end(lsa_header); + link_lsa = lsa_after_header(lsa_header); /* Fill Link-LSA */ link_lsa->priority = oi->priority; @@ -804,8 +726,7 @@ void ospf6_link_lsa_originate(struct event *thread) sizeof(struct in6_addr)); link_lsa->prefix_num = htonl(oi->route_connected->count); - op = (struct ospf6_prefix *)((caddr_t)link_lsa - + sizeof(struct ospf6_link_lsa)); + op = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_LINK); /* connected prefix to advertise */ for (route = ospf6_route_head(oi->route_connected); route; @@ -846,52 +767,22 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { - char *start, *end, *current; - struct ospf6_intra_prefix_lsa *intra_prefix_lsa; - struct in6_addr in6; - int prefixnum, cnt = 0; - struct ospf6_prefix *prefix; + struct ospf6_prefix *prefix = nth_prefix(lsa->header, pos); + struct in6_addr in6 = { 0 }; char tbuf[16]; - if (lsa) { - intra_prefix_lsa = - (struct ospf6_intra_prefix_lsa - *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); + /* ensure buflen >= INET6_ADDRSTRLEN + '/128\0' */ + if (!lsa || !prefix || !buf || buflen < (5 + INET6_ADDRSTRLEN)) + return NULL; - prefixnum = ntohs(intra_prefix_lsa->prefix_num); - if ((pos + 1) > prefixnum) - return NULL; + memcpy(&in6, OSPF6_PREFIX_BODY(prefix), + OSPF6_PREFIX_SPACE(prefix->prefix_length)); + inet_ntop(AF_INET6, &in6, buf, buflen); - start = (char *)intra_prefix_lsa - + sizeof(struct ospf6_intra_prefix_lsa); - end = ospf6_lsa_end(lsa->header); - current = start; + snprintf(tbuf, sizeof(tbuf), "/%d", prefix->prefix_length); + strlcat(buf, tbuf, buflen); - while (current + sizeof(struct ospf6_prefix) <= end) { - prefix = (struct ospf6_prefix *)current; - if (prefix->prefix_length == 0 - || current + OSPF6_PREFIX_SIZE(prefix) > end) { - return NULL; - } - - if (cnt < pos) { - current += OSPF6_PREFIX_SIZE(prefix); - cnt++; - } else { - memset(&in6, 0, sizeof(in6)); - memcpy(&in6, OSPF6_PREFIX_BODY(prefix), - OSPF6_PREFIX_SPACE( - prefix->prefix_length)); - inet_ntop(AF_INET6, &in6, buf, buflen); - snprintf(tbuf, sizeof(tbuf), "/%d", - prefix->prefix_length); - strlcat(buf, tbuf, buflen); - return (buf); - } - } - } - return NULL; + return buf; } static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, @@ -908,9 +799,7 @@ static int ospf6_intra_prefix_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, json_object *json_arr = NULL; char prefix_string[133]; - intra_prefix_lsa = (struct ospf6_intra_prefix_lsa - *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); + intra_prefix_lsa = lsa_after_header(lsa->header); prefixnum = ntohs(intra_prefix_lsa->prefix_num); @@ -1037,8 +926,7 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread) /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end( - lsa_header); + intra_prefix_lsa = lsa_after_header(lsa_header); /* Fill Intra-Area-Prefix-LSA */ intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER); @@ -1122,12 +1010,10 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread) /* put prefixes to advertise */ prefix_num = 0; - op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa - + sizeof(struct ospf6_intra_prefix_lsa)); + op = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_INTRA_PREFIX); for (route = ospf6_route_head(route_advertise); route; route = ospf6_route_best_next(route)) { if (((caddr_t)op - (caddr_t)lsa_header) > MAX_LSA_PAYLOAD) { - intra_prefix_lsa->prefix_num = htons(prefix_num); /* Fill LSA Header */ @@ -1153,8 +1039,7 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread) /* Prepare next buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) - ospf6_lsa_header_end(lsa_header); + intra_prefix_lsa = lsa_after_header(lsa_header); /* Fill Intra-Area-Prefix-LSA */ intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_ROUTER); @@ -1163,10 +1048,8 @@ void ospf6_intra_prefix_lsa_originate_stub(struct event *thread) /* Put next set of prefixes to advertise */ prefix_num = 0; - op = (struct ospf6_prefix - *)((caddr_t)intra_prefix_lsa - + sizeof(struct - ospf6_intra_prefix_lsa)); + op = lsdesc_start_lsa_type(lsa_header, + OSPF6_LSTYPE_INTRA_PREFIX); } op->prefix_length = route->prefix.prefixlen; @@ -1261,8 +1144,7 @@ void ospf6_intra_prefix_lsa_originate_transit(struct event *thread) /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end( - lsa_header); + intra_prefix_lsa = lsa_after_header(lsa_header); /* Fill Intra-Area-Prefix-LSA */ intra_prefix_lsa->ref_type = htons(OSPF6_LSTYPE_NETWORK); @@ -1311,9 +1193,7 @@ void ospf6_intra_prefix_lsa_originate_transit(struct event *thread) } } - link_lsa = (struct ospf6_link_lsa - *)((caddr_t)lsa->header - + sizeof(struct ospf6_lsa_header)); + link_lsa = lsa_after_header(lsa->header); prefix_num = (unsigned short)ntohl(link_lsa->prefix_num); start = (char *)link_lsa + sizeof(struct ospf6_link_lsa); @@ -1356,8 +1236,7 @@ void ospf6_intra_prefix_lsa_originate_transit(struct event *thread) zlog_debug("Trailing garbage in %s", lsa->name); } - op = (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa - + sizeof(struct ospf6_intra_prefix_lsa)); + op = lsdesc_start_lsa_type(lsa_header, OSPF6_LSTYPE_INTRA_PREFIX); prefix_num = 0; for (route = ospf6_route_head(route_advertise); route; @@ -1658,10 +1537,7 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa, } continue; } - intra_prefix_lsa = - (struct ospf6_intra_prefix_lsa *) - ospf6_lsa_header_end( - lsa->header); + intra_prefix_lsa = lsa_after_header(lsa->header); if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id) { @@ -1742,8 +1618,7 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) oa = OSPF6_AREA(lsa->lsdb->data); - intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end( - lsa->header); + intra_prefix_lsa = lsa_after_header(lsa->header); if (intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_ROUTER) || intra_prefix_lsa->ref_type == htons(OSPF6_LSTYPE_NETWORK)) ospf6_linkstate_prefix(intra_prefix_lsa->ref_adv_router, @@ -1971,8 +1846,7 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa) oa = OSPF6_AREA(lsa->lsdb->data); - intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)ospf6_lsa_header_end( - lsa->header); + intra_prefix_lsa = lsa_after_header(lsa->header); prefix_num = ntohs(intra_prefix_lsa->prefix_num); start = (caddr_t)intra_prefix_lsa diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h index 7d154cb4c6..fafa6d1282 100644 --- a/ospf6d/ospf6_intra.h +++ b/ospf6d/ospf6_intra.h @@ -13,10 +13,13 @@ extern in_addr_t conf_debug_ospf6_brouter_specific_area_id; #define OSPF6_DEBUG_BROUTER_SUMMARY 0x01 #define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER 0x02 #define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA 0x04 + #define OSPF6_DEBUG_BROUTER_ON() \ (conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SUMMARY) + #define OSPF6_DEBUG_BROUTER_OFF() \ (conf_debug_ospf6_brouter &= ~OSPF6_DEBUG_BROUTER_SUMMARY) + #define IS_OSPF6_DEBUG_BROUTER \ (conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SUMMARY) @@ -26,14 +29,17 @@ extern in_addr_t conf_debug_ospf6_brouter_specific_area_id; conf_debug_ospf6_brouter |= \ OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER; \ } while (0) + #define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF() \ do { \ conf_debug_ospf6_brouter_specific_router_id = 0; \ conf_debug_ospf6_brouter &= \ ~OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER; \ } while (0) + #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER \ (conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER) + #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(router_id) \ (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER \ && conf_debug_ospf6_brouter_specific_router_id == (router_id)) @@ -43,42 +49,21 @@ extern in_addr_t conf_debug_ospf6_brouter_specific_area_id; conf_debug_ospf6_brouter_specific_area_id = (area_id); \ conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SPECIFIC_AREA; \ } while (0) + #define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF() \ do { \ conf_debug_ospf6_brouter_specific_area_id = 0; \ conf_debug_ospf6_brouter &= \ ~OSPF6_DEBUG_BROUTER_SPECIFIC_AREA; \ } while (0) + #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA \ (conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SPECIFIC_AREA) + #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(area_id) \ (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA \ && conf_debug_ospf6_brouter_specific_area_id == (area_id)) -/* Router-LSA */ -#define OSPF6_ROUTER_LSA_MIN_SIZE 4U -struct ospf6_router_lsa { - uint8_t bits; - uint8_t options[3]; - /* followed by ospf6_router_lsdesc(s) */ -}; - -/* Link State Description in Router-LSA */ -#define OSPF6_ROUTER_LSDESC_FIX_SIZE 16U -struct ospf6_router_lsdesc { - uint8_t type; - uint8_t reserved; - uint16_t metric; /* output cost */ - uint32_t interface_id; - uint32_t neighbor_interface_id; - in_addr_t neighbor_router_id; -}; - -#define OSPF6_ROUTER_LSDESC_POINTTOPOINT 1 -#define OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK 2 -#define OSPF6_ROUTER_LSDESC_STUB_NETWORK 3 -#define OSPF6_ROUTER_LSDESC_VIRTUAL_LINK 4 - enum stub_router_mode { OSPF6_NOT_STUB_ROUTER, OSPF6_IS_STUB_ROUTER, @@ -92,49 +77,16 @@ enum stub_router_mode { : 0) #define ROUTER_LSDESC_GET_METRIC(x) \ (ntohs(((struct ospf6_router_lsdesc *)(x))->metric)) + #define ROUTER_LSDESC_GET_IFID(x) \ (ntohl(((struct ospf6_router_lsdesc *)(x))->interface_id)) + #define ROUTER_LSDESC_GET_NBR_IFID(x) \ (ntohl(((struct ospf6_router_lsdesc *)(x))->neighbor_interface_id)) + #define ROUTER_LSDESC_GET_NBR_ROUTERID(x) \ (((struct ospf6_router_lsdesc *)(x))->neighbor_router_id) -/* Network-LSA */ -#define OSPF6_NETWORK_LSA_MIN_SIZE 4U -struct ospf6_network_lsa { - uint8_t reserved; - uint8_t options[3]; - /* followed by ospf6_netowrk_lsd(s) */ -}; - -/* Link State Description in Router-LSA */ -#define OSPF6_NETWORK_LSDESC_FIX_SIZE 4U -struct ospf6_network_lsdesc { - in_addr_t router_id; -}; -#define NETWORK_LSDESC_GET_NBR_ROUTERID(x) \ - (((struct ospf6_network_lsdesc *)(x))->router_id) - -/* Link-LSA */ -#define OSPF6_LINK_LSA_MIN_SIZE 24U /* w/o 1st IPv6 prefix */ -struct ospf6_link_lsa { - uint8_t priority; - uint8_t options[3]; - struct in6_addr linklocal_addr; - uint32_t prefix_num; - /* followed by ospf6 prefix(es) */ -}; - -/* Intra-Area-Prefix-LSA */ -#define OSPF6_INTRA_PREFIX_LSA_MIN_SIZE 12U /* w/o 1st IPv6 prefix */ -struct ospf6_intra_prefix_lsa { - uint16_t prefix_num; - uint16_t ref_type; - uint32_t ref_id; - in_addr_t ref_adv_router; - /* followed by ospf6 prefix(es) */ -}; - #define OSPF6_ROUTER_LSA_SCHEDULE(oa) \ do { \ @@ -142,18 +94,21 @@ struct ospf6_intra_prefix_lsa { event_add_event(master, ospf6_router_lsa_originate, \ oa, 0, &(oa)->thread_router_lsa); \ } while (0) + #define OSPF6_NETWORK_LSA_SCHEDULE(oi) \ do { \ if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ event_add_event(master, ospf6_network_lsa_originate, \ oi, 0, &(oi)->thread_network_lsa); \ } while (0) + #define OSPF6_LINK_LSA_SCHEDULE(oi) \ do { \ if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ event_add_event(master, ospf6_link_lsa_originate, oi, \ 0, &(oi)->thread_link_lsa); \ } while (0) + #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa) \ do { \ if (CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \ @@ -161,6 +116,7 @@ struct ospf6_intra_prefix_lsa { master, ospf6_intra_prefix_lsa_originate_stub, \ oa, 0, &(oa)->thread_intra_prefix_lsa); \ } while (0) + #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi) \ do { \ if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 017751825f..622e5f9e0f 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -37,8 +37,85 @@ DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary"); +const uint8_t ospf6_lsa_min_size[OSPF6_LSTYPE_SIZE] = { + [OSPF6_LSTYPE_UNKNOWN] = 0, + [0x00ff & OSPF6_LSTYPE_ROUTER] = OSPF6_ROUTER_LSA_MIN_SIZE, + [0x00ff & OSPF6_LSTYPE_NETWORK] = OSPF6_NETWORK_LSA_MIN_SIZE, + [0x00ff & OSPF6_LSTYPE_INTER_PREFIX] = OSPF6_INTER_PREFIX_LSA_MIN_SIZE, + [0x00ff & OSPF6_LSTYPE_INTER_ROUTER] = OSPF6_INTER_ROUTER_LSA_FIX_SIZE, + [0x00ff & OSPF6_LSTYPE_AS_EXTERNAL] = OSPF6_AS_EXTERNAL_LSA_MIN_SIZE, + [0x00ff & OSPF6_LSTYPE_GROUP_MEMBERSHIP] = 0, /* Unused */ + [0x00ff & OSPF6_LSTYPE_TYPE_7] = OSPF6_AS_EXTERNAL_LSA_MIN_SIZE, + [0x00ff & OSPF6_LSTYPE_LINK] = OSPF6_LINK_LSA_MIN_SIZE, + [0x00ff & OSPF6_LSTYPE_INTRA_PREFIX] = OSPF6_INTRA_PREFIX_LSA_MIN_SIZE, + [0x00ff & OSPF6_LSTYPE_GRACE_LSA] = 0 +}; + +void *lsdesc_start_lsa_type(struct ospf6_lsa_header *header, int lsa_type) +{ + uint8_t t = (0x00ff & lsa_type); + + if (t == OSPF6_LSTYPE_UNKNOWN || t >= OSPF6_LSTYPE_SIZE) { + zlog_debug("Cannot get descriptor offset for unknown lsa type 0x%x", + t); + return ospf6_lsa_end(header); + } + return (char *)lsa_after_header(header) + ospf6_lsa_min_size[t]; +} + +void *lsdesc_start(struct ospf6_lsa_header *header) +{ + return lsdesc_start_lsa_type(header, ntohs(header->type)); +} + static struct ospf6_lsa_handler *lsa_handlers[OSPF6_LSTYPE_SIZE]; +void *nth_lsdesc(struct ospf6_lsa_header *header, int pos) +{ + char *lsdesc = lsdesc_start(header); + char *lsa_end = ospf6_lsa_end(header); + char *nth; + int lsdesc_size; + + if (ntohs(header->type) == OSPF6_LSTYPE_ROUTER) + lsdesc_size = OSPF6_ROUTER_LSDESC_FIX_SIZE; + else if (ntohs(header->type) == OSPF6_LSTYPE_NETWORK) + lsdesc_size = OSPF6_NETWORK_LSDESC_FIX_SIZE; + else + return NULL; + + nth = lsdesc + (pos * lsdesc_size); + + if (nth + lsdesc_size <= lsa_end) + return nth; + + return NULL; +} + +void *nth_prefix(struct ospf6_lsa_header *header, int pos) +{ + struct ospf6_prefix *prefix = lsdesc_start(header); + char *end = ospf6_lsa_end(header); + int i = 0; + + if (ntohs(header->type) != OSPF6_LSTYPE_LINK && + ntohs(header->type) != OSPF6_LSTYPE_INTRA_PREFIX) + return NULL; + + if (pos == 0) + return prefix; + + while ((char *)prefix < end && + (char *)prefix + OSPF6_PREFIX_SIZE(prefix) <= end) { + if (i == pos) + return prefix; + i++; + prefix = OSPF6_PREFIX_NEXT(prefix); + } + + return NULL; +} + struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa) { struct ospf6 *ospf6 = NULL; @@ -65,7 +142,7 @@ static int ospf6_unknown_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, { char *start, *end, *current; - start = ospf6_lsa_header_end(lsa->header); + start = lsa_after_header(lsa->header); end = ospf6_lsa_end(lsa->header); if (use_json) { @@ -234,8 +311,8 @@ int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) if (length <= 0) return 0; - return memcmp(ospf6_lsa_header_end(lsa1->header), - ospf6_lsa_header_end(lsa2->header), length); + return memcmp(lsa_after_header(lsa1->header), + lsa_after_header(lsa2->header), length); } /* ospf6 age functions */ diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 4fc2f0dd18..b2c83a1d37 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -87,11 +87,17 @@ struct ospf6_lsa_header { uint16_t length; /* LSA length */ }; + static inline char *ospf6_lsa_header_end(struct ospf6_lsa_header *header) { return (char *)header + sizeof(struct ospf6_lsa_header); } +static inline void *lsa_after_header(struct ospf6_lsa_header *header) +{ + return (char *)header + sizeof(struct ospf6_lsa_header); +} + static inline char *ospf6_lsa_end(struct ospf6_lsa_header *header) { return (char *)header + ntohs(header->length); @@ -116,6 +122,94 @@ static inline uint16_t ospf6_lsa_size(struct ospf6_lsa_header *header) #define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2) #define OSPF6_LSA_IS_SEQWRAP(L) ((L)->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER + 1)) +/* Router-LSA */ +#define OSPF6_ROUTER_LSA_MIN_SIZE 4U +struct ospf6_router_lsa { + uint8_t bits; + uint8_t options[3]; + /* followed by ospf6_router_lsdesc(s) */ +}; + +/* Link State Description in Router-LSA */ +#define OSPF6_ROUTER_LSDESC_FIX_SIZE 16U +struct ospf6_router_lsdesc { + uint8_t type; + uint8_t reserved; + uint16_t metric; /* output cost */ + uint32_t interface_id; + uint32_t neighbor_interface_id; + in_addr_t neighbor_router_id; +}; + +#define OSPF6_ROUTER_LSDESC_POINTTOPOINT 1 +#define OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK 2 +#define OSPF6_ROUTER_LSDESC_STUB_NETWORK 3 +#define OSPF6_ROUTER_LSDESC_VIRTUAL_LINK 4 + +/* Network-LSA */ +#define OSPF6_NETWORK_LSA_MIN_SIZE 4U +struct ospf6_network_lsa { + uint8_t reserved; + uint8_t options[3]; + /* followed by ospf6_network_lsdesc(s) */ +}; + +/* Link State Description in Network-LSA */ +#define OSPF6_NETWORK_LSDESC_FIX_SIZE 4U +struct ospf6_network_lsdesc { + in_addr_t router_id; +}; +#define NETWORK_LSDESC_GET_NBR_ROUTERID(x) \ + (((struct ospf6_network_lsdesc *)(x))->router_id) + +/* Inter-Area-Prefix-LSA */ +#define OSPF6_INTER_PREFIX_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ +struct ospf6_inter_prefix_lsa { + uint32_t metric; + struct ospf6_prefix prefix; +}; + +/* Inter-Area-Router-LSA */ +#define OSPF6_INTER_ROUTER_LSA_FIX_SIZE 12U +struct ospf6_inter_router_lsa { + uint8_t mbz; + uint8_t options[3]; + uint32_t metric; + uint32_t router_id; +}; + +/* AS-External-LSA */ +#define OSPF6_AS_EXTERNAL_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ +struct ospf6_as_external_lsa { + uint32_t bits_metric; + + struct ospf6_prefix prefix; + /* followed by none or one forwarding address */ + /* followed by none or one external route tag */ + /* followed by none or one referenced LS-ID */ +}; + +/* FIXME: move nssa lsa here. */ + +/* Link-LSA */ +#define OSPF6_LINK_LSA_MIN_SIZE 24U /* w/o 1st IPv6 prefix */ +struct ospf6_link_lsa { + uint8_t priority; + uint8_t options[3]; + struct in6_addr linklocal_addr; + uint32_t prefix_num; + /* followed by ospf6 prefix(es) */ +}; + +/* Intra-Area-Prefix-LSA */ +#define OSPF6_INTRA_PREFIX_LSA_MIN_SIZE 12U /* w/o 1st IPv6 prefix */ +struct ospf6_intra_prefix_lsa { + uint16_t prefix_num; + uint16_t ref_type; + uint32_t ref_id; + in_addr_t ref_adv_router; + /* followed by ospf6 prefix(es) */ +}; struct ospf6_lsa { char name[64]; /* dump string */ @@ -146,6 +240,7 @@ struct ospf6_lsa { bool tobe_acknowledged; }; + #define OSPF6_LSA_HEADERONLY 0x01 #define OSPF6_LSA_FLOODBACK 0x02 #define OSPF6_LSA_DUPLICATE 0x04 @@ -274,4 +369,11 @@ extern void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6); extern struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa); struct ospf6_lsa *ospf6_find_external_lsa(struct ospf6 *ospf6, struct prefix *p); + +void *lsdesc_start_lsa_type(struct ospf6_lsa_header *header, int lsa_type); +void *lsdesc_start(struct ospf6_lsa_header *header); + +void *nth_lsdesc(struct ospf6_lsa_header *header, int pos); +void *nth_prefix(struct ospf6_lsa_header *header, int pos); + #endif /* OSPF6_LSA_H */ diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 9aca5550a6..e5de30484a 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -229,8 +229,7 @@ struct ospf6_lsa *ospf6_find_inter_prefix_lsa(struct ospf6 *ospf6, struct ospf6_inter_prefix_lsa *prefix_lsa; struct prefix prefix; - prefix_lsa = (struct ospf6_inter_prefix_lsa *) - ospf6_lsa_header_end(lsa->header); + prefix_lsa = lsa_after_header(lsa->header); prefix.family = AF_INET6; prefix.prefixlen = prefix_lsa->prefix.prefix_length; ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa, diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index a6ee8d8b01..33d15e7243 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -33,6 +33,7 @@ #include "ospf6_flood.h" #include "ospf6d.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" #include <netinet/ip6.h> #include "lib/libospf.h" @@ -1303,9 +1304,7 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah, 4 bytes of referenced link state ID. */ if (headeronly) break; - as_external_lsa = - (struct ospf6_as_external_lsa - *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE); + as_external_lsa = lsa_after_header(lsah); exp_length = OSPF6_LSA_HEADER_SIZE + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE; /* To find out if the last optional field (Referenced Link State @@ -1350,8 +1349,7 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah, by N>=0 IPv6 prefix blocks (with N declared beforehand). */ if (headeronly) break; - link_lsa = (struct ospf6_link_lsa *)((caddr_t)lsah - + OSPF6_LSA_HEADER_SIZE); + link_lsa = lsa_after_header(lsah); return ospf6_prefixes_examin( (struct ospf6_prefix *)((caddr_t)link_lsa + OSPF6_LINK_LSA_MIN_SIZE), @@ -1366,9 +1364,7 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah, */ if (headeronly) break; - intra_prefix_lsa = - (struct ospf6_intra_prefix_lsa - *)((caddr_t)lsah + OSPF6_LSA_HEADER_SIZE); + intra_prefix_lsa = lsa_after_header(lsah); return ospf6_prefixes_examin( (struct ospf6_prefix *)((caddr_t)intra_prefix_lsa diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 0e44f2a142..acf15da4c3 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -30,6 +30,7 @@ #include "ospf6_lsa.h" #include "ospf6_spf.h" #include "ospf6_zebra.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" #include "lib/json.h" diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c index ea2be20cf3..8a5de468c9 100644 --- a/ospf6d/ospf6_nssa.c +++ b/ospf6d/ospf6_nssa.c @@ -52,8 +52,7 @@ static int ospf6_abr_nssa_am_elected(struct ospf6_area *oa) /* Verify all the router LSA to compare the router ID */ for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) { - router_lsa = (struct ospf6_router_lsa *)ospf6_lsa_header_end( - lsa->header); + router_lsa = lsa_after_header(lsa->header); /* ignore non-ABR routers */ if (!CHECK_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B)) @@ -414,8 +413,7 @@ static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area, } /* find the translated Type-5 for this Type-7 */ - nssa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - type7->header); + nssa = lsa_after_header(type7->header); prefix.family = AF_INET6; prefix.prefixlen = nssa->prefix.prefix_length; ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa, &nssa->prefix); @@ -435,10 +433,8 @@ static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area, /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - extnew = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa_header); - ext = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - type7->header); + extnew = lsa_after_header(lsa_header); + ext = lsa_after_header(type7->header); old_ptr = (caddr_t)((caddr_t)ext + sizeof(struct ospf6_as_external_lsa)); new_ptr = (caddr_t)((caddr_t)extnew @@ -546,8 +542,7 @@ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area, "%s: try to find translated Type-5 LSA for %s", __func__, type7->name); - ext_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - type7->header); + ext_lsa = lsa_after_header(type7->header); prefix.family = AF_INET6; prefix.prefixlen = ext_lsa->prefix.prefix_length; ospf6_prefix_in6_addr(&prefix.u.prefix6, ext_lsa, @@ -614,8 +609,7 @@ static void ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6 *ospf6; ospf6 = area->ospf6; - nssa_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa->header); + nssa_lsa = lsa_after_header(lsa->header); if (!CHECK_FLAG(nssa_lsa->prefix.prefix_options, OSPF6_PREFIX_OPTION_P)) { @@ -1240,8 +1234,7 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route, /* prepare buffer */ memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; - as_external_lsa = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa_header); + as_external_lsa = lsa_after_header(lsa_header); p = (caddr_t)((caddr_t)as_external_lsa + sizeof(struct ospf6_as_external_lsa)); diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h index 4307ee3c6e..645a408781 100644 --- a/ospf6d/ospf6_proto.h +++ b/ospf6d/ospf6_proto.h @@ -16,11 +16,12 @@ #define ALLSPFROUTERS6 "ff02::5" #define ALLDROUTERS6 "ff02::6" -#define OSPF6_ROUTER_BIT_W (1 << 3) +/* RFC 5340 A.4.3 Router-LSAs Options field */ +#define OSPF6_ROUTER_BIT_NT (1 << 4) +#define OSPF6_ROUTER_BIT_W (1 << 3) /* DEPRECATED */ #define OSPF6_ROUTER_BIT_V (1 << 2) #define OSPF6_ROUTER_BIT_E (1 << 1) #define OSPF6_ROUTER_BIT_B (1 << 0) -#define OSPF6_ROUTER_BIT_NT (1 << 4) /* OSPF options */ diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 36864d2a7d..9ac8b6c1af 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -748,8 +748,6 @@ static uint8_t *ospfv3AreaEntry(struct variable *v, oid *name, size_t *length, area_id = htonl(name[v->namelen]); inet_ntop(AF_INET, &area_id, a, sizeof(a)); - zlog_debug("SNMP access by area: %s, exact=%d len=%d length=%lu", a, - exact, len, (unsigned long)*length); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { if (area == NULL) { @@ -769,8 +767,6 @@ static uint8_t *ospfv3AreaEntry(struct variable *v, oid *name, size_t *length, name[v->namelen] = ntohl(area->area_id); inet_ntop(AF_INET, &area->area_id, a, sizeof(a)); - zlog_debug("SNMP found area: %s, exact=%d len=%d length=%lu", a, exact, - len, (unsigned long)*length); switch (v->magic) { case OSPFv3IMPORTASEXTERN: diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 7879dae8d7..5f2c5a6c47 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -16,11 +16,11 @@ #include "frrevent.h" #include "lib_errors.h" +#include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_area.h" -#include "ospf6_proto.h" #include "ospf6_abr.h" #include "ospf6_asbr.h" #include "ospf6_spf.h" @@ -290,8 +290,7 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v, != lsa->header->id) continue; - link_lsa = (struct ospf6_link_lsa *)ospf6_lsa_header_end( - lsa->header); + link_lsa = lsa_after_header(lsa->header); if (IS_OSPF6_DEBUG_SPF(PROCESS)) { inet_ntop(AF_INET6, &link_lsa->linklocal_addr, buf, sizeof(buf)); @@ -1136,8 +1135,7 @@ int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa, return 0; } - external = (struct ospf6_as_external_lsa *)ospf6_lsa_header_end( - lsa->header); + external = lsa_after_header(lsa->header); prefix.family = AF_INET6; prefix.prefixlen = external->prefix.prefix_length; ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix); diff --git a/ospf6d/ospf6_tlv.h b/ospf6d/ospf6_tlv.h new file mode 100644 index 0000000000..a687a05939 --- /dev/null +++ b/ospf6d/ospf6_tlv.h @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * OSPFv3 Type Length Value. + * + */ + +#ifndef OSPF6_TLV_H +#define OSPF6_TLV_H + +/* + * Generic TLV (type, length, value) macros + */ +struct tlv_header { + uint16_t type; /* Type of Value */ + uint16_t length; /* Length of Value portion only, in bytes */ +}; + +#ifdef roundup +#define ROUNDUP(val, gran) roundup(val, gran) +#else /* roundup */ +#define ROUNDUP(val, gran) (((val)-1 | (gran)-1) + 1) +#endif /* roundup */ + +#define TLV_HDR_SIZE (sizeof(struct tlv_header)) + +#define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(uint32_t))) + +#define TLV_SIZE(tlvh) ((uint32_t)(TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh))) + +#define TLV_HDR_NEXT(tlvh) \ + ((struct tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh))) + +/* + * RFC 5187 - OSPFv3 Graceful Restart - Grace-LSA + * Graceful restart predates Extended-LSA TLVs and IANA TLV register. + */ +/* Grace period TLV. */ +#define TLV_GRACE_PERIOD_TYPE 1 +#define TLV_GRACE_PERIOD_LENGTH 4 +struct tlv_grace_period { + struct tlv_header header; + uint32_t interval; +}; + +/* Restart reason TLV. */ +#define TLV_GRACE_RESTART_REASON_TYPE 2 +#define TLV_GRACE_RESTART_REASON_LENGTH 1 +struct tlv_grace_restart_reason { + struct tlv_header header; + uint8_t reason; + uint8_t reserved[3]; +}; + + +#endif /* OSPF6_TLV_H */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index a3fb205374..ad487f3565 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -37,6 +37,7 @@ #include "ospf6_intra.h" #include "ospf6_spf.h" #include "ospf6d.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 911f3567d4..466301309f 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -27,6 +27,7 @@ #include "ospf6_zebra.h" #include "ospf6d.h" #include "ospf6_area.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" #include "lib/json.h" diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index d90a950d79..e4e0354fc9 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -30,6 +30,7 @@ #include "ospf6_flood.h" #include "ospf6d.h" #include "ospf6_bfd.h" +#include "ospf6_tlv.h" #include "ospf6_gr.h" #include "lib/json.h" #include "ospf6_nssa.h" diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index 5f89af9508..a7bd94bd77 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -58,6 +58,7 @@ noinst_HEADERS += \ ospf6d/ospf6_route.h \ ospf6d/ospf6_routemap_nb.h \ ospf6d/ospf6_spf.h \ + ospf6d/ospf6_tlv.h \ ospf6d/ospf6_top.h \ ospf6d/ospf6_zebra.h \ ospf6d/ospf6d.h \ diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 40a76a0a34..e3398af74b 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -797,7 +797,7 @@ int ospf_flood_through_interface(struct ospf_interface *oi, ospf_ls_upd_send_lsa(nbr, lsa, OSPF_SEND_PACKET_DIRECT); } - } else + } else { /* If P2MP delayed reflooding is configured and the LSA was received from a neighbor on the P2MP interface, do not flood if back out on the interface. The LSA will be retransmitted @@ -815,9 +815,17 @@ int ospf_flood_through_interface(struct ospf_interface *oi, inbr ? &(inbr->router_id) : &(oi->ospf->router_id), IF_NAME(oi)); - } else - ospf_ls_upd_send_lsa(oi->nbr_self, lsa, - OSPF_SEND_PACKET_INDIRECT); + /* + * If reflooding is delayed, a delayed acknowledge + * should be sent since the LSA will not be immediately + * reflooded and interpreted as an implied + * acknowledgment by the sender. + */ + return 1; + } + ospf_ls_upd_send_lsa(oi->nbr_self, lsa, + OSPF_SEND_PACKET_INDIRECT); + } return 0; } diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 198309c1ef..97dc578679 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -1459,7 +1459,8 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) /* Update Algorithm, SRLB and MSD if present */ if (algo != NULL) { int i; - for (i = 0; i < ntohs(algo->header.length); i++) + for (i = 0; + i < ntohs(algo->header.length) && i < ALGORITHM_COUNT; i++) srn->algo[i] = algo->value[0]; for (; i < ALGORITHM_COUNT; i++) srn->algo[i] = SR_ALGORITHM_UNSET; diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 13138914fa..b7261da261 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2111,7 +2111,7 @@ DEFUN (ospf_abr_type, DEFUN (no_ospf_abr_type, no_ospf_abr_type_cmd, - "no ospf abr-type <cisco|ibm|shortcut|standard>", + "no ospf abr-type [<cisco|ibm|shortcut|standard>]", NO_STR "OSPF specific commands\n" "Set OSPF ABR type\n" @@ -2291,6 +2291,10 @@ static int ospf_timers_spf_set(struct vty *vty, unsigned int delay, { VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + if (ospf->spf_delay != delay || ospf->spf_holdtime != hold || + ospf->spf_max_holdtime != max) + ospf->spf_hold_multiplier = 1; + ospf->spf_delay = delay; ospf->spf_holdtime = hold; ospf->spf_max_holdtime = max; @@ -8157,7 +8161,7 @@ DEFUN (ip_ospf_dead_interval_minimal, DEFUN (no_ip_ospf_dead_interval, no_ip_ospf_dead_interval_cmd, - "no ip ospf dead-interval [<(1-65535)|minimal hello-multiplier (2-20)> [A.B.C.D]]", + "no ip ospf dead-interval [<(1-65535)|minimal hello-multiplier [(2-20)]> [A.B.C.D]]", NO_STR "IP Information\n" "OSPF interface commands\n" @@ -13184,6 +13188,10 @@ static void ospf_vty_if_init(void) install_element(INTERFACE_NODE, &ip_ospf_hello_interval_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd); + /* "ip ospf graceful-restart" commands. */ + install_element(INTERFACE_NODE, &ip_ospf_gr_hdelay_cmd); + install_element(INTERFACE_NODE, &no_ip_ospf_gr_hdelay_cmd); + /* "ip ospf network" commands. */ install_element(INTERFACE_NODE, &ip_ospf_network_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_network_cmd); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 2c518f2c9e..c7cba1e20f 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -119,8 +119,9 @@ static int ospf_interface_address_delete(ZAPI_CALLBACK_ARGS) return 0; if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: interface %s address delete %pFX", - c->ifp->name, c->address); + zlog_debug("Zebra: interface %s address delete %pFX vrf %s id %u", + c->ifp->name, c->address, + ospf_vrf_id_to_name(vrf_id), vrf_id); ifp = c->ifp; p = *c->address; @@ -261,9 +262,8 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p, if (ospf->gr_info.restart_in_progress) { if (IS_DEBUG_OSPF_GR) - zlog_debug( - "Zebra: Graceful Restart in progress -- not installing %pFX", - p); + zlog_debug("Zebra: Graceful Restart in progress -- not installing %pFX(%s)", + p, ospf_vrf_id_to_name(ospf->vrf_id)); return; } @@ -311,10 +311,10 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p, ifp = if_lookup_by_index(path->ifindex, ospf->vrf_id); - zlog_debug( - "Zebra: Route add %pFX nexthop %pI4, ifindex=%d %s", - p, &path->nexthop, path->ifindex, - ifp ? ifp->name : " "); + zlog_debug("Zebra: Route add %pFX(%s) nexthop %pI4, ifindex=%d %s", + p, ospf_vrf_id_to_name(ospf->vrf_id), + &path->nexthop, path->ifindex, + ifp ? ifp->name : " "); } } @@ -331,9 +331,8 @@ void ospf_zebra_delete(struct ospf *ospf, struct prefix_ipv4 *p, if (ospf->gr_info.restart_in_progress) { if (IS_DEBUG_OSPF_GR) - zlog_debug( - "Zebra: Graceful Restart in progress -- not uninstalling %pFX", - p); + zlog_debug("Zebra: Graceful Restart in progress -- not uninstalling %pFX(%s)", + p, ospf_vrf_id_to_name(ospf->vrf_id)); return; } @@ -345,7 +344,8 @@ void ospf_zebra_delete(struct ospf *ospf, struct prefix_ipv4 *p, memcpy(&api.prefix, p, sizeof(*p)); if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Zebra: Route delete %pFX", p); + zlog_debug("Zebra: Route delete %pFX(%s)", p, + ospf_vrf_id_to_name(ospf->vrf_id)); zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); } @@ -356,9 +356,8 @@ void ospf_zebra_add_discard(struct ospf *ospf, struct prefix_ipv4 *p) if (ospf->gr_info.restart_in_progress) { if (IS_DEBUG_OSPF_GR) - zlog_debug( - "Zebra: Graceful Restart in progress -- not installing %pFX", - p); + zlog_debug("Zebra: Graceful Restart in progress -- not installing %pFX(%s)", + p, ospf_vrf_id_to_name(ospf->vrf_id)); return; } @@ -373,7 +372,8 @@ void ospf_zebra_add_discard(struct ospf *ospf, struct prefix_ipv4 *p) zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Zebra: Route add discard %pFX", p); + zlog_debug("Zebra: Route add discard %pFX(%s)", p, + ospf_vrf_id_to_name(ospf->vrf_id)); } void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p) @@ -382,9 +382,8 @@ void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p) if (ospf->gr_info.restart_in_progress) { if (IS_DEBUG_OSPF_GR) - zlog_debug( - "Zebra: Graceful Restart in progress -- not uninstalling %pFX", - p); + zlog_debug("Zebra: Graceful Restart in progress -- not uninstalling %pFX(%s)", + p, ospf_vrf_id_to_name(ospf->vrf_id)); return; } @@ -399,7 +398,8 @@ void ospf_zebra_delete_discard(struct ospf *ospf, struct prefix_ipv4 *p) zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Zebra: Route delete discard %pFX", p); + zlog_debug("Zebra: Route delete discard %pFX(%s)", p, + ospf_vrf_id_to_name(ospf->vrf_id)); } struct ospf_external *ospf_external_lookup(struct ospf *ospf, uint8_t type, @@ -475,8 +475,9 @@ bool ospf_external_default_routemap_apply_walk(struct ospf *ospf, if (ret && ei) { if (IS_DEBUG_OSPF_DEFAULT_INFO) - zlog_debug("Default originate routemap permit ei: %pI4", - &ei->p.prefix); + zlog_debug("Default originate routemap permit ei: %pI4(%s)", + &ei->p.prefix, + ospf_vrf_id_to_name(ospf->vrf_id)); return true; } @@ -507,7 +508,8 @@ static void ospf_external_lsa_default_routemap_timer(struct event *thread) if (!default_ei) { /* Nothing to be done here. */ if (IS_DEBUG_OSPF_DEFAULT_INFO) - zlog_debug("Default originate info not present"); + zlog_debug("Default originate info not present(%s)", + ospf_vrf_id_to_name(ospf->vrf_id)); return; } @@ -821,11 +823,11 @@ int ospf_redistribute_update(struct ospf *ospf, struct ospf_redist *red, ospf_external_lsa_refresh_type(ospf, type, instance, force); if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug( - "Redistribute[%s][%d]: Refresh Type[%d], Metric[%d]", - ospf_redist_string(type), instance, - metric_type(ospf, type, instance), - metric_value(ospf, type, instance)); + zlog_debug("Redistribute[%s][%d][%s]: Refresh Type[%d], Metric[%d]", + ospf_redist_string(type), instance, + ospf_vrf_id_to_name(ospf->vrf_id), + metric_type(ospf, type, instance), + metric_value(ospf, type, instance)); return CMD_SUCCESS; } @@ -842,11 +844,11 @@ int ospf_redistribute_set(struct ospf *ospf, struct ospf_redist *red, int type, instance, ospf->vrf_id); if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug( - "Redistribute[%s][%d] vrf id %u: Start Type[%d], Metric[%d]", - ospf_redist_string(type), instance, ospf->vrf_id, - metric_type(ospf, type, instance), - metric_value(ospf, type, instance)); + zlog_debug("Redistribute[%s][%d][%s]: Start Type[%d], Metric[%d]", + ospf_redist_string(type), instance, + ospf_vrf_id_to_name(ospf->vrf_id), + metric_type(ospf, type, instance), + metric_value(ospf, type, instance)); ospf_asbr_status_update(ospf, ++ospf->redistribute); @@ -863,8 +865,9 @@ int ospf_redistribute_unset(struct ospf *ospf, int type, instance, ospf->vrf_id); if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Redistribute[%s][%d] vrf id %u: Stop", - ospf_redist_string(type), instance, ospf->vrf_id); + zlog_debug("Redistribute[%s][%d][%s]: Stop", + ospf_redist_string(type), instance, + ospf_vrf_id_to_name(ospf->vrf_id)); /* Remove the routes from OSPF table. */ ospf_redistribute_withdraw(ospf, type, instance); @@ -894,11 +897,11 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, if (cur_originate == originate) { /* Refresh the lsa since metric might different */ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug( - "Redistribute[%s]: Refresh Type[%d], Metric[%d]", - ospf_redist_string(DEFAULT_ROUTE), - metric_type(ospf, DEFAULT_ROUTE, 0), - metric_value(ospf, DEFAULT_ROUTE, 0)); + zlog_debug("Redistribute[%s][%s]: Refresh Type[%d], Metric[%d]", + ospf_redist_string(DEFAULT_ROUTE), + ospf_vrf_id_to_name(ospf->vrf_id), + metric_type(ospf, DEFAULT_ROUTE, 0), + metric_value(ospf, DEFAULT_ROUTE, 0)); ospf_external_lsa_refresh_default(ospf); return CMD_SUCCESS; @@ -939,10 +942,10 @@ int ospf_redistribute_default_set(struct ospf *ospf, int originate, int mtype, } if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug("Redistribute[DEFAULT]: %s Type[%d], Metric[%d]", - type_str, - metric_type(ospf, DEFAULT_ROUTE, 0), - metric_value(ospf, DEFAULT_ROUTE, 0)); + zlog_debug("Redistribute[DEFAULT][%s]: %s Type[%d], Metric[%d]", + ospf_vrf_id_to_name(ospf->vrf_id), type_str, + metric_type(ospf, DEFAULT_ROUTE, 0), + metric_value(ospf, DEFAULT_ROUTE, 0)); ospf_external_lsa_refresh_default(ospf); ospf_asbr_status_update(ospf, ospf->redistribute); @@ -1047,16 +1050,18 @@ static bool ospf_external_lsa_default_routemap_apply(struct ospf *ospf, } if (IS_DEBUG_OSPF_DEFAULT_INFO) - zlog_debug("Apply default originate routemap on ei: %pI4 cmd: %d", - &ei->p.prefix, cmd); + zlog_debug("Apply default originate routemap on ei: %pI4(%s) cmd: %d", + &ei->p.prefix, ospf_vrf_id_to_name(ospf->vrf_id), + cmd); ret = ospf_external_info_apply_default_routemap(ospf, ei, default_ei); /* If deny then nothing to be done both in add and del case. */ if (!ret) { if (IS_DEBUG_OSPF_DEFAULT_INFO) - zlog_debug("Default originte routemap deny for ei: %pI4", - &ei->p.prefix); + zlog_debug("Default originte routemap deny for ei: %pI4(%s)", + &ei->p.prefix, + ospf_vrf_id_to_name(ospf->vrf_id)); return false; } @@ -1068,12 +1073,14 @@ static bool ospf_external_lsa_default_routemap_apply(struct ospf *ospf, /* If permit and default already advertise then return. */ if (lsa && !IS_LSA_MAXAGE(lsa)) { if (IS_DEBUG_OSPF_DEFAULT_INFO) - zlog_debug("Default lsa already originated"); + zlog_debug("Default lsa already originated(%s)", + ospf_vrf_id_to_name(ospf->vrf_id)); return true; } if (IS_DEBUG_OSPF_DEFAULT_INFO) - zlog_debug("Originating/Refreshing default lsa"); + zlog_debug("Originating/Refreshing default lsa(%s)", + ospf_vrf_id_to_name(ospf->vrf_id)); if (lsa && IS_LSA_MAXAGE(lsa)) /* Refresh lsa.*/ @@ -1088,15 +1095,15 @@ static bool ospf_external_lsa_default_routemap_apply(struct ospf *ospf, /* If deny and lsa is not originated then nothing to be done.*/ if (!lsa) { if (IS_DEBUG_OSPF_DEFAULT_INFO) - zlog_debug( - "Default lsa not originated, not flushing"); + zlog_debug("Default lsa not originated, not flushing(%s)", + ospf_vrf_id_to_name(ospf->vrf_id)); return true; } if (IS_DEBUG_OSPF_DEFAULT_INFO) - zlog_debug( - "Running default route-map again as ei: %pI4 deleted", - &ei->p.prefix); + zlog_debug("Running default route-map again as ei: %pI4(%s) deleted", + &ei->p.prefix, + ospf_vrf_id_to_name(ospf->vrf_id)); /* * if this route delete was permitted then we need to check * there are any other external info which can still trigger @@ -1142,9 +1149,10 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei, if (access_list_apply(DISTRIBUTE_LIST(ospf, type), p) == FILTER_DENY) { if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug( - "Redistribute[%s]: %pFX filtered by distribute-list.", - ospf_redist_string(type), p); + zlog_debug("Redistribute[%s]: %pFX(%s) filtered by distribute-list.", + ospf_redist_string(type), p, + ospf_vrf_id_to_name( + ospf->vrf_id)); return 0; } @@ -1165,9 +1173,9 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei, if (ret == RMAP_DENYMATCH) { ei->route_map_set = save_values; if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug( - "Redistribute[%s]: %pFX filtered by route-map.", - ospf_redist_string(type), p); + zlog_debug("Redistribute[%s]: %pFX(%s) filtered by route-map.", + ospf_redist_string(type), p, + ospf_vrf_id_to_name(ospf->vrf_id)); return 0; } @@ -1230,7 +1238,8 @@ static int ospf_zebra_gr_update(struct ospf *ospf, int command, int ospf_zebra_gr_enable(struct ospf *ospf, uint32_t stale_time) { if (IS_DEBUG_OSPF_GR) - zlog_debug("Zebra enable GR [stale time %u]", stale_time); + zlog_debug("Zebra enable GR [stale time %u] vrf %s", stale_time, + ospf_vrf_id_to_name(ospf->vrf_id)); return ospf_zebra_gr_update(ospf, ZEBRA_CLIENT_GR_CAPABILITIES, stale_time); @@ -1239,7 +1248,8 @@ int ospf_zebra_gr_enable(struct ospf *ospf, uint32_t stale_time) int ospf_zebra_gr_disable(struct ospf *ospf) { if (IS_DEBUG_OSPF_GR) - zlog_debug("Zebra disable GR"); + zlog_debug("Zebra disable GR vrf: %s", + ospf_vrf_id_to_name(ospf->vrf_id)); return ospf_zebra_gr_update(ospf, ZEBRA_CLIENT_GR_DISABLE, 0); } @@ -1286,11 +1296,11 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) rt_type = DEFAULT_ROUTE; if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug( - "%s: cmd %s from client %s: vrf_id %d, p %pFX, metric %d", - __func__, zserv_command_string(cmd), - zebra_route_string(api.type), vrf_id, &api.prefix, - api.metric); + zlog_debug("%s: cmd %s from client %s: vrf %s(%u), p %pFX, metric %d", + __func__, zserv_command_string(cmd), + zebra_route_string(api.type), + ospf_vrf_id_to_name(vrf_id), vrf_id, &api.prefix, + api.metric); if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { /* XXX|HACK|TODO|FIXME: @@ -1343,11 +1353,12 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) return 0; if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR)) - zlog_debug( - "%s: Send Aggreate LSA (%pI4/%d)", - __func__, - &aggr->p.prefix, - aggr->p.prefixlen); + zlog_debug("%s: Send Aggreate LSA (%pI4/%d)(%s)", + __func__, + &aggr->p.prefix, + aggr->p.prefixlen, + ospf_vrf_id_to_name( + ospf->vrf_id)); ospf_originate_summary_lsa(ospf, aggr, ei); @@ -1402,10 +1413,11 @@ static int ospf_zebra_read_route(ZAPI_CALLBACK_ARGS) if (IS_DEBUG_OSPF( zebra, ZEBRA_REDISTRIBUTE)) - zlog_debug( - "%s: %pI4 refreshing LSA", - __func__, - &p.prefix); + zlog_debug("%s: %pI4(%s) refreshing LSA", + __func__, + &p.prefix, + ospf_vrf_id_to_name( + ospf->vrf_id)); ospf_external_lsa_refresh( ospf, current, ei, LSA_REFRESH_FORCE, @@ -1464,7 +1476,8 @@ void ospf_zebra_import_default_route(struct ospf *ospf, bool unreg) if (zclient->sock < 0) { if (IS_DEBUG_OSPF(zebra, ZEBRA)) - zlog_debug(" Not connected to Zebra"); + zlog_debug(" Not connected to Zebra vrf: %s", + ospf_vrf_id_to_name(ospf->vrf_id)); return; } @@ -1477,14 +1490,14 @@ void ospf_zebra_import_default_route(struct ospf *ospf, bool unreg) command = ZEBRA_NEXTHOP_REGISTER; if (IS_DEBUG_OSPF(zebra, ZEBRA)) - zlog_debug("%s: sending cmd %s for %pFX (vrf %u)", __func__, + zlog_debug("%s: sending cmd %s for %pFX(%s)", __func__, zserv_command_string(command), &prefix, - ospf->vrf_id); + ospf_vrf_id_to_name(ospf->vrf_id)); if (zclient_send_rnh(zclient, command, &prefix, SAFI_UNICAST, false, true, ospf->vrf_id) == ZCLIENT_SEND_FAILURE) - flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_send_rnh() failed", - __func__); + flog_err(EC_LIB_ZAPI_SOCKET, "%s(%s): zclient_send_rnh() failed", + __func__, ospf_vrf_id_to_name(ospf->vrf_id)); } static void ospf_zebra_import_check_update(struct vrf *vrf, struct prefix *match, @@ -1556,7 +1569,8 @@ static void ospf_distribute_list_update_timer(struct event *thread) ospf->t_distribute_update = NULL; - zlog_info("Zebra[Redistribute]: distribute-list update timer fired!"); + zlog_info("Zebra[Redistribute]: vrf: %s distribute-list update timer fired!", + ospf_vrf_id_to_name(ospf->vrf_id)); if (IS_DEBUG_OSPF_EVENT) { zlog_debug("%s: ospf distribute-list update vrf %s id %d", @@ -1607,10 +1621,12 @@ static void ospf_distribute_list_update_timer(struct event *thread) lsa, EXTNL_LSA_AGGR)) zlog_debug( - "%s: Send Aggregate LSA (%pI4/%d)", + "%s: Send Aggregate LSA (%pI4/%d)(%s)", __func__, &aggr->p.prefix, - aggr->p.prefixlen); + aggr->p.prefixlen, + ospf_vrf_id_to_name( + ospf->vrf_id)); /* Originate Aggregate * LSA diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 1d013b260e..7638e979a2 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -1098,6 +1098,15 @@ struct ospf_interface *add_ospf_interface(struct connected *co, oi->p2mp_delay_reflood = IF_DEF_PARAMS(co->ifp)->p2mp_delay_reflood; oi->p2mp_non_broadcast = IF_DEF_PARAMS(co->ifp)->p2mp_non_broadcast; + /* + * If a neighbor filter is configured, update the neighbor filter + * for the interface. + */ + if (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(co->ifp), nbr_filter_name)) + oi->nbr_filter = prefix_list_lookup(AFI_IP, + IF_DEF_PARAMS(co->ifp) + ->nbr_filter_name); + /* Add pseudo neighbor. */ ospf_nbr_self_reset(oi, oi->ospf->router_id); diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index f7a4e0e481..f1ebdb554c 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -1259,6 +1259,62 @@ DEFPY (no_ipv6_pim_ucast_bsm, return pim_process_no_unicast_bsm_cmd(vty); } +DEFPY (pim6_bsr_candidate_bsr, + pim6_bsr_candidate_bsr_cmd, + "[no] bsr candidate-bsr [{priority (0-255)|source <address X:X::X:X|interface IFNAME|loopback$loopback|any$any>}]", + NO_STR + BSR_STR + "Make this router a Candidate BSR\n" + "BSR Priority (higher wins)\n" + "BSR Priority (higher wins)\n" + "Specify IP address for BSR operation\n" + "Local address to use\n" + "Local address to use\n" + "Interface to pick address from\n" + "Interface to pick address from\n" + "Pick highest loopback address (default)\n" + "Pick highest address from any interface\n") +{ + return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_BSR_XPATH, no, + false, any, ifname, address_str, + priority_str, NULL); +} + +DEFPY (pim6_bsr_candidate_rp, + pim6_bsr_candidate_rp_cmd, + "[no] bsr candidate-rp [{priority (0-255)|interval (1-4294967295)|source <address X:X::X:X|interface IFNAME|loopback$loopback|any$any>}]", + NO_STR + "Bootstrap Router configuration\n" + "Make this router a Candidate RP\n" + "RP Priority (lower wins)\n" + "RP Priority (lower wins)\n" + "Advertisement interval (seconds)\n" + "Advertisement interval (seconds)\n" + "Specify IP address for RP operation\n" + "Local address to use\n" + "Local address to use\n" + "Interface to pick address from\n" + "Interface to pick address from\n" + "Pick highest loopback address (default)\n" + "Pick highest address from any interface\n") +{ + return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_RP_XPATH, no, + true, any, ifname, address_str, + priority_str, interval_str); +} + +DEFPY (pim6_bsr_candidate_rp_group, + pim6_bsr_candidate_rp_group_cmd, + "[no] bsr candidate-rp group X:X::X:X/M", + NO_STR + "Bootstrap Router configuration\n" + "Make this router a Candidate RP\n" + "Configure groups to become candidate RP for\n" + "Multicast group prefix\n") +{ + return pim_process_bsr_crp_grp_cmd(vty, group_str, no); +} + DEFPY (pim6_ssmpingd, pim6_ssmpingd_cmd, "ssmpingd [X:X::X:X]$source", @@ -1719,6 +1775,90 @@ DEFPY (show_ipv6_pim_secondary, return pim_show_secondary_helper(vrf, vty); } +DEFPY (show_ipv6_pim_bsr_cand_bsr, + show_ipv6_pim_bsr_cand_bsr_cmd, + "show ipv6 pim bsr candidate-bsr [vrf NAME$vrfname] [json$json]", + SHOW_STR + IPV6_STR + PIM_STR + BSR_STR + "Current PIM router candidate BSR state\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, !!json); + + if (!vrf || !vrf->info) + return CMD_WARNING; + + return pim_show_bsr_cand_bsr(vrf, vty, !!json); +} + +DEFPY (show_ipv6_pim_bsr_cand_rp, + show_ipv6_pim_bsr_cand_rp_cmd, + "show ipv6 pim bsr candidate-rp [vrf VRF_NAME] [json$json]", + SHOW_STR + IPV6_STR + PIM_STR + BSR_STR + "Current PIM router candidate RP state\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + struct vrf *vrf = pim_cmd_lookup(vty, vrf_name); + + if (!vrf || !vrf->info) + return CMD_WARNING; + + return pim_show_bsr_cand_rp(vrf, vty, !!json); +} + +DEFPY (show_ipv6_pim_bsr_rpdb, + show_ipv6_pim_bsr_rpdb_cmd, + "show ipv6 pim bsr candidate-rp-database [vrf VRF_NAME] [json$json]", + SHOW_STR + IPV6_STR + PIM_STR + BSR_STR + "Candidate RPs database on this router (if it is the BSR)\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + struct vrf *vrf = pim_cmd_lookup(vty, vrf_name); + + if (!vrf || !vrf->info) + return CMD_WARNING; + + struct pim_instance *pim = vrf->info; + struct bsm_scope *scope = &pim->global_scope; + + return pim_crp_db_show(vty, scope, !!json); +} + +DEFPY (show_ipv6_pim_bsr_groups, + show_ipv6_pim_bsr_groups_cmd, + "show ipv6 pim bsr groups [vrf VRF_NAME] [json$json]", + SHOW_STR + IPV6_STR + PIM_STR + "boot-strap router information\n" + "Candidate RP groups\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + struct vrf *vrf = pim_cmd_lookup(vty, vrf_name); + + if (!vrf || !vrf->info) + return CMD_WARNING; + + struct pim_instance *pim = vrf->info; + struct bsm_scope *scope = &pim->global_scope; + + return pim_crp_groups_show(vty, scope, !!json); +} + + DEFPY (show_ipv6_pim_statistics, show_ipv6_pim_statistics_cmd, "show ipv6 pim [vrf NAME] statistics [interface WORD$word] [json$json]", @@ -2650,6 +2790,9 @@ void pim_cmd_init(void) install_element(PIM6_NODE, &no_pim6_rp_prefix_list_cmd); install_element(PIM6_NODE, &pim6_ssmpingd_cmd); install_element(PIM6_NODE, &no_pim6_ssmpingd_cmd); + install_element(PIM6_NODE, &pim6_bsr_candidate_rp_cmd); + install_element(PIM6_NODE, &pim6_bsr_candidate_rp_group_cmd); + install_element(PIM6_NODE, &pim6_bsr_candidate_bsr_cmd); install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); @@ -2705,6 +2848,10 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ipv6_pim_rpf_cmd); install_element(VIEW_NODE, &show_ipv6_pim_rpf_vrf_all_cmd); install_element(VIEW_NODE, &show_ipv6_pim_secondary_cmd); + install_element(VIEW_NODE, &show_ipv6_pim_bsr_cand_bsr_cmd); + install_element(VIEW_NODE, &show_ipv6_pim_bsr_cand_rp_cmd); + install_element(VIEW_NODE, &show_ipv6_pim_bsr_rpdb_cmd); + install_element(VIEW_NODE, &show_ipv6_pim_bsr_groups_cmd); install_element(VIEW_NODE, &show_ipv6_pim_statistics_cmd); install_element(VIEW_NODE, &show_ipv6_pim_upstream_cmd); install_element(VIEW_NODE, &show_ipv6_pim_upstream_vrf_all_cmd); diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c index 24443404eb..07b70ae2b3 100644 --- a/pimd/pim6_main.c +++ b/pimd/pim6_main.c @@ -103,6 +103,7 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_routing_info, &frr_pim_info, &frr_pim_rp_info, + &frr_pim_candidate_info, &frr_gmp_info, }; diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index 8ccf42d729..a871837701 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -62,7 +62,6 @@ static void gm_sg_timer_start(struct gm_if *gm_ifp, struct gm_sg *sg, sg->iface->ifp->name, &sg->sgaddr /* clang-format off */ -#if PIM_IPV == 6 static const pim_addr gm_all_hosts = { .s6_addr = { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -84,13 +83,6 @@ static const pim_addr gm_dummy_untracked = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, }; -#else -/* 224.0.0.1 */ -static const pim_addr gm_all_hosts = { .s_addr = htonl(0xe0000001), }; -/* 224.0.0.22 */ -static const pim_addr gm_all_routers = { .s_addr = htonl(0xe0000016), }; -static const pim_addr gm_dummy_untracked = { .s_addr = 0xffffffff, }; -#endif /* clang-format on */ #define IPV6_MULTICAST_SCOPE_LINK 2 diff --git a/pimd/pim_autorp.c b/pimd/pim_autorp.c new file mode 100644 index 0000000000..1f4d0c65af --- /dev/null +++ b/pimd/pim_autorp.c @@ -0,0 +1,1163 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * pim_autorp.c: PIM AutoRP handling routines + * + * Copyright (C) 2024 ATCorp + * Nathan Bahr + */ + +#include <zebra.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include "lib/plist.h" +#include "lib/plist_int.h" +#include "lib/sockopt.h" +#include "lib/network.h" +#include "lib/termtable.h" +#include "lib/json.h" + +#include "pimd.h" +#include "pim_iface.h" +#include "pim_rp.h" +#include "pim_sock.h" +#include "pim_instance.h" +#include "pim_autorp.h" + +DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP, "PIM AutoRP info"); +DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP_RP, "PIM AutoRP advertised RP info"); +DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP_CRP, "PIM AutoRP candidate RP info"); +DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP_ANNOUNCE, "PIM AutoRP announcement packet"); + +static const char *PIM_AUTORP_ANNOUNCEMENT_GRP = "224.0.1.39"; +static const char *PIM_AUTORP_DISCOVERY_GRP = "224.0.1.40"; +static const in_port_t PIM_AUTORP_PORT = 496; + +static int pim_autorp_rp_cmp(const struct pim_autorp_rp *l, + const struct pim_autorp_rp *r) +{ + return pim_addr_cmp(l->addr, r->addr); +} + +DECLARE_SORTLIST_UNIQ(pim_autorp_rp, struct pim_autorp_rp, list, + pim_autorp_rp_cmp); + +static void pim_autorp_rp_free(struct pim_autorp_rp *rp) +{ + event_cancel(&rp->hold_timer); + + /* Clean up installed RP info */ + if (pim_rp_del(rp->autorp->pim, rp->addr, rp->grp, + (strlen(rp->grplist) ? rp->grplist : NULL), + RP_SRC_AUTORP)) + if (PIM_DEBUG_AUTORP) + zlog_err("%s: Failed to delete RP %pI4", __func__, + &rp->addr); + + XFREE(MTYPE_PIM_AUTORP_RP, rp); +} + +static void pim_autorp_rplist_free(struct pim_autorp_rp_head *head) +{ + struct pim_autorp_rp *rp; + + while ((rp = pim_autorp_rp_pop(head))) + pim_autorp_rp_free(rp); +} + +static void pim_autorp_rplist_cfree(struct pim_autorp_rp_head *head) +{ + struct pim_autorp_rp *rp; + + while ((rp = pim_autorp_rp_pop(head))) + XFREE(MTYPE_PIM_AUTORP_CRP, rp); +} + +static void pim_autorp_free(struct pim_autorp *autorp) +{ + pim_autorp_rplist_free(&(autorp->discovery_rp_list)); + pim_autorp_rp_fini(&(autorp->discovery_rp_list)); + + pim_autorp_rplist_cfree(&(autorp->candidate_rp_list)); + pim_autorp_rp_fini(&(autorp->candidate_rp_list)); +} + +static bool pim_autorp_join_groups(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct pim_instance *pim; + struct pim_autorp *autorp; + pim_addr grp; + + pim_ifp = ifp->info; + pim = pim_ifp->pim; + autorp = pim->autorp; + + inet_pton(PIM_AF, PIM_AUTORP_DISCOVERY_GRP, &grp); + if (pim_socket_join(autorp->sock, grp, pim_ifp->primary_address, + ifp->ifindex, pim_ifp)) { + zlog_err("Failed to join group %pI4 on interface %s", &grp, + ifp->name); + return false; + } + + /* TODO: Future Mapping agent implementation + * Join announcement group for AutoRP mapping agent + * inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &grp); + * if (pim_socket_join(pim->autorp->sock, grp, + * pim_ifp->primary_address, + * ifp->ifindex, pim_ifp)) { + * zlog_err("Failed to join group %pI4 on interface %s", + * &grp, ifp->name); + * return errno; + * } + */ + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Joined AutoRP groups on interface %s", __func__, + ifp->name); + + return true; +} + +static bool pim_autorp_leave_groups(struct interface *ifp) +{ + struct pim_interface *pim_ifp; + struct pim_instance *pim; + struct pim_autorp *autorp; + pim_addr grp; + + pim_ifp = ifp->info; + pim = pim_ifp->pim; + autorp = pim->autorp; + + inet_pton(PIM_AF, PIM_AUTORP_DISCOVERY_GRP, &grp); + if (pim_socket_leave(autorp->sock, grp, pim_ifp->primary_address, + ifp->ifindex, pim_ifp)) { + zlog_err("Failed to leave group %pI4 on interface %s", &grp, + ifp->name); + return false; + } + + /* TODO: Future Mapping agent implementation + * Leave announcement group for AutoRP mapping agent + * inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &grp); + * if (pim_socket_leave(pim->autorp->sock, grp, + * pim_ifp->primary_address, + * ifp->ifindex, pim_ifp)) { + * zlog_err("Failed to leave group %pI4 on interface %s", + * &grp, ifp->name); + * return errno; + * } + */ + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Left AutoRP groups on interface %s", __func__, + ifp->name); + + return true; +} + +static bool pim_autorp_setup(struct pim_autorp *autorp) +{ +#if defined(HAVE_IP_PKTINFO) + int data; + socklen_t data_len = sizeof(data); +#endif + + struct sockaddr_in autorp_addr = { .sin_family = AF_INET, + .sin_addr = { .s_addr = INADDR_ANY }, + .sin_port = htons(PIM_AUTORP_PORT) }; + + setsockopt_so_recvbuf(autorp->sock, 1024 * 1024 * 8); + +#if defined(HAVE_IP_PKTINFO) + /* Linux and Solaris IP_PKTINFO */ + data = 1; + if (setsockopt(autorp->sock, PIM_IPPROTO, IP_PKTINFO, &data, data_len)) { + zlog_err("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", + autorp->sock, errno, safe_strerror(errno)); + return false; + } +#endif + + if (set_nonblocking(autorp->sock) < 0) { + zlog_err("Could not set non blocking on socket fd=%d: errno=%d: %s", + autorp->sock, errno, safe_strerror(errno)); + return false; + } + + if (sockopt_reuseaddr(autorp->sock)) { + zlog_err("Could not set reuse addr on socket fd=%d: errno=%d: %s", + autorp->sock, errno, safe_strerror(errno)); + return false; + } + + if (bind(autorp->sock, (const struct sockaddr *)&autorp_addr, + sizeof(autorp_addr)) < 0) { + zlog_err("Could not bind socket: %pSUp, fd=%d, errno=%d, %s", + (union sockunion *)&autorp_addr, autorp->sock, errno, + safe_strerror(errno)); + return false; + } + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP finished setup", __func__); + + return true; +} + +static bool pim_autorp_announcement(struct pim_autorp *autorp, uint8_t rpcnt, + uint16_t holdtime, char *buf, + size_t buf_size) +{ + /* TODO: Future Mapping agent implementation + * Implement AutoRP mapping agent logic using received announcement messages + */ + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP processed announcement message", + __func__); + return true; +} + +static void autorp_rp_holdtime(struct event *evt) +{ + /* RP hold time expired, remove the RP */ + struct pim_autorp_rp *rp = EVENT_ARG(evt); + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP hold time expired, RP removed: addr=%pI4, grp=%pFX, grplist=%s", + __func__, &rp->addr, &rp->grp, + (strlen(rp->grplist) ? rp->grplist : "NONE")); + + pim_autorp_rp_del(&(rp->autorp->discovery_rp_list), rp); + pim_autorp_rp_free(rp); +} + +static bool pim_autorp_add_rp(struct pim_autorp *autorp, pim_addr rpaddr, + struct prefix grp, char *listname, + uint16_t holdtime) +{ + struct pim_autorp_rp *rp; + struct pim_autorp_rp *trp = NULL; + + if (pim_rp_new(autorp->pim, rpaddr, grp, listname, RP_SRC_AUTORP)) { + zlog_err("%s: Failed to add new RP addr=%pI4, grp=%pFX, grplist=%s", + __func__, &rpaddr, &grp, + (listname ? listname : "NONE")); + return false; + } + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Added new AutoRP learned RP addr=%pI4, grp=%pFX, grplist=%s", + __func__, &rpaddr, &grp, + (listname ? listname : "NONE")); + + rp = XCALLOC(MTYPE_PIM_AUTORP_RP, sizeof(*rp)); + rp->autorp = autorp; + memcpy(&(rp->addr), &rpaddr, sizeof(pim_addr)); + prefix_copy(&(rp->grp), &grp); + if (listname) + snprintf(rp->grplist, sizeof(rp->grplist), "%s", listname); + else + rp->grplist[0] = '\0'; + + rp->holdtime = holdtime; + rp->hold_timer = NULL; + trp = pim_autorp_rp_add(&(autorp->discovery_rp_list), rp); + if (trp == NULL) { + /* RP was brand new */ + trp = pim_autorp_rp_find(&(autorp->discovery_rp_list), + (const struct pim_autorp_rp *)rp); + } else { + /* RP already existed */ + XFREE(MTYPE_PIM_AUTORP_RP, rp); + event_cancel(&trp->hold_timer); + + /* We know the address matches, but these values may have changed */ + trp->holdtime = holdtime; + prefix_copy(&(trp->grp), &grp); + if (listname) { + snprintf(trp->grplist, sizeof(trp->grplist), "%s", + listname); + } else { + trp->grplist[0] = '\0'; + } + } + + if (holdtime > 0) { + event_add_timer(router->master, autorp_rp_holdtime, trp, + holdtime, &(trp->hold_timer)); + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Started %u second hold timer for RP %pI4", + __func__, holdtime, &rp->addr); + } else { + /* If hold time is zero, make sure there doesn't exist a hold timer for it already */ + event_cancel(&trp->hold_timer); + } + + return true; +} + +static bool pim_autorp_discovery(struct pim_autorp *autorp, uint8_t rpcnt, + uint16_t holdtime, char *buf, size_t buf_size) +{ + int i, j; + struct autorp_pkt_rp *rp; + struct autorp_pkt_grp *grp; + size_t offset = 0; + pim_addr rp_addr; + struct prefix grppfix; + char plname[32]; + struct prefix_list *pl; + struct prefix_list_entry *ple; + int64_t seq = 1; + bool success = true; + + for (i = 0; i < rpcnt; ++i) { + if ((buf_size - offset) < AUTORP_RPLEN) + return false; + + rp = (struct autorp_pkt_rp *)(buf + offset); + offset += AUTORP_RPLEN; + + rp_addr.s_addr = rp->addr; + + /* Ignore RP's limited to PIM version 1 or with an unknown version */ + if (rp->pimver == PIM_V1 || rp->pimver == PIM_VUNKNOWN) { + zlog_warn("%s: Ignoring unsupported PIM version in AutoRP Discovery for RP %pI4", + __func__, (in_addr_t *)&(rp->addr)); + /* Update the offset to skip past the groups advertised for this RP */ + offset += (AUTORP_GRPLEN * rp->grpcnt); + continue; + } + + + if (rp->grpcnt == 0) { + /* No groups?? */ + zlog_warn("%s: Discovery message has no groups for RP %pI4", + __func__, (in_addr_t *)&(rp->addr)); + continue; + } + + if ((buf_size - offset) < AUTORP_GRPLEN) { + zlog_warn("%s: Buffer underrun parsing groups for RP %pI4", + __func__, (in_addr_t *)&(rp->addr)); + return false; + } + + grp = (struct autorp_pkt_grp *)(buf + offset); + offset += AUTORP_GRPLEN; + + if (rp->grpcnt == 1 && grp->negprefix == 0) { + /* Only one group with positive prefix, we can use the standard RP API */ + grppfix.family = AF_INET; + grppfix.prefixlen = grp->masklen; + grppfix.u.prefix4.s_addr = grp->addr; + if (!pim_autorp_add_rp(autorp, rp_addr, grppfix, NULL, + holdtime)) + success = false; + } else { + /* More than one grp, or the only group is a negative prefix, need to make a prefix list for this RP */ + snprintfrr(plname, sizeof(plname), "__AUTORP_%pI4__", + &rp_addr); + pl = prefix_list_get(AFI_IP, 0, plname); + + for (j = 0; j < rp->grpcnt; ++j) { + /* grp is already pointing at the first group in the buffer */ + ple = prefix_list_entry_new(); + ple->pl = pl; + ple->seq = seq; + seq += 5; + memset(&ple->prefix, 0, sizeof(ple->prefix)); + prefix_list_entry_update_start(ple); + ple->type = (grp->negprefix ? PREFIX_DENY + : PREFIX_PERMIT); + ple->prefix.family = AF_INET; + ple->prefix.prefixlen = grp->masklen; + ple->prefix.u.prefix4.s_addr = grp->addr; + ple->any = false; + ple->ge = 0; + ple->le = 32; + prefix_list_entry_update_finish(ple); + + if ((buf_size - offset) < AUTORP_GRPLEN) + return false; + + grp = (struct autorp_pkt_grp *)(buf + offset); + offset += AUTORP_GRPLEN; + } + + if (!pim_autorp_add_rp(autorp, rp_addr, grppfix, plname, + holdtime)) + success = false; + } + } + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Processed AutoRP Discovery message", __func__); + + return success; +} + +static bool pim_autorp_msg(struct pim_autorp *autorp, char *buf, size_t buf_size) +{ + struct autorp_pkt_hdr *h; + + if (buf_size < AUTORP_HDRLEN) + return false; + + h = (struct autorp_pkt_hdr *)buf; + + if (h->version != AUTORP_VERSION) + return false; + + if (h->type == AUTORP_ANNOUNCEMENT_TYPE && + !pim_autorp_announcement(autorp, h->rpcnt, htons(h->holdtime), + buf + AUTORP_HDRLEN, + buf_size - AUTORP_HDRLEN)) + return false; + + if (h->type == AUTORP_DISCOVERY_TYPE && + !pim_autorp_discovery(autorp, h->rpcnt, htons(h->holdtime), + buf + AUTORP_HDRLEN, buf_size - AUTORP_HDRLEN)) + return false; + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Processed AutoRP packet", __func__); + + return true; +} + +static void autorp_read(struct event *t); + +static void autorp_read_on(struct pim_autorp *autorp) +{ + event_add_read(router->master, autorp_read, autorp, autorp->sock, + &(autorp->read_event)); + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP socket read enabled", __func__); +} + +static void autorp_read_off(struct pim_autorp *autorp) +{ + event_cancel(&(autorp->read_event)); + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP socket read disabled", __func__); +} + +static void autorp_read(struct event *evt) +{ + struct pim_autorp *autorp = evt->arg; + int fd = evt->u.fd; + char buf[10000]; + int rd; + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Reading from AutoRP socket", __func__); + + while (1) { + rd = pim_socket_recvfromto(fd, (uint8_t *)buf, sizeof(buf), + NULL, NULL, NULL, NULL, NULL); + if (rd <= 0) { + if (errno == EINTR) + continue; + if (errno == EWOULDBLOCK || errno == EAGAIN) + break; + + zlog_warn("%s: Failure reading rd=%d: fd=%d: errno=%d: %s", + __func__, rd, fd, errno, safe_strerror(errno)); + goto err; + } + + if (!pim_autorp_msg(autorp, buf, rd)) + zlog_err("%s: Failure parsing AutoRP message", __func__); + /* Keep reading until would block */ + } + + /* No error, enable read again */ + autorp_read_on(autorp); + +err: + return; +} + +static bool pim_autorp_socket_enable(struct pim_autorp *autorp) +{ + int fd; + + frr_with_privs (&pimd_privs) { + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (fd < 0) { + zlog_warn("Could not create autorp socket: errno=%d: %s", + errno, safe_strerror(errno)); + return false; + } + + autorp->sock = fd; + if (!pim_autorp_setup(autorp)) { + zlog_warn("Could not setup autorp socket fd=%d: errno=%d: %s", + fd, errno, safe_strerror(errno)); + close(fd); + autorp->sock = -1; + return false; + } + } + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP socket enabled", __func__); + + return true; +} + +static bool pim_autorp_socket_disable(struct pim_autorp *autorp) +{ + if (close(autorp->sock)) { + zlog_warn("Failure closing autorp socket: fd=%d errno=%d: %s", + autorp->sock, errno, safe_strerror(errno)); + return false; + } + + autorp_read_off(autorp); + autorp->sock = -1; + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP socket disabled", __func__); + + return true; +} + +static void autorp_send_announcement(struct event *evt) +{ + struct pim_autorp *autorp = EVENT_ARG(evt); + struct interface *ifp; + struct pim_interface *pim_ifp; + struct sockaddr_in announceGrp; + + announceGrp.sin_family = AF_INET; + announceGrp.sin_port = htons(PIM_AUTORP_PORT); + inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &announceGrp.sin_addr); + + if (autorp->annouce_pkt_sz >= MIN_AUTORP_PKT_SZ) { + if (setsockopt(autorp->sock, IPPROTO_IP, IP_MULTICAST_TTL, + &(autorp->announce_scope), + sizeof(autorp->announce_scope)) < 0) { + if (PIM_DEBUG_AUTORP) + zlog_err("%s: Failed to set Multicast TTL for sending AutoRP announcement message, errno=%d, %s", + __func__, errno, safe_strerror(errno)); + } + + FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) { + pim_ifp = ifp->info; + /* Only send on active interfaces with full pim enabled, non-passive + * and have a primary address set. + */ + if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && + pim_ifp && pim_ifp->pim_enable && + !pim_ifp->pim_passive_enable && + !pim_addr_is_any(pim_ifp->primary_address)) { + if (setsockopt(autorp->sock, IPPROTO_IP, + IP_MULTICAST_IF, + &(pim_ifp->primary_address), + sizeof(pim_ifp->primary_address)) < + 0) { + if (PIM_DEBUG_AUTORP) + zlog_err("%s: Failed to set Multicast Interface for sending AutoRP announcement message, errno=%d, %s", + __func__, errno, + safe_strerror(errno)); + } + if (sendto(autorp->sock, autorp->annouce_pkt, + autorp->annouce_pkt_sz, 0, + (struct sockaddr *)&announceGrp, + sizeof(announceGrp)) <= 0) { + if (PIM_DEBUG_AUTORP) + zlog_err("%s: Failed to send AutoRP announcement message, errno=%d, %s", + __func__, errno, + safe_strerror(errno)); + } + } + } + } + + /* Start the new timer for the entire announce interval */ + event_add_timer(router->master, autorp_send_announcement, autorp, + autorp->announce_interval, &(autorp->announce_timer)); +} + +static void autorp_announcement_on(struct pim_autorp *autorp) +{ + int interval = 5; + + if (interval > autorp->announce_interval) { + /* If the configured interval is less than 5 seconds, then just use that */ + interval = autorp->announce_interval; + } + event_add_timer(router->master, autorp_send_announcement, autorp, + interval, &(autorp->announce_timer)); + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP announcement sending enabled", __func__); +} + +static void autorp_announcement_off(struct pim_autorp *autorp) +{ + event_cancel(&(autorp->announce_timer)); + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP announcement sending disabled", __func__); +} + +/* Pack the groups of the RP + * rp - Pointer to the RP + * buf - Pointer to the buffer where to start packing groups + * returns - Total group count packed + */ +static uint8_t pim_autorp_new_announcement_rp_grps(struct pim_autorp_rp *rp, + uint8_t *buf) +{ + struct prefix_list *plist; + struct prefix_list_entry *ple; + struct autorp_pkt_grp *grpp = (struct autorp_pkt_grp *)buf; + uint8_t cnt = 0; + in_addr_t taddr; + + if (is_default_prefix(&(rp->grp))) { + /* No group so pack from the prefix list + * The grplist should be set and the prefix list exist with at least one group address + */ + plist = prefix_list_lookup(AFI_IP, rp->grplist); + for (ple = plist->head; ple; ple = ple->next) { + taddr = ntohl(ple->prefix.u.prefix4.s_addr); + if ((taddr & 0xF0000000) == 0xE0000000) { + grpp->addr = ple->prefix.u.prefix4.s_addr; + grpp->masklen = ple->prefix.prefixlen; + grpp->negprefix = + (ple->type == PREFIX_PERMIT ? 0 : 1); + grpp->reserved = 0; + + ++cnt; + grpp = (struct autorp_pkt_grp + *)(buf + + (sizeof(struct autorp_pkt_grp) * + cnt)); + } + } + + return cnt; + } + + /* Only one of group or prefix list should be defined */ + grpp->addr = rp->grp.u.prefix4.s_addr; + grpp->masklen = rp->grp.prefixlen; + grpp->negprefix = 0; + grpp->reserved = 0; + return 1; +} + +/* Pack a single candidate RP + * rp - Pointer to the RP to pack + * buf - Pointer to the buffer where to start packing the RP + * returns - Buffer pointer pointing to the start of the next RP + */ +static uint8_t *pim_autorp_new_announcement_rp(struct pim_autorp_rp *rp, + uint8_t *buf) +{ + struct autorp_pkt_rp *brp = (struct autorp_pkt_rp *)buf; + + /* Since this is an in_addr, assume it's already the right byte order */ + brp->addr = rp->addr.s_addr; + brp->pimver = PIM_V2; + brp->reserved = 0; + brp->grpcnt = + pim_autorp_new_announcement_rp_grps(rp, + buf + sizeof(struct autorp_pkt_rp)); + return buf + sizeof(struct autorp_pkt_rp) + + (brp->grpcnt * sizeof(struct autorp_pkt_grp)); +} + +/* Pack the candidate RP's on the announcement packet + * autorp - Pointer to the AutoRP instance + * buf - Pointer to the buffer where to start packing the first RP + * bufsz - Output parameter to track size of packed bytes + * returns - Total count of RP's packed + */ +static int pim_autorp_new_announcement_rps(struct pim_autorp *autorp, + uint8_t *buf, uint16_t *bufsz) +{ + int cnt = 0; + struct pim_autorp_rp *rp; + /* Keep the original buffer pointer to calculate final size after packing */ + uint8_t *obuf = buf; + struct prefix_list *plist; + struct prefix_list_entry *ple; + in_addr_t taddr; + + frr_each_safe (pim_autorp_rp, &(autorp->candidate_rp_list), rp) { + /* We must have an rp address and either group or list in order to pack this RP, so skip this one */ + if (pim_addr_is_any(rp->addr) || + (is_default_prefix(&(rp->grp)) && strlen(rp->grplist) == 0)) + continue; + + /* Group is net set, so list must be set, make sure the prefix list exists and has valid multicast groups */ + if (is_default_prefix(&(rp->grp))) { + plist = prefix_list_lookup(AFI_IP, rp->grplist); + if (plist == NULL) + continue; + plist = prefix_list_lookup(AFI_IP, rp->grplist); + for (ple = plist->head; ple; ple = ple->next) { + taddr = ntohl(ple->prefix.u.prefix4.s_addr); + if ((taddr & 0xF0000000) == 0xE0000000) + break; + } + + /* If we went through the entire list without finding a multicast prefix, then skip this RP */ + if (ple == NULL) + continue; + } + + /* Now we know for sure we will pack this RP, so count it */ + ++cnt; + /* This will return the buffer pointer at the location to start packing the next RP */ + buf = pim_autorp_new_announcement_rp(rp, buf); + } + + if (cnt > 0) + *bufsz = buf - obuf; + + return cnt; +} + +/* Build the new announcement packet. If there is a packet to send, restart the send timer with a short wait */ +static void pim_autorp_new_announcement(struct pim_instance *pim) +{ + struct pim_autorp *autorp = pim->autorp; + struct autorp_pkt_hdr *hdr; + int32_t holdtime; + + /* First disable any existing send timer */ + autorp_announcement_off(autorp); + + if (!autorp->annouce_pkt) { + /* + * First time building, allocate the space + * Allocate the max packet size of 65536 so we don't need to resize later. + * This should be ok since we are only allocating the memory once for a single packet (potentially per vrf) + */ + autorp->annouce_pkt = XCALLOC(MTYPE_PIM_AUTORP_ANNOUNCE, 65536); + } + + autorp->annouce_pkt_sz = 0; + + holdtime = autorp->announce_holdtime; + if (holdtime == DEFAULT_ANNOUNCE_HOLDTIME) + holdtime = autorp->announce_interval * 3; + if (holdtime > UINT16_MAX) + holdtime = UINT16_MAX; + + hdr = (struct autorp_pkt_hdr *)autorp->annouce_pkt; + hdr->version = AUTORP_VERSION; + hdr->type = AUTORP_ANNOUNCEMENT_TYPE; + hdr->holdtime = htons((uint16_t)holdtime); + hdr->reserved = 0; + hdr->rpcnt = + pim_autorp_new_announcement_rps(autorp, + autorp->annouce_pkt + + sizeof(struct autorp_pkt_hdr), + &(autorp->annouce_pkt_sz)); + + /* Still need to add on the size of the header */ + autorp->annouce_pkt_sz += sizeof(struct autorp_pkt_hdr); + + /* Only turn on the announcement timer if we have a packet to send */ + if (autorp->annouce_pkt_sz >= MIN_AUTORP_PKT_SZ) + autorp_announcement_on(autorp); +} + +bool pim_autorp_rm_candidate_rp(struct pim_instance *pim, pim_addr rpaddr) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *rp; + struct pim_autorp_rp find = { .addr = rpaddr }; + + rp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (!rp) + return false; + + pim_autorp_rp_del(&(autorp->candidate_rp_list), rp); + pim_autorp_rp_free(rp); + pim_autorp_new_announcement(pim); + return true; +} + +void pim_autorp_add_candidate_rp_group(struct pim_instance *pim, + pim_addr rpaddr, struct prefix group) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *rp; + struct pim_autorp_rp find = { .addr = rpaddr }; + + rp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (!rp) { + rp = XCALLOC(MTYPE_PIM_AUTORP_CRP, sizeof(*rp)); + memset(rp, 0, sizeof(struct pim_autorp_rp)); + rp->autorp = autorp; + memcpy(&(rp->addr), &rpaddr, sizeof(pim_addr)); + pim_autorp_rp_add(&(autorp->candidate_rp_list), rp); + } + + apply_mask(&group); + prefix_copy(&(rp->grp), &group); + /* A new group prefix implies that any previous prefix list is now invalid */ + rp->grplist[0] = '\0'; + + pim_autorp_new_announcement(pim); +} + +bool pim_autorp_rm_candidate_rp_group(struct pim_instance *pim, pim_addr rpaddr, + struct prefix group) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *rp; + struct pim_autorp_rp find = { .addr = rpaddr }; + + rp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (!rp) + return false; + + memset(&(rp->grp), 0, sizeof(rp->grp)); + pim_autorp_new_announcement(pim); + return true; +} + +void pim_autorp_add_candidate_rp_plist(struct pim_instance *pim, + pim_addr rpaddr, const char *plist) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *rp; + struct pim_autorp_rp find = { .addr = rpaddr }; + + rp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (!rp) { + rp = XCALLOC(MTYPE_PIM_AUTORP_CRP, sizeof(*rp)); + memset(rp, 0, sizeof(struct pim_autorp_rp)); + rp->autorp = autorp; + memcpy(&(rp->addr), &rpaddr, sizeof(pim_addr)); + pim_autorp_rp_add(&(autorp->candidate_rp_list), rp); + } + + snprintf(rp->grplist, sizeof(rp->grplist), "%s", plist); + /* A new group prefix list implies that any previous group prefix is now invalid */ + memset(&(rp->grp), 0, sizeof(rp->grp)); + rp->grp.family = AF_INET; + + pim_autorp_new_announcement(pim); +} + +bool pim_autorp_rm_candidate_rp_plist(struct pim_instance *pim, pim_addr rpaddr, + const char *plist) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *rp; + struct pim_autorp_rp find = { .addr = rpaddr }; + + rp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (!rp) + return false; + + rp->grplist[0] = '\0'; + pim_autorp_new_announcement(pim); + return true; +} + +void pim_autorp_announce_scope(struct pim_instance *pim, uint8_t scope) +{ + struct pim_autorp *autorp = pim->autorp; + + scope = (scope == 0 ? DEFAULT_ANNOUNCE_SCOPE : scope); + if (autorp->announce_scope != scope) { + autorp->announce_scope = scope; + pim_autorp_new_announcement(pim); + } +} + +void pim_autorp_announce_interval(struct pim_instance *pim, uint16_t interval) +{ + struct pim_autorp *autorp = pim->autorp; + + interval = (interval == 0 ? DEFAULT_ANNOUNCE_INTERVAL : interval); + if (autorp->announce_interval != interval) { + autorp->announce_interval = interval; + pim_autorp_new_announcement(pim); + } +} + +void pim_autorp_announce_holdtime(struct pim_instance *pim, int32_t holdtime) +{ + struct pim_autorp *autorp = pim->autorp; + + if (autorp->announce_holdtime != holdtime) { + autorp->announce_holdtime = holdtime; + pim_autorp_new_announcement(pim); + } +} + +void pim_autorp_add_ifp(struct interface *ifp) +{ + /* Add a new interface for autorp + * When autorp is enabled, we must join the autorp groups on all + * pim/multicast interfaces. When autorp first starts, if finds all + * current multicast interfaces and joins on them. If a new interface + * comes up or is configured for multicast after autorp is running, then + * this method will add it for autorp-> + * This is called even when adding a new pim interface that is not yet + * active, so make sure the check, it'll call in again once the interface is up. + */ + struct pim_instance *pim; + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && pim_ifp && + pim_ifp->pim_enable) { + pim = pim_ifp->pim; + if (pim && pim->autorp && pim->autorp->do_discovery) { + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Adding interface %s to AutoRP, joining AutoRP groups", + __func__, ifp->name); + if (!pim_autorp_join_groups(ifp)) { + zlog_err("Could not join AutoRP groups, errno=%d, %s", + errno, safe_strerror(errno)); + } + } + } +} + +void pim_autorp_rm_ifp(struct interface *ifp) +{ + /* Remove interface for autorp + * When an interface is no longer enabled for multicast, or at all, then + * we should leave the AutoRP groups on this interface. + */ + struct pim_instance *pim; + struct pim_interface *pim_ifp; + + pim_ifp = ifp->info; + if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && pim_ifp) { + pim = pim_ifp->pim; + if (pim && pim->autorp) { + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Removing interface %s from AutoRP, leaving AutoRP groups", + __func__, ifp->name); + if (!pim_autorp_leave_groups(ifp)) { + zlog_err("Could not leave AutoRP groups, errno=%d, %s", + errno, safe_strerror(errno)); + } + } + } +} + +void pim_autorp_start_discovery(struct pim_instance *pim) +{ + struct interface *ifp; + struct pim_autorp *autorp = pim->autorp; + + if (!autorp->do_discovery) { + autorp->do_discovery = true; + autorp_read_on(autorp); + + FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) { + pim_autorp_add_ifp(ifp); + } + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP Discovery started", __func__); + } +} + +void pim_autorp_stop_discovery(struct pim_instance *pim) +{ + struct interface *ifp; + struct pim_autorp *autorp = pim->autorp; + + if (autorp->do_discovery) { + FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) { + pim_autorp_rm_ifp(ifp); + } + + autorp->do_discovery = false; + autorp_read_off(autorp); + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP Discovery stopped", __func__); + } +} + +void pim_autorp_init(struct pim_instance *pim) +{ + struct pim_autorp *autorp; + + autorp = XCALLOC(MTYPE_PIM_AUTORP, sizeof(*autorp)); + autorp->pim = pim; + autorp->sock = -1; + autorp->read_event = NULL; + autorp->announce_timer = NULL; + autorp->do_discovery = false; + pim_autorp_rp_init(&(autorp->discovery_rp_list)); + pim_autorp_rp_init(&(autorp->candidate_rp_list)); + autorp->announce_scope = DEFAULT_ANNOUNCE_SCOPE; + autorp->announce_interval = DEFAULT_ANNOUNCE_INTERVAL; + autorp->announce_holdtime = DEFAULT_ANNOUNCE_HOLDTIME; + + if (!pim_autorp_socket_enable(autorp)) { + zlog_err("%s: AutoRP failed to initialize", __func__); + return; + } + + pim->autorp = autorp; + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP Initialized", __func__); + + /* Start AutoRP discovery by default on startup */ + pim_autorp_start_discovery(pim); +} + +void pim_autorp_finish(struct pim_instance *pim) +{ + struct pim_autorp *autorp = pim->autorp; + + autorp_read_off(autorp); + pim_autorp_free(autorp); + if (pim_autorp_socket_disable(autorp)) { + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP Finished", __func__); + } else + zlog_err("%s: AutoRP failed to finish", __func__); + + XFREE(MTYPE_PIM_AUTORP, pim->autorp); +} + +int pim_autorp_config_write(struct pim_instance *pim, struct vty *vty) +{ + struct pim_autorp_rp *rp; + struct pim_autorp *autorp = pim->autorp; + char interval_str[16] = { 0 }; + char scope_str[16] = { 0 }; + char holdtime_str[32] = { 0 }; + char grp_str[64] = { 0 }; + int writes = 0; + + if (!autorp->do_discovery) { + vty_out(vty, " no autorp discovery\n"); + ++writes; + } + + if (autorp->announce_interval != DEFAULT_ANNOUNCE_INTERVAL) { + snprintf(interval_str, sizeof(interval_str), " interval %u", + autorp->announce_interval); + } + + if (autorp->announce_scope != DEFAULT_ANNOUNCE_SCOPE) { + snprintf(scope_str, sizeof(scope_str), " scope %u", + autorp->announce_scope); + } + + if (autorp->announce_holdtime != DEFAULT_ANNOUNCE_HOLDTIME) { + snprintf(holdtime_str, sizeof(holdtime_str), " holdtime %u", + autorp->announce_holdtime); + } + + if (strlen(interval_str) || strlen(scope_str) || strlen(holdtime_str)) { + vty_out(vty, " autorp announce%s%s%s\n", interval_str, + scope_str, holdtime_str); + ++writes; + } + + frr_each_safe (pim_autorp_rp, &(autorp->candidate_rp_list), rp) { + /* Only print candidate RP's that have all the information needed to be announced */ + if (pim_addr_is_any(rp->addr) || + (is_default_prefix(&(rp->grp)) && strlen(rp->grplist) == 0)) + continue; + + /* Don't make sure the prefix list has multicast groups, user may not have created it yet */ + + if (!is_default_prefix(&(rp->grp))) + snprintfrr(grp_str, sizeof(grp_str), "%pFX", &(rp->grp)); + else + snprintfrr(grp_str, sizeof(grp_str), "group-list %s", + rp->grplist); + + vty_out(vty, " autorp announce %pI4 %s\n", &(rp->addr), grp_str); + ++writes; + } + + return writes; +} + +void pim_autorp_show_autorp(struct vty *vty, struct pim_instance *pim, + json_object *json) +{ + struct pim_autorp_rp *rp; + struct pim_autorp *autorp = pim->autorp; + struct ttable *tt = NULL; + char *table = NULL; + char grp_str[64] = { 0 }; + char plist_str[64] = { 0 }; + json_object *annouce_jobj; + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "RP address|group|prefix-list"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + + frr_each_safe (pim_autorp_rp, &(autorp->candidate_rp_list), rp) { + if (!is_default_prefix(&(rp->grp))) + snprintfrr(grp_str, sizeof(grp_str), "%pFX", &(rp->grp)); + else + snprintfrr(plist_str, sizeof(plist_str), "%s", + rp->grplist); + + ttable_add_row(tt, "%pI4|%s|%s", &(rp->addr), grp_str, + plist_str); + } + + if (json) { + json_object_boolean_add(json, "discoveryEnabled", + autorp->do_discovery); + + annouce_jobj = json_object_new_object(); + json_object_int_add(annouce_jobj, "scope", + autorp->announce_scope); + json_object_int_add(annouce_jobj, "interval", + autorp->announce_interval); + json_object_int_add(annouce_jobj, "holdtime", + autorp->announce_holdtime); + json_object_object_add(annouce_jobj, "rpList", + ttable_json_with_json_text( + tt, "sss", + "rpAddress|group|prefixList")); + + json_object_object_add(json, "announce", annouce_jobj); + } else { + vty_out(vty, "AutoRP Discovery is %sabled\n", + (autorp->do_discovery ? "en" : "dis")); + vty_out(vty, "AutoRP Candidate RPs\n"); + vty_out(vty, " interval %us, scope %u, holdtime %us\n", + autorp->announce_interval, autorp->announce_scope, + (autorp->announce_holdtime == DEFAULT_ANNOUNCE_HOLDTIME + ? (autorp->announce_interval * 3) + : autorp->announce_holdtime)); + + vty_out(vty, "\n"); + + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP_TTABLE, table); + } + + ttable_del(tt); +} diff --git a/pimd/pim_autorp.h b/pimd/pim_autorp.h new file mode 100644 index 0000000000..a0b029d00a --- /dev/null +++ b/pimd/pim_autorp.h @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * pim_autorp.h: PIM Auto RP handling related + * + * Copyright (C) 20224 ATCorp. + * Nathan Bahr + */ + +#ifndef __PIM_AUTORP_H__ +#define __PIM_AUTORP_H__ + +#include <typesafe.h> + +#define AUTORP_VERSION 1 +#define AUTORP_ANNOUNCEMENT_TYPE 1 +#define AUTORP_DISCOVERY_TYPE 2 +#define PIM_VUNKNOWN 0 +#define PIM_V1 1 +#define PIM_V2 2 +#define PIM_V1_2 3 + +#define DEFAULT_ANNOUNCE_INTERVAL 60 +#define DEFAULT_ANNOUNCE_SCOPE 31 +#define DEFAULT_ANNOUNCE_HOLDTIME -1 + +PREDECL_SORTLIST_UNIQ(pim_autorp_rp); + +struct autorp_pkt_grp { +#if __BYTE_ORDER == __LITTLE_ENDIAN + uint8_t negprefix : 1; + uint8_t reserved : 7; +#elif __BYTE_ORDER == __BIG_ENDIAN + uint8_t reserved : 7; + uint8_t negprefix : 1; +#else +#error "Please fix <bits/endian.h>" +#endif + uint8_t masklen; + uint32_t addr; +} __attribute__((__packed__)); + +struct autorp_pkt_rp { + uint32_t addr; +#if __BYTE_ORDER == __LITTLE_ENDIAN + uint8_t pimver : 2; + uint8_t reserved : 6; +#elif __BYTE_ORDER == __BIG_ENDIAN + uint8_t reserved : 6; + uint8_t pimver : 2; +#else +#error "Please fix <bits/endian.h>" +#endif + uint8_t grpcnt; +} __attribute__((__packed__)); + +struct autorp_pkt_hdr { +#if __BYTE_ORDER == __LITTLE_ENDIAN + uint8_t type : 4; + uint8_t version : 4; +#elif __BYTE_ORDER == __BIG_ENDIAN + uint8_t version : 4; + uint8_t type : 4; +#else +#error "Please fix <bits/endian.h>" +#endif + uint8_t rpcnt; + uint16_t holdtime; + uint32_t reserved; +} __attribute__((__packed__)); + +#define MIN_AUTORP_PKT_SZ \ + (sizeof(struct autorp_pkt_hdr) + sizeof(struct autorp_pkt_rp) + \ + sizeof(struct autorp_pkt_grp)) + +struct pim_autorp_rp { + struct pim_autorp *autorp; + struct in_addr addr; + uint16_t holdtime; + struct event *hold_timer; + struct prefix grp; + char grplist[32]; + struct pim_autorp_rp_item list; +}; + +struct pim_autorp { + /* backpointer to pim instance */ + struct pim_instance *pim; + + /* UDP socket bound to AutoRP port, used for sending and receiving all AutoRP packets */ + int sock; + + /* Event for reading AutoRP packets */ + struct event *read_event; + + /* Event for sending announcement packets */ + struct event *announce_timer; + + /* Event for sending discovery packets*/ + /* struct event *discovery_timer; */ + + /* Flag enabling reading discovery packets */ + bool do_discovery; + + /* Flag enabling mapping agent (reading announcements and sending discovery)*/ + /* bool do_mapping; */ + + /* List of RP's in received discovery packets */ + struct pim_autorp_rp_head discovery_rp_list; + + /* List of configured candidate RP's to send in announcement packets */ + struct pim_autorp_rp_head candidate_rp_list; + + /* List of announced RP's to send in discovery packets */ + /* struct pim_autorp_rp_head mapping_rp_list; */ + + /* Packet parameters for sending announcement packets */ + uint8_t announce_scope; + uint16_t announce_interval; + int32_t announce_holdtime; + + /* Pre-built announcement packet, only changes when configured RP's or packet parameters change */ + uint8_t *annouce_pkt; + uint16_t annouce_pkt_sz; + + /* TODO: Packet parameters for sending discovery packets + * int discovery_scope; + * int discovery_interval; + * int discovery_holdtime; + */ +}; + +#define AUTORP_GRPLEN 6 +#define AUTORP_RPLEN 6 +#define AUTORP_HDRLEN 8 + +bool pim_autorp_rm_candidate_rp(struct pim_instance *pim, pim_addr rpaddr); +void pim_autorp_add_candidate_rp_group(struct pim_instance *pim, + pim_addr rpaddr, struct prefix group); +bool pim_autorp_rm_candidate_rp_group(struct pim_instance *pim, pim_addr rpaddr, + struct prefix group); +void pim_autorp_add_candidate_rp_plist(struct pim_instance *pim, + pim_addr rpaddr, const char *plist); +bool pim_autorp_rm_candidate_rp_plist(struct pim_instance *pim, pim_addr rpaddr, + const char *plist); +void pim_autorp_announce_scope(struct pim_instance *pim, uint8_t scope); +void pim_autorp_announce_interval(struct pim_instance *pim, uint16_t interval); +void pim_autorp_announce_holdtime(struct pim_instance *pim, int32_t holdtime); +void pim_autorp_add_ifp(struct interface *ifp); +void pim_autorp_rm_ifp(struct interface *ifp); +void pim_autorp_start_discovery(struct pim_instance *pim); +void pim_autorp_stop_discovery(struct pim_instance *pim); +void pim_autorp_init(struct pim_instance *pim); +void pim_autorp_finish(struct pim_instance *pim); +int pim_autorp_config_write(struct pim_instance *pim, struct vty *vty); +void pim_autorp_show_autorp(struct vty *vty, struct pim_instance *pim, + json_object *json); + +#endif diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index 2d451718a9..115aec8933 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -10,6 +10,17 @@ #include "config.h" #endif +#include <math.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <lib/network.h> +#include <lib/iana_afi.h> +#include <lib/sockunion.h> +#include <lib/sockopt.h> + #include "if.h" #include "pimd.h" #include "pim_iface.h" @@ -23,18 +34,32 @@ #include "pim_time.h" #include "pim_zebra.h" #include "pim_util.h" +#include "pim_sock.h" /* Functions forward declaration */ static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout); static void pim_g2rp_timer_start(struct bsm_rpinfo *bsrp, int hold_time); static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp, int hold_time); +static void pim_bsm_accept_any(struct bsm_scope *scope); +static void pim_cand_bsr_trigger(struct bsm_scope *scope, bool verbose); +static void pim_cand_bsr_pending(struct bsm_scope *scope); /* Memory Types */ DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info"); DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_INFO, "PIM BSR advertised RP info"); -DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_FRAG, "PIM BSM fragment"); +DEFINE_MTYPE(PIMD, PIM_BSM_FRAG, "PIM BSM fragment"); DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet"); +DEFINE_MTYPE_STATIC(PIMD, PIM_CAND_RP_GRP, "PIM Candidate RP group"); + +static int cand_rp_group_cmp(const struct cand_rp_group *a, + const struct cand_rp_group *b) +{ + return prefix_cmp(&a->p, &b->p); +} + +DECLARE_RBTREE_UNIQ(cand_rp_groups, struct cand_rp_group, item, + cand_rp_group_cmp); /* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */ #define MAX_IP_HDR_LEN 24 @@ -90,7 +115,7 @@ static void pim_bsm_frag_free(struct bsm_frag *bsfrag) XFREE(MTYPE_PIM_BSM_FRAG, bsfrag); } -static void pim_bsm_frags_free(struct bsm_scope *scope) +void pim_bsm_frags_free(struct bsm_scope *scope) { struct bsm_frag *bsfrag; @@ -140,12 +165,12 @@ static struct bsgrp_node *pim_bsm_new_bsgrp_node(struct route_table *rt, return bsgrp; } +/* BS timer for NO_INFO, ACCEPT_ANY & ACCEPT_PREFERRED. + * Candidate BSR handling is separate further below + */ static void pim_on_bs_timer(struct event *t) { - struct route_node *rn; struct bsm_scope *scope; - struct bsgrp_node *bsgrp_node; - struct bsm_rpinfo *bsrp; scope = EVENT_ARG(t); EVENT_OFF(scope->bs_timer); @@ -154,7 +179,20 @@ static void pim_on_bs_timer(struct event *t) zlog_debug("%s: Bootstrap Timer expired for scope: %d", __func__, scope->sz_id); + assertf(scope->state <= ACCEPT_PREFERRED, "state=%d", scope->state); pim_nht_bsr_del(scope->pim, scope->current_bsr); + + pim_bsm_accept_any(scope); +} + +static void pim_bsm_accept_any(struct bsm_scope *scope) +{ + struct route_node *rn; + struct bsgrp_node *bsgrp_node; + struct bsm_rpinfo *bsrp; + + EVENT_OFF(scope->t_ebsr_regen_bsm); + /* Reset scope zone data */ scope->state = ACCEPT_ANY; scope->current_bsr = PIMADDR_ANY; @@ -181,6 +219,11 @@ static void pim_on_bs_timer(struct event *t) pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list); bsgrp_node->pend_rp_cnt = 0; } + + /* we're leaving ACCEPT_PREFERRED, which doubles as C-BSR if we're + * configured to be a Candidate BSR. See if we're P-BSR now. + */ + pim_cand_bsr_trigger(scope, false); } static void pim_bs_timer_stop(struct bsm_scope *scope) @@ -212,36 +255,77 @@ static inline void pim_bs_timer_restart(struct bsm_scope *scope, int bs_timeout) pim_bs_timer_start(scope, bs_timeout); } +static void bsm_unicast_sock_read(struct event *t) +{ + struct bsm_scope *scope = EVENT_ARG(t); + + pim_sock_read_helper(scope->unicast_sock, scope->pim, false); + + event_add_read(router->master, bsm_unicast_sock_read, scope, + scope->unicast_sock, &scope->unicast_read); +} + void pim_bsm_proc_init(struct pim_instance *pim) { - memset(&pim->global_scope, 0, sizeof(struct bsm_scope)); - - pim->global_scope.sz_id = PIM_GBL_SZ_ID; - pim->global_scope.bsrp_table = route_table_init(); - pim->global_scope.accept_nofwd_bsm = true; - pim->global_scope.state = NO_INFO; - pim->global_scope.pim = pim; - bsm_frags_init(pim->global_scope.bsm_frags); - pim_bs_timer_start(&pim->global_scope, PIM_BS_TIME); + struct bsm_scope *scope = &pim->global_scope; + + memset(scope, 0, sizeof(*scope)); + + scope->sz_id = PIM_GBL_SZ_ID; + scope->bsrp_table = route_table_init(); + scope->accept_nofwd_bsm = true; + scope->state = NO_INFO; + scope->pim = pim; + bsm_frags_init(scope->bsm_frags); + pim_bs_timer_start(scope, PIM_BS_TIME); + + scope->cand_rp_interval = PIM_CRP_ADV_INTERVAL; + cand_rp_groups_init(scope->cand_rp_groups); + + scope->unicast_sock = pim_socket_raw(IPPROTO_PIM); + set_nonblocking(scope->unicast_sock); + sockopt_reuseaddr(scope->unicast_sock); + + if (setsockopt_ifindex(PIM_AF, scope->unicast_sock, 1) == -1) + zlog_warn("%s: Without IP_PKTINFO, src interface can't be determined", + __func__); + + pim_socket_ip_hdr(scope->unicast_sock); + + frr_with_privs (&pimd_privs) { + vrf_bind(pim->vrf->vrf_id, scope->unicast_sock, NULL); + } + + event_add_read(router->master, bsm_unicast_sock_read, scope, + scope->unicast_sock, &scope->unicast_read); } void pim_bsm_proc_free(struct pim_instance *pim) { + struct bsm_scope *scope = &pim->global_scope; struct route_node *rn; struct bsgrp_node *bsgrp; + struct cand_rp_group *crpgrp; - pim_bs_timer_stop(&pim->global_scope); - pim_bsm_frags_free(&pim->global_scope); + EVENT_OFF(scope->unicast_read); + close(scope->unicast_sock); - for (rn = route_top(pim->global_scope.bsrp_table); rn; - rn = route_next(rn)) { + pim_bs_timer_stop(scope); + pim_bsm_frags_free(scope); + + for (rn = route_top(scope->bsrp_table); rn; rn = route_next(rn)) { bsgrp = rn->info; if (!bsgrp) continue; pim_free_bsgrp_data(bsgrp); } - route_table_finish(pim->global_scope.bsrp_table); + while ((crpgrp = cand_rp_groups_pop(scope->cand_rp_groups))) + XFREE(MTYPE_PIM_CAND_RP_GRP, crpgrp); + + cand_rp_groups_fini(scope->cand_rp_groups); + + route_table_finish(scope->bsrp_table); } static bool is_hold_time_elapsed(void *data) @@ -512,9 +596,6 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node) static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr, uint32_t bsr_prio) { - if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr)) - return true; - if (bsr_prio > pim->global_scope.current_bsr_prio) return true; @@ -523,6 +604,11 @@ static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr, return true; else return false; + } else if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr)) { + /* BSR config changed, lower prio now. local BSR check + * is handled separately in pim_bsm_update() + */ + return true; } else return false; } @@ -530,17 +616,52 @@ static bool is_preferred_bsr(struct pim_instance *pim, pim_addr bsr, static void pim_bsm_update(struct pim_instance *pim, pim_addr bsr, uint32_t bsr_prio) { - if (pim_addr_cmp(bsr, pim->global_scope.current_bsr)) { - pim_nht_bsr_del(pim, pim->global_scope.current_bsr); - pim_nht_bsr_add(pim, bsr); - - pim->global_scope.current_bsr = bsr; - pim->global_scope.current_bsr_first_ts = - pim_time_monotonic_sec(); - pim->global_scope.state = ACCEPT_PREFERRED; - } pim->global_scope.current_bsr_prio = bsr_prio; pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec(); + + if (pim->global_scope.bsr_addrsel.run && + pim->global_scope.cand_bsr_prio > bsr_prio && + pim->global_scope.state < BSR_PENDING) { + /* current BSR is now less preferred than ourselves */ + pim_cand_bsr_pending(&pim->global_scope); + return; + } + + if (!pim_addr_cmp(bsr, pim->global_scope.current_bsr)) + return; + + switch (pim->global_scope.state) { + case BSR_PENDING: + if (PIM_DEBUG_BSM) + zlog_debug("Candidate BSR dropping out of BSR election, better BSR (%u, %pPA)", + bsr_prio, &bsr); + break; + + case BSR_ELECTED: + if (PIM_DEBUG_BSM) + zlog_debug("Lost BSR status, better BSR (%u, %pPA)", + bsr_prio, &bsr); + break; + + case NO_INFO: + case ACCEPT_ANY: + case ACCEPT_PREFERRED: + break; + } + + EVENT_OFF(pim->global_scope.t_ebsr_regen_bsm); + + if (pim->global_scope.state == BSR_ELECTED) + pim_crp_db_clear(&pim->global_scope); + else + pim_nht_bsr_del(pim, pim->global_scope.current_bsr); + pim_nht_bsr_add(pim, bsr); + + pim->global_scope.current_bsr = bsr; + pim->global_scope.current_bsr_first_ts = pim_time_monotonic_sec(); + pim->global_scope.state = ACCEPT_PREFERRED; + + pim_cand_rp_trigger(&pim->global_scope); } void pim_bsm_clear(struct pim_instance *pim) @@ -555,7 +676,12 @@ void pim_bsm_clear(struct pim_instance *pim) struct rp_info *rp_info; bool upstream_updated = false; - pim_nht_bsr_del(pim, pim->global_scope.current_bsr); + EVENT_OFF(pim->global_scope.t_ebsr_regen_bsm); + + if (pim->global_scope.state == BSR_ELECTED) + pim_crp_db_clear(&pim->global_scope); + else + pim_nht_bsr_del(pim, pim->global_scope.current_bsr); /* Reset scope zone data */ pim->global_scope.accept_nofwd_bsm = false; @@ -1116,8 +1242,8 @@ static void pim_update_pending_rp_cnt(struct bsm_scope *sz, } /* Parsing BSR packet and adding to partial list of corresponding bsgrp node */ -static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, - int buflen, uint16_t bsm_frag_tag) +bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, + int buflen, uint16_t bsm_frag_tag) { struct bsmmsg_grpinfo grpinfo; struct bsmmsg_rpinfo rpinfo; @@ -1338,35 +1464,6 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, } } - /* Drop if bsr is not preferred bsr */ - if (!is_preferred_bsr(pim, bsr_addr, bshdr->bsr_prio)) { - if (PIM_DEBUG_BSM) - zlog_debug("%s : Received a non-preferred BSM", - __func__); - pim->bsm_dropped++; - return -1; - } - - if (no_fwd) { - /* only accept no-forward BSM if quick refresh on startup */ - if ((pim->global_scope.accept_nofwd_bsm) - || (frag_tag == pim->global_scope.bsm_frag_tag)) { - pim->global_scope.accept_nofwd_bsm = false; - } else { - if (PIM_DEBUG_BSM) - zlog_debug( - "%s : nofwd_bsm received on %pPAs when accpt_nofwd_bsm false", - __func__, &bsr_addr); - pim->bsm_dropped++; - pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++; - return -1; - } - } - - /* BSM packet is seen, so resetting accept_nofwd_bsm to false */ - if (pim->global_scope.accept_nofwd_bsm) - pim->global_scope.accept_nofwd_bsm = false; - if (!pim_addr_cmp(sg->grp, qpim_all_pim_routers_addr)) { /* Multicast BSMs are only accepted if source interface & IP * match RPF towards the BSR's IP address, or they have @@ -1403,6 +1500,57 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, return -1; } + /* when the BSR restarts, it can get its own BSR advertisement thrown + * back at it, and without this we'll go into ACCEPT_PREFERRED with + * ourselves as the BSR when we should be in BSR_ELECTED. + */ + if (if_address_is_local(&bshdr->bsr_addr.addr, PIM_AF, + pim->vrf->vrf_id)) { + if (PIM_DEBUG_BSM) + zlog_debug("%s : Dropping BSM from ourselves", __func__); + pim->bsm_dropped++; + return -1; + } + + /* Drop if bsr is not preferred bsr */ + if (!is_preferred_bsr(pim, bsr_addr, bshdr->bsr_prio)) { + if (pim->global_scope.state == BSR_PENDING && !no_fwd) { + /* in P-BSR state, non-preferred BSMs are forwarded, but + * content is ignored. + */ + if (PIM_DEBUG_BSM) + zlog_debug("%s : Forwarding non-preferred BSM during Pending-BSR state", + __func__); + + pim_bsm_fwd_whole_sz(pim_ifp->pim, buf, buf_size, sz); + return -1; + } + if (PIM_DEBUG_BSM) + zlog_debug("%s : Received a non-preferred BSM", + __func__); + pim->bsm_dropped++; + return -1; + } + + if (no_fwd) { + /* only accept no-forward BSM if quick refresh on startup */ + if ((pim->global_scope.accept_nofwd_bsm) || + (frag_tag == pim->global_scope.bsm_frag_tag)) { + pim->global_scope.accept_nofwd_bsm = false; + } else { + if (PIM_DEBUG_BSM) + zlog_debug("%s : nofwd_bsm received on %pPAs when accpt_nofwd_bsm false", + __func__, &bsr_addr); + pim->bsm_dropped++; + pim_ifp->pim_ifstat_ucast_bsm_cfg_miss++; + return -1; + } + } + + /* BSM packet is seen, so resetting accept_nofwd_bsm to false */ + if (pim->global_scope.accept_nofwd_bsm) + pim->global_scope.accept_nofwd_bsm = false; + if (empty_bsm) { if (PIM_DEBUG_BSM) zlog_debug("%s : Empty Pref BSM received", __func__); @@ -1413,9 +1561,8 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, (buf + PIM_BSM_HDR_LEN + PIM_MSG_HEADER_LEN), (buf_size - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN), frag_tag)) { - if (PIM_DEBUG_BSM) { - zlog_debug("%s, Parsing BSM failed.", __func__); - } + zlog_warn("BSM from %pPA failed to parse", + (pim_addr *)&bshdr->bsr_addr.addr); pim->bsm_dropped++; return -1; } @@ -1452,7 +1599,594 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, return 0; } -void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc) +static void pim_elec_bsr_timer(struct event *t) +{ + struct bsm_scope *scope = EVENT_ARG(t); + struct bsm_frag *frag; + struct bsm_hdr *hdr; + + assert(scope->state == BSR_ELECTED); + + scope->bsm_frag_tag++; + frag = bsm_frags_first(scope->bsm_frags); + assert(frag); + + hdr = (struct bsm_hdr *)(frag->data + PIM_MSG_HEADER_LEN); + hdr->frag_tag = htons(scope->bsm_frag_tag); + + unsigned int timer = PIM_BS_TIME; + + if (scope->changed_bsm_trigger) { + if (PIM_DEBUG_BSM) + zlog_debug("Sending triggered BSM"); + scope->changed_bsm_trigger--; + timer = 5; + } else { + if (PIM_DEBUG_BSM) + zlog_debug("Sending scheduled BSM"); + pim_bsm_sent(scope); + } + + pim_bsm_fwd_whole_sz(scope->pim, frag->data, frag->size, scope->sz_id); + scope->current_bsr_last_ts = pim_time_monotonic_sec(); + + event_add_timer(router->master, pim_elec_bsr_timer, scope, timer, + &scope->bs_timer); +} + +void pim_bsm_changed(struct bsm_scope *scope) +{ + struct event t; + + EVENT_OFF(scope->bs_timer); + scope->changed_bsm_trigger = 2; + + t.arg = scope; + pim_elec_bsr_timer(&t); +} + +static void pim_cand_bsr_pending_expire(struct event *t) +{ + struct bsm_scope *scope = EVENT_ARG(t); + + assertf(scope->state == BSR_PENDING, "state=%d", scope->state); + assertf(pim_addr_is_any(scope->current_bsr), "current_bsr=%pPA", + &scope->current_bsr); + + if (PIM_DEBUG_BSM) + zlog_debug("Elected BSR, wait expired without preferable BSMs"); + + scope->state = BSR_ELECTED; + scope->current_bsr_prio = scope->cand_bsr_prio; + scope->current_bsr = scope->bsr_addrsel.run_addr; + + scope->bsm_frag_tag = frr_weak_random(); + scope->current_bsr_first_ts = pim_time_monotonic_sec(); + + pim_cand_rp_trigger(scope); + pim_bsm_generate(scope); +} + +#if PIM_IPV == 6 +static float bsr_addr_delay(pim_addr best, pim_addr local) +{ + unsigned int pos; + uint32_t best_4b, local_4b; + float delay_log; + + for (pos = 0; pos < 12; pos++) { + if (best.s6_addr[pos] != local.s6_addr[pos]) + break; + } + + memcpy(&best_4b, &best.s6_addr[pos], 4); + memcpy(&local_4b, &local.s6_addr[pos], 4); + + delay_log = log2(1 + ntohl(best_4b) - ntohl(local_4b)); + delay_log += (12 - pos) * 8; + return delay_log / 64.; +} +#endif + +static void pim_cand_bsr_pending(struct bsm_scope *scope) +{ + unsigned int bs_rand_override; + uint8_t best_prio; + pim_addr best_addr; + float prio_delay, addr_delay; + + EVENT_OFF(scope->bs_timer); + EVENT_OFF(scope->t_ebsr_regen_bsm); + scope->state = BSR_PENDING; + + best_prio = MAX(scope->cand_bsr_prio, scope->current_bsr_prio); + best_addr = pim_addr_cmp(scope->bsr_addrsel.run_addr, + scope->current_bsr) > 0 + ? scope->bsr_addrsel.run_addr + : scope->current_bsr; + + /* RFC5059 sec.5 */ +#if PIM_IPV == 4 + if (scope->cand_bsr_prio == best_prio) { + prio_delay = 0.; /* log2(1) = 0 */ + addr_delay = log2(1 + ntohl(best_addr.s_addr) - + ntohl(scope->bsr_addrsel.run_addr.s_addr)) / + 16.; + } else { + prio_delay = 2. * log2(1 + best_prio - scope->cand_bsr_prio); + addr_delay = 2 - (ntohl(scope->bsr_addrsel.run_addr.s_addr) / + (float)(1 << 31)); + } +#else + if (scope->cand_bsr_prio == best_prio) { + prio_delay = 0.; /* log2(1) = 0 */ + addr_delay = bsr_addr_delay(best_addr, + scope->bsr_addrsel.run_addr); + } else { + prio_delay = 2. * log2(1 + best_prio - scope->cand_bsr_prio); + addr_delay = 2 - + (ntohl(scope->bsr_addrsel.run_addr.s6_addr32[0]) / + (float)(1 << 31)); + } +#endif + + bs_rand_override = 5000 + (int)((prio_delay + addr_delay) * 1000.); + + if (PIM_DEBUG_BSM) + zlog_debug("Pending-BSR (%u, %pPA), waiting %ums", + scope->cand_bsr_prio, &scope->bsr_addrsel.run_addr, + bs_rand_override); + + event_add_timer_msec(router->master, pim_cand_bsr_pending_expire, scope, + bs_rand_override, &scope->bs_timer); +} + +static inline pim_addr if_highest_addr(pim_addr cur, struct interface *ifp) +{ + struct connected *connected; + + frr_each (if_connected, ifp->connected, connected) { + pim_addr conn_addr; + + if (connected->address->family != PIM_AF) + continue; + + conn_addr = pim_addr_from_prefix(connected->address); + /* highest address */ + if (pim_addr_cmp(conn_addr, cur) > 0) + cur = conn_addr; + } + return cur; +} + +static void cand_addrsel_clear(struct cand_addrsel *asel) +{ + asel->run = false; + asel->run_addr = PIMADDR_ANY; +} + +/* returns whether address or active changed */ +static bool cand_addrsel_update(struct cand_addrsel *asel, struct vrf *vrf) +{ + bool is_any = false, prev_run = asel->run; + struct interface *ifp = NULL; + pim_addr new_addr = PIMADDR_ANY; + + if (!asel->cfg_enable) + goto out_disable; + + switch (asel->cfg_mode) { + case CAND_ADDR_EXPLICIT: + new_addr = asel->cfg_addr; + ifp = if_lookup_address_local(&asel->cfg_addr, PIM_AF, + vrf->vrf_id); + break; + + case CAND_ADDR_IFACE: + ifp = if_lookup_by_name_vrf(asel->cfg_ifname, vrf); + + if (ifp) + new_addr = if_highest_addr(PIMADDR_ANY, ifp); + break; + + case CAND_ADDR_ANY: + is_any = true; + /* fallthru */ + case CAND_ADDR_LO: + FOR_ALL_INTERFACES (vrf, ifp) { + if (!if_is_up(ifp)) + continue; + if (is_any || if_is_loopback(ifp) || if_is_vrf(ifp)) + new_addr = if_highest_addr(new_addr, ifp); + } + break; + } + + if (ifp && !if_is_up(ifp)) + goto out_disable; + + if (pim_addr_is_any(new_addr)) + goto out_disable; + + /* nothing changed re. address (don't care about interface changes) */ + if (asel->run && !pim_addr_cmp(asel->run_addr, new_addr)) + return !prev_run; + + asel->run = true; + asel->run_addr = new_addr; + return true; + +out_disable: + asel->run = false; + asel->run_addr = PIMADDR_ANY; + + return prev_run; +} + +static void pim_cand_bsr_stop(struct bsm_scope *scope, bool verbose) +{ + cand_addrsel_clear(&scope->bsr_addrsel); + + switch (scope->state) { + case NO_INFO: + case ACCEPT_ANY: + case ACCEPT_PREFERRED: + return; + case BSR_PENDING: + case BSR_ELECTED: + break; + } + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate BSR ceasing operation"); + + EVENT_OFF(scope->t_ebsr_regen_bsm); + EVENT_OFF(scope->bs_timer); + pim_crp_db_clear(scope); + pim_bsm_accept_any(scope); +} + +static void pim_cand_bsr_trigger(struct bsm_scope *scope, bool verbose) +{ + /* this is called on all state changes even if we aren't configured + * to be C-BSR at all. + */ + if (!scope->bsr_addrsel.run) + return; + + if (scope->current_bsr_prio > scope->cand_bsr_prio) { + assert(scope->state == ACCEPT_PREFERRED); + if (!verbose) + return; + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate BSR: known better BSR %pPA (higher priority %u > %u)", + &scope->current_bsr, scope->current_bsr_prio, + scope->cand_bsr_prio); + return; + } else if (scope->current_bsr_prio == scope->cand_bsr_prio && + pim_addr_cmp(scope->current_bsr, + scope->bsr_addrsel.run_addr) > 0) { + assert(scope->state == ACCEPT_PREFERRED); + if (!verbose) + return; + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate BSR: known better BSR %pPA (higher address > %pPA)", + &scope->current_bsr, + &scope->bsr_addrsel.run_addr); + return; + } + + if (!pim_addr_cmp(scope->current_bsr, scope->bsr_addrsel.run_addr)) + return; + + pim_cand_bsr_pending(scope); +} + +void pim_cand_bsr_apply(struct bsm_scope *scope) +{ + if (!cand_addrsel_update(&scope->bsr_addrsel, scope->pim->vrf)) + return; + + if (!scope->bsr_addrsel.run) { + pim_cand_bsr_stop(scope, true); + return; + } + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate BSR: %pPA, priority %u", + &scope->bsr_addrsel.run_addr, scope->cand_bsr_prio); + + pim_cand_bsr_trigger(scope, true); +} + +static void pim_cand_rp_adv_stop_maybe(struct bsm_scope *scope) +{ + /* actual check whether stop should be sent - covers address + * changes as well as run_addr = 0.0.0.0 (C-RP shutdown) + */ + if (pim_addr_is_any(scope->cand_rp_prev_addr) || + !pim_addr_cmp(scope->cand_rp_prev_addr, + scope->cand_rp_addrsel.run_addr)) + return; + + switch (scope->state) { + case ACCEPT_PREFERRED: + case BSR_ELECTED: + break; + + case NO_INFO: + case ACCEPT_ANY: + case BSR_PENDING: + default: + return; + } + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate-RP (-, %pPA) deregistering self to %pPA", + &scope->cand_rp_prev_addr, &scope->current_bsr); + + struct cand_rp_msg *msg; + uint8_t buf[PIM_MSG_HEADER_LEN + sizeof(*msg) + sizeof(pim_encoded_group)]; + + msg = (struct cand_rp_msg *)(&buf[PIM_MSG_HEADER_LEN]); + msg->prefix_cnt = 0; + msg->rp_prio = 255; + msg->rp_holdtime = 0; + msg->rp_addr.family = PIM_IANA_AFI; + msg->rp_addr.reserved = 0; + msg->rp_addr.addr = scope->cand_rp_prev_addr; + + pim_msg_build_header(PIMADDR_ANY, scope->current_bsr, buf, sizeof(buf), + PIM_MSG_TYPE_CANDIDATE, false); + + if (pim_msg_send(scope->unicast_sock, PIMADDR_ANY, scope->current_bsr, + buf, sizeof(buf), NULL)) { + zlog_warn("failed to send Cand-RP message: %m"); + } + + scope->cand_rp_prev_addr = PIMADDR_ANY; +} + +static void pim_cand_rp_adv(struct event *t) +{ + struct bsm_scope *scope = EVENT_ARG(t); + int next_msec; + + pim_cand_rp_adv_stop_maybe(scope); + + if (!scope->cand_rp_addrsel.run) { + scope->cand_rp_adv_trigger = 0; + return; + } + + switch (scope->state) { + case ACCEPT_PREFERRED: + case BSR_ELECTED: + break; + + case ACCEPT_ANY: + case BSR_PENDING: + case NO_INFO: + default: + /* state change will retrigger */ + scope->cand_rp_adv_trigger = 0; + + zlog_warn("Candidate-RP advertisement not sent in state %d", + scope->state); + return; + } + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate-RP (%u, %pPA) advertising %zu groups to %pPA", + scope->cand_rp_prio, &scope->cand_rp_addrsel.run_addr, + cand_rp_groups_count(scope->cand_rp_groups), + &scope->current_bsr); + + struct cand_rp_group *grp; + struct cand_rp_msg *msg; + uint8_t buf[PIM_MSG_HEADER_LEN + sizeof(*msg) + + sizeof(pim_encoded_group) * + cand_rp_groups_count(scope->cand_rp_groups)]; + size_t i = 0; + + + msg = (struct cand_rp_msg *)(&buf[PIM_MSG_HEADER_LEN]); + msg->prefix_cnt = cand_rp_groups_count(scope->cand_rp_groups); + msg->rp_prio = scope->cand_rp_prio; + msg->rp_holdtime = + htons(MAX(151, (scope->cand_rp_interval * 5 + 1) / 2)); + msg->rp_addr.family = PIM_IANA_AFI; + msg->rp_addr.reserved = 0; + msg->rp_addr.addr = scope->cand_rp_addrsel.run_addr; + + frr_each (cand_rp_groups, scope->cand_rp_groups, grp) { + memset(&msg->groups[i], 0, sizeof(msg->groups[i])); + + msg->groups[i].family = PIM_IANA_AFI; + msg->groups[i].mask = grp->p.prefixlen; + msg->groups[i].addr = grp->p.prefix; + i++; + } + + scope->cand_rp_prev_addr = scope->cand_rp_addrsel.run_addr; + + pim_msg_build_header(scope->cand_rp_addrsel.run_addr, scope->current_bsr, + buf, sizeof(buf), PIM_MSG_TYPE_CANDIDATE, false); + + if (pim_msg_send(scope->unicast_sock, scope->cand_rp_addrsel.run_addr, + scope->current_bsr, buf, sizeof(buf), NULL)) { + zlog_warn("failed to send Cand-RP message: %m"); + } + + /* -1s...+1s */ + next_msec = (frr_weak_random() & 2047) - 1024; + + if (scope->cand_rp_adv_trigger) { + scope->cand_rp_adv_trigger--; + next_msec += 2000; + } else + next_msec += scope->cand_rp_interval * 1000; + + event_add_timer_msec(router->master, pim_cand_rp_adv, scope, next_msec, + &scope->cand_rp_adv_timer); +} + +void pim_cand_rp_trigger(struct bsm_scope *scope) +{ + if (scope->cand_rp_adv_trigger && scope->cand_rp_addrsel.run) { + scope->cand_rp_adv_trigger = PIM_CRP_ADV_TRIGCOUNT; + + /* already scheduled to send triggered advertisements, don't + * reschedule so burst changes don't result in an advertisement + * burst + */ + return; + } + + EVENT_OFF(scope->cand_rp_adv_timer); + + if (!scope->cand_rp_addrsel.run) + return; + + scope->cand_rp_adv_trigger = PIM_CRP_ADV_TRIGCOUNT; + + struct event t; + + t.arg = scope; + pim_cand_rp_adv(&t); +} + +void pim_cand_rp_apply(struct bsm_scope *scope) { - /* stub for Candidate-RP */ + if (!cand_addrsel_update(&scope->cand_rp_addrsel, scope->pim->vrf)) + return; + + if (!scope->cand_rp_addrsel.run) { + if (PIM_DEBUG_BSM) + zlog_debug("Candidate RP ceasing operation"); + + cand_addrsel_clear(&scope->cand_rp_addrsel); + EVENT_OFF(scope->cand_rp_adv_timer); + pim_cand_rp_adv_stop_maybe(scope); + scope->cand_rp_adv_trigger = 0; + return; + } + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate RP: %pPA, priority %u", + &scope->cand_rp_addrsel.run_addr, + scope->cand_rp_prio); + + pim_cand_rp_trigger(scope); +} + +void pim_cand_rp_grp_add(struct bsm_scope *scope, const prefix_pim *p) +{ + struct cand_rp_group *grp, ref; + + ref.p = *p; + grp = cand_rp_groups_find(scope->cand_rp_groups, &ref); + if (grp) + return; + + grp = XCALLOC(MTYPE_PIM_CAND_RP_GRP, sizeof(*grp)); + grp->p = *p; + cand_rp_groups_add(scope->cand_rp_groups, grp); + + pim_cand_rp_trigger(scope); +} + +void pim_cand_rp_grp_del(struct bsm_scope *scope, const prefix_pim *p) +{ + struct cand_rp_group *grp, ref; + + ref.p = *p; + grp = cand_rp_groups_find(scope->cand_rp_groups, &ref); + if (!grp) + return; + + cand_rp_groups_del(scope->cand_rp_groups, grp); + XFREE(MTYPE_PIM_CAND_RP_GRP, grp); + + pim_cand_rp_trigger(scope); +} + +static struct event *t_cand_addrs_reapply; + +static void pim_cand_addrs_reapply(struct event *t) +{ + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + struct pim_instance *pi = vrf->info; + + if (!pi) + continue; + + /* these call cand_addrsel_update() and apply changes */ + pim_cand_bsr_apply(&pi->global_scope); + pim_cand_rp_apply(&pi->global_scope); + } +} + +void pim_cand_addrs_changed(void) +{ + EVENT_OFF(t_cand_addrs_reapply); + event_add_timer_msec(router->master, pim_cand_addrs_reapply, NULL, 1, + &t_cand_addrs_reapply); +} + +static void cand_addrsel_config_write(struct vty *vty, + struct cand_addrsel *addrsel) +{ + switch (addrsel->cfg_mode) { + case CAND_ADDR_LO: + break; + case CAND_ADDR_ANY: + vty_out(vty, " source any"); + break; + case CAND_ADDR_IFACE: + vty_out(vty, " source interface %s", addrsel->cfg_ifname); + break; + case CAND_ADDR_EXPLICIT: + vty_out(vty, " source address %pPA", &addrsel->cfg_addr); + break; + } +} + +int pim_cand_config_write(struct pim_instance *pim, struct vty *vty) +{ + struct bsm_scope *scope = &pim->global_scope; + int ret = 0; + + if (scope->cand_rp_addrsel.cfg_enable) { + vty_out(vty, " bsr candidate-rp"); + if (scope->cand_rp_prio != 192) + vty_out(vty, " priority %u", scope->cand_rp_prio); + if (scope->cand_rp_interval != PIM_CRP_ADV_INTERVAL) + vty_out(vty, " interval %u", scope->cand_rp_interval); + cand_addrsel_config_write(vty, &scope->cand_rp_addrsel); + vty_out(vty, "\n"); + ret++; + + struct cand_rp_group *group; + + frr_each (cand_rp_groups, scope->cand_rp_groups, group) { + vty_out(vty, " bsr candidate-rp group %pFX\n", + &group->p); + ret++; + } + } + + if (scope->bsr_addrsel.cfg_enable) { + vty_out(vty, " bsr candidate-bsr"); + if (scope->cand_bsr_prio != 64) + vty_out(vty, " priority %u", scope->cand_bsr_prio); + cand_addrsel_config_write(vty, &scope->bsr_addrsel); + vty_out(vty, "\n"); + ret++; + } + return ret; } diff --git a/pimd/pim_bsm.h b/pimd/pim_bsm.h index fb09e3b1cc..1eacc1be57 100644 --- a/pimd/pim_bsm.h +++ b/pimd/pim_bsm.h @@ -21,6 +21,13 @@ #define PIM_BS_TIME 60 /* RFC 5059 - Sec 5 */ #define PIM_BSR_DEFAULT_TIMEOUT 130 /* RFC 5059 - Sec 5 */ +/* number of times to include rp-count = 0 ranges */ +#define PIM_BSR_DEAD_COUNT 3 + +#define PIM_CRP_ADV_TRIGCOUNT 3 +#define PIM_CRP_ADV_INTERVAL 60 +#define PIM_CRP_HOLDTIME 150 + /* These structures are only encoded IPv4 specific */ #define PIM_BSM_HDR_LEN sizeof(struct bsm_hdr) #define PIM_BSM_GRP_LEN sizeof(struct bsmmsg_grpinfo) @@ -33,19 +40,61 @@ * ============== */ -/* Non candidate BSR states */ -enum ncbsr_state { +/* BSR states + * + * Candidate BSR starts at BSR_PENDING, moves to AP or E depending on + * loss/win. Will never go into AA (because in that case it'd become BSR + * itself.) + * + * Non-Candidate BSR starts at NO_INFO, moves to AP & AA depending on + * a BSR being available or not. + */ +enum bsr_state { NO_INFO = 0, ACCEPT_ANY, - ACCEPT_PREFERRED + ACCEPT_PREFERRED, /* = same as C-BSR if candidate */ + BSR_PENDING, + BSR_ELECTED, +}; + +enum cand_addr { + CAND_ADDR_LO = 0, + CAND_ADDR_ANY, + CAND_ADDR_IFACE, + CAND_ADDR_EXPLICIT, }; +/* used separately for Cand-RP and Cand-BSR */ +struct cand_addrsel { + bool cfg_enable; + enum cand_addr cfg_mode : 8; + + /* only valid for mode==CAND_ADDR_IFACE */ + char cfg_ifname[IFNAMSIZ]; + /* only valid for mode==CAND_ADDR_EXPLICIT */ + pim_addr cfg_addr; + + /* running state updated based on above on zebra events */ + pim_addr run_addr; + bool run; +}; + + PREDECL_DLIST(bsm_frags); +PREDECL_RBTREE_UNIQ(cand_rp_groups); + +/* n*m "table" accessed both by-RP and by-group */ +PREDECL_RBTREE_UNIQ(bsr_crp_rps); +PREDECL_RBTREE_UNIQ(bsr_crp_groups); + +PREDECL_RBTREE_UNIQ(bsr_crp_rp_groups); +PREDECL_RBTREE_UNIQ(bsr_crp_group_rps); /* BSM scope - bsm processing is per scope */ struct bsm_scope { int sz_id; /* scope zone id */ - enum ncbsr_state state; /* non candidate BSR state */ + enum bsr_state state; /* BSR state */ + bool accept_nofwd_bsm; /* no fwd bsm accepted for scope */ pim_addr current_bsr; /* current elected BSR for the sz */ uint32_t current_bsr_prio; /* current BSR priority */ @@ -60,6 +109,93 @@ struct bsm_scope { struct route_table *bsrp_table; /* group2rp mapping rcvd from BSR */ struct event *bs_timer; /* Boot strap timer */ + + /* Candidate BSR config */ + struct cand_addrsel bsr_addrsel; + uint8_t cand_bsr_prio; + + /* Candidate BSR state */ + uint8_t current_cand_bsr_prio; + /* if nothing changed from Cand-RP data we received, less work... */ + bool elec_rp_data_changed; + + /* data that the E-BSR keeps - not to be confused with Candidate-RP + * stuff below. These two here are the info about all the Cand-RPs + * that we as a BSR received information for in Cand-RP-adv packets. + */ + struct bsr_crp_rps_head ebsr_rps[1]; + struct bsr_crp_groups_head ebsr_groups[1]; + + /* set if we have any group ranges where we're currently advertising + * rp-count = 0 (includes both ranges without any RPs as well as + * ranges with only NHT-unreachable RPs) + */ + bool ebsr_have_dead_pending; + unsigned int changed_bsm_trigger; + + struct event *t_ebsr_regen_bsm; + + /* Candidate RP config */ + struct cand_addrsel cand_rp_addrsel; + uint8_t cand_rp_prio; + unsigned int cand_rp_interval; /* default: PIM_CRP_ADV_INTERVAL=60 */ + /* holdtime is not configurable, always 2.5 * interval. */ + struct cand_rp_groups_head cand_rp_groups[1]; + + /* Candidate RP state */ + int unicast_sock; + struct event *unicast_read; + struct event *cand_rp_adv_timer; + unsigned int cand_rp_adv_trigger; /* # trigg. C-RP-Adv left to send */ + + /* for sending holdtime=0 zap */ + pim_addr cand_rp_prev_addr; +}; + +struct cand_rp_group { + struct cand_rp_groups_item item; + + prefix_pim p; +}; + +struct bsr_crp_group { + struct bsr_crp_groups_item item; + + prefix_pim range; + struct bsr_crp_group_rps_head rps[1]; + + size_t n_selected; + bool deleted_selected : 1; + + /* number of times we've advertised this range with rp-count = 0 */ + unsigned int dead_count; +}; + +struct bsr_crp_rp { + struct bsr_crp_rps_item item; + + pim_addr addr; + struct bsr_crp_rp_groups_head groups[1]; + + struct bsm_scope *scope; + struct event *t_hold; + time_t seen_first; + time_t seen_last; + + uint16_t holdtime; + uint8_t prio; + bool nht_ok; +}; + +/* "n * m" RP<->Group tie-in */ +struct bsr_crp_item { + struct bsr_crp_rp_groups_item r_g_item; + struct bsr_crp_group_rps_item g_r_item; + + struct bsr_crp_group *group; + struct bsr_crp_rp *rp; + + bool selected : 1; }; /* BSM packet (= fragment) - this is stored as list in bsm_frags inside scope @@ -200,6 +336,14 @@ struct bsmmsg_rpinfo { uint8_t reserved; } __attribute__((packed)); +struct cand_rp_msg { + uint8_t prefix_cnt; + uint8_t rp_prio; + uint16_t rp_holdtime; + pim_encoded_unicast rp_addr; + pim_encoded_group groups[0]; +} __attribute__((packed)); + /* API */ void pim_bsm_proc_init(struct pim_instance *pim); void pim_bsm_proc_free(struct pim_instance *pim); @@ -210,4 +354,39 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp); struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope, struct prefix *grp); + +void pim_bsm_generate(struct bsm_scope *scope); +void pim_bsm_changed(struct bsm_scope *scope); +void pim_bsm_sent(struct bsm_scope *scope); +void pim_bsm_frags_free(struct bsm_scope *scope); + +bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, + int buflen, uint16_t bsm_frag_tag); + +void pim_cand_bsr_apply(struct bsm_scope *scope); +void pim_cand_rp_apply(struct bsm_scope *scope); +void pim_cand_rp_trigger(struct bsm_scope *scope); +void pim_cand_rp_grp_add(struct bsm_scope *scope, const prefix_pim *p); +void pim_cand_rp_grp_del(struct bsm_scope *scope, const prefix_pim *p); + +void pim_cand_addrs_changed(void); + +int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf, + uint32_t buf_size); + +struct pim_nexthop_cache; +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc); + +void pim_crp_db_clear(struct bsm_scope *scope); +int pim_crp_db_show(struct vty *vty, struct bsm_scope *scope, bool json); +int pim_crp_groups_show(struct vty *vty, struct bsm_scope *scope, bool json); + +int pim_cand_config_write(struct pim_instance *pim, struct vty *vty); + +DECLARE_MTYPE(PIM_BSM_FRAG); + +DECLARE_MTYPE(PIM_BSM_FRAG); + +DECLARE_MTYPE(PIM_BSM_FRAG); + #endif diff --git a/pimd/pim_bsr_rpdb.c b/pimd/pim_bsr_rpdb.c new file mode 100644 index 0000000000..3ec9f99cd1 --- /dev/null +++ b/pimd/pim_bsr_rpdb.c @@ -0,0 +1,634 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* PIM RP database for BSR operation + * Copyright (C) 2021 David Lamparter for NetDEF, Inc. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <math.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <lib/network.h> +#include <lib/iana_afi.h> +#include <lib/sockunion.h> + +#include "if.h" +#include "pimd.h" +#include "pim_iface.h" +#include "pim_instance.h" +#include "pim_rpf.h" +#include "pim_hello.h" +#include "pim_pim.h" +#include "pim_nht.h" +#include "pim_bsm.h" +#include "pim_time.h" + +/* safety limits to prevent DoS/memory exhaustion attacks against the BSR + * + * The BSR is more susceptible than other PIM protocol operation because + * Candidate-RP messages are unicast to the BSR without any 2-way interaction + * and can thus be spoofed blindly(!) from anywhere in the internet. + * + * Everything else is on-link, multicast, or requires an adjacency - much + * harder to mess with. + */ + +/* total number of RPs we keep information for */ +static size_t bsr_max_rps = 1024; + +DEFINE_MTYPE_STATIC(PIMD, PIM_BSR_CRP, "PIM BSR C-RP"); +DEFINE_MTYPE_STATIC(PIMD, PIM_BSR_GROUP, "PIM BSR range"); +DEFINE_MTYPE_STATIC(PIMD, PIM_BSR_ITEM, "PIM BSR C-RP range item"); + +static int rp_cmp(const struct bsr_crp_rp *a, const struct bsr_crp_rp *b) +{ + return pim_addr_cmp(a->addr, b->addr); +} + +DECLARE_RBTREE_UNIQ(bsr_crp_rps, struct bsr_crp_rp, item, rp_cmp); + +static int group_cmp(const struct bsr_crp_group *a, + const struct bsr_crp_group *b) +{ + return prefix_cmp(&a->range, &b->range); +} + +DECLARE_RBTREE_UNIQ(bsr_crp_groups, struct bsr_crp_group, item, group_cmp); + +static int r_g_cmp(const struct bsr_crp_item *a, const struct bsr_crp_item *b) +{ + return prefix_cmp(&a->group->range, &b->group->range); +} + +DECLARE_RBTREE_UNIQ(bsr_crp_rp_groups, struct bsr_crp_item, r_g_item, r_g_cmp); + +static int g_r_cmp(const struct bsr_crp_item *a, const struct bsr_crp_item *b) +{ + const struct bsr_crp_rp *rp_a = a->rp, *rp_b = b->rp; + + /* NHT-failed RPs last */ + if (rp_a->nht_ok > rp_b->nht_ok) + return -1; + if (rp_a->nht_ok < rp_b->nht_ok) + return 1; + + /* This function determines BSR policy in what subset of the received + * RP candidates to advertise. The BSR is free to make its choices + * any way it deems useful + */ + + /* lower numeric values are better */ + if (rp_a->prio < rp_b->prio) + return -1; + if (rp_a->prio > rp_b->prio) + return 1; + + /* prefer older RP for less churn */ + if (rp_a->seen_first < rp_b->seen_first) + return -1; + if (rp_a->seen_first > rp_b->seen_first) + return 1; + + return pim_addr_cmp(rp_a->addr, rp_b->addr); +} + +DECLARE_RBTREE_UNIQ(bsr_crp_group_rps, struct bsr_crp_item, g_r_item, g_r_cmp); + +void pim_bsm_generate(struct bsm_scope *scope) +{ + struct bsm_frag *frag; + struct bsm_hdr *hdr; + bool have_dead = false; + + assertf(scope->state == BSR_ELECTED, "state=%d", scope->state); + + pim_bsm_frags_free(scope); + + struct bsr_crp_group *group; + struct bsr_crp_item *item; + struct bsr_crp_rp *rp; + size_t n_groups = 0, n_rps = 0; + + frr_each (bsr_crp_groups, scope->ebsr_groups, group) { + if (group->n_selected == 0) { + if (group->dead_count >= PIM_BSR_DEAD_COUNT) + continue; + + have_dead = true; + } else + group->dead_count = 0; + + n_groups++; + n_rps += group->n_selected; + } + + if (PIM_DEBUG_BSM) + zlog_debug("Generating BSM (%zu ranges, %zu RPs)", n_groups, n_rps); + + size_t datalen = PIM_MSG_HEADER_LEN + sizeof(*hdr) + + n_groups * sizeof(struct bsmmsg_grpinfo) + + n_rps * sizeof(struct bsmmsg_rpinfo); + + frag = XCALLOC(MTYPE_PIM_BSM_FRAG, sizeof(*frag) + datalen); + + uint8_t *pos = frag->data + PIM_MSG_HEADER_LEN; + uint8_t *end = frag->data + datalen; + + hdr = (struct bsm_hdr *)pos; + pos += sizeof(*hdr); + assert(pos <= end); + + /* TODO: make BSR hashmasklen configurable */ +#if PIM_IPV == 6 + hdr->hm_len = 126; +#else + hdr->hm_len = 30; +#endif + hdr->bsr_prio = scope->current_bsr_prio; + hdr->bsr_addr.family = PIM_IANA_AFI; + hdr->bsr_addr.reserved = 0; + hdr->bsr_addr.addr = scope->bsr_addrsel.run_addr; + + frr_each (bsr_crp_groups, scope->ebsr_groups, group) { + if (group->n_selected == 0 && + group->dead_count >= PIM_BSR_DEAD_COUNT) + continue; + + struct bsmmsg_grpinfo *gi = (struct bsmmsg_grpinfo *)pos; + + pos += sizeof(*gi); + assert(pos <= end); + + gi->group.family = PIM_MSG_ADDRESS_FAMILY; + gi->group.mask = group->range.prefixlen; + gi->group.addr = group->range.prefix; + + size_t n_added = 0; + + frr_each (bsr_crp_group_rps, group->rps, item) { + if (!item->selected) + break; + + struct bsmmsg_rpinfo *ri = (struct bsmmsg_rpinfo *)pos; + + pos += sizeof(*ri); + assert(pos <= end); + + rp = item->rp; + ri->rpaddr.family = PIM_MSG_ADDRESS_FAMILY; + ri->rpaddr.addr = rp->addr; + ri->rp_holdtime = htons(rp->holdtime); + ri->rp_pri = rp->prio; + + n_added++; + } + + gi->rp_count = group->n_selected; + gi->frag_rp_count = n_added; + assert(n_added == group->n_selected); + } + + assertf(pos == end, "end-pos=%td", end - pos); + frag->size = datalen; + + bsm_frags_add_head(scope->bsm_frags, frag); + + scope->ebsr_have_dead_pending = have_dead; + + /* + * The BSR itself doesn't receive (no loopback) the BSM msgs advertising + * the rps. Install the rps directly for the local BSR node. + */ + pim_bsm_parse_install_g2rp(scope, ((uint8_t *) hdr) + PIM_BSM_HDR_LEN, + datalen - PIM_BSM_HDR_LEN - PIM_MSG_HEADER_LEN, scope->bsm_frag_tag); + + pim_bsm_changed(scope); +} + +static void pim_bsm_generate_timer(struct event *t) +{ + struct bsm_scope *scope = EVENT_ARG(t); + + pim_bsm_generate(scope); +} + +static void pim_bsm_generate_sched(struct bsm_scope *scope) +{ + assertf(scope->state == BSR_ELECTED, "state=%d", scope->state); + + if (scope->t_ebsr_regen_bsm) + return; + + event_add_timer(router->master, pim_bsm_generate_timer, scope, 1, + &scope->t_ebsr_regen_bsm); +} + +void pim_bsm_sent(struct bsm_scope *scope) +{ + struct bsr_crp_group *group; + bool have_dead = false, changed = false; + + if (!scope->ebsr_have_dead_pending) + return; + + frr_each_safe (bsr_crp_groups, scope->ebsr_groups, group) { + if (group->n_selected != 0) + continue; + + if (group->dead_count < PIM_BSR_DEAD_COUNT) { + group->dead_count++; + have_dead = true; + continue; + } + + changed = true; + + if (bsr_crp_group_rps_count(group->rps)) + /* have RPs, but none selected */ + continue; + + /* no reason to keep this range anymore */ + bsr_crp_groups_del(scope->ebsr_groups, group); + bsr_crp_group_rps_fini(group->rps); + XFREE(MTYPE_PIM_BSR_GROUP, group); + continue; + } + + scope->ebsr_have_dead_pending = have_dead; + if (changed) + pim_bsm_generate_sched(scope); +} + +static void bsr_crp_reselect(struct bsm_scope *scope, + struct bsr_crp_group *group) +{ + bool changed = false; + struct bsr_crp_item *item; + size_t n_selected = 0; + + frr_each (bsr_crp_group_rps, group->rps, item) { + bool select = false; + + /* hardcode best 2 RPs for now */ + if (item->rp->nht_ok && n_selected < 2) { + select = true; + n_selected++; + } + + if (item->selected != select) { + changed = true; + item->selected = select; + } + } + + changed |= group->deleted_selected; + group->deleted_selected = false; + group->n_selected = n_selected; + + if (changed) + pim_bsm_generate_sched(scope); + + scope->elec_rp_data_changed |= changed; +} + +/* changing rp->nht_ok or rp->prio affects the sort order in group->rp + * lists, so need a delete & re-add if either changes + */ +static void pim_crp_nht_prio_change(struct bsr_crp_rp *rp, bool nht_ok, + uint8_t prio) +{ + struct bsr_crp_item *item; + + frr_each (bsr_crp_rp_groups, rp->groups, item) + bsr_crp_group_rps_del(item->group->rps, item); + + rp->prio = prio; + rp->nht_ok = nht_ok; + + frr_each (bsr_crp_rp_groups, rp->groups, item) { + bsr_crp_group_rps_add(item->group->rps, item); + bsr_crp_reselect(rp->scope, item->group); + } +} + +static struct bsr_crp_group *group_get(struct bsm_scope *scope, + prefix_pim *range) +{ + struct bsr_crp_group *group, ref; + + ref.range = *range; + group = bsr_crp_groups_find(scope->ebsr_groups, &ref); + if (!group) { + group = XCALLOC(MTYPE_PIM_BSR_GROUP, sizeof(*group)); + group->range = *range; + bsr_crp_group_rps_init(group->rps); + bsr_crp_groups_add(scope->ebsr_groups, group); + } + return group; +} + +static void pim_crp_update(struct bsr_crp_rp *rp, struct cand_rp_msg *msg, + size_t ngroups) +{ + struct bsr_crp_rp_groups_head oldgroups[1]; + struct bsr_crp_item *item, itemref; + struct bsr_crp_group *group, groupref; + + //struct bsm_scope *scope = rp->scope; + + bsr_crp_rp_groups_init(oldgroups); + bsr_crp_rp_groups_swap_all(rp->groups, oldgroups); + + itemref.rp = rp; + itemref.group = &groupref; + + assert(msg || ngroups == 0); + + for (size_t i = 0; i < ngroups; i++) { + if (msg->groups[i].family != PIM_MSG_ADDRESS_FAMILY) + continue; + if (msg->groups[i].bidir) + continue; + + prefix_pim pfx; + + pfx.family = PIM_AF; + pfx.prefixlen = msg->groups[i].mask; + pfx.prefix = msg->groups[i].addr; + +#if PIM_IPV == 4 + if (pfx.prefixlen < 4) + continue; + if (!IPV4_CLASS_DE(ntohl(pfx.prefix.s_addr))) + continue; +#endif + + apply_mask(&pfx); + + groupref.range = pfx; + item = bsr_crp_rp_groups_find(oldgroups, &itemref); + + if (item) { + bsr_crp_rp_groups_del(oldgroups, item); + bsr_crp_rp_groups_add(rp->groups, item); + continue; + } + + group = group_get(rp->scope, &pfx); + + item = XCALLOC(MTYPE_PIM_BSR_ITEM, sizeof(*item)); + item->rp = rp; + item->group = group; + + bsr_crp_group_rps_add(group->rps, item); + bsr_crp_rp_groups_add(rp->groups, item); + + bsr_crp_reselect(rp->scope, group); + } + + while ((item = bsr_crp_rp_groups_pop(oldgroups))) { + group = item->group; + if (item->selected) + group->deleted_selected = true; + + bsr_crp_group_rps_del(group->rps, item); + XFREE(MTYPE_PIM_BSR_ITEM, item); + + bsr_crp_reselect(rp->scope, group); + } + bsr_crp_rp_groups_fini(oldgroups); + + if (msg && msg->rp_prio != rp->prio) + pim_crp_nht_prio_change(rp, rp->nht_ok, msg->rp_prio); +} + +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc) +{ + struct bsm_scope *scope = &pim->global_scope; + struct bsr_crp_rp *rp, ref; + bool ok; + + ref.addr = pnc->rpf.rpf_addr; + rp = bsr_crp_rps_find(scope->ebsr_rps, &ref); + assertf(rp, "addr=%pPA", &ref.addr); + + ok = CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID); + if (ok == rp->nht_ok) + return; + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate-RP %pPA NHT %s", &rp->addr, ok ? "UP" : "DOWN"); + pim_crp_nht_prio_change(rp, ok, rp->prio); +} + +static void pim_crp_free(struct pim_instance *pim, struct bsr_crp_rp *rp) +{ + EVENT_OFF(rp->t_hold); + pim_nht_candrp_del(pim, rp->addr); + bsr_crp_rp_groups_fini(rp->groups); + + XFREE(MTYPE_PIM_BSR_CRP, rp); +} + +static void pim_crp_expire(struct event *t) +{ + struct bsr_crp_rp *rp = EVENT_ARG(t); + struct pim_instance *pim = rp->scope->pim; + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate-RP %pPA holdtime expired", &rp->addr); + + pim_crp_update(rp, NULL, 0); + + bsr_crp_rps_del(rp->scope->ebsr_rps, rp); + pim_crp_free(pim, rp); +} + +int pim_crp_process(struct interface *ifp, pim_sgaddr *src_dst, uint8_t *buf, + uint32_t buf_size) +{ + struct pim_interface *pim_ifp = NULL; + struct pim_instance *pim; + struct bsm_scope *scope; + + pim_ifp = ifp->info; + if (!pim_ifp) { + if (PIM_DEBUG_BSM) + zlog_debug("%s: multicast not enabled on interface %s", + __func__, ifp->name); + return -1; + } + + //pim_ifp->pim_ifstat_bsm_rx++; + pim = pim_ifp->pim; + //pim->bsm_rcvd++; + + if (!pim_ifp->bsm_enable) { + zlog_warn("%s: BSM not enabled on interface %s", __func__, + ifp->name); + //pim_ifp->pim_ifstat_bsm_cfg_miss++; + //pim->bsm_dropped++; + return -1; + } + + if (buf_size < (PIM_MSG_HEADER_LEN + sizeof(struct cand_rp_msg))) { + if (PIM_DEBUG_BSM) + zlog_debug("%s: received buffer length of %d which is too small to properly decode", + __func__, buf_size); + return -1; + } + + scope = &pim->global_scope; + + if (scope->state < BSR_PENDING) { + if (PIM_DEBUG_BSM) + zlog_debug("received Candidate-RP message from %pPA while not BSR", + &src_dst->src); + return -1; + } + + size_t remain = buf_size; + struct cand_rp_msg *crp_hdr; + + buf += PIM_MSG_HEADER_LEN; + remain -= PIM_MSG_HEADER_LEN; + + crp_hdr = (struct cand_rp_msg *)buf; + buf += sizeof(*crp_hdr); + remain -= sizeof(*crp_hdr); + + size_t ngroups = crp_hdr->prefix_cnt; + + if (remain < ngroups * sizeof(struct pim_encoded_group_ipv4)) { + if (PIM_DEBUG_BSM) + zlog_debug("truncated Candidate-RP advertisement for RP %pPA from %pPA (too short for %zu groups)", + (pim_addr *)&crp_hdr->rp_addr.addr, + &src_dst->src, ngroups); + return -1; + } + + if (PIM_DEBUG_BSM) + zlog_debug("Candidate-RP: %pPA, prio=%u (from %pPA, %zu groups)", + (pim_addr *)&crp_hdr->rp_addr.addr, crp_hdr->rp_prio, + &src_dst->src, ngroups); + + + struct bsr_crp_rp *rp, ref; + + ref.addr = crp_hdr->rp_addr.addr; + rp = bsr_crp_rps_find(scope->ebsr_rps, &ref); + + if (!rp) { + if (bsr_crp_rps_count(scope->ebsr_rps) >= bsr_max_rps) { + zlog_err("BSR: number of tracked Candidate RPs (%zu) exceeds DoS-protection limit (%zu), dropping advertisement for RP %pPA (packet source %pPA)", + bsr_crp_rps_count(scope->ebsr_rps), + bsr_max_rps, (pim_addr *)&crp_hdr->rp_addr.addr, + &src_dst->src); + return -1; + } + + if (PIM_DEBUG_BSM) + zlog_debug("new Candidate-RP: %pPA (from %pPA)", + (pim_addr *)&crp_hdr->rp_addr.addr, + &src_dst->src); + + rp = XCALLOC(MTYPE_PIM_BSR_CRP, sizeof(*rp)); + rp->scope = scope; + rp->addr = crp_hdr->rp_addr.addr; + rp->prio = 255; + bsr_crp_rp_groups_init(rp->groups); + rp->seen_first = monotime(NULL); + + bsr_crp_rps_add(scope->ebsr_rps, rp); + rp->nht_ok = pim_nht_candrp_add(pim, rp->addr); + } + + rp->seen_last = monotime(NULL); + rp->holdtime = ntohs(crp_hdr->rp_holdtime); + + EVENT_OFF(rp->t_hold); + event_add_timer(router->master, pim_crp_expire, rp, + ntohs(crp_hdr->rp_holdtime), &rp->t_hold); + + pim_crp_update(rp, crp_hdr, ngroups); + return 0; +} + +void pim_crp_db_clear(struct bsm_scope *scope) +{ + struct bsr_crp_rp *rp; + struct bsr_crp_group *group; + struct bsr_crp_item *item; + + while ((rp = bsr_crp_rps_pop(scope->ebsr_rps))) { + while ((item = bsr_crp_rp_groups_pop(rp->groups))) { + group = item->group; + + if (item->selected) + group->deleted_selected = true; + + bsr_crp_group_rps_del(group->rps, item); + XFREE(MTYPE_PIM_BSR_ITEM, item); + } + pim_crp_free(scope->pim, rp); + } + + while ((group = bsr_crp_groups_pop(scope->ebsr_groups))) { + assertf(!bsr_crp_group_rps_count(group->rps), + "range=%pFX rp_count=%zu", &group->range, + bsr_crp_group_rps_count(group->rps)); + + bsr_crp_group_rps_fini(group->rps); + XFREE(MTYPE_PIM_BSR_GROUP, group); + } +} + +int pim_crp_db_show(struct vty *vty, struct bsm_scope *scope, bool json) +{ + struct bsr_crp_rp *rp; + struct bsr_crp_item *item; + + vty_out(vty, "RP/Group NHT Prio Uptime Hold\n"); + + frr_each (bsr_crp_rps, scope->ebsr_rps, rp) { + vty_out(vty, "%-15pPA %4s %4u %8ld %4lu\n", &rp->addr, + rp->nht_ok ? "UP" : "DOWN", rp->prio, + (long)(monotime(NULL) - rp->seen_first), + event_timer_remain_second(rp->t_hold)); + + frr_each (bsr_crp_rp_groups, rp->groups, item) + vty_out(vty, "%c %-18pFX\n", item->selected ? '>' : ' ', + &item->group->range); + } + + return CMD_SUCCESS; +} + +int pim_crp_groups_show(struct vty *vty, struct bsm_scope *scope, bool json) +{ + struct bsr_crp_group *group; + struct bsr_crp_item *item; + + if (scope->ebsr_have_dead_pending) + vty_out(vty, "have_dead_pending\n"); + + frr_each (bsr_crp_groups, scope->ebsr_groups, group) { + vty_out(vty, "%c %pFX", group->n_selected ? '^' : '!', + &group->range); + if (group->n_selected == 0) + vty_out(vty, " (dead %u)", group->dead_count); + + vty_out(vty, "\n"); + + frr_each (bsr_crp_group_rps, group->rps, item) + vty_out(vty, "%c %pPA\n", item->selected ? '>' : ' ', + &item->rp->addr); + } + + return CMD_SUCCESS; +} diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 633c46966e..934da2d53e 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -66,27 +66,6 @@ static struct cmd_node debug_node = { .config_write = pim_debug_config_write, }; -static struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[], - const int argc, int *idx, bool uj) -{ - struct vrf *vrf; - - if (argv_find(argv, argc, "NAME", idx)) - vrf = vrf_lookup_by_name(argv[*idx]->arg); - else - vrf = vrf_lookup_by_id(VRF_DEFAULT); - - if (!vrf) { - if (uj) - vty_json_empty(vty, NULL); - else - vty_out(vty, "Specified VRF: %s does not exist\n", - argv[*idx]->arg); - } - - return vrf; -} - static void pim_show_assert_helper(struct vty *vty, struct pim_interface *pim_ifp, struct pim_ifchannel *ch, time_t now) @@ -588,7 +567,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, } static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty, - bool uj) + bool uj, enum gm_join_type join_type) { struct interface *ifp; time_t now; @@ -633,6 +612,10 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty, char source_str[INET_ADDRSTRLEN]; char uptime[10]; + if (ij->join_type != join_type && + ij->join_type != GM_JOIN_BOTH) + continue; + pim_time_uptime(uptime, sizeof(uptime), now - ij->sock_creation); pim_inet4_dump("<grp?>", ij->group_addr, group_str, @@ -1805,7 +1788,7 @@ DEFUN (show_ip_igmp_join, if (!vrf) return CMD_WARNING; - igmp_show_interface_join(vrf->info, vty, uj); + igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_STATIC); return CMD_SUCCESS; } @@ -1843,7 +1826,61 @@ DEFUN (show_ip_igmp_join_vrf_all, first = false; } else vty_out(vty, "VRF: %s\n", vrf->name); - igmp_show_interface_join(vrf->info, vty, uj); + igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_STATIC); + } + if (uj) + vty_out(vty, "}\n"); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_proxy, + show_ip_igmp_proxy_cmd, + "show ip igmp [vrf NAME] proxy [json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + "IGMP proxy join information\n" + JSON_STR) +{ + int idx = 2; + bool uj = use_json(argc, argv); + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj); + + if (!vrf) + return CMD_WARNING; + + igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_PROXY); + + return CMD_SUCCESS; +} + +DEFUN (show_ip_igmp_proxy_vrf_all, + show_ip_igmp_proxy_vrf_all_cmd, + "show ip igmp vrf all proxy [json]", + SHOW_STR + IP_STR + IGMP_STR + VRF_CMD_HELP_STR + "IGMP proxy join information\n" + JSON_STR) +{ + bool uj = use_json(argc, argv); + struct vrf *vrf; + bool first = true; + + if (uj) + vty_out(vty, "{ "); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (uj) { + if (!first) + vty_out(vty, ", "); + vty_out(vty, " \"%s\": ", vrf->name); + first = false; + } else + vty_out(vty, "VRF: %s\n", vrf->name); + igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_PROXY); } if (uj) vty_out(vty, "}\n"); @@ -2783,6 +2820,75 @@ DEFPY (show_ip_pim_rp_vrf_all, (struct prefix *)group, !!json); } +DEFPY (show_ip_pim_autorp, + show_ip_pim_autorp_cmd, + "show ip pim [vrf NAME] autorp [json$json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM AutoRP information\n" + JSON_STR) +{ + struct vrf *v; + json_object *json_parent = NULL; + + v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME); + if (!v || !v->info) { + if (!json) + vty_out(vty, "%% Unable to find pim instance\n"); + return CMD_WARNING; + } + + if (json) + json_parent = json_object_new_object(); + + pim_autorp_show_autorp(vty, v->info, json_parent); + + if (json) + vty_json(vty, json_parent); + + return CMD_SUCCESS; +} + +DEFPY (show_ip_pim_autorp_vrf_all, + show_ip_pim_autorp_vrf_all_cmd, + "show ip pim vrf all autorp [json$json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM AutoRP information\n" + JSON_STR) +{ + struct vrf *vrf; + json_object *json_parent = NULL; + json_object *json_vrf = NULL; + + if (json) + json_parent = json_object_new_object(); + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (vrf->info) { + if (!json) + vty_out(vty, "VRF: %s\n", vrf->name); + else + json_vrf = json_object_new_object(); + + pim_autorp_show_autorp(vty, vrf->info, json_vrf); + + if (json) + json_object_object_add(json_parent, vrf->name, + json_vrf); + } + } + + if (json) + vty_json(vty, json_parent); + + return CMD_SUCCESS; +} + DEFPY (show_ip_pim_rpf, show_ip_pim_rpf_cmd, "show ip pim [vrf NAME] rpf [json$json]", @@ -2864,7 +2970,7 @@ DEFPY (show_ip_pim_bsm_db, return pim_show_bsm_db_helper(vrf, vty, !!json); } -DEFPY (show_ip_pim_bsrp, +DEFPY_HIDDEN (show_ip_pim_bsrp, show_ip_pim_bsrp_cmd, "show ip pim bsrp-info [vrf NAME] [json$json]", SHOW_STR @@ -2877,6 +2983,109 @@ DEFPY (show_ip_pim_bsrp, return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json); } +DEFPY (show_ip_pim_bsr_rpinfo, + show_ip_pim_bsr_rpinfo_cmd, + "show ip pim bsr rp-info [vrf NAME] [json$json]", + SHOW_STR + IP_STR + PIM_STR + BSR_STR + "PIM cached group-rp mappings information received from BSR\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json); +} + +DEFPY (show_ip_pim_bsr_cand_bsr, + show_ip_pim_bsr_cand_bsr_cmd, + "show ip pim bsr candidate-bsr [vrf NAME$vrfname] [json$json]", + SHOW_STR + IP_STR + PIM_STR + BSR_STR + "Current PIM router candidate BSR state\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, !!json); + + if (!vrf || !vrf->info) + return CMD_WARNING; + + return pim_show_bsr_cand_bsr(vrf, vty, !!json); +} + + +DEFPY (show_ip_pim_bsr_cand_rp, + show_ip_pim_bsr_cand_rp_cmd, + "show ip pim bsr candidate-rp [vrf NAME$vrfname] [json$json]", + SHOW_STR + IP_STR + PIM_STR + BSR_STR + "Current PIM router candidate RP state\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, !!json); + + + if (!vrf || !vrf->info) + return CMD_WARNING; + + + return pim_show_bsr_cand_rp(vrf, vty, !!json); +} + +DEFPY (show_ip_pim_bsr_rpdb, + show_ip_pim_bsr_rpdb_cmd, + "show ip pim bsr candidate-rp-database [vrf NAME$vrfname] [json$json]", + SHOW_STR + IP_STR + PIM_STR + BSR_STR + "Candidate RPs database on this router (if it is the BSR)\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); + + if (!vrf || !vrf->info) + return CMD_WARNING; + + struct pim_instance *pim = vrf->info; + struct bsm_scope *scope = &pim->global_scope; + + return pim_crp_db_show(vty, scope, !!json); +} + +DEFPY (show_ip_pim_bsr_groups, + show_ip_pim_bsr_groups_cmd, + "show ip pim bsr groups [vrf NAME$vrfname] [json$json]", + SHOW_STR + IP_STR + PIM_STR + "boot-strap router information\n" + "Candidate RP groups\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, false); + + if (!vrf || !vrf->info) + return CMD_WARNING; + + struct pim_instance *pim = vrf->info; + struct bsm_scope *scope = &pim->global_scope; + + return pim_crp_groups_show(vty, scope, !!json); +} + DEFPY (show_ip_pim_statistics, show_ip_pim_statistics_cmd, "show ip pim [vrf NAME] statistics [interface WORD$word] [json$json]", @@ -4376,6 +4585,108 @@ DEFPY_ATTR(no_ip_pim_rp_prefix_list, return ret; } +DEFPY (pim_autorp_discovery, + pim_autorp_discovery_cmd, + "[no] autorp discovery", + NO_STR + "AutoRP\n" + "Enable AutoRP discovery\n") +{ + if (no) + return pim_process_no_autorp_cmd(vty); + else + return pim_process_autorp_cmd(vty); +} + +DEFPY (pim_autorp_announce_rp, + pim_autorp_announce_rp_cmd, + "[no] autorp announce A.B.C.D$rpaddr ![A.B.C.D/M$grp|group-list PREFIX_LIST$plist]", + NO_STR + "AutoRP\n" + "AutoRP Candidate RP announcement\n" + "AutoRP Candidate RP address\n" + "Group prefix\n" + "Prefix list\n" + "List name\n") +{ + return pim_process_autorp_candidate_rp_cmd(vty, no, rpaddr_str, (grp_str ? grp : NULL), + plist); +} + +DEFPY (pim_autorp_announce_scope_int, + pim_autorp_announce_scope_int_cmd, + "[no] autorp announce ![{scope (1-255) | interval (1-65535) | holdtime (0-65535)}]", + NO_STR + "AutoRP\n" + "AutoRP Candidate RP announcement\n" + "Packet scope (TTL)\n" + "TTL value\n" + "Announcement interval\n" + "Time in seconds\n" + "Announcement holdtime\n" + "Time in seconds\n") +{ + return pim_process_autorp_announce_scope_int_cmd(vty, no, scope_str, + interval_str, + holdtime_str); +} + +DEFPY (pim_bsr_candidate_bsr, + pim_bsr_candidate_bsr_cmd, + "[no] bsr candidate-bsr [{priority (0-255)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]", + NO_STR + BSR_STR + "Make this router a Candidate BSR\n" + "BSR Priority (higher wins)\n" + "BSR Priority (higher wins)\n" + "Specify IP address for BSR operation\n" + "Local address to use\n" + "Local address to use\n" + "Interface to pick address from\n" + "Interface to pick address from\n" + "Pick highest loopback address (default)\n" + "Pick highest address from any interface\n") +{ + return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_BSR_XPATH, no, + false, any, ifname, address_str, + priority_str, NULL); +} + +DEFPY (pim_bsr_candidate_rp, + pim_bsr_candidate_rp_cmd, + "[no] bsr candidate-rp [{priority (0-255)|interval (1-4294967295)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]", + NO_STR + BSR_STR + "Make this router a Candidate RP\n" + "RP Priority (lower wins)\n" + "RP Priority (lower wins)\n" + "Advertisement interval (seconds)\n" + "Advertisement interval (seconds)\n" + "Specify IP address for RP operation\n" + "Local address to use\n" + "Local address to use\n" + "Interface to pick address from\n" + "Interface to pick address from\n" + "Pick highest loopback address (default)\n" + "Pick highest address from any interface\n") +{ + return pim_process_bsr_candidate_cmd(vty, FRR_PIM_CAND_RP_XPATH, no, + true, any, ifname, address_str, + priority_str, interval_str); +} + +DEFPY (pim_bsr_candidate_rp_group, + pim_bsr_candidate_rp_group_cmd, + "[no] bsr candidate-rp group A.B.C.D/M", + NO_STR + BSR_STR + "Make this router a Candidate RP\n" + "Configure groups to become candidate RP for (At least one group must be configured)\n" + "Multicast group prefix\n") +{ + return pim_process_bsr_crp_grp_cmd(vty, group_str, no); +} + DEFPY (pim_ssm_prefix_list, pim_ssm_prefix_list_cmd, "ssm prefix-list PREFIXLIST4_NAME$plist", @@ -5618,6 +5929,18 @@ DEFUN (interface_no_ip_pim_hello, return pim_process_no_ip_pim_hello_cmd(vty); } +DEFPY (interface_ip_igmp_proxy, + interface_ip_igmp_proxy_cmd, + "[no] ip igmp proxy", + NO_STR + IP_STR + IGMP_STR + "Proxy IGMP join/prune operations\n") +{ + return pim_process_ip_gmp_proxy_cmd(vty, !no); +} + + DEFUN (debug_igmp, debug_igmp_cmd, "debug igmp", @@ -6169,6 +6492,29 @@ DEFUN (no_debug_bsm, return CMD_SUCCESS; } +DEFUN (debug_autorp, + debug_autorp_cmd, + "debug pim autorp", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_AUTORP_STR) +{ + PIM_DO_DEBUG_AUTORP; + return CMD_SUCCESS; +} + +DEFUN (no_debug_autorp, + no_debug_autorp_cmd, + "no debug pim autorp", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_AUTORP_STR) +{ + PIM_DONT_DEBUG_AUTORP; + return CMD_SUCCESS; +} + DEFUN_NOSH (show_debugging_pim, show_debugging_pim_cmd, @@ -8506,6 +8852,9 @@ void pim_cmd_init(void) install_element(PIM_NODE, &no_pim_rp_cmd); install_element(PIM_NODE, &pim_rp_prefix_list_cmd); install_element(PIM_NODE, &no_pim_rp_prefix_list_cmd); + install_element(PIM_NODE, &pim_autorp_discovery_cmd); + install_element(PIM_NODE, &pim_autorp_announce_rp_cmd); + install_element(PIM_NODE, &pim_autorp_announce_scope_int_cmd); install_element(PIM_NODE, &no_pim_ssm_prefix_list_cmd); install_element(PIM_NODE, &no_pim_ssm_prefix_list_name_cmd); install_element(PIM_NODE, &pim_ssm_prefix_list_cmd); @@ -8550,6 +8899,10 @@ void pim_cmd_init(void) install_element(PIM_NODE, &no_pim_msdp_mesh_group_source_cmd); install_element(PIM_NODE, &no_pim_msdp_mesh_group_cmd); + install_element(PIM_NODE, &pim_bsr_candidate_rp_cmd); + install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd); + install_element(PIM_NODE, &pim_bsr_candidate_bsr_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd); @@ -8576,6 +8929,7 @@ void pim_cmd_init(void) &interface_ip_igmp_last_member_query_interval_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_last_member_query_interval_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_proxy_cmd); install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd); install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd); install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); @@ -8619,6 +8973,8 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_igmp_join_group_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_static_group_cmd); install_element(VIEW_NODE, &show_ip_igmp_static_group_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_igmp_proxy_cmd); + install_element(VIEW_NODE, &show_ip_igmp_proxy_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_groups_cmd); install_element(VIEW_NODE, &show_ip_igmp_groups_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); @@ -8653,6 +9009,8 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd); install_element(VIEW_NODE, &show_ip_pim_rp_cmd); install_element(VIEW_NODE, &show_ip_pim_rp_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_pim_autorp_cmd); + install_element(VIEW_NODE, &show_ip_pim_autorp_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_bsr_cmd); install_element(VIEW_NODE, &show_ip_multicast_cmd); install_element(VIEW_NODE, &show_ip_multicast_vrf_all_cmd); @@ -8670,6 +9028,11 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd); install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd); install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd); + install_element(VIEW_NODE, &show_ip_pim_bsr_rpinfo_cmd); + install_element(VIEW_NODE, &show_ip_pim_bsr_cand_bsr_cmd); + install_element(VIEW_NODE, &show_ip_pim_bsr_cand_rp_cmd); + install_element(VIEW_NODE, &show_ip_pim_bsr_rpdb_cmd); + install_element(VIEW_NODE, &show_ip_pim_bsr_groups_cmd); install_element(VIEW_NODE, &show_ip_pim_statistics_cmd); install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); @@ -8755,6 +9118,8 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd); install_element(ENABLE_NODE, &debug_ssmpingd_cmd); install_element(CONFIG_NODE, &debug_ssmpingd_cmd); + install_element(ENABLE_NODE, &debug_autorp_cmd); + install_element(ENABLE_NODE, &no_debug_autorp_cmd); install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd); install_element(ENABLE_NODE, &debug_pim_zebra_cmd); @@ -8787,6 +9152,8 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &debug_bsm_cmd); install_element(ENABLE_NODE, &no_debug_bsm_cmd); install_element(CONFIG_NODE, &no_debug_bsm_cmd); + install_element(CONFIG_NODE, &debug_autorp_cmd); + install_element(CONFIG_NODE, &no_debug_autorp_cmd); install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); diff --git a/pimd/pim_cmd.h b/pimd/pim_cmd.h index d39d77cd2f..17cf4bb362 100644 --- a/pimd/pim_cmd.h +++ b/pimd/pim_cmd.h @@ -56,6 +56,7 @@ #define DEBUG_MSDP_PACKETS_STR "MSDP protocol packets\n" #define DEBUG_MTRACE_STR "Mtrace protocol activity\n" #define DEBUG_PIM_BSM_STR "BSR message processing activity\n" +#define DEBUG_PIM_AUTORP_STR "AutoRP message processing activity\n" void pim_cmd_init(void); diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index a87f5b6981..02ddea8252 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -420,6 +420,17 @@ int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty) FRR_PIM_AF_XPATH_VAL); } +int pim_process_ip_gmp_proxy_cmd(struct vty *vty, bool enable) +{ + if (enable) + nb_cli_enqueue_change(vty, "./proxy", NB_OP_MODIFY, "true"); + else + nb_cli_enqueue_change(vty, "./proxy", NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + FRR_PIM_AF_XPATH_VAL); +} + int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface, const char *group_str, const char *source_str) { @@ -595,6 +606,165 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, return nb_cli_apply_changes(vty, NULL); } +int pim_process_autorp_cmd(struct vty *vty) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "%s/%s", FRR_PIM_AUTORP_XPATH, + "discovery-enabled"); + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_no_autorp_cmd(struct vty *vty) +{ + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), "%s/%s", FRR_PIM_AUTORP_XPATH, + "discovery-enabled"); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_autorp_candidate_rp_cmd(struct vty *vty, bool no, + const char *rpaddr_str, + const struct prefix_ipv4 *grp, + const char *plist) +{ + char xpath[XPATH_MAXLEN]; + char grpstr[64]; + + if (no) { + if ((grp && !is_default_prefix((const struct prefix *)grp)) || plist) { + /* If any single values are set, only destroy those */ + if (grp && !is_default_prefix((const struct prefix *)grp)) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']/group", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + if (plist) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']/prefix-list", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + } else { + /* No values set, remove the entire RP */ + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } + } else { + if ((grp && !is_default_prefix((const struct prefix *)grp)) || plist) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (grp && !is_default_prefix((const struct prefix *)grp)) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']/group", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + prefix2str(grp, grpstr, + sizeof(grpstr))); + } + if (plist) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']/prefix-list", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + plist); + } + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_autorp_announce_scope_int_cmd(struct vty *vty, bool no, + const char *scope, + const char *interval, + const char *holdtime) +{ + char xpath[XPATH_MAXLEN]; + + if (no) { + if (scope || interval || holdtime) { + /* If any single values are set, only destroy those */ + if (scope) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-scope"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + if (interval) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-interval"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + if (holdtime) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-holdtime"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + } else { + /* No values set, remove all */ + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, "announce-scope"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, "announce-interval"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, "announce-holdtime"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } + } else { + if (scope || interval || holdtime) { + if (scope) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-scope"); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + scope); + } + if (interval) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-interval"); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + interval); + } + if (holdtime) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-holdtime"); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + holdtime); + } + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } + + return nb_cli_apply_changes(vty, NULL); +} + bool pim_sgaddr_match(pim_sgaddr item, pim_sgaddr match) { return (pim_addr_is_any(match.grp) || @@ -3389,6 +3559,55 @@ int pim_process_no_unicast_bsm_cmd(struct vty *vty) FRR_PIM_AF_XPATH_VAL); } +/* helper for bsr/rp candidate commands*/ +int pim_process_bsr_candidate_cmd(struct vty *vty, const char *cand_str, + bool no, bool is_rp, bool any, + const char *ifname, const char *addr, + const char *prio, const char *interval) +{ + if (no) + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); + else { + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + + if (any) + nb_cli_enqueue_change(vty, "./if-any", NB_OP_CREATE, + NULL); + else if (ifname) + nb_cli_enqueue_change(vty, "./interface", NB_OP_CREATE, + ifname); + else if (addr) + nb_cli_enqueue_change(vty, "./address", NB_OP_CREATE, + addr); + else + nb_cli_enqueue_change(vty, "./if-loopback", + NB_OP_CREATE, NULL); + + if (prio) + nb_cli_enqueue_change(vty, + (is_rp ? "./rp-priority" + : "./bsr-priority"), + NB_OP_MODIFY, prio); + + /* only valid for rp candidate case*/ + if (is_rp && interval) + nb_cli_enqueue_change(vty, "./advertisement-interval", + NB_OP_MODIFY, interval); + } + + return nb_cli_apply_changes(vty, "%s", cand_str); +} + +int pim_process_bsr_crp_grp_cmd(struct vty *vty, const char *grp, bool no) +{ + if (no) + nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, grp); + else + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, grp); + + return nb_cli_apply_changes(vty, "%s/group-list", FRR_PIM_CAND_RP_XPATH); +} + static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty, time_t now) { @@ -4158,6 +4377,27 @@ struct vrf *pim_cmd_lookup(struct vty *vty, const char *name) return vrf; } +struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[], + const int argc, int *idx, bool uj) +{ + struct vrf *vrf; + + if (argv_find(argv, argc, "NAME", idx)) + vrf = vrf_lookup_by_name(argv[*idx]->arg); + else + vrf = vrf_lookup_by_id(VRF_DEFAULT); + + if (!vrf) { + if (uj) + vty_json_empty(vty, NULL); + else + vty_out(vty, "Specified VRF: %s does not exist\n", + argv[*idx]->arg); + } + + return vrf; +} + void clear_mroute(struct pim_instance *pim) { struct pim_upstream *up; @@ -5188,6 +5428,12 @@ void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj) case ACCEPT_PREFERRED: strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state)); break; + case BSR_PENDING: + strlcpy(bsr_state, "BSR_PENDING", sizeof(bsr_state)); + break; + case BSR_ELECTED: + strlcpy(bsr_state, "BSR_ELECTED", sizeof(bsr_state)); + break; default: strlcpy(bsr_state, "", sizeof(bsr_state)); } @@ -5207,7 +5453,7 @@ void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj) } else { - vty_out(vty, "PIMv2 Bootstrap information\n"); + vty_out(vty, "PIMv2 Bootstrap Router information\n"); vty_out(vty, "Current preferred BSR address: %pPA\n", &pim->global_scope.current_bsr); vty_out(vty, @@ -5416,6 +5662,98 @@ int pim_show_group_rp_mappings_info_helper(const char *vrf, struct vty *vty, return CMD_SUCCESS; } +int pim_show_bsr_cand_rp(const struct vrf *vrf, struct vty *vty, bool uj) +{ + struct pim_instance *pim; + struct bsm_scope *scope; + json_object *jsondata = NULL; + + if (!vrf || !vrf->info) + return CMD_WARNING; + + pim = (struct pim_instance *)vrf->info; + scope = &pim->global_scope; + + if (!scope->cand_rp_addrsel.run) { + if (!!uj) + vty_out(vty, "{}\n"); + else + vty_out(vty, + "This router is not currently operating as Candidate RP\n"); + return CMD_SUCCESS; + } + + if (!!uj) { + jsondata = json_object_new_object(); + json_object_string_addf(jsondata, "address", "%pPA", + &scope->cand_rp_addrsel.run_addr); + json_object_int_add(jsondata, "priority", scope->cand_rp_prio); + json_object_int_add(jsondata, "nextAdvertisementMsec", + event_timer_remain_msec( + scope->cand_rp_adv_timer)); + + vty_json(vty, jsondata); + return CMD_SUCCESS; + } + + vty_out(vty, "Candidate-RP\nAddress: %pPA\nPriority: %u\n\n", + &scope->cand_rp_addrsel.run_addr, scope->cand_rp_prio); + vty_out(vty, "Next adv.: %lu msec\n", + event_timer_remain_msec(scope->cand_rp_adv_timer)); + + + return CMD_SUCCESS; +} + +int pim_show_bsr_cand_bsr(const struct vrf *vrf, struct vty *vty, bool uj) +{ + struct pim_instance *pim; + struct bsm_scope *scope; + json_object *jsondata = NULL; + + if (!vrf || !vrf->info) + return CMD_WARNING; + + pim = (struct pim_instance *)vrf->info; + scope = &pim->global_scope; + + if (!scope->bsr_addrsel.cfg_enable) { + if (!!uj) + vty_out(vty, "{}\n"); + else + vty_out(vty, + "This router is not currently operating as Candidate BSR\n"); + return CMD_SUCCESS; + } + + if (uj) { + char buf[INET_ADDRSTRLEN]; + + jsondata = json_object_new_object(); + inet_ntop(AF_INET, &scope->bsr_addrsel.run_addr, buf, + sizeof(buf)); + json_object_string_add(jsondata, "address", buf); + json_object_int_add(jsondata, "priority", scope->cand_bsr_prio); + json_object_boolean_add(jsondata, "elected", + pim->global_scope.state == BSR_ELECTED); + + vty_json(vty, jsondata); + return CMD_SUCCESS; + } + + vty_out(vty, + "Candidate-BSR\nAddress: %pPA\nPriority: %u\nElected: %s\n", + &scope->bsr_addrsel.run_addr, scope->cand_bsr_prio, + (pim->global_scope.state == BSR_ELECTED) ? " Yes" : " No"); + + if (!pim_addr_cmp(scope->bsr_addrsel.run_addr, PIMADDR_ANY)) + vty_out(vty, + "\nThis router is not currently operating as Candidate BSR\n" + "Configure a BSR address to enable this feature\n\n"); + + return CMD_SUCCESS; +} + /* Display the bsm database details */ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj) { diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h index da2e44be58..d7c97e31d4 100644 --- a/pimd/pim_cmd_common.h +++ b/pimd/pim_cmd_common.h @@ -7,6 +7,8 @@ #ifndef PIM_CMD_COMMON_H #define PIM_CMD_COMMON_H +#define BSR_STR "Bootstrap Router configuration\n" + struct pim_upstream; struct pim_instance; @@ -33,7 +35,16 @@ int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list); int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list); - +int pim_process_autorp_cmd(struct vty *vty); +int pim_process_no_autorp_cmd(struct vty *vty); +int pim_process_autorp_candidate_rp_cmd(struct vty *vty, bool no, + const char *rpaddr_str, + const struct prefix_ipv4 *grp, + const char *plist); +int pim_process_autorp_announce_scope_int_cmd(struct vty *vty, bool no, + const char *scope, + const char *interval, + const char *holdtime); int pim_process_ip_pim_cmd(struct vty *vty); int pim_process_no_ip_pim_cmd(struct vty *vty); int pim_process_ip_pim_passive_cmd(struct vty *vty, bool enable); @@ -45,6 +56,7 @@ int pim_process_no_ip_pim_hello_cmd(struct vty *vty); int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no); int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil); int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty); +int pim_process_ip_gmp_proxy_cmd(struct vty *vty, bool enable); int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface, const char *group_str, const char *source_str); int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, @@ -53,6 +65,13 @@ int pim_process_bsm_cmd(struct vty *vty); int pim_process_no_bsm_cmd(struct vty *vty); int pim_process_unicast_bsm_cmd(struct vty *vty); int pim_process_no_unicast_bsm_cmd(struct vty *vty); + +int pim_process_bsr_candidate_cmd(struct vty *vty, const char *cand_str, + bool no, bool is_rp, bool any, + const char *ifname, const char *addr, + const char *prio, const char *interval); +int pim_process_bsr_crp_grp_cmd(struct vty *vty, const char *grp, bool no); + void json_object_pim_upstream_add(json_object *json, struct pim_upstream *up); void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json); void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty); @@ -131,6 +150,8 @@ void show_mroute_summary(struct pim_instance *pim, struct vty *vty, json_object *json); int clear_ip_mroute_count_command(struct vty *vty, const char *name); struct vrf *pim_cmd_lookup(struct vty *vty, const char *name); +struct vrf *pim_cmd_lookup_vrf(struct vty *vty, struct cmd_token *argv[], + const int argc, int *idx, bool uj); void clear_mroute(struct pim_instance *pim); void clear_pim_statistics(struct pim_instance *pim); int clear_pim_interface_traffic(const char *vrf, struct vty *vty); @@ -182,6 +203,8 @@ int pim_show_interface_traffic_helper(const char *vrf, const char *if_name, void clear_pim_interfaces(struct pim_instance *pim); void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj); int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj); +int pim_show_bsr_cand_bsr(const struct vrf *vrf, struct vty *vty, bool uj); +int pim_show_bsr_cand_rp(const struct vrf *vrf, struct vty *vty, bool uj); int pim_router_config_write(struct vty *vty); /* diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 45a2435ae5..20e3ba184b 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -527,77 +527,66 @@ void pim_if_addr_add(struct connected *ifc) detect_address_change(ifp, 0, __func__); - // if (ifc->address->family != AF_INET) - // return; - #if PIM_IPV == 4 - struct in_addr ifaddr = ifc->address->u.prefix4; + if (ifc->address->family == AF_INET) { + struct in_addr ifaddr = ifc->address->u.prefix4; - if (pim_ifp->gm_enable) { - struct gm_sock *igmp; + if (pim_ifp->gm_enable) { + struct gm_sock *igmp; - /* lookup IGMP socket */ - igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, - ifaddr); - if (!igmp) { - /* if addr new, add IGMP socket */ - if (ifc->address->family == AF_INET) + /* lookup IGMP socket */ + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr); + if (!igmp) { + /* if addr new, add IGMP socket */ pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp, false); - } else if (igmp->mtrace_only) { - igmp_sock_delete(igmp); - pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp, - false); - } + } else if (igmp->mtrace_only) { + igmp_sock_delete(igmp); + pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp, false); + } - /* Replay Static IGMP groups */ - if (pim_ifp->gm_join_list) { - struct listnode *node; - struct listnode *nextnode; - struct gm_join *ij; - int join_fd; - - for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, - nextnode, ij)) { - /* Close socket and reopen with Source and Group - */ - close(ij->sock_fd); - join_fd = gm_join_sock( - ifp->name, ifp->ifindex, ij->group_addr, - ij->source_addr, pim_ifp); - if (join_fd < 0) { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<grp?>", ij->group_addr, - group_str, - sizeof(group_str)); - pim_inet4_dump( - "<src?>", ij->source_addr, - source_str, sizeof(source_str)); - zlog_warn( - "%s: gm_join_sock() failure for IGMP group %s source %s on interface %s", - __func__, group_str, source_str, - ifp->name); - /* warning only */ - } else - ij->sock_fd = join_fd; + /* Replay Static IGMP groups */ + if (pim_ifp->gm_join_list) { + struct listnode *node; + struct listnode *nextnode; + struct gm_join *ij; + int join_fd; + + for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij)) { + /* Close socket and reopen with Source and Group + */ + close(ij->sock_fd); + join_fd = gm_join_sock(ifp->name, ifp->ifindex, + ij->group_addr, ij->source_addr, + pim_ifp); + if (join_fd < 0) { + char group_str[INET_ADDRSTRLEN]; + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<grp?>", ij->group_addr, group_str, + sizeof(group_str)); + pim_inet4_dump("<src?>", ij->source_addr, + source_str, sizeof(source_str)); + zlog_warn("%s: gm_join_sock() failure for IGMP group %s source %s on interface %s", + __func__, group_str, source_str, + ifp->name); + /* warning only */ + } else + ij->sock_fd = join_fd; + } } - } - } /* igmp */ - else { - struct gm_sock *igmp; - - /* lookup IGMP socket */ - igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, - ifaddr); - if (ifc->address->family == AF_INET) { + } /* igmp */ + else { + struct gm_sock *igmp; + + /* lookup IGMP socket */ + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr); if (igmp) igmp_sock_delete(igmp); /* if addr new, add IGMP socket */ pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp, true); - } - } /* igmp mtrace only */ + } /* igmp mtrace only */ + } #endif if (pim_ifp->pim_enable) { @@ -1294,7 +1283,8 @@ static int gm_join_sock(const char *ifname, ifindex_t ifindex, } static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr, - pim_addr source_addr) + pim_addr source_addr, + enum gm_join_type join_type) { struct pim_interface *pim_ifp; struct gm_join *ij; @@ -1317,6 +1307,7 @@ static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr, ij->sock_fd = join_fd; ij->group_addr = group_addr; ij->source_addr = source_addr; + ij->join_type = join_type; ij->sock_creation = pim_time_monotonic_sec(); listnode_add(pim_ifp->gm_join_list, ij); @@ -1353,7 +1344,7 @@ static struct static_group *static_group_new(struct interface *ifp, } ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr, - pim_addr source_addr) + pim_addr source_addr, enum gm_join_type join_type) { struct pim_interface *pim_ifp; struct gm_join *ij; @@ -1375,10 +1366,13 @@ ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr, * group */ if (ij) { + /* turn an existing join into a "both" join */ + if (ij->join_type != join_type) + ij->join_type = GM_JOIN_BOTH; return ferr_ok(); } - if (!gm_join_new(ifp, group_addr, source_addr)) { + if (!gm_join_new(ifp, group_addr, source_addr, join_type)) { return ferr_cfg_invalid("can't join (%pPA,%pPA) on interface %s", &source_addr, &group_addr, ifp->name); } @@ -1394,7 +1388,7 @@ ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr, } int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr, - pim_addr source_addr) + pim_addr source_addr, enum gm_join_type join_type) { struct pim_interface *pim_ifp; struct gm_join *ij; @@ -1420,6 +1414,20 @@ int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr, return -3; } + if (ij->join_type != join_type) { + if (ij->join_type != GM_JOIN_BOTH) { + zlog_warn("%s: wrong " GM + " gm_join_type %pPAs source %pPAs on interface %s", + __func__, &group_addr, &source_addr, + ifp->name); + return -4; + } + /* drop back to a single join type from current setting of GM_JOIN_BOTH */ + ij->join_type = (join_type == GM_JOIN_STATIC ? GM_JOIN_PROXY + : GM_JOIN_STATIC); + return 0; + } + if (close(ij->sock_fd)) { zlog_warn( "%s: failure closing sock_fd=%d for " GM @@ -1456,7 +1464,8 @@ static void pim_if_gm_join_del_all(struct interface *ifp) return; for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij)) - pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr); + pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr, + GM_JOIN_STATIC); } ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr, @@ -1562,6 +1571,55 @@ static void pim_if_static_group_del_all(struct interface *ifp) stgrp->source_addr); } +void pim_if_gm_proxy_init(struct pim_instance *pim, struct interface *oif) +{ + struct interface *ifp; + + FOR_ALL_INTERFACES (pim->vrf, ifp) { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *source_node, *group_node; + struct gm_group *group; + struct gm_source *src; + + if (!pim_ifp) + continue; + + if (ifp == oif) /* skip the source interface */ + continue; + + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, group_node, + group)) { + for (ALL_LIST_ELEMENTS_RO(group->group_source_list, + source_node, src)) { + pim_if_gm_join_add(oif, group->group_addr, + src->source_addr, + GM_JOIN_PROXY); + } + } + } /* scan interfaces */ +} + +void pim_if_gm_proxy_finis(struct pim_instance *pim, struct interface *ifp) +{ + struct pim_interface *pim_ifp = ifp->info; + struct listnode *join_node; + struct listnode *next_join_node; + struct gm_join *join; + + if (!pim_ifp) { + zlog_warn("%s: multicast not enabled on interface %s", __func__, + ifp->name); + return; + } + + for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, join_node, next_join_node, + join)) { + if (join) + pim_if_gm_join_del(ifp, join->group_addr, + join->source_addr, GM_JOIN_PROXY); + } +} + /* RFC 4601 @@ -1844,6 +1902,14 @@ static int pim_ifp_up(struct interface *ifp) } } } + +#if PIM_IPV == 4 + if (pim->autorp && pim->autorp->do_discovery && pim_ifp && + pim_ifp->pim_enable) + pim_autorp_add_ifp(ifp); +#endif + + pim_cand_addrs_changed(); return 0; } @@ -1880,6 +1946,11 @@ static int pim_ifp_down(struct interface *ifp) pim_ifstat_reset(ifp); } +#if PIM_IPV == 4 + pim_autorp_rm_ifp(ifp); +#endif + + pim_cand_addrs_changed(); return 0; } @@ -1951,6 +2022,11 @@ void pim_pim_interface_delete(struct interface *ifp) if (!pim_ifp) return; +#if PIM_IPV == 4 + if (pim_ifp->pim_enable) + pim_autorp_rm_ifp(ifp); +#endif + pim_ifp->pim_enable = false; pim_if_membership_clear(ifp); diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 4d20379665..95bac084d2 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -63,6 +63,7 @@ struct pim_interface { bool pim_passive_enable : 1; bool gm_enable : 1; + bool gm_proxy : 1; /* proxy IGMP joins/prunes */ ifindex_t mroute_vif_index; struct pim_instance *pim; @@ -219,9 +220,11 @@ int pim_if_t_override_msec(struct interface *ifp); pim_addr pim_find_primary_addr(struct interface *ifp); ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr, - pim_addr source_addr); + pim_addr source_addr, enum gm_join_type join_type); int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr, - pim_addr source_addr); + pim_addr source_addr, enum gm_join_type join_type); +void pim_if_gm_proxy_init(struct pim_instance *pim, struct interface *oif); +void pim_if_gm_proxy_finis(struct pim_instance *pim, struct interface *ifp); ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr, pim_addr source_addr); diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 063ba6edd2..1ba9bc45a2 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -213,15 +213,17 @@ void igmp_source_forward_stop(struct gm_source *source) IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); } + group = source->source_group; + pim_oif = group->interface->info; + /* Prevent IGMP interface from removing multicast route multiple times */ if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { + tib_sg_proxy_join_prune_check(pim_oif->pim, sg, + group->interface, false); return; } - group = source->source_group; - pim_oif = group->interface->info; - tib_sg_gm_prune(pim_oif->pim, sg, group->interface, &source->source_channel_oil); IGMP_SOURCE_DONT_FORWARDING(source->source_flags); diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index de0ec01a65..83524e3980 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -51,10 +51,13 @@ output |= *((ptr) + 1); \ } while (0) +enum gm_join_type { GM_JOIN_STATIC = 0, GM_JOIN_PROXY = 1, GM_JOIN_BOTH = 2 }; + struct gm_join { pim_addr group_addr; pim_addr source_addr; int sock_fd; + enum gm_join_type join_type; time_t sock_creation; }; diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index a9eec9a9d2..f7c5ea3bcf 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -57,6 +57,10 @@ static void pim_instance_terminate(struct pim_instance *pim) pim_mroute_socket_disable(pim); +#if PIM_IPV == 4 + pim_autorp_finish(pim); +#endif + XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist); XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist); @@ -125,6 +129,10 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf) pim->msdp.keep_alive = PIM_MSDP_PEER_KA_TIME; pim->msdp.connection_retry = PIM_MSDP_PEER_CONNECT_RETRY_TIME; +#if PIM_IPV == 4 + pim_autorp_init(pim); +#endif + return pim; } @@ -253,6 +261,7 @@ void pim_vrf_terminate(void) if (!pim) continue; + pim_crp_db_clear(&pim->global_scope); pim_ssmpingd_destroy(pim); pim_instance_terminate(pim); diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index ec331332cf..f484d847b2 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -17,6 +17,7 @@ #include "pim_oil.h" #include "pim_upstream.h" #include "pim_mroute.h" +#include "pim_autorp.h" enum pim_spt_switchover { PIM_SPT_IMMEDIATE, @@ -152,6 +153,8 @@ struct pim_instance { struct pim_msdp msdp; struct pim_vxlan_instance vxlan; + struct pim_autorp *autorp; + struct list *ssmpingd_list; pim_addr ssmpingd_group_addr; diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 8f2ce0bed3..f88aca719e 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -68,6 +68,7 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_routing_info, &frr_pim_info, &frr_pim_rp_info, + &frr_pim_candidate_info, &frr_gmp_info, }; diff --git a/pimd/pim_msg.h b/pimd/pim_msg.h index 56923b7ec1..1f916af881 100644 --- a/pimd/pim_msg.h +++ b/pimd/pim_msg.h @@ -148,6 +148,7 @@ struct pim_encoded_source_ipv6 { typedef struct pim_encoded_ipv4_unicast pim_encoded_unicast; typedef struct pim_encoded_group_ipv4 pim_encoded_group; typedef struct pim_encoded_source_ipv4 pim_encoded_source; +#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4 typedef struct ip ipv_hdr; #define IPV_SRC(ip_hdr) ((ip_hdr))->ip_src #define IPV_DST(ip_hdr) ((ip_hdr))->ip_dst @@ -156,6 +157,7 @@ typedef struct ip ipv_hdr; typedef struct pim_encoded_ipv6_unicast pim_encoded_unicast; typedef struct pim_encoded_group_ipv6 pim_encoded_group; typedef struct pim_encoded_source_ipv6 pim_encoded_source; +#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6 typedef struct ip6_hdr ipv_hdr; #define IPV_SRC(ip_hdr) ((ip_hdr))->ip6_src #define IPV_DST(ip_hdr) ((ip_hdr))->ip6_dst diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index c154c18afa..66001d1463 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -380,6 +380,161 @@ const struct frr_yang_module_info frr_pim_rp_info = { } }, { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/discovery-enabled", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-scope", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-interval", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-holdtime", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/group", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/prefix-list", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; + +const struct frr_yang_module_info frr_pim_candidate_info = { + .name = "frr-pim-candidate", + .nodes = { + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/bsr-priority", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_priority_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/address", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/interface", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/if-loopback", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-bsr/if-any", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy, + } + }, + + /* Candidate-RP */ + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/rp-priority", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/advertisement-interval", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_adv_interval_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/group-list", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/address", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/interface", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/if-loopback", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/if-any", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy, + } + }, + { .xpath = NULL, }, } @@ -447,7 +602,13 @@ const struct frr_yang_module_info frr_gmp_info = { .destroy = lib_interface_gmp_address_family_join_group_destroy, } }, - { + { + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/proxy", + .cbs = { + .modify = lib_interface_gmp_address_family_proxy_modify, + } + }, +{ .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group", .cbs = { .create = lib_interface_gmp_address_family_static_group_create, diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index fc4c11cea9..befad4efe4 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -9,6 +9,7 @@ extern const struct frr_yang_module_info frr_pim_info; extern const struct frr_yang_module_info frr_pim_rp_info; +extern const struct frr_yang_module_info frr_pim_candidate_info; extern const struct frr_yang_module_info frr_gmp_info; /* frr-pim prototypes*/ @@ -158,6 +159,68 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy( struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy( + struct nb_cb_destroy_args *args); + +/* frr-cand-bsr */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_priority_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy( + struct nb_cb_destroy_args *args); + +/* frr-candidate */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_adv_interval_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy( + struct nb_cb_destroy_args *args); /* frr-gmp prototypes*/ int lib_interface_gmp_address_family_create( @@ -186,6 +249,7 @@ int lib_interface_gmp_address_family_join_group_create( struct nb_cb_create_args *args); int lib_interface_gmp_address_family_join_group_destroy( struct nb_cb_destroy_args *args); +int lib_interface_gmp_address_family_proxy_modify(struct nb_cb_modify_args *args); int lib_interface_gmp_address_family_static_group_create( struct nb_cb_create_args *args); int lib_interface_gmp_address_family_static_group_destroy( @@ -204,6 +268,9 @@ int routing_control_plane_protocols_name_validate( #define FRR_PIM_AF_XPATH_VAL "frr-routing:ipv6" #endif +#define FRR_PIM_CAND_RP_XPATH "./frr-pim-candidate:candidate-rp" +#define FRR_PIM_CAND_BSR_XPATH "./frr-pim-candidate:candidate-bsr" + #define FRR_PIM_VRF_XPATH \ "/frr-routing:routing/control-plane-protocols/" \ "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ @@ -219,6 +286,7 @@ int routing_control_plane_protocols_name_validate( "mroute[source-addr='%s'][group-addr='%s']" #define FRR_PIM_STATIC_RP_XPATH \ "frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']" +#define FRR_PIM_AUTORP_XPATH "./frr-pim-rp:rp/auto-rp" #define FRR_GMP_INTERFACE_XPATH \ "./frr-gmp:gmp/address-family[address-family='%s']" #define FRR_GMP_ENABLE_XPATH \ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 037bfea786..ea8b56fee3 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -26,6 +26,8 @@ #include "lib_errors.h" #include "pim_util.h" #include "pim6_mld.h" +#include "pim_autorp.h" +#include "pim_igmp.h" #if PIM_IPV == 6 #define pim6_msdp_err(funcname, argtype) \ @@ -146,6 +148,11 @@ static int pim_cmd_interface_add(struct interface *ifp) pim_if_membership_refresh(ifp); pim_if_create_pimreg(pim_ifp->pim); + +#if PIM_IPV == 4 + pim_autorp_add_ifp(ifp); +#endif + return 1; } @@ -927,10 +934,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss yang_dnode_get_pimaddr(&source_addr, args->dnode, NULL); result = pim_ssmpingd_start(pim, source_addr); if (result) { - snprintf( - args->errmsg, args->errmsg_len, - "%% Failure starting ssmpingd for source %pPA: %d", - &source_addr, result); + snprintfrr(args->errmsg, args->errmsg_len, + "%% Failure starting ssmpingd for source %pPA: %d", &source_addr, + result); return NB_ERR_INCONSISTENCY; } } @@ -957,10 +963,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss yang_dnode_get_pimaddr(&source_addr, args->dnode, NULL); result = pim_ssmpingd_stop(pim, source_addr); if (result) { - snprintf( - args->errmsg, args->errmsg_len, - "%% Failure stopping ssmpingd for source %pPA: %d", - &source_addr, result); + snprintfrr(args->errmsg, args->errmsg_len, + "%% Failure stopping ssmpingd for source %pPA: %d", &source_addr, + result); return NB_ERR_INCONSISTENCY; } @@ -2058,6 +2063,10 @@ int lib_interface_pim_address_family_bsm_modify(struct nb_cb_modify_args *args) case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; + if (!pim_ifp) { + pim_ifp = pim_if_new(ifp, false, true, false, false); + ifp->info = pim_ifp; + } pim_ifp->bsm_enable = yang_dnode_get_bool(args->dnode, NULL); break; @@ -2083,6 +2092,10 @@ int lib_interface_pim_address_family_unicast_bsm_modify( case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; + if (!pim_ifp) { + pim_ifp = pim_if_new(ifp, false, true, false, false); + ifp->info = pim_ifp; + } pim_ifp->ucast_bsm_accept = yang_dnode_get_bool(args->dnode, NULL); @@ -2672,6 +2685,750 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp } /* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/discovery-enabled + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + bool enabled; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + enabled = yang_dnode_get_bool(args->dnode, NULL); + if (enabled) + pim_autorp_start_discovery(pim); + else + pim_autorp_stop_discovery(pim); + break; + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + bool enabled; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + enabled = yang_dnode_get_bool(args->dnode, NULL); + /* Run AutoRP discovery by default */ + if (!enabled) + pim_autorp_start_discovery(pim); + break; + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-scope + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + uint8_t scope; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = yang_dnode_get_uint8(args->dnode, NULL); + pim_autorp_announce_scope(pim, scope); + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim_autorp_announce_scope(pim, 0); + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-interval + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + uint16_t interval; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + interval = yang_dnode_get_uint16(args->dnode, NULL); + pim_autorp_announce_interval(pim, interval); + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + pim_autorp_announce_interval(pim, 0); + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-holdtime + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + uint16_t holdtime; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + holdtime = yang_dnode_get_uint16(args->dnode, NULL); + pim_autorp_announce_holdtime(pim, holdtime); + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + /* 0 is a valid value, so -1 indicates deleting (go back to default) */ + pim_autorp_announce_holdtime(pim, -1); + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create( + struct nb_cb_create_args *args) +{ +#if PIM_IPV == 4 + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + pim_addr rp_addr; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "rp-address"); + if (!pim_autorp_rm_candidate_rp(pim, rp_addr)) + return NB_ERR_INCONSISTENCY; + break; + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/group + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + struct prefix group; + pim_addr rp_addr; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_prefix(&group, args->dnode, NULL); + apply_mask(&group); + pim_autorp_add_candidate_rp_group(pim, rp_addr, group); + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + struct prefix group; + pim_addr rp_addr; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_prefix(&group, args->dnode, NULL); + apply_mask(&group); + if (!pim_autorp_rm_candidate_rp_group(pim, rp_addr, group)) + return NB_ERR_INCONSISTENCY; + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/prefix-list + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + pim_addr rp_addr; + const char *plist; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + plist = yang_dnode_get_string(args->dnode, NULL); + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + pim_autorp_add_candidate_rp_plist(pim, rp_addr, plist); + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + pim_addr rp_addr; + const char *plist; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address"); + plist = yang_dnode_get_string(args->dnode, NULL); + if (!pim_autorp_rm_candidate_rp_plist(pim, rp_addr, plist)) + return NB_ERR_INCONSISTENCY; + break; + } +#endif + + return NB_OK; +} + +static void yang_addrsel(struct cand_addrsel *addrsel, + const struct lyd_node *node) +{ + memset(addrsel->cfg_ifname, 0, sizeof(addrsel->cfg_ifname)); + addrsel->cfg_addr = PIMADDR_ANY; + + if (yang_dnode_exists(node, "if-any")) { + addrsel->cfg_mode = CAND_ADDR_ANY; + } else if (yang_dnode_exists(node, "address")) { + addrsel->cfg_mode = CAND_ADDR_EXPLICIT; + yang_dnode_get_pimaddr(&addrsel->cfg_addr, node, "address"); + } else if (yang_dnode_exists(node, "interface")) { + addrsel->cfg_mode = CAND_ADDR_IFACE; + strlcpy(addrsel->cfg_ifname, + yang_dnode_get_string(node, "interface"), + sizeof(addrsel->cfg_ifname)); + } else if (yang_dnode_exists(node, "if-loopback")) { + addrsel->cfg_mode = CAND_ADDR_LO; + } +} + +static int candidate_bsr_addrsel(struct bsm_scope *scope, + const struct lyd_node *cand_bsr_node) +{ + yang_addrsel(&scope->bsr_addrsel, cand_bsr_node); + pim_cand_bsr_apply(scope); + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_create( + struct nb_cb_create_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + scope->bsr_addrsel.cfg_enable = true; + scope->cand_bsr_prio = yang_dnode_get_uint8(args->dnode, + "bsr-priority"); + + candidate_bsr_addrsel(scope, args->dnode); + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + scope->bsr_addrsel.cfg_enable = false; + + pim_cand_bsr_apply(scope); + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_priority_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + scope->cand_bsr_prio = yang_dnode_get_uint8(args->dnode, NULL); + + /* FIXME: force prio update */ + candidate_bsr_addrsel(scope, args->dnode); + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_create( + struct nb_cb_create_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + const struct lyd_node *cand_bsr_node; + + cand_bsr_node = yang_dnode_get_parent(args->dnode, "candidate-bsr"); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + return candidate_bsr_addrsel(scope, cand_bsr_node); + } + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + const struct lyd_node *cand_bsr_node; + + cand_bsr_node = yang_dnode_get_parent(args->dnode, "candidate-bsr"); + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + return candidate_bsr_addrsel(scope, cand_bsr_node); + } + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_addrsel_destroy( + struct nb_cb_destroy_args *args) +{ + /* nothing to do here, we'll get a CREATE for something else */ + return NB_OK; +} + +static int candidate_rp_addrsel(struct bsm_scope *scope, + const struct lyd_node *cand_rp_node) +{ + yang_addrsel(&scope->cand_rp_addrsel, cand_rp_node); + pim_cand_rp_apply(scope); + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create( + struct nb_cb_create_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + scope->cand_rp_addrsel.cfg_enable = true; + scope->cand_rp_prio = yang_dnode_get_uint8(args->dnode, + "rp-priority"); + scope->cand_rp_interval = + yang_dnode_get_uint32(args->dnode, + "advertisement-interval"); + + candidate_rp_addrsel(scope, args->dnode); + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + scope->cand_rp_addrsel.cfg_enable = false; + + pim_cand_rp_apply(scope); + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + scope->cand_rp_prio = yang_dnode_get_uint8(args->dnode, NULL); + + pim_cand_rp_trigger(scope); + break; + } + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_adv_interval_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + scope->cand_rp_interval = yang_dnode_get_uint32(args->dnode, + NULL); + + pim_cand_rp_trigger(scope); + break; + } + + return NB_OK; +} + +#if PIM_IPV == 4 +#define yang_dnode_get_pim_p yang_dnode_get_ipv4p +#else +#define yang_dnode_get_pim_p yang_dnode_get_ipv6p +#endif + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create( + struct nb_cb_create_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + prefix_pim p; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + yang_dnode_get_pim_p(&p, args->dnode, "."); + pim_cand_rp_grp_add(scope, &p); + break; + } + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + prefix_pim p; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(args->dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + yang_dnode_get_pim_p(&p, args->dnode, "."); + pim_cand_rp_grp_del(scope, &p); + break; + } + return NB_OK; +} + +static int candidate_rp_addrsel_common(enum nb_event event, + const struct lyd_node *dnode) +{ + struct vrf *vrf; + struct pim_instance *pim; + struct bsm_scope *scope; + + dnode = lyd_parent(dnode); + + switch (event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrf = nb_running_get_entry(dnode, NULL, true); + pim = vrf->info; + scope = &pim->global_scope; + + candidate_rp_addrsel(scope, dnode); + break; + } + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create( + struct nb_cb_create_args *args) +{ + return candidate_rp_addrsel_common(args->event, args->dnode); +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify( + struct nb_cb_modify_args *args) +{ + return candidate_rp_addrsel_common(args->event, args->dnode); +} + +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy( + struct nb_cb_destroy_args *args) +{ + /* nothing to do here - we'll get a create or modify event too */ + return NB_OK; +} + +/* * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family */ int lib_interface_gmp_address_family_create(struct nb_cb_create_args *args) @@ -2989,6 +3746,34 @@ int lib_interface_gmp_address_family_robustness_variable_modify( } /* + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/proxy + */ +int lib_interface_gmp_address_family_proxy_modify(struct nb_cb_modify_args *args) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); + pim_ifp = ifp->info; + if (pim_ifp) { + pim_ifp->gm_proxy = yang_dnode_get_bool(args->dnode, + NULL); + + if (pim_ifp->gm_proxy) + pim_if_gm_proxy_init(pim_ifp->pim, ifp); + else + pim_if_gm_proxy_finis(pim_ifp->pim, ifp); + } + } + return NB_OK; +} +/* * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/join-group */ int lib_interface_gmp_address_family_join_group_create( @@ -3039,7 +3824,8 @@ int lib_interface_gmp_address_family_join_group_create( "./source-addr"); yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr"); - result = pim_if_gm_join_add(ifp, group_addr, source_addr); + result = pim_if_gm_join_add(ifp, group_addr, source_addr, + GM_JOIN_STATIC); if (result) { snprintf(args->errmsg, args->errmsg_len, "Failure joining " GM " group"); @@ -3068,13 +3854,13 @@ int lib_interface_gmp_address_family_join_group_destroy( "./source-addr"); yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr"); - result = pim_if_gm_join_del(ifp, group_addr, source_addr); + result = pim_if_gm_join_del(ifp, group_addr, source_addr, + GM_JOIN_STATIC); if (result) { - snprintf(args->errmsg, args->errmsg_len, - "%% Failure leaving " GM - " group %pPAs %pPAs on interface %s: %d", - &source_addr, &group_addr, ifp->name, result); + snprintfrr(args->errmsg, args->errmsg_len, + "%% Failure leaving " GM " group %pPAs %pPAs on interface %s: %d", + &source_addr, &group_addr, ifp->name, result); return NB_ERR_INCONSISTENCY; } @@ -3163,9 +3949,9 @@ int lib_interface_gmp_address_family_static_group_destroy( result = pim_if_static_group_del(ifp, group_addr, source_addr); if (result) { - snprintf(args->errmsg, args->errmsg_len, - "%% Failure removing static group %pPAs %pPAs on interface %s: %d", - &source_addr, &group_addr, ifp->name, result); + snprintfrr(args->errmsg, args->errmsg_len, + "%% Failure removing static group %pPAs %pPAs on interface %s: %d", + &source_addr, &group_addr, ifp->name, result); return NB_ERR_INCONSISTENCY; } diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 57dcff3b47..030b933e09 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -343,7 +343,8 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, if (!nbr) continue; - return znh->ifindex == src_ifp->ifindex; + return znh->ifindex == src_ifp->ifindex && + (!pim_addr_cmp(znh->nexthop_addr, src_ip)); } return false; } @@ -404,13 +405,12 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, return true; /* MRIB (IGP) may be pointing at a router where PIM is down */ - nbr = pim_neighbor_find(ifp, nhaddr, true); - if (!nbr) continue; - return nh->ifindex == src_ifp->ifindex; + return nh->ifindex == src_ifp->ifindex && + (!pim_addr_cmp(nhaddr, src_ip)); } return false; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 6a7e8924f2..a41bbacea7 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -13,7 +13,6 @@ #include "network.h" #include "pimd.h" -#include "pim_instance.h" #include "pim_pim.h" #include "pim_time.h" #include "pim_iface.h" @@ -139,7 +138,7 @@ static bool pim_pkt_dst_addr_ok(enum pim_msg_type type, pim_addr addr) } int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, - pim_sgaddr sg) + pim_sgaddr sg, bool is_mcast) { struct iovec iov[2], *iovp = iov; #if PIM_IPV == 4 @@ -274,6 +273,22 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, return -1; } + if (!is_mcast) { + if (header->type == PIM_MSG_TYPE_CANDIDATE) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("%s %s: Candidate RP PIM message from %pPA on %s", + __FILE__, __func__, &sg.src, + ifp->name); + + return pim_crp_process(ifp, &sg, pim_msg, pim_msg_len); + } + + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug( + "ignoring link traffic on BSR unicast socket"); + return -1; + } + switch (header->type) { case PIM_MSG_TYPE_HELLO: return pim_hello_recv(ifp, sg.src, pim_msg + PIM_MSG_HEADER_LEN, @@ -322,6 +337,13 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, return pim_bsm_process(ifp, &sg, pim_msg, pim_msg_len, no_fwd); break; + case PIM_MSG_TYPE_CANDIDATE: + /* return pim_crp_process(ifp, &sg, pim_msg, pim_msg_len); */ + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug( + "ignoring Candidate-RP packet on multicast socket"); + return 0; + default: if (PIM_DEBUG_PIM_PACKETS) { zlog_debug( @@ -332,13 +354,9 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, } } -static void pim_sock_read_on(struct interface *ifp); - -static void pim_sock_read(struct event *t) +int pim_sock_read_helper(int fd, struct pim_instance *pim, bool is_mcast) { - struct interface *ifp, *orig_ifp; - struct pim_interface *pim_ifp; - int fd; + struct interface *ifp = NULL; struct sockaddr_storage from; struct sockaddr_storage to; socklen_t fromlen = sizeof(from); @@ -346,16 +364,9 @@ static void pim_sock_read(struct event *t) uint8_t buf[PIM_PIM_BUFSIZE_READ]; int len; ifindex_t ifindex = -1; - int result = -1; /* defaults to bad */ - static long long count = 0; - int cont = 1; - - orig_ifp = ifp = EVENT_ARG(t); - fd = EVENT_FD(t); - - pim_ifp = ifp->info; + int i; - while (cont) { + for (i = 0; i < router->packet_process; i++) { pim_sgaddr sg; len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from, @@ -369,7 +380,7 @@ static void pim_sock_read(struct event *t) if (PIM_DEBUG_PIM_PACKETS) zlog_debug("Received errno: %d %s", errno, safe_strerror(errno)); - goto done; + return -1; } /* @@ -378,14 +389,21 @@ static void pim_sock_read(struct event *t) * the right ifindex, so just use it. We know * it's the right interface because we bind to it */ - ifp = if_lookup_by_index(ifindex, pim_ifp->pim->vrf->vrf_id); - if (!ifp || !ifp->info) { + if (pim != NULL) + ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id); + + /* + * unicast BSM pkts (C-RP) may arrive on non pim interfaces + * mcast pkts are only expected in pim interfaces + */ + if (!ifp || (is_mcast && !ifp->info)) { if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "%s: Received incoming pim packet on interface(%s:%d) not yet configured for pim", - __func__, ifp ? ifp->name : "Unknown", - ifindex); - goto done; + zlog_debug("%s: Received incoming pim packet on interface(%s:%d)%s", + __func__, + ifp ? ifp->name : "Unknown", ifindex, + is_mcast ? " not yet configured for pim" + : ""); + return -1; } #if PIM_IPV == 4 sg.src = ((struct sockaddr_in *)&from)->sin_addr; @@ -395,27 +413,34 @@ static void pim_sock_read(struct event *t) sg.grp = ((struct sockaddr_in6 *)&to)->sin6_addr; #endif - int fail = pim_pim_packet(ifp, buf, len, sg); + int fail = pim_pim_packet(ifp, buf, len, sg, is_mcast); if (fail) { if (PIM_DEBUG_PIM_PACKETS) zlog_debug("%s: pim_pim_packet() return=%d", __func__, fail); - goto done; + return -1; } - - count++; - if (count % router->packet_process == 0) - cont = 0; } + return 0; +} + +static void pim_sock_read_on(struct interface *ifp); - result = 0; /* good */ +static void pim_sock_read(struct event *t) +{ + struct interface *ifp; + struct pim_interface *pim_ifp; + int fd; + + ifp = EVENT_ARG(t); + fd = EVENT_FD(t); -done: - pim_sock_read_on(orig_ifp); + pim_ifp = ifp->info; - if (result) { + if (pim_sock_read_helper(fd, pim_ifp->pim, true) == 0) ++pim_ifp->pim_ifstat_hello_recvfail; - } + + pim_sock_read_on(ifp); } static void pim_sock_read_on(struct interface *ifp) diff --git a/pimd/pim_pim.h b/pimd/pim_pim.h index 35e693013a..39b27bceda 100644 --- a/pimd/pim_pim.h +++ b/pimd/pim_pim.h @@ -10,6 +10,7 @@ #include <zebra.h> #include "if.h" +#include "pim_instance.h" #define PIM_PIM_BUFSIZE_READ (20000) #define PIM_PIM_BUFSIZE_WRITE (20000) @@ -42,10 +43,12 @@ void pim_hello_restart_now(struct interface *ifp); void pim_hello_restart_triggered(struct interface *ifp); int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, - pim_sgaddr sg); + pim_sgaddr sg, bool is_mcast); int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, int pim_msg_size, struct interface *ifp); int pim_hello_send(struct interface *ifp, uint16_t holdtime); + +int pim_sock_read_helper(int fd, struct pim_instance *pim, bool is_mcast); #endif /* PIM_PIM_H */ diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index a2ddc82164..0c47bc1582 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -1140,7 +1140,8 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty) if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; - if (rp_info->rp_src == RP_SRC_BSR) + if (rp_info->rp_src != RP_SRC_NONE && + rp_info->rp_src != RP_SRC_STATIC) continue; rp_addr = rp_info->rp.rpf_addr; @@ -1200,6 +1201,8 @@ void pim_rp_show_information(struct pim_instance *pim, struct prefix *range, strlcpy(source, "Static", sizeof(source)); else if (rp_info->rp_src == RP_SRC_BSR) strlcpy(source, "BSR", sizeof(source)); + else if (rp_info->rp_src == RP_SRC_AUTORP) + strlcpy(source, "AutoRP", sizeof(source)); else strlcpy(source, "None", sizeof(source)); if (json) { diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 32c6306740..24832d0dbd 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -16,11 +16,7 @@ struct pim_interface; -enum rp_source { - RP_SRC_NONE = 0, - RP_SRC_STATIC, - RP_SRC_BSR -}; +enum rp_source { RP_SRC_NONE = 0, RP_SRC_STATIC, RP_SRC_BSR, RP_SRC_AUTORP }; struct rp_info { struct prefix group; diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 3476c177b7..8900652df9 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -292,6 +292,36 @@ int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex, return ret; } +int pim_socket_leave(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex, + struct pim_interface *pim_ifp) +{ + int ret; + +#if PIM_IPV == 4 + ret = setsockopt_ipv4_multicast(fd, IP_DROP_MEMBERSHIP, ifaddr, + group.s_addr, ifindex); +#else + struct ipv6_mreq opt; + + memcpy(&opt.ipv6mr_multiaddr, &group, 16); + opt.ipv6mr_interface = ifindex; + ret = setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &opt, sizeof(opt)); +#endif + + if (ret) { + flog_err(EC_LIB_SOCKET, + "Failure socket leaving fd=%d group %pPAs on interface address %pPAs: %m", + fd, &group, &ifaddr); + pim_ifp->igmp_ifstat_joins_failed++; + return ret; + } + + if (PIM_DEBUG_TRACE) + zlog_debug("Socket fd=%d left group %pPAs on interface address %pPAs", + fd, &group, &ifaddr); + return ret; +} + #if PIM_IPV == 4 static void cmsg_getdstaddr(struct msghdr *mh, struct sockaddr_storage *dst, ifindex_t *ifindex) diff --git a/pimd/pim_sock.h b/pimd/pim_sock.h index 04ab864744..0a81c6943a 100644 --- a/pimd/pim_sock.h +++ b/pimd/pim_sock.h @@ -26,11 +26,14 @@ struct pim_instance; int pim_socket_bind(int fd, struct interface *ifp); void pim_socket_ip_hdr(int fd); +int pim_setsockopt_packetinfo(int fd); int pim_socket_raw(int protocol); int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp, uint8_t loop); int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex, struct pim_interface *pim_ifp); +int pim_socket_leave(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex, + struct pim_interface *pim_ifp); int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_storage *from, socklen_t *fromlen, struct sockaddr_storage *to, socklen_t *tolen, diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c index 4081786c1e..ac07154f86 100644 --- a/pimd/pim_tib.c +++ b/pimd/pim_tib.c @@ -78,6 +78,31 @@ tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif) return pim_channel_oil_add(pim, &sg, __func__); } +void tib_sg_proxy_join_prune_check(struct pim_instance *pim, pim_sgaddr sg, + struct interface *oif, bool join) +{ + struct interface *ifp; + + FOR_ALL_INTERFACES (pim->vrf, ifp) { + struct pim_interface *pim_ifp = ifp->info; + + if (!pim_ifp) + continue; + + if (ifp == oif) /* skip the source interface */ + continue; + + if (pim_ifp->gm_enable && pim_ifp->gm_proxy) { + if (join) + pim_if_gm_join_add(ifp, sg.grp, sg.src, + GM_JOIN_PROXY); + else + pim_if_gm_join_del(ifp, sg.grp, sg.src, + GM_JOIN_PROXY); + } + } /* scan interfaces */ +} + bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif, struct channel_oil **oilp) { @@ -95,6 +120,8 @@ bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg, if (!*oilp) return false; + tib_sg_proxy_join_prune_check(pim, sg, oif, true); + if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) { int result; @@ -137,6 +164,8 @@ void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg, { int result; + tib_sg_proxy_join_prune_check(pim, sg, oif, false); + /* It appears that in certain circumstances that igmp_source_forward_stop is called when IGMP forwarding @@ -164,5 +193,5 @@ void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg, */ pim_ifchannel_local_membership_del(oif, &sg); - pim_channel_oil_del(*oilp, __func__); + *oilp = pim_channel_oil_del(*oilp, __func__); } diff --git a/pimd/pim_tib.h b/pimd/pim_tib.h index 081ad908b5..a41d0a8475 100644 --- a/pimd/pim_tib.h +++ b/pimd/pim_tib.h @@ -16,5 +16,8 @@ extern bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif, struct channel_oil **oilp); extern void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif, struct channel_oil **oilp); +extern void tib_sg_proxy_join_prune_check(struct pim_instance *pim, + pim_sgaddr sg, struct interface *oif, + bool join); #endif /* _FRR_PIM_GLUE_H */ diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index c463fa227c..dd1bf2c059 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -19,12 +19,6 @@ #include "pim_iface.h" #include "pim_addr.h" -#if PIM_IPV == 4 -#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4 -#else -#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV6 -#endif - uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value) { diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 9cf4bb3e87..b633e81d55 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -165,6 +165,11 @@ int pim_debug_config_write(struct vty *vty) ++writes; } + if (PIM_DEBUG_AUTORP) { + vty_out(vty, "debug pim autorp\n"); + ++writes; + } + return writes; } @@ -182,6 +187,10 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) } writes += pim_rp_config_write(pim, vty); +#if PIM_IPV == 4 + writes += pim_autorp_config_write(pim, vty); +#endif + writes += pim_cand_config_write(pim, vty); if (pim->vrf->vrf_id == VRF_DEFAULT) { if (router->register_suppress_time @@ -269,6 +278,11 @@ static int gm_config_write(struct vty *vty, int writes, ++writes; } + if (pim_ifp->gm_proxy) { + vty_out(vty, " ip igmp proxy\n"); + ++writes; + } + /* ip igmp version */ if (pim_ifp->igmp_version != IGMP_DEFAULT_VERSION) { vty_out(vty, " ip igmp version %d\n", pim_ifp->igmp_version); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index e25eafc28e..ce4d85a2c8 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -157,6 +157,8 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS) pim_if_addr_add_all(ifp); } } + + pim_cand_addrs_changed(); return 0; } @@ -205,6 +207,8 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS) } connected_free(&c); + + pim_cand_addrs_changed(); return 0; } diff --git a/pimd/pimd.h b/pimd/pimd.h index 3d9318953b..461b7d08a3 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -95,6 +95,7 @@ #define PIM_MASK_VXLAN (1 << 26) #define PIM_MASK_BSM_PROC (1 << 27) #define PIM_MASK_MLAG (1 << 28) +#define PIM_MASK_AUTORP (1 << 29) /* Remember 32 bits!!! */ /* PIM error codes */ @@ -167,6 +168,7 @@ extern uint8_t qpim_ecmp_rebalance_enable; #define PIM_DEBUG_MTRACE (router->debugs & PIM_MASK_MTRACE) #define PIM_DEBUG_VXLAN (router->debugs & PIM_MASK_VXLAN) #define PIM_DEBUG_BSM (router->debugs & PIM_MASK_BSM_PROC) +#define PIM_DEBUG_AUTORP (router->debugs & PIM_MASK_AUTORP) #define PIM_DEBUG_EVENTS \ (router->debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_GM_EVENTS | \ @@ -209,6 +211,7 @@ extern uint8_t qpim_ecmp_rebalance_enable; #define PIM_DO_DEBUG_PIM_NHT_RP (router->debugs |= PIM_MASK_PIM_NHT_RP) #define PIM_DO_DEBUG_MTRACE (router->debugs |= PIM_MASK_MTRACE) #define PIM_DO_DEBUG_VXLAN (router->debugs |= PIM_MASK_VXLAN) +#define PIM_DO_DEBUG_AUTORP (router->debugs |= PIM_MASK_AUTORP) #define PIM_DONT_DEBUG_PIM_EVENTS (router->debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_PACKETS (router->debugs &= ~PIM_MASK_PIM_PACKETS) @@ -243,6 +246,7 @@ extern uint8_t qpim_ecmp_rebalance_enable; #define PIM_DONT_DEBUG_MTRACE (router->debugs &= ~PIM_MASK_MTRACE) #define PIM_DONT_DEBUG_VXLAN (router->debugs &= ~PIM_MASK_VXLAN) #define PIM_DONT_DEBUG_BSM (router->debugs &= ~PIM_MASK_BSM_PROC) +#define PIM_DONT_DEBUG_AUTORP (router->debugs &= ~PIM_MASK_AUTORP) /* RFC 3376: 8.1. Robustness Variable - Default: 2 for IGMP */ /* RFC 2710: 7.1. Robustness Variable - Default: 2 for MLD */ diff --git a/pimd/subdir.am b/pimd/subdir.am index 1e787a3525..bda594e5c4 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -17,6 +17,7 @@ pim_common = \ pimd/pim_assert.c \ pimd/pim_bfd.c \ pimd/pim_bsm.c \ + pimd/pim_bsr_rpdb.c \ pimd/pim_cmd_common.c \ pimd/pim_errors.c \ pimd/pim_hello.c \ @@ -58,6 +59,7 @@ pim_common = \ pimd_pimd_SOURCES = \ $(pim_common) \ + pimd/pim_autorp.c \ pimd/pim_cmd.c \ pimd/pim_igmp.c \ pimd/pim_igmp_mtrace.c \ @@ -76,6 +78,7 @@ pimd_pimd_SOURCES = \ nodist_pimd_pimd_SOURCES = \ yang/frr-pim.yang.c \ yang/frr-pim-rp.yang.c \ + yang/frr-pim-candidate.yang.c \ yang/frr-gmp.yang.c \ # end @@ -89,12 +92,14 @@ pimd_pim6d_SOURCES = \ nodist_pimd_pim6d_SOURCES = \ yang/frr-pim.yang.c \ yang/frr-pim-rp.yang.c \ + yang/frr-pim-candidate.yang.c \ yang/frr-gmp.yang.c \ # end noinst_HEADERS += \ pimd/pim_addr.h \ pimd/pim_assert.h \ + pimd/pim_autorp.h \ pimd/pim_bfd.h \ pimd/pim_bsm.h \ pimd/pim_cmd.h \ @@ -160,12 +165,12 @@ clippy_scan += \ # end pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4 -pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP) +pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP) -lm if PIM6D sbin_PROGRAMS += pimd/pim6d pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6 -pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP) +pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP) -lm endif pimd_test_igmpv3_join_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4 diff --git a/tests/bgpd/subdir.am b/tests/bgpd/subdir.am index 5148e7e440..97845ec1aa 100644 --- a/tests/bgpd/subdir.am +++ b/tests/bgpd/subdir.am @@ -52,17 +52,6 @@ tests_bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD) tests_bgpd_test_mp_attr_SOURCES = tests/bgpd/test_mp_attr.c EXTRA_DIST += tests/bgpd/test_mp_attr.py - -if BGPD -check_PROGRAMS += tests/bgpd/test_mpath -endif -tests_bgpd_test_mpath_CFLAGS = $(TESTS_CFLAGS) -tests_bgpd_test_mpath_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD) -tests_bgpd_test_mpath_SOURCES = tests/bgpd/test_mpath.c -EXTRA_DIST += tests/bgpd/test_mpath.py - - if BGPD check_PROGRAMS += tests/bgpd/test_packet endif diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c deleted file mode 100644 index ebbe3ac3e2..0000000000 --- a/tests/bgpd/test_mpath.c +++ /dev/null @@ -1,482 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * BGP Multipath Unit Test - * Copyright (C) 2010 Google Inc. - * - * This file is part of Quagga - */ - -#include <zebra.h> - -#include "qobj.h" -#include "vty.h" -#include "stream.h" -#include "privs.h" -#include "linklist.h" -#include "memory.h" -#include "zclient.h" -#include "queue.h" -#include "filter.h" - -#include "bgpd/bgpd.h" -#include "bgpd/bgp_table.h" -#include "bgpd/bgp_route.h" -#include "bgpd/bgp_attr.h" -#include "bgpd/bgp_nexthop.h" -#include "bgpd/bgp_mpath.h" -#include "bgpd/bgp_evpn.h" -#include "bgpd/bgp_network.h" - -#define VT100_RESET "\x1b[0m" -#define VT100_RED "\x1b[31m" -#define VT100_GREEN "\x1b[32m" -#define VT100_YELLOW "\x1b[33m" -#define OK VT100_GREEN "OK" VT100_RESET -#define FAILED VT100_RED "failed" VT100_RESET - -#define TEST_PASSED 0 -#define TEST_FAILED -1 - -#define EXPECT_TRUE(expr, res) \ - if (!(expr)) { \ - printf("Test failure in %s line %u: %s\n", __func__, __LINE__, \ - #expr); \ - (res) = TEST_FAILED; \ - } - -typedef struct testcase_t__ testcase_t; - -typedef int (*test_setup_func)(testcase_t *); -typedef int (*test_run_func)(testcase_t *); -typedef int (*test_cleanup_func)(testcase_t *); - -struct testcase_t__ { - const char *desc; - void *test_data; - void *verify_data; - void *tmp_data; - test_setup_func setup; - test_run_func run; - test_cleanup_func cleanup; -}; - -/* need these to link in libbgp */ -struct event_loop *master = NULL; -extern struct zclient *zclient; -struct zebra_privs_t bgpd_privs = { - .user = NULL, - .group = NULL, - .vty_group = NULL, -}; - -static int tty = 0; - -/* Create fake bgp instance */ -static struct bgp *bgp_create_fake(as_t *as, const char *name) -{ - struct bgp *bgp; - afi_t afi; - safi_t safi; - - if ((bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp))) == NULL) - return NULL; - - bgp_lock(bgp); - // bgp->peer_self = peer_new (bgp); - // bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static - // announcement"); - - bgp->peer = list_new(); - // bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp; - - bgp->group = list_new(); - // bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; - - bgp_evpn_init(bgp); - FOREACH_AFI_SAFI (afi, safi) { - bgp->route[afi][safi] = bgp_table_init(bgp, afi, safi); - bgp->aggregate[afi][safi] = bgp_table_init(bgp, afi, safi); - bgp->rib[afi][safi] = bgp_table_init(bgp, afi, safi); - bgp->maxpaths[afi][safi].maxpaths_ebgp = MULTIPATH_NUM; - bgp->maxpaths[afi][safi].maxpaths_ibgp = MULTIPATH_NUM; - } - - bgp_scan_init(bgp); - bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; - bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; - bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; - bgp->restart_time = BGP_DEFAULT_RESTART_TIME; - bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; - - bgp->as = *as; - - if (name) - bgp->name = strdup(name); - - return bgp; -} - -/*========================================================= - * Testcase for maximum-paths configuration - */ -static int setup_bgp_cfg_maximum_paths(testcase_t *t) -{ - as_t asn = 1; - t->tmp_data = bgp_create_fake(&asn, NULL); - if (!t->tmp_data) - return -1; - return 0; -} - -static int run_bgp_cfg_maximum_paths(testcase_t *t) -{ - afi_t afi; - safi_t safi; - struct bgp *bgp; - int api_result; - int test_result = TEST_PASSED; - - bgp = t->tmp_data; - FOREACH_AFI_SAFI (afi, safi) { - /* test bgp_maximum_paths_set */ - api_result = bgp_maximum_paths_set(bgp, afi, safi, - BGP_PEER_EBGP, 10, 0); - EXPECT_TRUE(api_result == 0, test_result); - api_result = bgp_maximum_paths_set(bgp, afi, safi, - BGP_PEER_IBGP, 10, 0); - EXPECT_TRUE(api_result == 0, test_result); - EXPECT_TRUE(bgp->maxpaths[afi][safi].maxpaths_ebgp == 10, - test_result); - EXPECT_TRUE(bgp->maxpaths[afi][safi].maxpaths_ibgp == 10, - test_result); - - /* test bgp_maximum_paths_unset */ - api_result = - bgp_maximum_paths_unset(bgp, afi, safi, BGP_PEER_EBGP); - EXPECT_TRUE(api_result == 0, test_result); - api_result = - bgp_maximum_paths_unset(bgp, afi, safi, BGP_PEER_IBGP); - EXPECT_TRUE(api_result == 0, test_result); - EXPECT_TRUE((bgp->maxpaths[afi][safi].maxpaths_ebgp - == MULTIPATH_NUM), - test_result); - EXPECT_TRUE((bgp->maxpaths[afi][safi].maxpaths_ibgp - == MULTIPATH_NUM), - test_result); - } - - return test_result; -} - -static int cleanup_bgp_cfg_maximum_paths(testcase_t *t) -{ - return bgp_delete((struct bgp *)t->tmp_data); -} - -testcase_t test_bgp_cfg_maximum_paths = { - .desc = "Test bgp maximum-paths config", - .setup = setup_bgp_cfg_maximum_paths, - .run = run_bgp_cfg_maximum_paths, - .cleanup = cleanup_bgp_cfg_maximum_paths, -}; - -/*========================================================= - * Testcase for bgp_mp_list - */ -struct peer test_mp_list_peer[] = { - {.local_as = 1, .as = 2}, {.local_as = 1, .as = 2}, - {.local_as = 1, .as = 2}, {.local_as = 1, .as = 2}, - {.local_as = 1, .as = 2}, -}; -int test_mp_list_peer_count = array_size(test_mp_list_peer); -struct attr test_mp_list_attr[4]; -struct bgp_path_info test_mp_list_info[] = { - {.peer = &test_mp_list_peer[0], .attr = &test_mp_list_attr[0]}, - {.peer = &test_mp_list_peer[1], .attr = &test_mp_list_attr[1]}, - {.peer = &test_mp_list_peer[2], .attr = &test_mp_list_attr[1]}, - {.peer = &test_mp_list_peer[3], .attr = &test_mp_list_attr[2]}, - {.peer = &test_mp_list_peer[4], .attr = &test_mp_list_attr[3]}, -}; -int test_mp_list_info_count = array_size(test_mp_list_info); - -static int setup_bgp_mp_list(testcase_t *t) -{ - test_mp_list_attr[0].nexthop.s_addr = 0x01010101; - test_mp_list_attr[1].nexthop.s_addr = 0x02020202; - test_mp_list_attr[2].nexthop.s_addr = 0x03030303; - test_mp_list_attr[3].nexthop.s_addr = 0x04040404; - - if ((test_mp_list_peer[0].su_remote = sockunion_str2su("1.1.1.1")) - == NULL) - return -1; - if ((test_mp_list_peer[1].su_remote = sockunion_str2su("2.2.2.2")) - == NULL) - return -1; - if ((test_mp_list_peer[2].su_remote = sockunion_str2su("3.3.3.3")) - == NULL) - return -1; - if ((test_mp_list_peer[3].su_remote = sockunion_str2su("4.4.4.4")) - == NULL) - return -1; - if ((test_mp_list_peer[4].su_remote = sockunion_str2su("5.5.5.5")) - == NULL) - return -1; - - return 0; -} - -static int run_bgp_mp_list(testcase_t *t) -{ - struct list mp_list; - struct listnode *mp_node; - struct bgp_path_info *info; - int i; - int test_result = TEST_PASSED; - bgp_mp_list_init(&mp_list); - EXPECT_TRUE(listcount(&mp_list) == 0, test_result); - - bgp_mp_list_add(&mp_list, &test_mp_list_info[1]); - bgp_mp_list_add(&mp_list, &test_mp_list_info[4]); - bgp_mp_list_add(&mp_list, &test_mp_list_info[2]); - bgp_mp_list_add(&mp_list, &test_mp_list_info[3]); - bgp_mp_list_add(&mp_list, &test_mp_list_info[0]); - - for (i = 0, mp_node = mp_list.head; i < test_mp_list_info_count; - i++, mp_node = listnextnode(mp_node)) { - info = listgetdata(mp_node); - info->lock++; - EXPECT_TRUE(info == &test_mp_list_info[i], test_result); - } - - bgp_mp_list_clear(&mp_list); - EXPECT_TRUE(listcount(&mp_list) == 0, test_result); - - return test_result; -} - -static int cleanup_bgp_mp_list(testcase_t *t) -{ - int i; - - for (i = 0; i < test_mp_list_peer_count; i++) - sockunion_free(test_mp_list_peer[i].su_remote); - - return 0; -} - -testcase_t test_bgp_mp_list = { - .desc = "Test bgp_mp_list", - .setup = setup_bgp_mp_list, - .run = run_bgp_mp_list, - .cleanup = cleanup_bgp_mp_list, -}; - -/*========================================================= - * Testcase for bgp_path_info_mpath_update - */ - -static struct bgp_dest *dest; - -static int setup_bgp_path_info_mpath_update(testcase_t *t) -{ - int i; - struct bgp *bgp; - struct bgp_table *rt; - struct prefix p; - as_t asn = 1; - - t->tmp_data = bgp_create_fake(&asn, NULL); - if (!t->tmp_data) - return -1; - - bgp = t->tmp_data; - rt = bgp->rib[AFI_IP][SAFI_UNICAST]; - - if (!rt) - return -1; - - str2prefix("42.1.1.0/24", &p); - dest = bgp_node_get(rt, &p); - - setup_bgp_mp_list(t); - for (i = 0; i < test_mp_list_info_count; i++) - bgp_path_info_add(dest, &test_mp_list_info[i]); - return 0; -} - -static int run_bgp_path_info_mpath_update(testcase_t *t) -{ - struct bgp_path_info *new_best, *old_best, *mpath; - struct list mp_list; - struct bgp_maxpaths_cfg mp_cfg = {3, 3}; - - int test_result = TEST_PASSED; - bgp_mp_list_init(&mp_list); - bgp_mp_list_add(&mp_list, &test_mp_list_info[4]); - bgp_mp_list_add(&mp_list, &test_mp_list_info[3]); - bgp_mp_list_add(&mp_list, &test_mp_list_info[0]); - bgp_mp_list_add(&mp_list, &test_mp_list_info[1]); - new_best = &test_mp_list_info[3]; - old_best = NULL; - bgp_path_info_mpath_update(NULL, dest, new_best, old_best, &mp_list, - &mp_cfg); - bgp_mp_list_clear(&mp_list); - EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 2, test_result); - mpath = bgp_path_info_mpath_first(new_best); - EXPECT_TRUE(mpath == &test_mp_list_info[0], test_result); - EXPECT_TRUE(CHECK_FLAG(mpath->flags, BGP_PATH_MULTIPATH), test_result); - mpath = bgp_path_info_mpath_next(mpath); - EXPECT_TRUE(mpath == &test_mp_list_info[1], test_result); - EXPECT_TRUE(CHECK_FLAG(mpath->flags, BGP_PATH_MULTIPATH), test_result); - - bgp_mp_list_add(&mp_list, &test_mp_list_info[0]); - bgp_mp_list_add(&mp_list, &test_mp_list_info[1]); - new_best = &test_mp_list_info[0]; - old_best = &test_mp_list_info[3]; - bgp_path_info_mpath_update(NULL, dest, new_best, old_best, &mp_list, - &mp_cfg); - bgp_mp_list_clear(&mp_list); - EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 1, test_result); - mpath = bgp_path_info_mpath_first(new_best); - EXPECT_TRUE(mpath == &test_mp_list_info[1], test_result); - EXPECT_TRUE(CHECK_FLAG(mpath->flags, BGP_PATH_MULTIPATH), test_result); - EXPECT_TRUE(!CHECK_FLAG(test_mp_list_info[0].flags, BGP_PATH_MULTIPATH), - test_result); - - return test_result; -} - -static int cleanup_bgp_path_info_mpath_update(testcase_t *t) -{ - int i; - - for (i = 0; i < test_mp_list_peer_count; i++) - sockunion_free(test_mp_list_peer[i].su_remote); - - return bgp_delete((struct bgp *)t->tmp_data); -} - -testcase_t test_bgp_path_info_mpath_update = { - .desc = "Test bgp_path_info_mpath_update", - .setup = setup_bgp_path_info_mpath_update, - .run = run_bgp_path_info_mpath_update, - .cleanup = cleanup_bgp_path_info_mpath_update, -}; - -/*========================================================= - * Set up testcase vector - */ -testcase_t *all_tests[] = { - &test_bgp_cfg_maximum_paths, &test_bgp_mp_list, - &test_bgp_path_info_mpath_update, -}; - -int all_tests_count = array_size(all_tests); - -/*========================================================= - * Test Driver Functions - */ -static int global_test_init(void) -{ - qobj_init(); - master = event_master_create(NULL); - zclient = zclient_new(master, &zclient_options_default, NULL, 0); - bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); - vrf_init(NULL, NULL, NULL, NULL); - bgp_option_set(BGP_OPT_NO_LISTEN); - - if (fileno(stdout) >= 0) - tty = isatty(fileno(stdout)); - return 0; -} - -static int global_test_cleanup(void) -{ - if (zclient != NULL) - zclient_free(zclient); - event_master_free(master); - return 0; -} - -static void display_result(testcase_t *test, int result) -{ - if (tty) - printf("%s: %s\n", test->desc, - result == TEST_PASSED ? OK : FAILED); - else - printf("%s: %s\n", test->desc, - result == TEST_PASSED ? "OK" : "FAILED"); -} - -static int setup_test(testcase_t *t) -{ - int res = 0; - if (t->setup) - res = t->setup(t); - return res; -} - -static int cleanup_test(testcase_t *t) -{ - int res = 0; - if (t->cleanup) - res = t->cleanup(t); - return res; -} - -static void run_tests(testcase_t *tests[], int num_tests, int *pass_count, - int *fail_count) -{ - int test_index, result; - testcase_t *cur_test; - - *pass_count = *fail_count = 0; - - for (test_index = 0; test_index < num_tests; test_index++) { - cur_test = tests[test_index]; - if (!cur_test->desc) { - printf("error: test %d has no description!\n", - test_index); - continue; - } - if (!cur_test->run) { - printf("error: test %s has no run function!\n", - cur_test->desc); - continue; - } - if (setup_test(cur_test) != 0) { - printf("error: setup failed for test %s\n", - cur_test->desc); - continue; - } - result = cur_test->run(cur_test); - if (result == TEST_PASSED) - *pass_count += 1; - else - *fail_count += 1; - display_result(cur_test, result); - if (cleanup_test(cur_test) != 0) { - printf("error: cleanup failed for test %s\n", - cur_test->desc); - continue; - } - } -} - -int main(void) -{ - int pass_count, fail_count; - time_t cur_time; - char buf[32]; - - time(&cur_time); - printf("BGP Multipath Tests Run at %s", ctime_r(&cur_time, buf)); - if (global_test_init() != 0) { - printf("Global init failed. Terminating.\n"); - exit(1); - } - run_tests(all_tests, all_tests_count, &pass_count, &fail_count); - global_test_cleanup(); - printf("Total pass/fail: %d/%d\n", pass_count, fail_count); - return fail_count; -} diff --git a/tests/bgpd/test_mpath.py b/tests/bgpd/test_mpath.py deleted file mode 100644 index 582fd25c20..0000000000 --- a/tests/bgpd/test_mpath.py +++ /dev/null @@ -1,10 +0,0 @@ -import frrtest - - -class TestMpath(frrtest.TestMultiOut): - program = "./test_mpath" - - -TestMpath.okfail("bgp maximum-paths config") -TestMpath.okfail("bgp_mp_list") -TestMpath.okfail("bgp_path_info_mpath_update") 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 195a7dd8c1..05e9f723a1 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/lib/test_frrlua.c b/tests/lib/test_frrlua.c index 2760a273bd..4aa8c8a8c3 100644 --- a/tests/lib/test_frrlua.c +++ b/tests/lib/test_frrlua.c @@ -13,6 +13,8 @@ static void test_encode_decode(void) { lua_State *L = luaL_newstate(); + luaL_openlibs(L); + int a = 123; int b = a; @@ -99,6 +101,20 @@ static void test_encode_decode(void) lua_decode_sockunion(L, -1, &su_a); assert(sockunion_cmp(&su_a, &su_b) == 0); assert(lua_gettop(L) == 0); + + /* Test if built-in functions (string() in this case) are working */ + const char *result; + + lua_getglobal(L, "string"); + lua_getfield(L, -1, "upper"); + lua_pushstring(L, "testas"); + lua_pcall(L, 1, 1, 0); + + result = lua_tostring(L, -1); + assert(strmatch(result, "TESTAS")); + lua_pop(L, 1); + lua_close(L); + /* End of built-in functions test */ } int main(int argc, char **argv) diff --git a/tests/ospf6d/test_lsdb.c b/tests/ospf6d/test_lsdb.c index f9df73538a..9cec4a3182 100644 --- a/tests/ospf6d/test_lsdb.c +++ b/tests/ospf6d/test_lsdb.c @@ -12,6 +12,7 @@ #include "vector.h" #include "vty.h" +#include "ospf6d/ospf6_proto.h" /* for struct ospf6_prefix */ #include "ospf6d/ospf6_lsa.h" #include "ospf6d/ospf6_lsdb.h" diff --git a/tests/topotests/all_protocol_startup/r1/ip_nht.ref b/tests/topotests/all_protocol_startup/r1/ip_nht.ref index 3592f29b54..2b4363b69e 100644 --- a/tests/topotests/all_protocol_startup/r1/ip_nht.ref +++ b/tests/topotests/all_protocol_startup/r1/ip_nht.ref @@ -1,35 +1,35 @@ VRF default: Resolve via default: on 1.1.1.1 - resolved via static + resolved via static, prefix 1.1.1.1/32 is directly connected, r1-eth1 (vrf default), weight 1 Client list: pbr(fd XX) 1.1.1.2 - resolved via static + resolved via static, prefix 1.1.1.2/32 is directly connected, r1-eth2 (vrf default), weight 1 Client list: pbr(fd XX) 1.1.1.3 - resolved via static + resolved via static, prefix 1.1.1.3/32 is directly connected, r1-eth3 (vrf default), weight 1 Client list: pbr(fd XX) 1.1.1.4 - resolved via static + resolved via static, prefix 1.1.1.4/32 is directly connected, r1-eth4 (vrf default), weight 1 Client list: pbr(fd XX) 1.1.1.5 - resolved via static + resolved via static, prefix 1.1.1.5/32 is directly connected, r1-eth5 (vrf default), weight 1 Client list: pbr(fd XX) 1.1.1.6 - resolved via static + resolved via static, prefix 1.1.1.6/32 is directly connected, r1-eth6 (vrf default), weight 1 Client list: pbr(fd XX) 1.1.1.7 - resolved via static + resolved via static, prefix 1.1.1.7/32 is directly connected, r1-eth7 (vrf default), weight 1 Client list: pbr(fd XX) 1.1.1.8 - resolved via static + resolved via static, prefix 1.1.1.8/32 is directly connected, r1-eth8 (vrf default), weight 1 Client list: pbr(fd XX) 2.2.2.1 @@ -54,19 +54,19 @@ VRF default: unresolved Client list: pbr(fd XX) 192.168.0.2 - resolved via connected + resolved via connected, prefix 192.168.0.0/24 is directly connected, r1-eth0 (vrf default), weight 1 Client list: static(fd XX) 192.168.0.4 - resolved via connected + resolved via connected, prefix 192.168.0.0/24 is directly connected, r1-eth0 (vrf default), weight 1 Client list: static(fd XX) 192.168.7.10 - resolved via connected + resolved via connected, prefix 192.168.7.0/26 is directly connected, r1-eth7 (vrf default), weight 1 Client list: bgp(fd XX) 192.168.7.20(Connected) - resolved via connected + resolved via connected, prefix 192.168.7.0/26 is directly connected, r1-eth7 (vrf default), weight 1 Client list: bgp(fd XX) 192.168.161.4 diff --git a/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref index 7b71761185..3f03d6fe93 100644 --- a/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref +++ b/tests/topotests/all_protocol_startup/r1/ipv6_nht.ref @@ -1,15 +1,15 @@ VRF default: Resolve via default: on fc00::2 - resolved via connected + resolved via connected, prefix fc00::/64 is directly connected, r1-eth0 (vrf default), weight 1 Client list: static(fd XX) fc00:0:0:8::1000 - resolved via connected + resolved via connected, prefix fc00:0:0:8::/64 is directly connected, r1-eth8 (vrf default), weight 1 Client list: bgp(fd XX) fc00:0:0:8::2000(Connected) - resolved via connected + resolved via connected, prefix fc00:0:0:8::/64 is directly connected, r1-eth8 (vrf default), weight 1 Client list: bgp(fd XX) diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py index f4f874f942..bcdd987889 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py @@ -266,21 +266,21 @@ def verify_the_uptime(time_stamp_before, time_stamp_after, incremented=None): if incremented == True: if uptime_before < uptime_after: logger.info( - " The Uptime [{}] is incremented than [{}].......PASSED ".format( + " The Uptime before [{}] is less than [{}].......PASSED ".format( time_stamp_before, time_stamp_after ) ) return True else: logger.error( - " The Uptime [{}] is expected to be incremented than [{}].......FAILED ".format( + " The Uptime before [{}] is greater than the uptime after [{}].......FAILED ".format( time_stamp_before, time_stamp_after ) ) return False else: logger.info( - " The Uptime [{}] is not incremented than [{}] ".format( + " The Uptime before [{}] the same as after [{}] ".format( time_stamp_before, time_stamp_after ) ) @@ -1027,7 +1027,7 @@ def test_verify_bgp_default_originate_with_default_static_route_p1(request): result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) - step("Taking uptime snapshot before removing redisctribute static ") + step("Taking uptime snapshot before removing redistribute static") uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict) uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict) sleep(1) @@ -1074,6 +1074,7 @@ def test_verify_bgp_default_originate_with_default_static_route_p1(request): ) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + step("Now look that the route is not pointed at link2") result = verify_rib_default_route( tgen, topo, @@ -1093,7 +1094,7 @@ def test_verify_bgp_default_originate_with_default_static_route_p1(request): ) assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result) - step("Taking uptime snapshot before removing redisctribute static ") + step("Taking uptime snapshot after removing redistribute static") uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict) uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict) diff --git a/tests/topotests/bgp_dual_as/__init__.py b/tests/topotests/bgp_dual_as/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_dual_as/__init__.py diff --git a/tests/topotests/bgp_dual_as/r1/frr.conf b/tests/topotests/bgp_dual_as/r1/frr.conf new file mode 100644 index 0000000000..9dcfe05d69 --- /dev/null +++ b/tests/topotests/bgp_dual_as/r1/frr.conf @@ -0,0 +1,11 @@ +! +interface r1-eth0 + ip address 10.0.0.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 10.0.0.2 remote-as 65002 + neighbor 10.0.0.2 local-as 65001 no-prepend replace-as dual-as + neighbor 10.0.0.2 timers 3 10 + neighbor 10.0.0.2 timers connect 1 +! diff --git a/tests/topotests/bgp_dual_as/r2/frr.conf b/tests/topotests/bgp_dual_as/r2/frr.conf new file mode 100644 index 0000000000..a901d49a53 --- /dev/null +++ b/tests/topotests/bgp_dual_as/r2/frr.conf @@ -0,0 +1,10 @@ +! +interface r2-eth0 + ip address 10.0.0.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 10.0.0.1 remote-as 65000 + neighbor 10.0.0.1 timers 3 10 + neighbor 10.0.0.1 timers connect 1 +! diff --git a/tests/topotests/bgp_dual_as/test_bgp_dual_as.py b/tests/topotests/bgp_dual_as/test_bgp_dual_as.py new file mode 100644 index 0000000000..b202d7819b --- /dev/null +++ b/tests/topotests/bgp_dual_as/test_bgp_dual_as.py @@ -0,0 +1,92 @@ +#!/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 +from lib.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + r1 = tgen.add_router("r1") + r2 = tgen.add_router("r2") + + switch = tgen.add_switch("s1") + switch.add_link(r1) + switch.add_link(r2) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + for _, (rname, router) in enumerate(tgen.routers().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_dual_as(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge_65000(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 summary json")) + expected = { + "ipv4Unicast": { + "as": 65000, + "peers": { + "10.0.0.2": { + "hostname": "r2", + "remoteAs": 65002, + "localAs": 65000, + "state": "Established", + "peerState": "OK", + } + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge_65000) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't establish BGP session using global AS 65000" + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_match_peer/__init__.py b/tests/topotests/bgp_match_peer/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_match_peer/__init__.py diff --git a/tests/topotests/bgp_match_peer/r1/frr.conf b/tests/topotests/bgp_match_peer/r1/frr.conf new file mode 100644 index 0000000000..f30da3b896 --- /dev/null +++ b/tests/topotests/bgp_match_peer/r1/frr.conf @@ -0,0 +1,37 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as external + neighbor r3 peer-group + neighbor r3 remote-as external + neighbor 192.168.1.3 peer-group r3 + neighbor r4 peer-group + neighbor r4 remote-as external + neighbor 192.168.1.4 peer-group r4 + address-family ipv4 unicast + network 10.0.0.1/32 route-map all + neighbor 192.168.1.2 route-map all in + neighbor r3 route-map all in + neighbor r4 route-map all in + exit-address-family +! +route-map all permit 5 + match peer local + set metric 1 +! +route-map all permit 10 + match peer 192.168.1.2 + set metric 2 +! +route-map all permit 15 + match peer r3 + set metric 3 +! +route-map all permit 20 + match peer r4 + set metric 4 +! diff --git a/tests/topotests/bgp_match_peer/r2/frr.conf b/tests/topotests/bgp_match_peer/r2/frr.conf new file mode 100644 index 0000000000..86dd8e3389 --- /dev/null +++ b/tests/topotests/bgp_match_peer/r2/frr.conf @@ -0,0 +1,14 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.2/32 + exit-address-family +! diff --git a/tests/topotests/bgp_match_peer/r3/frr.conf b/tests/topotests/bgp_match_peer/r3/frr.conf new file mode 100644 index 0000000000..978f967a0f --- /dev/null +++ b/tests/topotests/bgp_match_peer/r3/frr.conf @@ -0,0 +1,14 @@ +! +int r3-eth0 + ip address 192.168.1.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.3/32 + exit-address-family +! diff --git a/tests/topotests/bgp_match_peer/r4/frr.conf b/tests/topotests/bgp_match_peer/r4/frr.conf new file mode 100644 index 0000000000..6fb0bc660d --- /dev/null +++ b/tests/topotests/bgp_match_peer/r4/frr.conf @@ -0,0 +1,14 @@ +! +int r4-eth0 + ip address 192.168.1.4/24 +! +router bgp 65004 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.4/32 + exit-address-family +! diff --git a/tests/topotests/bgp_match_peer/test_bgp_match_peer.py b/tests/topotests/bgp_match_peer/test_bgp_match_peer.py new file mode 100644 index 0000000000..4eb7473df0 --- /dev/null +++ b/tests/topotests/bgp_match_peer/test_bgp_match_peer.py @@ -0,0 +1,88 @@ +#!/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", "r3", "r4")} + 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_match_peer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.0.0.1/32": [ + { + "metric": 1, + } + ], + "10.0.0.2/32": [ + { + "metric": 2, + } + ], + "10.0.0.3/32": [ + { + "metric": 3, + } + ], + "10.0.0.4/32": [ + { + "metric": 4, + } + ], + } + } + + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py index 63f1719e1d..a5232ad694 100644 --- a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py +++ b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py @@ -108,7 +108,7 @@ def test_bgp_set_aspath_exclude(): pytest.skip(tgen.errors) test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1) - _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed overriding incoming AS-PATH with route-map" @@ -128,7 +128,6 @@ def test_bgp_set_aspath_exclude_access_list(): conf bgp as-path access-list FIRST permit ^65 route-map r2 permit 6 - no set as-path exclude as-path-access-list SECOND set as-path exclude as-path-access-list FIRST """ ) @@ -140,21 +139,20 @@ clear bgp * ) test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_2) - _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed change of exclude rule in route map" r1.vtysh_cmd( """ conf route-map r2 permit 6 - no set as-path exclude as-path-access-list FIRST set as-path exclude as-path-access-list SECOND """ ) # tgen.mininet_cli() test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_1) - _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed reverting exclude rule in route map" @@ -182,7 +180,7 @@ clear bgp * ) test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) - _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to removing current accesslist" @@ -200,7 +198,7 @@ clear bgp * ) test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_4) - _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to renegotiate with peers 2" @@ -208,7 +206,7 @@ clear bgp * """ conf route-map r2 permit 6 - no set as-path exclude as-path-access-list SECOND + set as-path exclude 65555 """ ) @@ -219,7 +217,26 @@ clear bgp * ) test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) - _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, "Failed to renegotiate with peers 2" + + r1.vtysh_cmd( + """ +conf + route-map r2 permit 6 + set as-path exclude as-path-access-list NON-EXISTING + """ + ) + + r1.vtysh_cmd( + """ +clear bgp * + """ + ) + + test_func = functools.partial(bgp_converge, tgen.gears["r1"], expected_3) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to renegotiate with peers 2" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py index 2400cd2853..bba0061858 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py @@ -21,7 +21,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.common_config import required_linux_kernel_version -from lib.checkping import check_ping, check_ping +from lib.checkping import check_ping pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py index be28b388ba..44536e945e 100755 --- a/tests/topotests/conftest.py +++ b/tests/topotests/conftest.py @@ -18,12 +18,11 @@ from pathlib import Path import lib.fixtures import pytest from lib.common_config import generate_support_bundle -from lib.micronet_compat import Mininet from lib.topogen import diagnose_env, get_topogen from lib.topolog import get_test_logdir, logger from lib.topotest import json_cmp_result from munet import cli -from munet.base import Commander, proc_error +from munet.base import BaseMunet, Commander, proc_error from munet.cleanup import cleanup_current, cleanup_previous from munet.config import ConfigOptionsProxy from munet.testing.util import pause_test @@ -86,7 +85,7 @@ def pytest_addoption(parser): parser.addoption( "--cli-on-error", action="store_true", - help="Mininet cli on test failure", + help="Munet cli on test failure", ) parser.addoption( @@ -711,7 +710,7 @@ def pytest_runtest_makereport(item, call): wait_for_procs = [] # Really would like something better than using this global here. # Not all tests use topogen though so get_topogen() won't work. - for node in Mininet.g_mnet_inst.hosts.values(): + for node in BaseMunet.g_unet.hosts.values(): pause = True if is_tmux: @@ -720,13 +719,15 @@ def pytest_runtest_makereport(item, call): if not isatty else None ) - Commander.tmux_wait_gen += 1 - wait_for_channels.append(channel) + # If we don't have a tty to pause on pause for tmux windows to exit + if channel is not None: + Commander.tmux_wait_gen += 1 + wait_for_channels.append(channel) pane_info = node.run_in_window( error_cmd, new_window=win_info is None, - background=True, + background=not isatty, title="{} ({})".format(title, node.name), name=title, tmux_target=win_info, @@ -737,9 +738,13 @@ def pytest_runtest_makereport(item, call): win_info = pane_info elif is_xterm: assert isinstance(pane_info, subprocess.Popen) - wait_for_procs.append(pane_info) + # If we don't have a tty to pause on pause for xterm procs to exit + if not isatty: + wait_for_procs.append(pane_info) # Now wait on any channels + if wait_for_channels or wait_for_procs: + logger.info("Pausing for error command windows to exit") for channel in wait_for_channels: logger.debug("Waiting on TMUX channel %s", channel) commander.cmd_raises([commander.get_exec_path("tmux"), "wait", channel]) @@ -752,10 +757,10 @@ def pytest_runtest_makereport(item, call): if error and item.config.option.cli_on_error: # Really would like something better than using this global here. # Not all tests use topogen though so get_topogen() won't work. - if Mininet.g_mnet_inst: - cli.cli(Mininet.g_mnet_inst, title=title, background=False) + if BaseMunet.g_unet: + cli.cli(BaseMunet.g_unet, title=title, background=False) else: - logger.error("Could not launch CLI b/c no mininet exists yet") + logger.error("Could not launch CLI b/c no munet exists yet") if pause and isatty: pause_test() @@ -800,9 +805,20 @@ done""" def pytest_terminal_summary(terminalreporter, exitstatus, config): # Only run if we are the top level test runner is_xdist_worker = "PYTEST_XDIST_WORKER" in os.environ + is_xdist = os.environ["PYTEST_XDIST_MODE"] != "no" if config.option.cov_topotest and not is_xdist_worker: coverage_finish(terminalreporter, config) + if ( + is_xdist + and not is_xdist_worker + and ( + bool(config.getoption("--pause")) + or bool(config.getoption("--pause-at-end")) + ) + ): + pause_test("pause-at-end") + # # Add common fixtures available to all tests as parameters diff --git a/tests/topotests/dump_of_bgp/r1/frr.conf b/tests/topotests/dump_of_bgp/r1/frr.conf new file mode 100644 index 0000000000..d677e2007e --- /dev/null +++ b/tests/topotests/dump_of_bgp/r1/frr.conf @@ -0,0 +1,12 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.2 capability dynamic + ! +! diff --git a/tests/topotests/dump_of_bgp/r2/frr.conf b/tests/topotests/dump_of_bgp/r2/frr.conf new file mode 100644 index 0000000000..d68d13d075 --- /dev/null +++ b/tests/topotests/dump_of_bgp/r2/frr.conf @@ -0,0 +1,17 @@ +! +int lo + ip address 10.10.10.10/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/dump_of_bgp/test_dump_of_bgp.py b/tests/topotests/dump_of_bgp/test_dump_of_bgp.py new file mode 100644 index 0000000000..1359c57f31 --- /dev/null +++ b/tests/topotests/dump_of_bgp/test_dump_of_bgp.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by Nvidia Corporation +# Donald Sharp <sharpd@nvidia.com> + +import os +import sys +import json +import pytest +import functools +from lib.topolog import logger + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dump(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Test the ability for bgp to dump a file specified") + r1 = tgen.gears["r1"] + + logger.info("Converge BGP") + def _converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + logger.info("Dumping file") + #### + # Create a dump file + #### + r1.vtysh_cmd( + """ + configure terminal + dump bgp all bgp_dump.file + """ + ) + + def _test_dump_file_existence(): + dump_file = "{}/r1/bgp_dump.file".format(tgen.logdir) + + logger.info("Looking for {} file".format(dump_file)) + logger.info(os.path.isfile(dump_file)) + return os.path.isfile(dump_file) + + logger.info("Ensure that Log file exists") + _, result = topotest.run_and_expect(_test_dump_file_existence, True, count=30, wait = 3) + assert result is True + + # At this point all we have done is ensure that the dump file + # is generated for r1. What is correctness of the dump anyways? + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/forwarding_on_off/r1/frr.conf b/tests/topotests/forwarding_on_off/r1/frr.conf new file mode 100644 index 0000000000..677ba8f63e --- /dev/null +++ b/tests/topotests/forwarding_on_off/r1/frr.conf @@ -0,0 +1,14 @@ +int lo + ip address 10.1.1.1/32 + ip address 10:1::1:1/128 + +int eth0 + ip address 10.1.2.1/24 + ipv6 address 10:1::2:1/120 + +ip route 10.1.1.2/32 10.1.2.2 +ip route 10.1.1.3/32 10.1.2.2 +ip route 10.1.3.0/24 10.1.2.2 +ipv6 route 10:1::1:2/128 10:1::2:2 +ipv6 route 10:1::1:3/128 10:1::2:2 +ipv6 route 10:1::3:0/90 10:1::2:2
\ No newline at end of file diff --git a/tests/topotests/forwarding_on_off/r2/frr.conf b/tests/topotests/forwarding_on_off/r2/frr.conf new file mode 100644 index 0000000000..b6da6e2231 --- /dev/null +++ b/tests/topotests/forwarding_on_off/r2/frr.conf @@ -0,0 +1,19 @@ +no ip forwarding +no ipv6 forwarding + +int lo + ip address 10.1.1.2/32 + ipv6 address 10:1::1:2/128 + +int eth0 + ip address 10.1.2.2/24 + ipv6 address 10:1::2:2/120 + +int eth1 + ip address 10.1.3.2/24 + ipv6 address 10:1::3:2/120 + +ip route 10.1.1.1/32 10.1.2.1 +ip route 10.1.1.3/32 10.1.3.3 +ipv6 route 10:1::1:1/128 10:1::2:1 +ipv6 route 10:1::1:3/128 10:1::3:3 diff --git a/tests/topotests/forwarding_on_off/r3/frr.conf b/tests/topotests/forwarding_on_off/r3/frr.conf new file mode 100644 index 0000000000..ea05f18400 --- /dev/null +++ b/tests/topotests/forwarding_on_off/r3/frr.conf @@ -0,0 +1,15 @@ +int lo + ip address 10.1.1.3/32 + ipv6 address 10:1::1:3/128 + +int eth0 + ip address 10.1.3.3/24 + ipv6 address 10:1::3:3/120 + + +ip route 10.1.1.1/32 10.1.3.2 +ip route 10.1.1.2/32 10.1.3.2 +ip route 10.1.2.0/24 10.1.3.2 +ipv6 route 10:1::1:1/128 10:1::3:2 +ipv6 route 10:1::1:2/128 10:1::3:2 +ipv6 route 10:1::2:0/120 10:1::3:2
\ No newline at end of file diff --git a/tests/topotests/forwarding_on_off/test_forwarding_on_off.py b/tests/topotests/forwarding_on_off/test_forwarding_on_off.py new file mode 100644 index 0000000000..fa0483888c --- /dev/null +++ b/tests/topotests/forwarding_on_off/test_forwarding_on_off.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC +# +# test_forwarding_on_off.py +# +# Copyright (c) 2024 by Nvidia Corporation +# Donald Sharp +# + +""" +test_forwarding_on_off.py: Test that forwarding is turned off then back on + +""" + +import ipaddress +import json +import pytest +import sys +import time + +from functools import partial +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger +from lib.checkping import check_ping + +pytestmark = [ + pytest.mark.staticd, +] + + +def build_topo(tgen): + """Build the topology used by all tests below.""" + + # Create 3 routers + r1 = tgen.add_router("r1") + r2 = tgen.add_router("r2") + r3 = tgen.add_router("r3") + + # Add a link between r1 <-> r2 and r2 <-> r3 + tgen.add_link(r1, r2, ifname1="eth0", ifname2="eth0") + tgen.add_link(r2, r3, ifname1="eth1", ifname2="eth0") + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, router in router_list.items(): + router.load_frr_config("frr.conf") + + tgen.start_router() + + +def teardown_module(): + tgen = get_topogen() + tgen.stop_topology() + + +def test_no_forwarding(): + tgen = get_topogen() + r2 = tgen.gears["r2"] + + def _no_forwarding(family, status): + logger.info("Testing for: {} {}".format(family, status)) + rc, o, e = r2.net.cmd_status( + 'vtysh -c "show zebra" | grep "{}" | grep "{}"'.format(family, status) + ) + + logger.info("Output: {}".format(o)) + return rc + + test_func = partial(_no_forwarding, "v4 Forwarding", "Off") + _, result = topotest.run_and_expect(test_func, 0, count=15, wait=1) + assert result == 0 + + test_func = partial(_no_forwarding, "v6 Forwarding", "Off") + _, result = topotest.run_and_expect(test_func, 0, count=15, wait=1) + assert result == 0 + + logger.info("Sending pings that should fail") + check_ping("r1", "10.1.1.3", False, 10, 1) + check_ping("r1", "10:1::1:3", False, 10, 1) + + logger.info("Turning on Forwarding") + r2.vtysh_cmd("conf\nip forwarding\nipv6 forwarding") + + test_func = partial(_no_forwarding, "v4 Forwarding", "On") + _, result = topotest.run_and_expect(test_func, 0, count=15, wait=1) + assert result == 0 + + test_func = partial(_no_forwarding, "v6 Forwarding", "On") + _, result = topotest.run_and_expect(test_func, 0, count=15, wait=1) + assert result == 0 + + check_ping("r1", "10.1.1.3", True, 10, 1) + check_ping("r1", "10:1::1:3", True, 10, 1) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 2cee5fdaed..f34c48b890 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -936,7 +936,7 @@ def generate_support_bundle(): tgen = get_topogen() if tgen is None: - logger.warn( + logger.warning( "Support bundle attempted to be generated, but topogen is not being used" ) return True diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py index 71e36b6229..369a794ebc 100644 --- a/tests/topotests/lib/pim.py +++ b/tests/topotests/lib/pim.py @@ -1607,7 +1607,7 @@ def verify_pim_rp_info( if type(group_addresses) is not list: group_addresses = [group_addresses] - if type(oif) is not list: + if oif is not None and type(oif) is not list: oif = [oif] for grp in group_addresses: @@ -1746,6 +1746,49 @@ def verify_pim_rp_info( @retry(retry_timeout=60, diag_pct=0) +def verify_pim_rp_info_is_empty(tgen, dut, af="ipv4"): + """ + Verify pim rp info by running "show ip pim rp-info" cli + + Parameters + ---------- + * `tgen`: topogen object + * `dut`: device under test + + Usage + ----- + dut = "r1" + result = verify_pim_rp_info_is_empty(tgen, dut) + + Returns + ------- + errormsg(str) or True + """ + + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + + if dut not in tgen.routers(): + return False + + rnode = tgen.routers()[dut] + + ip_cmd = "ip" + if af == "ipv6": + ip_cmd = "ipv6" + + logger.info("[DUT: %s]: Verifying %s rp info", dut, ip_cmd) + cmd = "show {} pim rp-info json".format(ip_cmd) + show_ip_rp_info_json = run_frr_cmd(rnode, cmd, isjson=True) + + if show_ip_rp_info_json: + errormsg = "[DUT %s]: Verifying empty rp-info [FAILED]!!" % (dut) + return errormsg + + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return True + + +@retry(retry_timeout=60, diag_pct=0) def verify_pim_state( tgen, dut, @@ -2411,10 +2454,11 @@ def clear_igmp_interfaces(tgen, dut): # Verify uptime for groups for group in group_before_clear.keys(): - d1 = datetime.datetime.strptime(group_before_clear[group], "%H:%M:%S") - d2 = datetime.datetime.strptime(group_after_clear[group], "%H:%M:%S") - if d2 >= d1: - errormsg = ("[DUT: %s]: IGMP group is not cleared", " [FAILED!!]", dut) + if group in group_after_clear: + d1 = datetime.datetime.strptime(group_before_clear[group], "%H:%M:%S") + d2 = datetime.datetime.strptime(group_after_clear[group], "%H:%M:%S") + if d2 >= d1: + errormsg = ("[DUT: %s]: IGMP group is not cleared", " [FAILED!!]", dut) logger.info("[DUT: %s]: IGMP group is cleared [PASSED!!]") @@ -2751,6 +2795,48 @@ def scapy_send_bsr_raw_packet(tgen, topo, senderRouter, receiverRouter, packet=N return True +def scapy_send_autorp_raw_packet(tgen, senderRouter, senderInterface, packet=None): + """ + Using scapy Raw() method to send AutoRP raw packet from one FRR + to other + + Parameters: + ----------- + * `tgen` : Topogen object + * `senderRouter` : Sender router + * `senderInterface` : SenderInterface + * `packet` : AutoRP packet in raw format + + returns: + -------- + errormsg or True + """ + + global CWD + result = "" + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + + python3_path = tgen.net.get_exec_path(["python3", "python"]) + # send_bsr_packet.py has no direct ties to bsr, just sends a raw packet out + # a given interface, so just reuse it + script_path = os.path.join(CWD, "send_bsr_packet.py") + node = tgen.net[senderRouter] + + cmd = [ + python3_path, + script_path, + packet, + senderInterface, + "--interval=1", + "--count=1", + ] + logger.info("Scapy cmd: \n %s", cmd) + node.cmd_raises(cmd) + + logger.debug("Exiting lib API: scapy_send_autorp_raw_packet") + return True + + def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None): """ Find which RP is having lowest prioriy and returns rp IP @@ -4260,6 +4346,7 @@ def verify_local_igmp_groups(tgen, dut, interface, group_addresses): logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return True + @retry(retry_timeout=62) def verify_static_groups(tgen, dut, interface, group_addresses): """ @@ -4293,7 +4380,9 @@ def verify_static_groups(tgen, dut, interface, group_addresses): rnode = tgen.routers()[dut] logger.info("[DUT: %s]: Verifying static groups received:", dut) - show_static_group_json = run_frr_cmd(rnode, "show ip igmp static-group json", isjson=True) + show_static_group_json = run_frr_cmd( + rnode, "show ip igmp static-group json", isjson=True + ) if type(group_addresses) is not list: group_addresses = [group_addresses] @@ -4330,6 +4419,71 @@ def verify_static_groups(tgen, dut, interface, group_addresses): logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return True + +@retry(retry_timeout=62) +def verify_local_igmp_proxy_groups( + tgen, dut, group_addresses_present, group_addresses_not_present +): + """ + Verify igmp proxy groups are as expected by running + "show ip igmp static-group json" command + + Parameters + ---------- + * `tgen`: topogen object + * `dut`: device under test + * `group_addresses_present`: IGMP group addresses which should + currently be proxied + * `group_addresses_not_present`: IGMP group addresses which should + not currently be proxied + + Usage + ----- + dut = "r1" + group_addresses_present = "225.1.1.1" + group_addresses_not_present = "225.2.2.2" + result = verify_igmp_proxy_groups(tgen, dut, group_p, group_np) + + Returns + ------- + errormsg(str) or True + """ + + if dut not in tgen.routers(): + errormsg = "[DUT %s]: Device not found!" + return errormsg + + rnode = tgen.routers()[dut] + + logger.info("[DUT: %s]: Verifying local IGMP proxy groups:", dut) + + out = rnode.vtysh_cmd("show ip igmp proxy json", isjson=True) + groups = [g["group"] if "group" in g else None for g in out["r1-eth1"]["groups"]] + + if type(group_addresses_present) is not list: + group_addresses_present = [group_addresses_present] + if type(group_addresses_not_present) is not list: + group_addresses_not_present = [group_addresses_not_present] + + for test_addr in group_addresses_present: + if not test_addr in groups: + errormsg = ( + "[DUT %s]: Verifying local IGMP proxy joins FAILED!! " + " Expected but not found: %s " % (dut, test_addr) + ) + return errormsg + + for test_addr in group_addresses_not_present: + if test_addr in groups: + errormsg = ( + "[DUT %s]: Verifying local IGMP proxy join removed FAILED!! " + " Unexpected but found: %s " % (dut, test_addr) + ) + return errormsg + + return True + + def verify_pim_interface_traffic(tgen, input_dict, return_stats=True, addr_type="ipv4"): """ Verify ip pim interface traffic by running diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 5a8c2e5964..d15fefc039 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -396,6 +396,9 @@ def run_and_expect(func, what, count=20, wait=3): waiting `wait` seconds between tries. By default it tries 20 times with 3 seconds delay between tries. + Changing default count/wait values, please change them below also for + `minimum_wait`, and `minimum_count`. + Returns (True, func-return) on success or (False, func-return) on failure. @@ -414,13 +417,18 @@ def run_and_expect(func, what, count=20, wait=3): # Just a safety-check to avoid running topotests with very # small wait/count arguments. + # If too low count/wait values are defined, override them + # with the minimum values. + minimum_count = 20 + minimum_wait = 3 + minimum_wait_time = 15 # The overall minimum seconds for the test to wait wait_time = wait * count - if wait_time < 5: - assert ( - wait_time >= 5 - ), "Waiting time is too small (count={}, wait={}), adjust timer values".format( - count, wait + if wait_time < minimum_wait_time: + logger.warning( + f"Waiting time is too small (count={count}, wait={wait}), using default values (count={minimum_count}, wait={minimum_wait})" ) + count = minimum_count + wait = minimum_wait logger.debug( "'{}' polling started (interval {} secs, maximum {} tries)".format( diff --git a/tests/topotests/mgmt_oper/r1/frr-yanglib.conf b/tests/topotests/mgmt_oper/r1/frr-yanglib.conf new file mode 100644 index 0000000000..f37766b158 --- /dev/null +++ b/tests/topotests/mgmt_oper/r1/frr-yanglib.conf @@ -0,0 +1,10 @@ +log timestamp precision 6 +log file frr.log + +no debug memstats-at-exit + +debug mgmt backend datastore frontend transaction + +interface r1-eth0 + ip address 1.1.1.1/24 +exit diff --git a/tests/topotests/mgmt_oper/test_yanglib.py b/tests/topotests/mgmt_oper/test_yanglib.py new file mode 100644 index 0000000000..e094ca5443 --- /dev/null +++ b/tests/topotests/mgmt_oper/test_yanglib.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# +# September 17 2024, Christian Hopps <chopps@labn.net> +# +# Copyright (c) 2024, LabN Consulting, L.L.C. +# + +import json +import pytest +from lib.topogen import Topogen + +pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] + + +@pytest.fixture(scope="module") +def tgen(request): + "Setup/Teardown the environment and provide tgen argument to tests" + + topodef = {"s1": ("r1",)} + + tgen = Topogen(topodef, request.module.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + router.load_frr_config("frr-yanglib.conf") + + tgen.start_router() + yield tgen + tgen.stop_topology() + + +def test_yang_lib(tgen): + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"].net + output = r1.cmd_nostatus( + "vtysh -c 'show mgmt get-data /ietf-yang-library:yang-library'" + ) + ret = json.loads(output) + loaded_modules = ret['ietf-yang-library:yang-library']['module-set'][0]['module'] + assert len(loaded_modules) > 10, "Modules missing from yang-library" diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json index 715aa1de72..44a7db56f1 100644 --- a/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_group_all_detail.json @@ -1 +1 @@ -{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} +{"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json index 3bbcce1370..982157a624 100644 --- a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_brief.json @@ -1,5 +1,4 @@ { - "totalGroups":5, "watermarkLimit":0, "l1-i1-eth1":{ "name":"l1-i1-eth1", @@ -48,4 +47,3 @@ ] } } - diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json index 876befa1b8..6042ef4dbf 100644 --- a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_group_all_detail.json @@ -1 +1 @@ -{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} +{"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json index a3fb496d25..0312c3026d 100644 --- a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_brief.json @@ -1,5 +1,4 @@ { - "totalGroups":5, "watermarkLimit":0, "l1-i1-eth1":{ "name":"l1-i1-eth1", diff --git a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json index 11ac5a01e7..537be377be 100644 --- a/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json +++ b/tests/topotests/multicast_pim_sm_topo3/igmp_single_if_single_group_detail.json @@ -1 +1 @@ -{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} +{"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}} diff --git a/tests/topotests/munet/cli.py b/tests/topotests/munet/cli.py index 01a7091512..d273a30ead 100644 --- a/tests/topotests/munet/cli.py +++ b/tests/topotests/munet/cli.py @@ -745,7 +745,7 @@ async def cli_client_connected(unet, background, reader, writer): await writer.drain() -async def remote_cli(unet, prompt, title, background): +async def remote_cli(unet, prompt, title, background, remote_wait=False): """Open a CLI in a new window.""" try: if not unet.cli_sockpath: @@ -756,6 +756,13 @@ async def remote_cli(unet, prompt, title, background): unet.cli_sockpath = sockpath logging.info("server created on :\n%s\n", sockpath) + if remote_wait: + wait_tmux = bool(os.getenv("TMUX", "")) + wait_x11 = not wait_tmux and bool(os.getenv("DISPLAY", "")) + else: + wait_tmux = False + wait_x11 = False + # Open a new window with a new CLI python_path = await unet.async_get_exec_path(["python3", "python"]) us = os.path.realpath(__file__) @@ -765,7 +772,32 @@ async def remote_cli(unet, prompt, title, background): if prompt: cmd += f" --prompt='{prompt}'" cmd += " " + unet.cli_sockpath - unet.run_in_window(cmd, title=title, background=False) + + channel = None + if wait_tmux: + from .base import Commander # pylint: disable=import-outside-toplevel + + channel = "{}-{}".format(os.getpid(), Commander.tmux_wait_gen) + logger.info("XXX channel is %s", channel) + # If we don't have a tty to pause on pause for tmux windows to exit + if channel is not None: + Commander.tmux_wait_gen += 1 + + pane_info = unet.run_in_window( + cmd, title=title, background=False, wait_for=channel + ) + + if wait_tmux and channel: + from .base import commander # pylint: disable=import-outside-toplevel + + logger.debug("Waiting on TMUX CLI window") + await commander.async_cmd_raises( + [commander.get_exec_path("tmux"), "wait", channel] + ) + elif wait_x11 and isinstance(pane_info, subprocess.Popen): + logger.debug("Waiting on xterm CLI process %s", pane_info) + if hasattr(asyncio, "to_thread"): + await asyncio.to_thread(pane_info.wait) # pylint: disable=no-member except Exception as error: logging.error("cli server: unexpected exception: %s", error) @@ -906,8 +938,22 @@ def cli( prompt=None, background=True, ): + # In the case of no tty a remote_cli will be used, and we want it to wait on finish + # of the spawned cli.py script, otherwise it returns back here and exits async loop + # which kills the server side CLI socket operation. + remote_wait = not sys.stdin.isatty() + asyncio.run( - async_cli(unet, histfile, sockpath, force_window, title, prompt, background) + async_cli( + unet, + histfile, + sockpath, + force_window, + title, + prompt, + background, + remote_wait=remote_wait, + ) ) @@ -919,12 +965,14 @@ async def async_cli( title=None, prompt=None, background=True, + remote_wait=False, ): if prompt is None: prompt = "munet> " if force_window or not sys.stdin.isatty(): - await remote_cli(unet, prompt, title, background) + await remote_cli(unet, prompt, title, background, remote_wait) + return if not unet: logger.debug("client-cli using sockpath %s", sockpath) diff --git a/tests/topotests/munet/native.py b/tests/topotests/munet/native.py index b7c6e4a63e..e3b782396e 100644 --- a/tests/topotests/munet/native.py +++ b/tests/topotests/munet/native.py @@ -2733,7 +2733,7 @@ ff02::2\tip6-allrouters ), "format": "stdout HOST [HOST ...]", "help": "tail -f on the stdout of the qemu/cmd for this node", - "new-window": True, + "new-window": {"background": True, "ns_only": True}, }, { "name": "stderr", @@ -2743,7 +2743,7 @@ ff02::2\tip6-allrouters ), "format": "stderr HOST [HOST ...]", "help": "tail -f on the stdout of the qemu/cmd for this node", - "new-window": True, + "new-window": {"background": True, "ns_only": True}, }, ] } diff --git a/tests/topotests/munet/testing/util.py b/tests/topotests/munet/testing/util.py index a1a94bcd1b..99687c0a83 100644 --- a/tests/topotests/munet/testing/util.py +++ b/tests/topotests/munet/testing/util.py @@ -52,12 +52,13 @@ def pause_test(desc=""): asyncio.run(async_pause_test(desc)) -def retry(retry_timeout, initial_wait=0, expected=True): +def retry(retry_timeout, initial_wait=0, retry_sleep=2, expected=True): """decorator: retry while functions return is not None or raises an exception. * `retry_timeout`: Retry for at least this many seconds; after waiting initial_wait seconds * `initial_wait`: Sleeps for this many seconds before first executing function + * `retry_sleep`: The time to sleep between retries. * `expected`: if False then the return logic is inverted, except for exceptions, (i.e., a non None ends the retry loop, and returns that value) """ @@ -65,9 +66,8 @@ def retry(retry_timeout, initial_wait=0, expected=True): def _retry(func): @functools.wraps(func) def func_retry(*args, **kwargs): - retry_sleep = 2 - # Allow the wrapped function's args to override the fixtures + _retry_sleep = float(kwargs.pop("retry_sleep", retry_sleep)) _retry_timeout = kwargs.pop("retry_timeout", retry_timeout) _expected = kwargs.pop("expected", expected) _initial_wait = kwargs.pop("initial_wait", initial_wait) @@ -82,13 +82,21 @@ def retry(retry_timeout, initial_wait=0, expected=True): while True: seconds_left = (retry_until - datetime.datetime.now()).total_seconds() try: - ret = func(*args, **kwargs) - if _expected and ret is None: + try: + ret = func(*args, seconds_left=seconds_left, **kwargs) + except TypeError as error: + if "seconds_left" not in str(error): + raise + ret = func(*args, **kwargs) + + logging.debug("Function returned %s", ret) + + positive_result = ret is None + if _expected == positive_result: logging.debug("Function succeeds") return ret - logging.debug("Function returned %s", ret) except Exception as error: - logging.info("Function raised exception: %s", str(error)) + logging.info('Function raised exception: "%s"', error) ret = error if seconds_left < 0: @@ -99,10 +107,10 @@ def retry(retry_timeout, initial_wait=0, expected=True): logging.info( "Sleeping %ds until next retry with %.1f retry time left", - retry_sleep, + _retry_sleep, seconds_left, ) - time.sleep(retry_sleep) + time.sleep(_retry_sleep) func_retry._original = func # pylint: disable=W0212 return func_retry diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt index 797bced7b8..131085a47a 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt @@ -2,7 +2,7 @@ O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX C>* 10.0.1.0/24 is directly connected, r1-eth0, weight 1, XX:XX:XX L>* 10.0.1.1/32 is directly connected, r1-eth0, weight 1, XX:XX:XX O>* 10.0.2.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX -B>* 10.0.3.0/24 [20/20] via 10.0.30.3, r1-eth2 (vrf neno), weight 1, XX:XX:XX +B>* 10.0.3.0/24 [110/20] via 10.0.30.3, r1-eth2 (vrf neno), weight 1, XX:XX:XX O>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX O 10.0.20.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX C>* 10.0.20.0/24 is directly connected, r1-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt index 1dc574f360..45ee1071d4 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt @@ -1,7 +1,7 @@ VRF neno: O>* 10.0.3.0/24 [110/20] via 10.0.30.3, r1-eth2, weight 1, XX:XX:XX -B>* 10.0.4.0/24 [20/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX +B>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX O 10.0.30.0/24 [110/10] is directly connected, r1-eth2, weight 1, XX:XX:XX C>* 10.0.30.0/24 is directly connected, r1-eth2, weight 1, XX:XX:XX L>* 10.0.30.1/32 is directly connected, r1-eth2, weight 1, XX:XX:XX -B>* 10.0.40.0/24 [20/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX +B>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt index b5e81bc0e9..f3724bbb9f 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt @@ -4,7 +4,7 @@ O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX C>* 10.0.2.0/24 is directly connected, r2-eth0, weight 1, XX:XX:XX L>* 10.0.2.2/32 is directly connected, r2-eth0, weight 1, XX:XX:XX O>* 10.0.3.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX -B>* 10.0.4.0/24 [20/20] via 10.0.40.4, r2-eth2 (vrf ray), weight 1, XX:XX:XX +B>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2 (vrf ray), weight 1, XX:XX:XX O 10.0.20.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX C>* 10.0.20.0/24 is directly connected, r2-eth1, weight 1, XX:XX:XX L>* 10.0.20.2/32 is directly connected, r2-eth1, weight 1, XX:XX:XX diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt index c403496ff6..0f8b12bdfa 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt @@ -1,10 +1,10 @@ VRF ray: -B 10.0.1.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX +B 10.0.1.0/24 [110/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX B 10.0.2.0/24 [20/0] is directly connected, r2-eth0 (vrf default) inactive, weight 1, XX:XX:XX -B>* 10.0.3.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX +B>* 10.0.3.0/24 [110/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX O>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2, weight 1, XX:XX:XX B 10.0.20.0/24 [20/0] is directly connected, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX -B>* 10.0.30.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX +B>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX O 10.0.40.0/24 [110/10] is directly connected, r2-eth2, weight 1, XX:XX:XX C>* 10.0.40.0/24 is directly connected, r2-eth2, weight 1, XX:XX:XX L>* 10.0.40.2/32 is directly connected, r2-eth2, weight 1, XX:XX:XX diff --git a/tests/topotests/pim_autorp/__init__.py b/tests/topotests/pim_autorp/__init__.py new file mode 100755 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/pim_autorp/__init__.py diff --git a/tests/topotests/pim_autorp/r1/frr.conf b/tests/topotests/pim_autorp/r1/frr.conf new file mode 100644 index 0000000000..2fddbc3ae2 --- /dev/null +++ b/tests/topotests/pim_autorp/r1/frr.conf @@ -0,0 +1,16 @@ +! +hostname r1 +password zebra +log file /tmp/r1-frr.log +debug pim autorp +! +interface r1-eth0 + ip address 10.10.76.1/24 + ip igmp + ip pim +! +ip forwarding +! +router pim + autorp discovery +!
\ No newline at end of file diff --git a/tests/topotests/pim_autorp/r2/frr.conf b/tests/topotests/pim_autorp/r2/frr.conf new file mode 100644 index 0000000000..fd3c0cad39 --- /dev/null +++ b/tests/topotests/pim_autorp/r2/frr.conf @@ -0,0 +1,16 @@ +! +hostname r2 +password zebra +log file /tmp/r2-frr.log +debug pim autorp +! +interface r2-eth0 + ip address 10.10.76.2/24 + ip igmp + ip pim +! +ip forwarding +! +router pim + autorp discovery +!
\ No newline at end of file diff --git a/tests/topotests/pim_autorp/test_pim_autorp.py b/tests/topotests/pim_autorp/test_pim_autorp.py new file mode 100644 index 0000000000..ad618af29e --- /dev/null +++ b/tests/topotests/pim_autorp/test_pim_autorp.py @@ -0,0 +1,341 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_pim_autorp.py +# +# Copyright (c) 2024 ATCorp +# Nathan Bahr +# + +import os +import sys +import pytest +from functools import partial + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger +from lib.pim import ( + scapy_send_autorp_raw_packet, + verify_pim_rp_info, + verify_pim_rp_info_is_empty, +) +from lib.common_config import step, write_test_header + +from time import sleep + +""" +test_pim_autorp.py: Test general PIM AutoRP functionality +""" + +TOPOLOGY = """ + Basic AutoRP functionality + + +---+---+ +---+---+ + | | 10.10.76.0/24 | | + + R1 + <------------------> + R2 | + | | .1 .2 | | + +---+---+ +---+---+ +""" + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# Required to instantiate the topology builder class. +pytestmark = [pytest.mark.pimd] + + +def build_topo(tgen): + "Build function" + + # Create routers + tgen.add_router("r1") + tgen.add_router("r2") + + # Create link between router 1 and 2 + switch = tgen.add_switch("s1-2") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + logger.info("PIM AutoRP basic functionality:\n {}".format(TOPOLOGY)) + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # Router 1 will be the router configured with "fake" autorp configuration, so give it a default route + # to router 2 so that routing to the RP address is not an issue + # r1_defrt_setup_cmds = [ + # "ip route add default via 10.10.76.1 dev r1-eth0", + # ] + # for cmd in r1_defrt_setup_cmds: + # tgen.net["r1"].cmd(cmd) + + logger.info("Testing PIM AutoRP support") + router_list = tgen.routers() + for rname, router in router_list.items(): + logger.info("Loading router %s" % rname) + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + # Initialize all routers. + tgen.start_router() + for router in router_list.values(): + if router.has_version("<", "4.0"): + tgen.set_error("unsupported version") + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_pim_autorp_discovery_single_rp(request): + "Test PIM AutoRP Discovery with single RP" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Start with no RP configuration") + result = verify_pim_rp_info_is_empty(tgen, "r1") + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Send AutoRP packet from r1 to r2") + # 1 RP(s), hold time 5 secs, 10.10.76.1, group(s) 224.0.0.0/4 + data = "01005e00012800127f55cfb1080045c00030700c000008110abe0a0a4c01e000012801f001f0001c798b12010005000000000a0a4c0103010004e0000000" + scapy_send_autorp_raw_packet(tgen, "r1", "r1-eth0", data) + + step("Verify rp-info from AutoRP packet") + result = verify_pim_rp_info( + tgen, + None, + "r2", + "224.0.0.0/4", + "r2-eth0", + "10.10.76.1", + "AutoRP", + False, + "ipv4", + True, + ) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify AutoRP configuration times out") + result = verify_pim_rp_info_is_empty(tgen, "r2") + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + +def test_pim_autorp_discovery_multiple_rp(request): + "Test PIM AutoRP Discovery with multiple RP's" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + step("Start with no RP configuration") + result = verify_pim_rp_info_is_empty(tgen, "r2") + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Send AutoRP packet from r1 to r2") + # 2 RP(s), hold time 5 secs, 10.10.76.1, group(s) 224.0.0.0/8, 10.10.76.3, group(s) 225.0.0.0/8 + data = "01005e00012800127f55cfb1080045c0003c700c000008110ab20a0a4c01e000012801f001f000283f5712020005000000000a0a4c0103010008e00000000a0a4c0303010008e1000000" + scapy_send_autorp_raw_packet(tgen, "r1", "r1-eth0", data) + + step("Verify rp-info from AutoRP packet") + result = verify_pim_rp_info( + tgen, + None, + "r2", + "224.0.0.0/8", + "r2-eth0", + "10.10.76.1", + "AutoRP", + False, + "ipv4", + True, + ) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + result = verify_pim_rp_info( + tgen, + None, + "r2", + "225.0.0.0/8", + "r2-eth0", + "10.10.76.3", + "AutoRP", + False, + "ipv4", + True, + ) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + +def test_pim_autorp_discovery_static(request): + "Test PIM AutoRP Discovery with Static RP" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + step("Start with no RP configuration") + result = verify_pim_rp_info_is_empty(tgen, "r2") + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Add static RP configuration to r2") + rnode = tgen.routers()["r2"] + rnode.cmd("vtysh -c 'conf t' -c 'router pim' -c 'rp 10.10.76.3 224.0.0.0/4'") + + step("Verify static rp-info from r2") + result = verify_pim_rp_info( + tgen, + None, + "r2", + "224.0.0.0/4", + "r2-eth0", + "10.10.76.3", + "Static", + False, + "ipv4", + True, + ) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Send AutoRP packet from r1 to r2") + # 1 RP(s), hold time 5 secs, 10.10.76.1, group(s) 224.0.0.0/4 + data = "01005e00012800127f55cfb1080045c00030700c000008110abe0a0a4c01e000012801f001f0001c798b12010005000000000a0a4c0103010004e0000000" + scapy_send_autorp_raw_packet(tgen, "r1", "r1-eth0", data) + + step("Verify rp-info from AutoRP packet") + result = verify_pim_rp_info( + tgen, + None, + "r2", + "224.0.0.0/4", + "r2-eth0", + "10.10.76.1", + "AutoRP", + False, + "ipv4", + True, + ) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + +def test_pim_autorp_announce_cli(request): + "Test PIM AutoRP Announcement CLI commands" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + step("Add AutoRP announcement configuration to r1") + r1 = tgen.routers()["r1"] + r1.vtysh_cmd( + """ + conf + router pim + autorp announce holdtime 90 + autorp announce interval 120 + autorp announce scope 5 + autorp announce 10.2.3.4 225.0.0.0/24 +""" + ) + + expected = { + "discoveryEnabled": True, + "announce": { + "scope": 5, + "interval": 120, + "holdtime": 90, + "rpList": [ + {"rpAddress": "10.2.3.4", "group": "225.0.0.0/24", "prefixList": ""} + ], + }, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip pim autorp json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(r1.name) + assert result is None, assertmsg + + r1.vtysh_cmd( + """ + conf + router pim + autorp announce 10.2.3.4 group-list ListA +""" + ) + expected = { + "discoveryEnabled": True, + "announce": { + "scope": 5, + "interval": 120, + "holdtime": 90, + "rpList": [{"rpAddress": "10.2.3.4", "group": "", "prefixList": "ListA"}], + }, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip pim autorp json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(r1.name) + assert result is None, assertmsg + + +def test_pim_autorp_announce_group(request): + "Test PIM AutoRP Announcement with a single group" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + step("Add candidate RP configuration to r1") + rnode = tgen.routers()["r1"] + rnode.cmd( + "vtysh -c 'conf t' -c 'router pim' -c 'send-rp-announce 10.10.76.1 224.0.0.0/4'" + ) + step("Verify Announcement sent data") + # TODO: Verify AutoRP mapping agent receives candidate RP announcement + # Mapping agent is not yet implemented + # sleep(10) + step("Change AutoRP Announcement packet parameters") + rnode.cmd( + "vtysh -c 'conf t' -c 'router pim' -c 'send-rp-announce scope 8 interval 10 holdtime 60'" + ) + step("Verify Announcement sent data") + # TODO: Verify AutoRP mapping agent receives updated candidate RP announcement + # Mapping agent is not yet implemented + # sleep(10) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/pim_basic_igmp_proxy/r1/frr.conf b/tests/topotests/pim_basic_igmp_proxy/r1/frr.conf new file mode 100644 index 0000000000..72d031e1a3 --- /dev/null +++ b/tests/topotests/pim_basic_igmp_proxy/r1/frr.conf @@ -0,0 +1,29 @@ +hostname r1 +! +interface r1-eth0 + ip address 10.0.20.1/24 + ip igmp + ip pim + ip igmp join 225.1.1.1 + ip igmp join 225.2.2.2 +! +interface r1-eth1 + ip address 10.0.30.1/24 + ip pim + ip igmp + ip igmp proxy +! +interface r1-eth2 + ip address 10.0.40.1/24 + ip igmp + ip pim + ip igmp join 225.3.3.3 + ip igmp join 225.4.4.4 +! +interface lo + ip address 10.254.0.1/32 + ip pim +! +router pim + rp 10.254.0.3 + join-prune-interval 5 diff --git a/tests/topotests/pim_basic_igmp_proxy/r2/frr.conf b/tests/topotests/pim_basic_igmp_proxy/r2/frr.conf new file mode 100644 index 0000000000..08f721ddea --- /dev/null +++ b/tests/topotests/pim_basic_igmp_proxy/r2/frr.conf @@ -0,0 +1,19 @@ +hostname r2 +! +interface r2-eth0 + ip address 10.0.20.2/24 + ip igmp + ip pim + ip igmp proxy +! +interface r2-eth1 + ip address 10.0.80.1/24 + ip igmp + ip pim passive +! +interface lo + ip address 10.254.0.2/32 +! +router pim + rp 10.254.0.3 + join-prune-interval 5 diff --git a/tests/topotests/pim_basic_igmp_proxy/r3/frr.conf b/tests/topotests/pim_basic_igmp_proxy/r3/frr.conf new file mode 100644 index 0000000000..8e58e8c66a --- /dev/null +++ b/tests/topotests/pim_basic_igmp_proxy/r3/frr.conf @@ -0,0 +1,8 @@ +hostname r3 +! +interface r3-eth0 + ip address 10.0.40.4/24 +! +interface lo + ip address 10.254.0.4/32 +! diff --git a/tests/topotests/pim_basic_igmp_proxy/rp/frr.conf b/tests/topotests/pim_basic_igmp_proxy/rp/frr.conf new file mode 100644 index 0000000000..ed60fdd4e7 --- /dev/null +++ b/tests/topotests/pim_basic_igmp_proxy/rp/frr.conf @@ -0,0 +1,16 @@ +hostname rp +! +interface rp-eth0 + ip address 10.0.30.3/24 + ip pim +! +interface lo + ip address 10.254.0.3/32 + ip pim +! +router pim + join-prune-interval 5 + rp 10.254.0.3 + register-accept-list ACCEPT + +ip prefix-list ACCEPT seq 5 permit 10.0.20.0/24 le 32 diff --git a/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py b/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py new file mode 100644 index 0000000000..b6804fa1d8 --- /dev/null +++ b/tests/topotests/pim_basic_igmp_proxy/test_pim_igmp_proxy.py @@ -0,0 +1,319 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_pim_igmp_proxy.py +# +# Copyright (c) 2024 ATCorp +# Barry A. Trent +# + +""" +Following tests are covered to test pim igmp proxy: + +1. TC:1 Verify correct joins were read from the config and proxied +2. TC:2 Verify joins from another interface are proxied +3. TC:3 Verify correct proxy disable on 'no ip igmp proxy' +4. TC:4 Verify that proper proxy joins are set up on run-time enable +5. TC:5 Verify igmp drops/timeouts from another interface cause + proxy join removal +""" + +import os +import sys +import pytest +import json +import time +from functools import partial + +pytestmark = [pytest.mark.pimd] + +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, TopoRouter, get_topogen +from lib.topolog import logger +from lib.pim import verify_local_igmp_proxy_groups + + +def build_topo(tgen): + "Build function" + + for routern in range(1, 4): + tgen.add_router("r{}".format(routern)) + + tgen.add_router("rp") + + # rp ------ r1 -------- r2 ------- + # \ + # --------- r3 + # r1 -> .1 + # r2 -> .2 + # rp -> .3 + # r3 -> .4 + # loopback network is 10.254.0.X/32 + # + # r1 <- sw1 -> r2 + # r1-eth0 <-> r2-eth0 + # 10.0.20.0/24 + sw = tgen.add_switch("sw1") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["r2"]) + + # r1 <- sw2 -> rp + # r1-eth1 <-> rp-eth0 + # 10.0.30.0/24 + sw = tgen.add_switch("sw2") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["rp"]) + + # 10.0.40.0/24 + sw = tgen.add_switch("sw3") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["r3"]) + + # Dummy interface for static joins + tgen.gears["r2"].run("ip link add r2-eth1 type dummy") + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + # For all registered routers, load the zebra configuration file + for rname, router in tgen.routers().items(): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + # tgen.mininet_cli() + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_pim_igmp_proxy_config(): + "Ensure correct joins were read from the config and proxied" + logger.info("Verify initial igmp proxy setup from config file") + tgen = get_topogen() + + r1 = tgen.gears["r1"] + + expected = { + "vrf": "default", + "r1-eth1": { + "name": "r1-eth1", + "groups": [ + { + "source": "*", + "group": "225.4.4.4", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.3.3.3", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.2.2.2", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.1.1.1", + "primaryAddr": "10.0.30.1", + }, + ], + }, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp proxy json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(r1.name) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_pim_igmp_proxy_learn(): + "Ensure joins learned from a neighbor are propagated" + logger.info("Verify joins can be learned") + tgen = get_topogen() + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + r2.vtysh_cmd( + "conf\nint r2-eth0\nip igmp join 225.5.5.5\nip igmp join 225.6.6.6\nexit\nexit" + ) + r2.vtysh_cmd( + "conf\nint r2-eth1\nip igmp join 225.7.7.7\nip igmp join 225.8.8.8\nexit\nexit" + ) + expected = { + "vrf": "default", + "r1-eth1": { + "name": "r1-eth1", + "groups": [ + { + "source": "*", + "group": "225.5.5.5", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.6.6.6", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.7.7.7", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.8.8.8", + "primaryAddr": "10.0.30.1", + }, + ], + }, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp proxy json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(r1.name) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_pim_no_igmp_proxy(): + "Check for correct proxy disable" + logger.info("Verify no ip igmp proxy") + tgen = get_topogen() + + r1 = tgen.gears["r1"] + + r1.vtysh_cmd("conf\nint r1-eth1\nno ip igmp proxy\nexit\nexit") + expected = {"vrf": "default"} + + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp proxy json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(r1.name) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_pim_igmp_proxy_restart(): + "Check that all proxy joins are captured at run-time enable" + logger.info("Verify runtime ip igmp proxy") + tgen = get_topogen() + + r1 = tgen.gears["r1"] + + r1.vtysh_cmd("conf\nint r1-eth1\nip igmp proxy\nexit\nexit") + expected = { + "vrf": "default", + "r1-eth1": { + "name": "r1-eth1", + "groups": [ + { + "source": "*", + "group": "225.8.8.8", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.7.7.7", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.6.6.6", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.5.5.5", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.4.4.4", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.3.3.3", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.2.2.2", + "primaryAddr": "10.0.30.1", + }, + { + "source": "*", + "group": "225.1.1.1", + "primaryAddr": "10.0.30.1", + }, + ], + }, + } + + test_func = partial( + topotest.router_json_cmp, r1, "show ip igmp proxy json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(r1.name) + assert result is None, assertmsg + # tgen.mininet_cli() + + +def test_pim_igmp_proxy_leave(): + "Ensure drops/timeouts learned from a neighbor are propagated" + logger.info("Verify joins can be dropped") + tgen = get_topogen() + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + r1.vtysh_cmd("conf\nint r1-eth0\nno ip igmp join 225.1.1.1\nexit\nexit") + r2.vtysh_cmd("conf\nint r2-eth0\nno ip igmp join 225.6.6.6\nexit\nexit") + r2.vtysh_cmd("conf\nint r2-eth1\nno ip igmp join 225.8.8.8\nexit\nexit") + + joined_addresses = ["225.2.2.2", "225.3.3.3", "225.4.4.4", "225.5.5.5", "225.7.7.7"] + deleted_addresses = ["225.1.1.1", "225.6.6.6", "225.8.8.8"] + + result = verify_local_igmp_proxy_groups( + tgen, "r1", joined_addresses, deleted_addresses + ) + + assert result is True, "Error: {}".format(result) + # tgen.mininet_cli() + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/pim_cand_rp_bsr/__init__.py b/tests/topotests/pim_cand_rp_bsr/__init__.py new file mode 100755 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/__init__.py diff --git a/tests/topotests/pim_cand_rp_bsr/r1/frr.conf b/tests/topotests/pim_cand_rp_bsr/r1/frr.conf new file mode 100644 index 0000000000..d0aa3d529f --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r1/frr.conf @@ -0,0 +1,25 @@ +! +hostname r1 +password zebra +log file /tmp/r1-frr.log +! +!debug pim packet +!debug pim bsm +! +ip route 0.0.0.0/0 10.0.0.4 +! +interface r1-eth0 + ip address 10.0.0.1/24 + ip igmp + ip pim +! +interface r1-eth1 + ip address 10.0.1.1/24 + ip igmp + ip pim +! +router pim + bsr candidate-bsr priority 200 source address 10.0.0.1 +! +ip forwarding +! diff --git a/tests/topotests/pim_cand_rp_bsr/r2/frr.conf b/tests/topotests/pim_cand_rp_bsr/r2/frr.conf new file mode 100644 index 0000000000..741c839f19 --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r2/frr.conf @@ -0,0 +1,22 @@ +! +hostname r2 +password zebra +log file /tmp/r2-frr.log +! +ip route 0.0.0.0/0 10.0.0.4 +! +interface r2-eth0 + ip address 10.0.0.2/24 + ip igmp + ip pim +! +interface r2-eth1 + ip address 10.0.2.2/24 + ip igmp + ip pim +! +router pim + bsr candidate-bsr priority 100 source address 10.0.0.2 +! +ip forwarding +! diff --git a/tests/topotests/pim_cand_rp_bsr/r3/frr.conf b/tests/topotests/pim_cand_rp_bsr/r3/frr.conf new file mode 100644 index 0000000000..bd5c8ce93f --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r3/frr.conf @@ -0,0 +1,32 @@ +! +hostname r3 +password zebra +log file /tmp/r3-frr.log +! +!debug pim packet +!debug pim bsm +! +ip route 0.0.0.0/0 10.0.3.4 +ip route 10.0.6.0/24 10.0.3.6 +! +interface r3-eth0 + ip address 10.0.1.3/24 + ip igmp + ip pim +! +interface r3-eth1 + ip address 10.0.3.3/24 + ip igmp + ip pim +! +interface r3-eth2 + ip address 10.0.4.3/24 + ip igmp + ip pim +! +router pim + bsr candidate-rp group 239.0.0.0/16 + bsr candidate-rp priority 10 source address 10.0.3.3 +! +ip forwarding +! diff --git a/tests/topotests/pim_cand_rp_bsr/r4/frr.conf b/tests/topotests/pim_cand_rp_bsr/r4/frr.conf new file mode 100644 index 0000000000..825b227728 --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r4/frr.conf @@ -0,0 +1,37 @@ +! +hostname r4 +password zebra +log file /tmp/r4-frr.log +! +ip route 10.0.1.0/24 10.0.0.1 +ip route 10.0.4.0/24 10.0.3.3 +ip route 10.0.6.0/24 10.0.3.6 +! +interface r4-eth0 + ip address 10.0.2.4/24 + ip igmp + ip pim +! +interface r4-eth1 + ip address 10.0.3.4/24 + ip igmp + ip pim +! +interface r4-eth2 + ip address 10.0.5.4/24 + ip igmp + ip pim +! +interface r4-eth3 + ip address 10.0.0.4/24 + ip igmp + ip pim +! +router pim + bsr candidate-rp group 239.0.0.0/24 + bsr candidate-rp group 239.0.0.0/16 + bsr candidate-rp group 239.0.0.0/8 + bsr candidate-rp priority 20 source address 10.0.3.4 +! +ip forwarding +! diff --git a/tests/topotests/pim_cand_rp_bsr/r5/frr.conf b/tests/topotests/pim_cand_rp_bsr/r5/frr.conf new file mode 100644 index 0000000000..c934717d08 --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r5/frr.conf @@ -0,0 +1,17 @@ +! +hostname r5 +password zebra +log file /tmp/r5-frr.log +! +ip route 0.0.0.0/0 10.0.4.3 +! +interface r5-eth0 + ip address 10.0.4.5/24 + ip igmp + ip pim +! +interface r5-eth1 + ip address 10.0.6.5/24 +! +ip forwarding +! diff --git a/tests/topotests/pim_cand_rp_bsr/r6/frr.conf b/tests/topotests/pim_cand_rp_bsr/r6/frr.conf new file mode 100644 index 0000000000..fd9d1eb5c4 --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/r6/frr.conf @@ -0,0 +1,22 @@ +! +hostname r6 +password zebra +log file /tmp/r6-frr.log +! +ip route 0.0.0.0/0 10.0.6.6 +! +interface r6-eth0 + ip address 10.0.5.6/24 + ip igmp + ip pim +! +interface r6-eth1 + ip address 10.0.6.6/24 +! +interface r6-eth2 + ip address 10.0.3.6/24 + ip igmp + ip pim +! +ip forwarding +! diff --git a/tests/topotests/pim_cand_rp_bsr/test_pim_cand_rp_bsr.py b/tests/topotests/pim_cand_rp_bsr/test_pim_cand_rp_bsr.py new file mode 100644 index 0000000000..ce7bc9dc56 --- /dev/null +++ b/tests/topotests/pim_cand_rp_bsr/test_pim_cand_rp_bsr.py @@ -0,0 +1,324 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_pim_cand_rp_bsr.py +# +# Copyright (c) 2024 ATCorp +# Jafar Al-Gharaibeh +# + +import os +import sys +import pytest +import json +from functools import partial + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger +from lib.pim import verify_pim_rp_info +from lib.common_config import step, write_test_header, retry + +from time import sleep + +""" +test_pim_cand_rp_bsr.py: Test candidate RP/BSR functionality +""" + +TOPOLOGY = """ + Candidate RP/BSR functionality + + +---+---+ +---+---+ + | C-BSR | 10.0.0.0/24 | C-BSR | + + R1 + <--------+---------> + R2 | + |elected| .1 | .2 | | + +---+---+ | +---+---+ + .1 | | 10.0.2.0/24 | .2 + | 10.0.1.0/24 | | + .3 | +-----| .4 | .4 + +---+---+ |---->+---+---+ + | C-RP | 10.0.3.0/24 | C-RP | + + R3 + <--------+---------> + R4 | + | prio | .3 | .4 | | + +---+---+ | +---+---+ + .3 | | | .4 + |10.0.4.0/24 | 10.0.5.0/24| + .5 | | .6 | .6 + +---+---+ +---------->+---+---+ + | | | | + + R5 + <------------------> + R6 | + | | .5 .6 | | + +---+---+ 10.0.6.0/24 +---+---+ +""" + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# Required to instantiate the topology builder class. +pytestmark = [pytest.mark.pimd] + + +def build_topo(tgen): + "Build function" + + # Create 6 routers + for rn in range(1, 7): + tgen.add_router("r{}".format(rn)) + + # Create 7 switches and connect routers + sw1 = tgen.add_switch("s1") + sw1.add_link(tgen.gears["r1"]) + sw1.add_link(tgen.gears["r2"]) + + sw = tgen.add_switch("s2") + sw.add_link(tgen.gears["r1"]) + sw.add_link(tgen.gears["r3"]) + + sw = tgen.add_switch("s3") + sw.add_link(tgen.gears["r2"]) + sw.add_link(tgen.gears["r4"]) + + sw3 = tgen.add_switch("s4") + sw3.add_link(tgen.gears["r3"]) + sw3.add_link(tgen.gears["r4"]) + + sw = tgen.add_switch("s5") + sw.add_link(tgen.gears["r3"]) + sw.add_link(tgen.gears["r5"]) + + sw = tgen.add_switch("s6") + sw.add_link(tgen.gears["r4"]) + sw.add_link(tgen.gears["r6"]) + + sw = tgen.add_switch("s7") + sw.add_link(tgen.gears["r5"]) + sw.add_link(tgen.gears["r6"]) + + # make the diagnoal connections + sw1.add_link(tgen.gears["r4"]) + sw3.add_link(tgen.gears["r6"]) + +def setup_module(mod): + logger.info("PIM Candidate RP/BSR:\n {}".format(TOPOLOGY)) + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + logger.info("Loading router %s" % rname) + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + # Initialize all routers. + tgen.start_router() + for router in router_list.values(): + if router.has_version("<", "4.0"): + tgen.set_error("unsupported version") + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + +def test_pim_bsr_election_r1(request): + "Test PIM BSR Election" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + r2 = tgen.gears["r2"] + # r1 should be the BSR winner because it has higher priority + expected = { + "bsr":"10.0.0.1", + "priority":200, + "state":"ACCEPT_PREFERRED", + } + + test_func = partial( + topotest.router_json_cmp, r2, "show ip pim bsr json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + + assertmsg = "r2: r1 was not elected, bsr election mismatch" + assert result is None, assertmsg + +def test_pim_bsr_cand_bsr_r1(request): + "Test PIM BSR candidate BSR" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + r2 = tgen.gears["r2"] + + # r2 is a candidate bsr with low priority: elected = False + expected = { + "address": "10.0.0.2", + "priority": 100, + "elected": False + } + test_func = partial( + topotest.router_json_cmp, r2, "show ip pim bsr candidate-bsr json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + + assertmsg = "r2: candidate bsr mismatch " + assert result is None, assertmsg + +def test_pim_bsr_cand_rp(request): + "Test PIM BSR candidate RP" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + r3 = tgen.gears["r3"] + + # r3 is a candidate rp + expected = { + "address":"10.0.3.3", + "priority":10 + } + test_func = partial( + topotest.router_json_cmp, r3, "show ip pim bsr candidate-rp json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + + assertmsg = "r3: bsr candidate rp mismatch" + assert result is None, assertmsg + + +def test_pim_bsr_rp_info(request): + "Test RP info state" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + # At this point, all nodes, including r5 should have synced the RP state + step("Verify rp-info on r5 from BSR") + result = verify_pim_rp_info(tgen, None, "r5", "239.0.0.0/16", None, "10.0.3.3", + "BSR", False, "ipv4", True, retry_timeout = 90) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + result = verify_pim_rp_info(tgen, None, "r5", "239.0.0.0/8", None, "10.0.3.4", + "BSR", False, "ipv4", True, retry_timeout = 30) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + result = verify_pim_rp_info(tgen, None, "r5", "239.0.0.0/24", None, "10.0.3.4", + "BSR", False, "ipv4", True, retry_timeout = 30) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify rp-info on the BSR node itself r1") + result = verify_pim_rp_info(tgen, None, "r1", "239.0.0.0/16", None, "10.0.3.3", + "BSR", False, "ipv4", True, retry_timeout = 10) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + result = verify_pim_rp_info(tgen, None, "r1", "239.0.0.0/8", None, "10.0.3.4", + "BSR", False, "ipv4", True, retry_timeout = 10) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + result = verify_pim_rp_info(tgen, None, "r1", "239.0.0.0/24", None, "10.0.3.4", + "BSR", False, "ipv4", True, retry_timeout = 10) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + +def test_pim_bsr_election_fallback_r2(request): + "Test PIM BSR Election Backup" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + step("Take r1 out from BSR candidates") + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ + configure + router pim + no bsr candidate-bsr priority 200 source address 10.0.0.1 + """) + + step("Verify r1 is no longer a BSR candidate") + expected = {} + + test_func = partial( + topotest.router_json_cmp, r1, "show ip pim bsr candidate-bsr json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=1) + + assertmsg = "r1: failed to remove bsr candidate configuration" + assert result is None, assertmsg + + r2 = tgen.gears["r2"] + # We should fall back to r2 as the BSR + expected = { + "bsr":"10.0.0.2", + "priority":100, + "state":"BSR_ELECTED", + } + + step("Verify that we fallback to r2 as the new BSR") + + test_func = partial( + topotest.router_json_cmp, r2, "show ip pim bsr json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=180, wait=1) + + assertmsg = "r2: failed to fallback to r2 as a BSR" + assert result is None, assertmsg + + +def test_pim_bsr_rp_info_fallback(request): + "Test RP info state on r5" + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + if tgen.routers_have_failure(): + pytest.skip("skipped because of router(s) failure") + + step("Take r3 out from RP candidates for group 239.0.0.0/16") + r3 = tgen.gears["r3"] + r3.vtysh_cmd( + """ + configure + router pim + no bsr candidate-rp group 239.0.0.0/16 + """) + + step("Verify falling back to r4 as the new RP for 239.0.0.0/16") + + result = verify_pim_rp_info(tgen, None, "r5", "239.0.0.0/16", None, "10.0.3.4", + "BSR", False, "ipv4", True, retry_timeout = 30) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/srv6_encap_src_addr/r1/zebra.conf b/tests/topotests/srv6_encap_src_addr/r1/zebra.conf index c570756b52..c245dd2d96 100644 --- a/tests/topotests/srv6_encap_src_addr/r1/zebra.conf +++ b/tests/topotests/srv6_encap_src_addr/r1/zebra.conf @@ -4,7 +4,6 @@ hostname r1 ! debug zebra rib detailed ! log stdout notifications -log monitor notifications log commands log file zebra.log debugging ! diff --git a/tests/topotests/srv6_sid_manager/rt1/bgpd.conf b/tests/topotests/srv6_sid_manager/rt1/bgpd.conf index 461e9023f0..20c396afde 100644 --- a/tests/topotests/srv6_sid_manager/rt1/bgpd.conf +++ b/tests/topotests/srv6_sid_manager/rt1/bgpd.conf @@ -6,7 +6,6 @@ hostname rt1 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/srv6_sid_manager/rt6/bgpd.conf b/tests/topotests/srv6_sid_manager/rt6/bgpd.conf index fe82feece4..c36fae7901 100644 --- a/tests/topotests/srv6_sid_manager/rt6/bgpd.conf +++ b/tests/topotests/srv6_sid_manager/rt6/bgpd.conf @@ -6,7 +6,6 @@ hostname rt6 password zebra ! log stdout notifications -log monitor notifications log commands ! !debug bgp neighbor-events diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index 93296cd51a..c0a79ed79d 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -153,7 +153,7 @@ def test_zebra_kernel_admin_distance(): # metric. That needs to be properly resolved. Making a note for # coming back around later and fixing this. # tgen.mininet_cli() - for i in range(1, 2): + for i in range(1, 3): json_file = "{}/r1/v4_route_{}.json".format(CWD, i) expected = json.loads(open(json_file).read()) diff --git a/tests/topotests/zebra_seg6local_route/r1/routes.json b/tests/topotests/zebra_seg6local_route/r1/routes.json index e391922566..7dcc6450fa 100644 --- a/tests/topotests/zebra_seg6local_route/r1/routes.json +++ b/tests/topotests/zebra_seg6local_route/r1/routes.json @@ -119,5 +119,78 @@ }] }], "required_kernel": "5.14" + }, + { + "in": { + "dest": "6::1", + "context": "End_DX6 2001::1" + }, + "out":[{ + "prefix":"6::1/128", + "protocol":"sharp", + "selected":true, + "destSelected":true, + "distance":150, + "metric":0, + "installed":true, + "table":254, + "nexthops":[{ + "flags":3, + "fib":true, + "active":true, + "directlyConnected":true, + "interfaceName": "dum0", + "seg6local": { "action": "End.DX6" } + }] + }] + }, + { + "in": { + "dest": "7::1", + "context": "End_DT4 10" + }, + "out":[{ + "prefix":"7::1/128", + "protocol":"sharp", + "selected":true, + "destSelected":true, + "distance":150, + "metric":0, + "installed":true, + "table":254, + "nexthops":[{ + "flags":3, + "fib":true, + "active":true, + "directlyConnected":true, + "interfaceName": "dum0", + "seg6local": { "action": "End.DT4" } + }] + }], + "required_kernel": "5.11" + }, + { + "in": { + "dest": "8::1", + "context": "End_DT6 10" + }, + "out":[{ + "prefix":"8::1/128", + "protocol":"sharp", + "selected":true, + "destSelected":true, + "distance":150, + "metric":0, + "installed":true, + "table":254, + "nexthops":[{ + "flags":3, + "fib":true, + "active":true, + "directlyConnected":true, + "interfaceName": "dum0", + "seg6local": { "action": "End.DT6" } + }] + }] } ] diff --git a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py index a90f5c9c98..59c681df48 100755 --- a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py +++ b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py @@ -42,7 +42,7 @@ def setup_module(mod): tgen = Topogen({None: "r1"}, mod.__name__) tgen.start_topology() router_list = tgen.routers() - for rname, router in tgen.routers().items(): + for rname, router in router_list.items(): router.run( "/bin/bash {}".format(os.path.join(CWD, "{}/setup.sh".format(rname))) ) diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 9dae348b8e..53bb6513e2 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -1140,14 +1140,14 @@ def pim_delete_move_lines(lines_to_add, lines_to_del): # they are implicitly deleted by 'no ip pim'. # Remove all such depdendent options from delete # pending list. - pim_disable = False + pim_disable = [] lines_to_del_to_del = [] index = -1 for ctx_keys, line in lines_to_del: index = index + 1 if ctx_keys[0].startswith("interface") and line and line == "ip pim": - pim_disable = True + pim_disable.append(ctx_keys[0]) # no ip msdp peer <> does not accept source so strip it off. if line and line.startswith("ip msdp peer "): @@ -1158,14 +1158,14 @@ def pim_delete_move_lines(lines_to_add, lines_to_del): lines_to_del.remove((ctx_keys, line)) lines_to_del.insert(index, (ctx_keys, new_line)) - if pim_disable: - for ctx_keys, line in lines_to_del: - if ( - ctx_keys[0].startswith("interface") - and line - and (line.startswith("ip pim ") or line.startswith("ip multicast ")) - ): - lines_to_del_to_del.append((ctx_keys, line)) + for ctx_keys, line in lines_to_del: + if ( + ctx_keys[0] in pim_disable + and ctx_keys[0].startswith("interface") + and line + and (line.startswith("ip pim ") or line.startswith("ip multicast ")) + ): + lines_to_del_to_del.append((ctx_keys, line)) for ctx_keys, line in lines_to_del_to_del: lines_to_del.remove((ctx_keys, line)) diff --git a/yang/frr-bgp-common.yang b/yang/frr-bgp-common.yang index 2b1babdd28..9d21597304 100644 --- a/yang/frr-bgp-common.yang +++ b/yang/frr-bgp-common.yang @@ -320,6 +320,19 @@ submodule frr-bgp-common { When set to 'false' BGP instance type is regular."; } + leaf as-notation { + type enumeration { + enum "plain" { value 0; } + enum "dot" { value 1; } + enum "dot+" { value 2; } + } + description + "The as-notation type: + - plain: use plain format for all AS values + - dot: use 'AA.BB' format for AS 4 byte values. + - dot+: use 'AA.BB' format for all AS values."; + } + leaf ebgp-multihop-connected-route-check { type boolean; default "false"; diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index abfb14c23c..44058ab04e 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -847,7 +847,7 @@ identity set-extcommunity-color { } case extcommunity-nt { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-nt')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-nt')"; description "Value of the ext-community"; leaf extcommunity-nt { @@ -1008,7 +1008,7 @@ identity set-extcommunity-color { } case aigp-metric { - when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:aigp-metric')"; + when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:aigp-metric')"; leaf aigp-metric { type string; description @@ -1127,16 +1127,14 @@ identity set-extcommunity-color { case comm-list-name { when "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:comm-list-delete') or " + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:large-comm-list-delete') or " - + "derived-from-or-self(../frr-route-map:action, -'frr-bgp-route-map:extended-comm-list-delete')"; + + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:extended-comm-list-delete')"; leaf comm-list-name { type bgp-filter:bgp-list-name; } } case evpn-gateway-ip-ipv4 { when - "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, - 'frr-bgp-route-map:set-evpn-gateway-ip-ipv4')"; + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-evpn-gateway-ip-ipv4')"; description "Set EVPN gateway IP overlay index IPv4"; leaf evpn-gateway-ip-ipv4 { @@ -1145,8 +1143,7 @@ identity set-extcommunity-color { } case evpn-gateway-ip-ipv6 { when - "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, - 'frr-bgp-route-map:set-evpn-gateway-ip-ipv6')"; + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-evpn-gateway-ip-ipv6')"; description "Set EVPN gateway IP overlay index IPv6"; leaf evpn-gateway-ip-ipv6 { @@ -1155,8 +1152,7 @@ identity set-extcommunity-color { } case l3vpn-nexthop-encapsulation { when - "derived-from-or-self(../frr-route-map:action, - 'frr-bgp-route-map:set-l3vpn-nexthop-encapsulation')"; + "derived-from-or-self(../frr-route-map:action, 'frr-bgp-route-map:set-l3vpn-nexthop-encapsulation')"; description "Accept L3VPN traffic over other than LSP encapsulation"; leaf l3vpn-nexthop-encapsulation { diff --git a/yang/frr-gmp.yang b/yang/frr-gmp.yang index e6a1f7f640..5636010d91 100644 --- a/yang/frr-gmp.yang +++ b/yang/frr-gmp.yang @@ -146,6 +146,13 @@ module frr-gmp { "Querier's Robustness Variable allows tuning for the expected packet loss on a network."; } + + leaf proxy { + type boolean; + default "false"; + description + "Enable IGMP proxy on the interface."; + } list join-group { key "group-addr source-addr"; diff --git a/yang/frr-pim-candidate.yang b/yang/frr-pim-candidate.yang new file mode 100644 index 0000000000..09d0a06353 --- /dev/null +++ b/yang/frr-pim-candidate.yang @@ -0,0 +1,174 @@ +module frr-pim-candidate { + yang-version "1.1"; + namespace "http://frrouting.org/yang/pim-candidate"; + + prefix frr-pim-candidate; + + import frr-interface { + prefix frr-interface; + } + + import ietf-inet-types { + prefix "inet"; + } + + import frr-routing { + prefix "frr-rt"; + } + + import frr-pim { + prefix "frr-pim"; + } + + import frr-route-types { + prefix frr-route-types; + } + + organization + "FRRouting"; + + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + + description + "The module defines a collection of YANG definitions common for + all PIM (Protocol Independent Multicast) Candidate RP & BSR + (Rendezvous Point & Bootstrap Router) operation. + + Copyright 2020 FRRouting + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."; + + revision 2021-05-04 { + description + "Initial revision."; + reference + "TBD"; + } + + /* + * Groupings + */ + grouping candidate-bsr-container { + description + "Grouping of Candidate BSR settings."; + + container candidate-bsr { + presence + "Enable router to be a Candidate BSR."; + + description + "Candidate BSR settings"; + + leaf bsr-priority { + type uint8; + default "64"; + description + "BSR priority for this router, higher values win."; + } + + choice source-address-or-interface { + description "IP address to use for BSR operation"; + default if-loopback; + leaf address { + type inet:ip-address; + } + leaf interface { + type frr-interface:interface-ref; + } + leaf if-loopback { + type empty; + } + leaf if-any { + type empty; + } + } + } // candidate-bsr + } // candidate-bsr-container + + grouping candidate-rp-container { + description + "Grouping of Candidate RP settings."; + + container candidate-rp { + presence + "Enable router to be a Candidate RP."; + + description + "Candidate RP settings"; + + leaf rp-priority { + type uint8; + default "192"; + description + "RP priority for this router, lower values win."; + } + + leaf advertisement-interval { + type uint32 { + range 1..4294967295; + } + default "60"; + description + "RP advertisement interval (seconds). Holdtime is 2.5 times this."; + } + + leaf-list group-list { + type frr-route-types:ip-multicast-group-prefix; + description + "List of multicast group address."; + } + + choice source-address-or-interface { + description "IP address to use for RP operation"; + default if-loopback; + leaf address { + type inet:ip-address; + } + leaf interface { + type frr-interface:interface-ref; + } + leaf if-loopback { + type empty; + } + leaf if-any { + type empty; + } + } + } + } + + /* + * Configuration data nodes + */ + augment "/frr-rt:routing/frr-rt:control-plane-protocols/" + + "frr-rt:control-plane-protocol/frr-pim:pim/" + + "frr-pim:address-family" { + description "PIM Candidate RP augmentation."; + + uses candidate-bsr-container; + uses candidate-rp-container; + } +} diff --git a/yang/frr-pim-rp.yang b/yang/frr-pim-rp.yang index 4cc214135d..dbd5513ee5 100644 --- a/yang/frr-pim-rp.yang +++ b/yang/frr-pim-rp.yang @@ -111,6 +111,70 @@ module frr-pim-rp { } // static-rp } // static-rp-container + grouping auto-rp-container { + description + "Grouping of AutoRP container."; + + container auto-rp { + description + "Containing AutoRP attributes."; + + leaf discovery-enabled { + type boolean; + description + "Flag indicating if Auto RP discovery is enabled."; + } + + leaf announce-scope { + type uint8; + description + "The TTL of the C-RP Announcement packet."; + } + + leaf announce-interval { + type uint16; + description + "The time between sending C-RP announcement packets."; + } + + leaf announce-holdtime { + type uint16; + description + "The hold time in seconds advertised in the announcement packet."; + } + + list candidate-rp-list { + key "rp-address"; + description + "A list of Candidate RP addresses."; + + leaf rp-address { + type inet:ip-address; + description + "Specifies a candidate RP address."; + } + + choice group-or-prefix-list { + description "Use group or prefix-list"; + case group { + leaf group { + type frr-route-types:ip-multicast-group-prefix; + description + "Multicast group prefix."; + } + } + case prefix-list { + leaf prefix-list { + type plist-ref; + description + "Group prefix-list filter"; + } + } + } + } // candidate-rp-list + } // auto-rp + } // auto-rp-container + /* * Configuration data nodes */ @@ -123,6 +187,13 @@ module frr-pim-rp { description "PIM RP configuration data."; uses static-rp-container; + + uses auto-rp-container { + when "../frr-pim:address-family = 'frr-rt:ipv4'" { + description + "Only applicable to IPv4 address family."; + } + } } // rp } // augment } diff --git a/yang/subdir.am b/yang/subdir.am index 71aa040878..786bd0bca6 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -80,6 +80,7 @@ if PIMD dist_yangmodels_DATA += yang/frr-gmp.yang dist_yangmodels_DATA += yang/frr-pim.yang dist_yangmodels_DATA += yang/frr-pim-rp.yang +dist_yangmodels_DATA += yang/frr-pim-candidate.yang endif if BGPD diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 1d2f9e695f..d594fc2c86 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -1336,7 +1336,7 @@ static void fpm_enqueue_l3vni_table(struct hash_bucket *bucket, void *arg) struct zebra_l3vni *zl3vni = bucket->data; fra->zl3vni = zl3vni; - hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, zl3vni); + hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, fra); } static void fpm_rmac_send(struct event *t) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 3233519873..5fb908eb0d 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1799,14 +1799,18 @@ int netlink_tunneldump_read(struct zebra_ns *zns) ret = netlink_request_tunneldump(zns, PF_BRIDGE, tmp_if->ifindex); - if (ret < 0) + if (ret < 0) { + route_unlock_node(rn); return ret; + } ret = netlink_parse_info(netlink_link_change, netlink_cmd, &dp_info, 0, true); - if (ret < 0) + if (ret < 0) { + route_unlock_node(rn); return ret; + } } return 0; diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index d2f1db67ee..84aabc4254 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -672,21 +672,6 @@ void netlink_parse_rtattr_nested(struct rtattr **tb, int max, netlink_parse_rtattr(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta)); } -bool nl_addraw_l(struct nlmsghdr *n, unsigned int maxlen, const void *data, - unsigned int len) -{ - if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { - zlog_err("ERROR message exceeded bound of %d", maxlen); - return false; - } - - memcpy(NLMSG_TAIL(n), data, len); - memset((uint8_t *)NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); - - return true; -} - bool nl_attr_put(struct nlmsghdr *n, unsigned int maxlen, int type, const void *data, unsigned int alen) { diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index e37bba0cf6..9db4e5789a 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -77,14 +77,6 @@ extern void netlink_parse_rtattr_flags(struct rtattr **tb, int max, unsigned short flags); extern void netlink_parse_rtattr_nested(struct rtattr **tb, int max, struct rtattr *rta); -/* - * nl_addraw_l copies raw form the netlink message buffer into netlink - * message header pointer. It ensures the aligned data buffer does not - * override past max length. - * return value is 0 if its successful - */ -extern bool nl_addraw_l(struct nlmsghdr *n, unsigned int maxlen, - const void *data, unsigned int len); extern const char *nl_msg_type_to_str(uint16_t msg_type); extern const char *nl_rtproto_to_str(uint8_t rtproto); extern const char *nl_family_to_str(uint8_t family); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index ddcb83cd8c..75e4396e92 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1688,7 +1688,7 @@ static bool _netlink_route_build_singlepath(const struct prefix *p, return false; if (!nl_attr_put(nlmsg, req_size, SEG6_LOCAL_NH6, &ctx->nh6, - sizeof(struct in_addr))) + sizeof(struct in6_addr))) return false; break; case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: @@ -2979,7 +2979,7 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd, if (!nl_attr_put(&req->n, buflen, SEG6_LOCAL_NH6, &ctx->nh6, - sizeof(struct in_addr))) + sizeof(struct in6_addr))) return 0; break; case SEG6_LOCAL_ACTION_END_DT6: diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index ebb5a42298..a733b5917f 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -663,6 +663,7 @@ static int zebra_evpn_map_vlan_ns(struct ns *ns, vni_id = zebra_vxlan_if_access_vlan_vni_find(zif, br_if); if (vni_id) { found = 1; + route_unlock_node(rn); break; } } @@ -757,6 +758,7 @@ static int zebra_evpn_from_svi_ns(struct ns *ns, zebra_vxlan_if_access_vlan_vni_find(zif, br_if); if (vni_id) { found = 1; + route_unlock_node(rn); break; } } @@ -842,6 +844,7 @@ static int zvni_map_to_macvlan_ns(struct ns *ns, void *_in_param, void **_p_ifp) if (zif->link == in_param->svi_if) { *p_ifp = tmp_if; + route_unlock_node(rn); return NS_WALK_STOP; } } diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index bfc060db61..0d53591336 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -47,9 +47,9 @@ uint32_t num_valid_macs(struct zebra_evpn *zevpn) for (i = 0; i < hash->size; i++) { for (hb = hash->index[i]; hb; hb = hb->next) { mac = (struct zebra_mac *)hb->data; - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - || CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) - || !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) || + !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) num_macs++; } } @@ -103,7 +103,8 @@ static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)", - zmac->zevpn->vni, &zmac->macaddr, ifp->name, ifp->ifindex); + zmac->zevpn->vni, &zmac->macaddr, ifp->name, + ifp->ifindex); zif = ifp->info; list_delete_node(zif->mac_list, &zmac->ifp_listnode); @@ -117,16 +118,17 @@ void zebra_evpn_mac_ifp_del(struct interface *ifp) struct listnode *node; struct zebra_mac *zmac; - if (zif->mac_list) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug("MAC list deleted for ifp %s (%u)", - zif->ifp->name, zif->ifp->ifindex); + if (!zif->mac_list) + return; - for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) { - zebra_evpn_mac_ifp_unlink(zmac); - } - list_delete(&zif->mac_list); - } + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug("MAC list deleted for ifp %s (%u)", zif->ifp->name, + zif->ifp->ifindex); + + for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) + zebra_evpn_mac_ifp_unlink(zmac); + + list_delete(&zif->mac_list); } /* Link local mac to destination access port. This is done only if the @@ -159,7 +161,8 @@ static void zebra_evpn_mac_ifp_link(struct zebra_mac *zmac, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)", - zmac->zevpn->vni, &zmac->macaddr, ifp->name, ifp->ifindex); + zmac->zevpn->vni, &zmac->macaddr, ifp->name, + ifp->ifindex); zmac->ifp = ifp; listnode_init(&zmac->ifp_listnode, zmac); @@ -201,7 +204,7 @@ int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac, return -1; sticky = !!CHECK_FLAG(mac->flags, - (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); + (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); /* If nexthop group for the FDB entry is inactive (not programmed in * the dataplane) the MAC entry cannot be installed @@ -245,14 +248,14 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn, enum zebra_dplane_result res; /* If the MAC was not installed there is no need to uninstall it */ - if (!force && mac->es && !CHECK_FLAG(mac->es->flags, ZEBRA_EVPNES_NHG_ACTIVE)) + if (!force && mac->es && + !CHECK_FLAG(mac->es->flags, ZEBRA_EVPNES_NHG_ACTIVE)) return -1; if (!zevpn->vxlan_if) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "VNI %u hash %p couldn't be uninstalled - no intf", - zevpn->vni, zevpn); + zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", + zevpn->vni, zevpn); return -1; } @@ -278,7 +281,8 @@ int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn, ifp = zevpn->vxlan_if; vtep_ip = mac->fwd_info.r_vtep_ip; - res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni, vtep_ip); + res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vni->vni, + vtep_ip); if (res != ZEBRA_DPLANE_REQUEST_FAILURE) return 0; else @@ -297,9 +301,9 @@ void zebra_evpn_deref_ip2mac(struct zebra_evpn *zevpn, struct zebra_mac *mac) /* If all remote neighbors referencing a remote MAC go away, * we need to uninstall the MAC. */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - && remote_neigh_count(mac) == 0) { - zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && + remote_neigh_count(mac) == 0) { + zebra_evpn_rem_mac_uninstall(zevpn, mac, false); zebra_evpn_es_mac_deref_entry(mac); UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); } @@ -336,7 +340,8 @@ static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac, *vid = mac->fwd_info.local.vid; zns = zebra_ns_lookup(mac->fwd_info.local.ns_id); - *p_ifp = if_lookup_by_index_per_ns(zns, mac->fwd_info.local.ifindex); + *p_ifp = if_lookup_by_index_per_ns(zns, + mac->fwd_info.local.ifindex); } } @@ -350,18 +355,26 @@ static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac *mac, char *buf, } snprintfrr(buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s", - CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ? "LOC " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ? "REM " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) ? "AUTO " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? "STICKY " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) ? "Default GW " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "PEER Active " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "", - CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) ? "LOC Inactive " : ""); + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ? "LOC " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ? "REM " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) ? "AUTO " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? "STICKY " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router " + : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) ? "Default GW " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) + ? "REM DEF GW " + : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) + ? "PEER Active " + : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " + : "", + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE) + ? "LOC Inactive " + : ""); return buf; } @@ -391,11 +404,11 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired", - __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), - mac->dad_count, listcount(mac->neigh_list)); + zlog_debug("%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired", + __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + mac->dad_count, listcount(mac->neigh_list)); } /* Remove all IPs as duplicate associcated with this MAC */ @@ -404,7 +417,7 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) ZEBRA_NEIGH_SET_INACTIVE(nbr); else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) - zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/); + zebra_evpn_rem_neigh_install(zevpn, nbr, false); } UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); @@ -423,11 +436,12 @@ static void zebra_evpn_dad_mac_auto_recovery_exp(struct event *t) if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { /* Inform to BGP */ if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr, - mac->flags, mac->loc_seq, mac->es)) + mac->flags, mac->loc_seq, + mac->es)) return; /* Process all neighbors associated with this MAC. */ - zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, 0 /*es_change*/); + zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, 0); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac); @@ -445,7 +459,7 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, { struct zebra_neigh *nbr; struct listnode *node = NULL; - struct timeval elapsed = {0, 0}; + struct timeval elapsed = { 0, 0 }; bool reset_params = false; if (!(zebra_evpn_do_dup_addr_detect(zvrf) && do_dad)) @@ -459,11 +473,11 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u", - __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), - mac->dad_count, zvrf->dad_freeze_time); + zlog_debug("%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u", + __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + mac->dad_count, zvrf->dad_freeze_time); } /* For duplicate MAC do not update * client but update neigh due to @@ -495,11 +509,11 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u", - __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), - mac->dad_count); + zlog_debug("%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u", + __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + mac->dad_count); } mac->dad_count = 0; @@ -526,10 +540,11 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (mac->dad_count >= zvrf->dad_max_moves) { flog_warn(EC_ZEBRA_DUP_MAC_DETECTED, - "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4", - mac->zevpn->vni, &mac->macaddr, - is_local ? "local update, last" : "remote update, from", - &vtep_ip); + "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4", + mac->zevpn->vni, &mac->macaddr, + is_local ? "local update, last" + : "remote update, from", + &vtep_ip); SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE); @@ -540,7 +555,6 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, * associcated with this MAC */ for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) { - /* Ony Mark IPs which are Local */ if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) continue; @@ -561,16 +575,18 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start", - __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), - zvrf->dad_freeze_time); + zlog_debug("%s: duplicate addr MAC %pEA flags %sauto recovery time %u start", + __func__, &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, + sizeof(mac_buf)), + zvrf->dad_freeze_time); } event_add_timer(zrouter.master, - zebra_evpn_dad_mac_auto_recovery_exp, mac, - zvrf->dad_freeze_time, &mac->dad_mac_auto_recovery_timer); + zebra_evpn_dad_mac_auto_recovery_exp, + mac, zvrf->dad_freeze_time, + &mac->dad_mac_auto_recovery_timer); } /* In case of local update, do not inform to client (BGPd), @@ -592,7 +608,7 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; struct zebra_vrf *zvrf; - struct timeval detect_start_time = {0, 0}; + struct timeval detect_start_time = { 0, 0 }; char timebuf[MONOTIME_STRLEN]; char thread_buf[EVENT_TIMER_STRLEN]; time_t uptime; @@ -617,18 +633,22 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) zebra_evpn_mac_get_access_info(mac, &ifp, &vid); json_object_string_add(json_mac, "type", "local"); if (ifp) { - json_object_string_add(json_mac, "intf", ifp->name); - json_object_int_add(json_mac, "ifindex", ifp->ifindex); + json_object_string_add(json_mac, "intf", + ifp->name); + json_object_int_add(json_mac, "ifindex", + ifp->ifindex); } if (vid) json_object_int_add(json_mac, "vlan", vid); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { json_object_string_add(json_mac, "type", "remote"); if (mac->es) - json_object_string_add(json_mac, "remoteEs", mac->es->esi_str); + json_object_string_add(json_mac, "remoteEs", + mac->es->esi_str); else - json_object_string_addf( - json_mac, "remoteVtep", "%pI4", &mac->fwd_info.r_vtep_ip); + json_object_string_addf(json_mac, "remoteVtep", + "%pI4", + &mac->fwd_info.r_vtep_ip); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) json_object_string_add(json_mac, "type", "auto"); @@ -642,7 +662,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) json_object_boolean_true_add(json_mac, "defaultGateway"); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)) - json_object_boolean_true_add(json_mac, "remoteGatewayMac"); + json_object_boolean_true_add(json_mac, + "remoteGatewayMac"); json_object_string_add(json_mac, "uptime", up_str); json_object_int_add(json_mac, "localSequence", mac->loc_seq); @@ -663,30 +684,42 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) json_object_boolean_true_add(json_mac, "peerActive"); if (mac->hold_timer) - json_object_string_add(json_mac, "peerActiveHold", - event_timer_to_hhmmss(thread_buf, sizeof(thread_buf), mac->hold_timer)); + json_object_string_add( + json_mac, "peerActiveHold", + event_timer_to_hhmmss(thread_buf, + sizeof(thread_buf), + mac->hold_timer)); if (mac->es) - json_object_string_add(json_mac, "esi", mac->es->esi_str); + json_object_string_add(json_mac, "esi", + mac->es->esi_str); /* print all the associated neigh */ if (!listcount(mac->neigh_list)) json_object_string_add(json_mac, "neighbors", "none"); else { json_object *json_active_nbrs = json_object_new_array(); - json_object *json_inactive_nbrs = json_object_new_array(); + json_object *json_inactive_nbrs = + json_object_new_array(); json_object *json_nbrs = json_object_new_object(); for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) { if (IS_ZEBRA_NEIGH_ACTIVE(n)) - json_object_array_add(json_active_nbrs, - json_object_new_string(ipaddr2str(&n->ip, buf2, sizeof(buf2)))); + json_object_array_add( + json_active_nbrs, + json_object_new_string( + ipaddr2str(&n->ip, buf2, + sizeof(buf2)))); else json_object_array_add( json_inactive_nbrs, - json_object_new_string(ipaddr2str(&n->ip, buf2, sizeof(buf2)))); + json_object_new_string( + ipaddr2str(&n->ip, buf2, + sizeof(buf2)))); } - json_object_object_add(json_nbrs, "active", json_active_nbrs); - json_object_object_add(json_nbrs, "inactive", json_inactive_nbrs); + json_object_object_add(json_nbrs, "active", + json_active_nbrs); + json_object_object_add(json_nbrs, "inactive", + json_inactive_nbrs); json_object_object_add(json_mac, "neighbors", json_nbrs); } @@ -704,7 +737,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) vty_out(vty, " ESI: %s\n", mac->es->esi_str); if (ifp) - vty_out(vty, " Intf: %s(%u)", ifp->name, ifp->ifindex); + vty_out(vty, " Intf: %s(%u)", ifp->name, + ifp->ifindex); else vty_out(vty, " Intf: -"); vty_out(vty, " VLAN: %u", vid); @@ -712,7 +746,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) if (mac->es) vty_out(vty, " Remote ES: %s", mac->es->esi_str); else - vty_out(vty, " Remote VTEP: %pI4", &mac->fwd_info.r_vtep_ip); + vty_out(vty, " Remote VTEP: %pI4", + &mac->fwd_info.r_vtep_ip); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { vty_out(vty, " Auto Mac "); } @@ -739,18 +774,24 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) vty_out(vty, " peer-active"); if (mac->hold_timer) vty_out(vty, " (ht: %s)", - event_timer_to_hhmmss(thread_buf, sizeof(thread_buf), mac->hold_timer)); + event_timer_to_hhmmss(thread_buf, + sizeof(thread_buf), + mac->hold_timer)); vty_out(vty, "\n"); - vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq, mac->rem_seq); + vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq, + mac->rem_seq); vty_out(vty, " Uptime: %s\n", up_str); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { vty_out(vty, " Duplicate, detected at %s", - time_to_string(mac->dad_dup_detect_time, timebuf)); + time_to_string(mac->dad_dup_detect_time, + timebuf)); } else if (mac->dad_count) { - monotime_since(&mac->detect_start_time, &detect_start_time); + monotime_since(&mac->detect_start_time, + &detect_start_time); if (detect_start_time.tv_sec <= zvrf->dad_time) { - time_to_string(mac->detect_start_time.tv_sec, timebuf); + time_to_string(mac->detect_start_time.tv_sec, + timebuf); vty_out(vty, " Duplicate detection started at %s, detection count %u\n", timebuf, mac->dad_count); @@ -765,7 +806,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) { vty_out(vty, " %s %s\n", ipaddr2str(&n->ip, buf2, sizeof(buf2)), - (IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active" : "Inactive")); + (IS_ZEBRA_NEIGH_ACTIVE(n) ? "Active" + : "Inactive")); } } @@ -817,12 +859,14 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) zebra_evpn_mac_get_access_info(mac, &ifp, &vid); if (json_mac_hdr == NULL) { vty_out(vty, "%-17s %-6s %-5s %-30s", buf1, "local", - zebra_evpn_print_mac_flags(mac, flags_buf, sizeof(flags_buf)), + zebra_evpn_print_mac_flags(mac, flags_buf, + sizeof(flags_buf)), ifp ? ifp->name : "-"); } else { json_object_string_add(json_mac, "type", "local"); if (ifp) - json_object_string_add(json_mac, "intf", ifp->name); + json_object_string_add(json_mac, "intf", + ifp->name); } if (vid) { if (json_mac_hdr == NULL) @@ -831,35 +875,41 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) json_object_int_add(json_mac, "vlan", vid); } else /* No vid? fill out the space */ if (json_mac_hdr == NULL) - vty_out(vty, " %-5s", ""); + vty_out(vty, " %-5s", ""); if (json_mac_hdr == NULL) { vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq); vty_out(vty, "\n"); } else { - json_object_int_add(json_mac, "localSequence", mac->loc_seq); - json_object_int_add(json_mac, "remoteSequence", mac->rem_seq); - json_object_int_add(json_mac, "detectionCount", mac->dad_count); + json_object_int_add(json_mac, "localSequence", + mac->loc_seq); + json_object_int_add(json_mac, "remoteSequence", + mac->rem_seq); + json_object_int_add(json_mac, "detectionCount", + mac->dad_count); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - json_object_boolean_true_add(json_mac, "isDuplicate"); + json_object_boolean_true_add(json_mac, + "isDuplicate"); else - json_object_boolean_false_add(json_mac, "isDuplicate"); + json_object_boolean_false_add(json_mac, + "isDuplicate"); json_object_object_add(json_mac_hdr, buf1, json_mac); } wctx->count++; } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { - - if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) - && !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) + if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) && + !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) return; if (json_mac_hdr == NULL) { - if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) - && (wctx->count == 0)) { + if (CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP) && + (wctx->count == 0)) { vty_out(vty, "\nVNI %u\n\n", wctx->zevpn->vni); vty_out(vty, "%-17s %-6s %-5s%-30s %-5s %s\n", - "MAC", "Type", "Flags", "Intf/Remote ES/VTEP", "VLAN", "Seq #'s"); + "MAC", "Type", "Flags", + "Intf/Remote ES/VTEP", "VLAN", + "Seq #'s"); } if (mac->es == NULL) inet_ntop(AF_INET, &mac->fwd_info.r_vtep_ip, @@ -867,24 +917,32 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1, "remote", - zebra_evpn_print_mac_flags(mac, flags_buf, sizeof(flags_buf)), - mac->es ? mac->es->esi_str : addr_buf, - "", mac->loc_seq, mac->rem_seq); + zebra_evpn_print_mac_flags(mac, flags_buf, + sizeof(flags_buf)), + mac->es ? mac->es->esi_str : addr_buf, "", + mac->loc_seq, mac->rem_seq); } else { json_object_string_add(json_mac, "type", "remote"); if (mac->es) - json_object_string_add(json_mac, "remoteEs", mac->es->esi_str); + json_object_string_add(json_mac, "remoteEs", + mac->es->esi_str); else - json_object_string_addf( - json_mac, "remoteVtep", "%pI4", &mac->fwd_info.r_vtep_ip); + json_object_string_addf(json_mac, "remoteVtep", + "%pI4", + &mac->fwd_info.r_vtep_ip); json_object_object_add(json_mac_hdr, buf1, json_mac); - json_object_int_add(json_mac, "localSequence", mac->loc_seq); - json_object_int_add(json_mac, "remoteSequence", mac->rem_seq); - json_object_int_add(json_mac, "detectionCount", mac->dad_count); + json_object_int_add(json_mac, "localSequence", + mac->loc_seq); + json_object_int_add(json_mac, "remoteSequence", + mac->rem_seq); + json_object_int_add(json_mac, "detectionCount", + mac->dad_count); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) - json_object_boolean_true_add(json_mac, "isDuplicate"); + json_object_boolean_true_add(json_mac, + "isDuplicate"); else - json_object_boolean_false_add(json_mac, "isDuplicate"); + json_object_boolean_false_add(json_mac, + "isDuplicate"); } wctx->count++; @@ -917,8 +975,7 @@ void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt) /* * Inform BGP about local MACIP. */ -int zebra_evpn_macip_send_msg_to_client(vni_t vni, - const struct ethaddr *macaddr, +int zebra_evpn_macip_send_msg_to_client(vni_t vni, const struct ethaddr *macaddr, const struct ipaddr *ip, uint8_t flags, uint32_t seq, int state, struct zebra_evpn_es *es, uint16_t cmd) @@ -966,13 +1023,12 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, if (IS_ZEBRA_DEBUG_VXLAN) { char flag_buf[MACIP_BUF_SIZE]; - zlog_debug( - "Send MACIP %s f %s state %u MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s", - (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", - zclient_evpn_dump_macip_flags(flags, flag_buf, sizeof(flag_buf)), - state, macaddr, ip, seq, vni, - es ? es->esi_str : "-", - zebra_route_string(client->proto)); + zlog_debug("Send MACIP %s f %s state %u MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s", + (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", + zclient_evpn_dump_macip_flags(flags, flag_buf, + sizeof(flag_buf)), + state, macaddr, ip, seq, vni, es ? es->esi_str : "-", + zebra_route_string(client->proto)); } if (cmd == ZEBRA_MACIP_ADD) @@ -1005,7 +1061,8 @@ static bool mac_cmp(const void *p1, const void *p2) if (pmac1 == NULL || pmac2 == NULL) return false; - return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN) == 0); + return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN) == + 0); } /* @@ -1046,7 +1103,8 @@ struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevpn, char mac_buf[MAC_BUF_SIZE]; zlog_debug("%s: MAC %pEA flags %s", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } return mac; } @@ -1062,7 +1120,8 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) char mac_buf[MAC_BUF_SIZE]; zlog_debug("%s: MAC %pEA flags %s", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } /* force de-ref any ES entry linked to the MAC */ @@ -1087,10 +1146,10 @@ int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) */ if (!list_isempty(mac->neigh_list)) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list " - "count %u, mark MAC as AUTO", &mac->macaddr, mac->flags, - zevpn->vni, listcount(mac->neigh_list)); + zlog_debug("MAC %pEA (flags 0x%x vni %u) has non-empty neigh list " + "count %u, mark MAC as AUTO", + &mac->macaddr, mac->flags, zevpn->vni, + listcount(mac->neigh_list)); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); return 0; @@ -1127,25 +1186,26 @@ struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn, static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx, struct zebra_mac *mac) { - if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) - && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) + if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) && + CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) return true; - else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC) - && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) + else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC) && + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) return true; - else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC_FROM_VTEP) - && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) + else if (CHECK_FLAG(wctx->flags, DEL_REMOTE_MAC_FROM_VTEP) && + CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && + IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) return true; - else if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) - && CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) - && !listcount(mac->neigh_list)) { + else if (CHECK_FLAG(wctx->flags, DEL_LOCAL_MAC) && + CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) && + !listcount(mac->neigh_list)) { if (IS_ZEBRA_DEBUG_VXLAN) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "%s: Del MAC %pEA flags %s", __func__, &mac->macaddr, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("%s: Del MAC %pEA flags %s", __func__, + &mac->macaddr, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } wctx->uninstall = 0; @@ -1163,23 +1223,25 @@ static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg) struct mac_walk_ctx *wctx = arg; struct zebra_mac *mac = bucket->data; - if (zebra_evpn_check_mac_del_from_db(wctx, mac)) { - if (wctx->upd_client && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { - zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni, - &mac->macaddr, mac->flags, false); - } - if (wctx->uninstall) { - if (zebra_evpn_mac_is_static(mac)) - zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - true /* force_clear_static */, __func__); + if (!zebra_evpn_check_mac_del_from_db(wctx, mac)) + return; - if (mac->flags & ZEBRA_MAC_REMOTE) - zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false /*force*/); - } + if (wctx->upd_client && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { + zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni, + &mac->macaddr, mac->flags, + false); + } + if (wctx->uninstall) { + if (zebra_evpn_mac_is_static(mac)) + zebra_evpn_sync_mac_dp_install(mac, false, true, + __func__); - zebra_evpn_mac_del(wctx->zevpn, mac); + if (mac->flags & ZEBRA_MAC_REMOTE) + zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac, false); } + zebra_evpn_mac_del(wctx->zevpn, mac); + return; } @@ -1249,7 +1311,8 @@ int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr, SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, flags, - seq, ZEBRA_NEIGH_ACTIVE, es, ZEBRA_MACIP_ADD); + seq, ZEBRA_NEIGH_ACTIVE, es, + ZEBRA_MACIP_ADD); } /* @@ -1261,8 +1324,8 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, int state = ZEBRA_NEIGH_ACTIVE; if (!force) { - if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE) - && !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE)) + if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE) && + !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE)) /* the host was not advertised - nothing to delete */ return 0; @@ -1275,8 +1338,8 @@ int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr, state = ZEBRA_NEIGH_INACTIVE; } - return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, - 0 /* flags */, 0 /* seq */, state, NULL, ZEBRA_MACIP_DEL); + return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, 0, 0, + state, NULL, ZEBRA_MACIP_DEL); } /* @@ -1308,12 +1371,11 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, es_evi = zebra_evpn_es_evi_find(mac->es, mac->zevpn); if (!es_evi) { if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug( - "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi", - caller, zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", - mac->flags, - set_inactive ? "inactive " : ""); + zlog_debug("%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi", + caller, zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + mac->flags, + set_inactive ? "inactive " : ""); return -1; } } @@ -1325,12 +1387,12 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port", - caller, zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), - set_inactive ? "inactive " : ""); + zlog_debug("%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port", + caller, zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + set_inactive ? "inactive " : ""); } return -1; } @@ -1341,12 +1403,12 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br", - caller, zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), - set_inactive ? "inactive " : ""); + zlog_debug("%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br", + caller, zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + set_inactive ? "inactive " : ""); } return -1; } @@ -1365,21 +1427,21 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s", - set_static ? "install" : "uninstall", - zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), - set_inactive ? "inactive " : ""); + zlog_debug("dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s", + set_static ? "install" : "uninstall", + zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + set_inactive ? "inactive " : ""); } if (set_static) /* XXX - old_static needs to be computed more * accurately */ - zebra_evpn_rem_mac_install(zevpn, mac, true /* old_static */); + zebra_evpn_rem_mac_install(zevpn, mac, true); else - zebra_evpn_rem_mac_uninstall(zevpn, mac, false /* force */); + zebra_evpn_rem_mac_uninstall(zevpn, mac, false); return 0; } @@ -1390,13 +1452,14 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s", zevpn->vni, &mac->macaddr, mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), set_static ? "static " : "", set_inactive ? "inactive " : ""); } dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky, - set_static, set_inactive); + set_static, set_inactive); return 0; } @@ -1406,11 +1469,11 @@ void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac *mac, { if (new_bgp_ready) zebra_evpn_mac_send_add_to_client(mac->zevpn->vni, - &mac->macaddr, mac->flags, - mac->loc_seq, mac->es); + &mac->macaddr, mac->flags, + mac->loc_seq, mac->es); else if (old_bgp_ready) - zebra_evpn_mac_send_del_to_client(mac->zevpn->vni, - &mac->macaddr, mac->flags, true /* force */); + zebra_evpn_mac_send_del_to_client(mac->zevpn->vni, &mac->macaddr, + mac->flags, true); } /* MAC hold timer is used to age out peer-active flag. @@ -1443,23 +1506,23 @@ static void zebra_evpn_mac_hold_exp_cb(struct event *t) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "sync-mac vni %u mac %pEA es %s %shold expired", - mac->zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("sync-mac vni %u mac %pEA es %s %shold expired", + mac->zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } /* re-program the local mac in the dataplane if the mac is no * longer static */ if (old_static != new_static) - zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, __func__); + zebra_evpn_sync_mac_dp_install(mac, false, false, __func__); /* inform bgp if needed */ if (old_bgp_ready != new_bgp_ready) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, + new_bgp_ready); } static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac) @@ -1470,11 +1533,11 @@ static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "sync-mac vni %u mac %pEA es %s %shold started", - mac->zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("sync-mac vni %u mac %pEA es %s %shold started", + mac->zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } event_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac, zmh_info->mac_hold_time, &mac->hold_timer); @@ -1488,11 +1551,11 @@ void zebra_evpn_mac_stop_hold_timer(struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "sync-mac vni %u mac %pEA es %s %shold stopped", - mac->zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("sync-mac vni %u mac %pEA es %s %shold stopped", + mac->zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } EVENT_OFF(mac->hold_timer); @@ -1506,11 +1569,11 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac) if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "sync-mac del vni %u mac %pEA es %s seq %d f %s", - mac->zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("sync-mac del vni %u mac %pEA es %s seq %d f %s", + mac->zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", mac->loc_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } old_static = zebra_evpn_mac_is_static(mac); @@ -1521,8 +1584,7 @@ void zebra_evpn_sync_mac_del(struct zebra_mac *mac) if (old_static != new_static) /* program the local mac in the kernel */ - zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, __func__); + zebra_evpn_sync_mac_dp_install(mac, false, false, __func__); } static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, @@ -1543,44 +1605,41 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn, n_type = "remote"; } - if (seq < tmp_seq) { - - if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x", - sync ? "sync" : "rem", zevpn->vni, - n_type, &mac->macaddr, tmp_seq, mac->flags); - return true; - } - - /* if the mac was never advertised to bgp we must accept - * whatever sequence number bgp sends - */ - if (!is_local && zebra_vxlan_get_accept_bgp_seq()) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || - IS_ZEBRA_DEBUG_VXLAN) { - zlog_debug( - "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s", - (sync ? "sync" : "rem"), - zevpn->vni, n_type, &mac->macaddr, tmp_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); - } + if (seq >= tmp_seq) + return true; - return true; - } + if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x", + sync ? "sync" : "rem", zevpn->vni, n_type, + &mac->macaddr, tmp_seq, mac->flags); + return true; + } + /* if the mac was never advertised to bgp we must accept + * whatever sequence number bgp sends + */ + if (!is_local && zebra_vxlan_get_accept_bgp_seq()) { if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) { - zlog_debug( - "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s", - (sync ? "sync" : "rem"), zevpn->vni, n_type, &mac->macaddr, tmp_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("%s-macip accept vni %u %s-mac %pEA lower seq %u f %s", + (sync ? "sync" : "rem"), zevpn->vni, n_type, + &mac->macaddr, tmp_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } - return false; + return true; } - return true; + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) { + zlog_debug("%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s", + (sync ? "sync" : "rem"), zevpn->vni, n_type, + &mac->macaddr, tmp_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); + } + + return false; } struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, @@ -1644,13 +1703,14 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW); if (sticky || remote_gw) { if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) - zlog_debug( - "Ignore sync-macip vni %u mac %pEA%s%s%s%s", - zevpn->vni, macaddr, - ipa_len ? " IP " : "", - ipa_len ? ipaddr2str(ipaddr, ipbuf, sizeof(ipbuf)) : "", - sticky ? " sticky" : "", - remote_gw ? " remote_gw" : ""); + zlog_debug("Ignore sync-macip vni %u mac %pEA%s%s%s%s", + zevpn->vni, macaddr, + ipa_len ? " IP " : "", + ipa_len ? ipaddr2str(ipaddr, ipbuf, + sizeof(ipbuf)) + : "", + sticky ? " sticky" : "", + remote_gw ? " remote_gw" : ""); return NULL; } if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, true)) @@ -1664,7 +1724,9 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, SET_FLAG(new_flags, ZEBRA_MAC_LOCAL); /* retain old local activity flag */ if (CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL)) - SET_FLAG (new_flags, CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL_INACTIVE)); + SET_FLAG(new_flags, + CHECK_FLAG(old_flags, + ZEBRA_MAC_LOCAL_INACTIVE)); else SET_FLAG(new_flags, ZEBRA_MAC_LOCAL_INACTIVE); @@ -1672,7 +1734,9 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, /* if mac-ip route do NOT update the peer flags * i.e. retain only flags as is */ - SET_FLAG(new_flags, CHECK_FLAG(old_flags, ZEBRA_MAC_ALL_PEER_FLAGS)); + SET_FLAG(new_flags, + CHECK_FLAG(old_flags, + ZEBRA_MAC_ALL_PEER_FLAGS)); } else { /* if mac-only route update peer flags */ if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) { @@ -1682,8 +1746,10 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, * holdtimer on it. the peer-active flag is * cleared on holdtimer expiry. */ - if (CHECK_FLAG(old_flags, ZEBRA_MAC_ES_PEER_ACTIVE)) { - SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE); + if (CHECK_FLAG(old_flags, + ZEBRA_MAC_ES_PEER_ACTIVE)) { + SET_FLAG(new_flags, + ZEBRA_MAC_ES_PEER_ACTIVE); zebra_evpn_mac_start_hold_timer(mac); } } else { @@ -1703,11 +1769,13 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, struct zebra_mac omac; omac.flags = old_flags; - zlog_debug( - "sync-mac vni %u mac %pEA old_f %snew_f %s", - zevpn->vni, macaddr, - zebra_evpn_zebra_mac_flag_dump(&omac, omac_buf, sizeof(omac_buf)), - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("sync-mac vni %u mac %pEA old_f %snew_f %s", + zevpn->vni, macaddr, + zebra_evpn_zebra_mac_flag_dump(&omac, + omac_buf, + sizeof(omac_buf)), + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } /* update es */ @@ -1747,24 +1815,25 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, char mac_buf[MAC_BUF_SIZE]; zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s", - created ? "created" : "updated", - zevpn->vni, macaddr, - mac->es ? mac->es->esi_str : "-", - mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), - inform_bgp ? "inform_bgp" : "", - inform_dataplane ? " inform_dp" : ""); + created ? "created" : "updated", zevpn->vni, macaddr, + mac->es ? mac->es->esi_str : "-", mac->loc_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + inform_bgp ? "inform_bgp" : "", + inform_dataplane ? " inform_dp" : ""); } if (inform_bgp) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, + new_bgp_ready); /* neighs using the mac may need to be re-sent to * bgp with updated info */ if (seq_change || es_change || !old_local) - zebra_evpn_process_neigh_on_local_mac_change( - zevpn, mac, seq_change, es_change); + zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, + seq_change, + es_change); if (inform_dataplane && !ipa_len) { /* program the local mac in the kernel. when the ES @@ -1772,8 +1841,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, * the activity as we are yet to establish activity * locally */ - zebra_evpn_sync_mac_dp_install(mac, mac_inactive /* set_inactive */, - false /* force_clear_static */, __func__); + zebra_evpn_sync_mac_dp_install(mac, mac_inactive, false, + __func__); } return mac; @@ -1783,7 +1852,8 @@ struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn, * is detected */ static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac *mac, - struct interface *ifp, vlanid_t vid) + struct interface *ifp, + vlanid_t vid) { struct zebra_if *zif = ifp->info; bool es_change; @@ -1825,8 +1895,8 @@ static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket *bucket, if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) zebra_evpn_mac_send_add_to_client(wctx->zevpn->vni, - &zmac->macaddr, zmac->flags, - zmac->loc_seq, zmac->es); + &zmac->macaddr, zmac->flags, + zmac->loc_seq, zmac->es); } /* Iterator to Notify Local MACs of a EVPN */ @@ -1840,7 +1910,8 @@ void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevpn) memset(&wctx, 0, sizeof(wctx)); wctx.zevpn = zevpn; - hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client, &wctx); + hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client, + &wctx); } void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) @@ -1857,7 +1928,7 @@ void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac) * go away, we need to uninstall the MAC. */ if (remote_neigh_count(mac) == 0) { - zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/); + zebra_evpn_rem_mac_uninstall(zevpn, mac, false); zebra_evpn_es_mac_deref_entry(mac); UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); } @@ -1917,12 +1988,11 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, mac = zebra_evpn_mac_lookup(zevpn, macaddr); /* Ignore if the mac is already present as a gateway mac */ - if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) - && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { + if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) && + CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC", - zevpn->vni, macaddr); + zlog_debug("Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC", + zevpn->vni, macaddr); return -1; } @@ -1932,13 +2002,11 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, * If so, that needs to be updated first. Note that client could * install MAC and MACIP separately or just install the latter. */ - if (!mac - || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) - || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) - || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) - || memcmp(old_esi, esi, sizeof(esi_t)) - || seq != mac->rem_seq) + if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || + sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) || + remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) || + !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) || + memcmp(old_esi, esi, sizeof(esi_t)) || seq != mac->rem_seq) update_mac = 1; if (update_mac) { @@ -1954,7 +2022,8 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, * the sequence number and ignore this update * if appropriate. */ - if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, false)) + if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, + false)) return -1; old_es_present = !!mac->es; @@ -1981,8 +2050,9 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, * MAC is already marked duplicate set dad, then * is_dup_detect will be set to not install the entry. */ - if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && mac->dad_count) - || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) + if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && + mac->dad_count) || + CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) do_dad = true; /* Remove local MAC from BGP. */ @@ -1992,17 +2062,18 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "sync-mac->remote vni %u mac %pEA es %s seq %d f %s", - zevpn->vni, macaddr, - mac->es ? mac->es->esi_str : "-", - mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("sync-mac->remote vni %u mac %pEA es %s seq %d f %s", + zevpn->vni, macaddr, + mac->es ? mac->es->esi_str : "-", + mac->loc_seq, + zebra_evpn_zebra_mac_flag_dump( + mac, mac_buf, + sizeof(mac_buf))); } zebra_evpn_mac_clear_sync_info(mac); - zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, mac->flags, - false /* force */); + zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr, + mac->flags, false); } /* Set "auto" and "remote" forwarding info. */ @@ -2021,8 +2092,10 @@ int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn, else UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); - zebra_evpn_dup_addr_detect_for_mac( - zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad, &is_dup_detect, false); + zebra_evpn_dup_addr_detect_for_mac(zvrf, mac, + mac->fwd_info.r_vtep_ip, + do_dad, &is_dup_detect, + false); if (!is_dup_detect) { zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac); @@ -2049,7 +2122,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, bool inform_client = false; bool upd_neigh = false; bool is_dup_detect = false; - struct in_addr vtep_ip = {.s_addr = 0}; + struct in_addr vtep_ip = { .s_addr = 0 }; bool es_change = false; bool new_bgp_ready; /* assume inactive if not present or if not local */ @@ -2064,11 +2137,10 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, mac = zebra_evpn_mac_lookup(zevpn, macaddr); if (!mac) { if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug( - "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s", - sticky ? "sticky " : "", - macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, - local_inactive ? " local-inactive" : ""); + zlog_debug("ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s", + sticky ? "sticky " : "", macaddr, ifp->name, + ifp->ifindex, vid, zevpn->vni, + local_inactive ? " local-inactive" : ""); mac = zebra_evpn_mac_add(zevpn, macaddr); SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); @@ -2080,12 +2152,12 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s", - sticky ? "sticky " : "", - macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, - local_inactive ? "local-inactive " : "", - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s", + sticky ? "sticky " : "", macaddr, ifp->name, + ifp->ifindex, vid, zevpn->vni, + local_inactive ? "local-inactive " : "", + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { @@ -2094,27 +2166,34 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, bool old_static; zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid); - old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); - old_local_inactive = !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE); + old_bgp_ready = + zebra_evpn_mac_is_ready_for_bgp(mac->flags); + old_local_inactive = !!(mac->flags & + ZEBRA_MAC_LOCAL_INACTIVE); old_static = zebra_evpn_mac_is_static(mac); if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) mac_sticky = true; - es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid); + es_change = zebra_evpn_local_mac_update_fwd_info(mac, + ifp, + vid); /* * Update any changes and if changes are relevant to * BGP, note it. */ - if (mac_sticky == sticky && old_ifp == ifp && old_vid == vid - && old_local_inactive == local_inactive - && dp_static == old_static && !es_change) { + if (mac_sticky == sticky && old_ifp == ifp && + old_vid == vid && + old_local_inactive == local_inactive && + dp_static == old_static && !es_change) { if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, " - "entry exists and has not changed ", - sticky ? "sticky " : "", - macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, - local_inactive ? " local_inactive" : ""); + zlog_debug(" Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, " + "entry exists and has not changed ", + sticky ? "sticky " : "", + macaddr, ifp->name, + ifp->ifindex, vid, zevpn->vni, + local_inactive + ? " local_inactive" + : ""); return 0; } if (mac_sticky != sticky) { @@ -2139,9 +2218,11 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, /* force drop the peer/sync info as it is * simply no longer relevant */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ALL_PEER_FLAGS)) { + if (CHECK_FLAG(mac->flags, + ZEBRA_MAC_ALL_PEER_FLAGS)) { zebra_evpn_mac_clear_sync_info(mac); - new_static = zebra_evpn_mac_is_static(mac); + new_static = + zebra_evpn_mac_is_static(mac); /* if we clear peer-flags we * also need to notify the dataplane * to drop the static flag @@ -2150,8 +2231,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, inform_dataplane = true; } } - } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) - || CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { + } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || + CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { bool do_dad = false; /* @@ -2161,16 +2242,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, * operator error. */ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) { - flog_warn( - EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT, - "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u", - macaddr, &mac->fwd_info.r_vtep_ip, zevpn->vni); + flog_warn(EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT, + "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u", + macaddr, &mac->fwd_info.r_vtep_ip, + zevpn->vni); return 0; } /* If an actual move, compute MAC's seq number */ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { - mac->loc_seq = MAX(mac->rem_seq + 1, mac->loc_seq); + mac->loc_seq = MAX(mac->rem_seq + 1, + mac->loc_seq); vtep_ip = mac->fwd_info.r_vtep_ip; /* Trigger DAD for remote MAC */ do_dad = true; @@ -2179,7 +2261,9 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); - es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid); + es_change = zebra_evpn_local_mac_update_fwd_info(mac, + ifp, + vid); if (sticky) SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); else @@ -2191,8 +2275,9 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, inform_client = true; upd_neigh = true; - zebra_evpn_dup_addr_detect_for_mac( - zvrf, mac, vtep_ip, do_dad, &is_dup_detect, true); + zebra_evpn_dup_addr_detect_for_mac(zvrf, mac, vtep_ip, + do_dad, + &is_dup_detect, true); if (is_dup_detect) { inform_client = false; upd_neigh = false; @@ -2218,17 +2303,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, /* if local-activity has changed we need update bgp * even if bgp already knows about the mac */ - if ((old_local_inactive != local_inactive) - || (new_bgp_ready != old_bgp_ready)) { + if ((old_local_inactive != local_inactive) || + (new_bgp_ready != old_bgp_ready)) { if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "local mac vni %u mac %pEA es %s seq %d f %s%s", - zevpn->vni, macaddr, - mac->es ? mac->es->esi_str : "", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf)), - local_inactive ? "local-inactive" : ""); + zlog_debug("local mac vni %u mac %pEA es %s seq %d f %s%s", + zevpn->vni, macaddr, + mac->es ? mac->es->esi_str : "", mac->loc_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf)), + local_inactive ? "local-inactive" : ""); } if (!is_dup_detect) @@ -2242,16 +2327,17 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, /* Inform dataplane if required. */ if (inform_dataplane) - zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, - false /* force_clear_static */, __func__); + zebra_evpn_sync_mac_dp_install(mac, false, false, __func__); /* Inform BGP if required. */ if (inform_client) - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, new_bgp_ready); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, + new_bgp_ready); /* Process all neighbors associated with this MAC, if required. */ if (upd_neigh) - zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, es_change); + zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0, + es_change); return 0; } @@ -2277,24 +2363,25 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) { char mac_buf[MAC_BUF_SIZE]; - zlog_debug( - "re-add sync-mac vni %u mac %pEA es %s seq %d f %s", - zevpn->vni, &mac->macaddr, - mac->es ? mac->es->esi_str : "-", mac->loc_seq, - zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, sizeof(mac_buf))); + zlog_debug("re-add sync-mac vni %u mac %pEA es %s seq %d f %s", + zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + mac->loc_seq, + zebra_evpn_zebra_mac_flag_dump(mac, mac_buf, + sizeof(mac_buf))); } /* inform-bgp about change in local-activity if any */ if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) { SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE); - new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); - zebra_evpn_mac_send_add_del_to_client( - mac, old_bgp_ready, new_bgp_ready); + new_bgp_ready = + zebra_evpn_mac_is_ready_for_bgp(mac->flags); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, + new_bgp_ready); } /* re-install the inactive entry in the kernel */ - zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */, - false /* force_clear_static */, __func__); + zebra_evpn_sync_mac_dp_install(mac, true, false, __func__); return 0; } @@ -2307,7 +2394,7 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, /* Remove MAC from BGP. */ zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags, - clear_static /* force */); + clear_static); zebra_evpn_es_mac_deref_entry(mac); @@ -2329,8 +2416,7 @@ int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac, return 0; } -void zebra_evpn_mac_gw_macip_add(struct interface *ifp, - struct zebra_evpn *zevpn, +void zebra_evpn_mac_gw_macip_add(struct interface *ifp, struct zebra_evpn *zevpn, const struct ipaddr *ip, struct zebra_mac **macp, const struct ethaddr *macaddr, @@ -2376,15 +2462,17 @@ void zebra_evpn_mac_svi_del(struct interface *ifp, struct zebra_evpn *zevpn) memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); mac = zebra_evpn_mac_lookup(zevpn, &macaddr); - if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) { - if (IS_ZEBRA_DEBUG_EVPN_MH_ES) - zlog_debug("SVI %s mac free", ifp->name); - - old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); - UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI); - zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, false); - zebra_evpn_deref_ip2mac(mac->zevpn, mac); - } + + if (!mac || CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) + return; + + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("SVI %s mac free", ifp->name); + + old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); + UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, false); + zebra_evpn_deref_ip2mac(mac->zevpn, mac); } void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn) @@ -2395,8 +2483,8 @@ void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn) bool old_bgp_ready; bool new_bgp_ready; - if (!zebra_evpn_mh_do_adv_svi_mac() - || !zebra_evpn_send_to_client_ok(zevpn)) + if (!zebra_evpn_mh_do_adv_svi_mac() || + !zebra_evpn_send_to_client_ok(zevpn)) return; memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); @@ -2410,8 +2498,9 @@ void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn) if (IS_ZEBRA_DEBUG_EVPN_MH_ES) zlog_debug("SVI %s mac add", zif->ifp->name); - old_bgp_ready = - (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags)) ? true : false; + old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags)) + ? true + : false; zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index b5b8e22552..81f1411ee5 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1171,7 +1171,8 @@ static void zebra_nhg_handle_install(struct nhg_hash_entry *nhe, bool install) "%s nh id %u (flags 0x%x) associated dependent NHG %pNG install", __func__, nhe->id, nhe->flags, rb_node_dep->nhe); - zebra_nhg_install_kernel(rb_node_dep->nhe, true); + zebra_nhg_install_kernel(rb_node_dep->nhe, + ZEBRA_ROUTE_MAX); } } } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 303a81bb3e..89317be74d 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -1344,13 +1344,17 @@ static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json) } if (rnh->state) { - if (json) + if (json) { json_object_string_add( json_nht, "resolvedProtocol", zebra_route_string(rnh->state->type)); - else - vty_out(vty, " resolved via %s\n", - zebra_route_string(rnh->state->type)); + json_object_string_addf(json_nht, "prefix", "%pFX", + &rnh->resolved_route); + } else { + vty_out(vty, " resolved via %s, prefix %pFX\n", + zebra_route_string(rnh->state->type), + &rnh->resolved_route); + } for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) { diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 1c6d58159e..4b4f523253 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -229,6 +229,8 @@ static int proto_trans(int type) return 3; /* static route */ case ZEBRA_ROUTE_RIP: return 8; /* rip */ + case ZEBRA_ROUTE_ISIS: + return 9; case ZEBRA_ROUTE_RIPNG: return 1; /* shouldn't happen */ case ZEBRA_ROUTE_OSPF: @@ -237,6 +239,8 @@ static int proto_trans(int type) return 1; /* shouldn't happen */ case ZEBRA_ROUTE_BGP: return 14; /* bgp */ + case ZEBRA_ROUTE_EIGRP: + return 16; default: return 1; /* other */ } @@ -253,9 +257,11 @@ static void check_replace(struct route_node *np2, struct route_entry *re2, return; } - if (prefix_cmp(&(*np)->p, &np2->p) < 0) + if (in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4, + (uint8_t *)&np2->p.u.prefix4) < 0) return; - if (prefix_cmp(&(*np)->p, &np2->p) > 0) { + if (in_addr_cmp((uint8_t *)&(*np)->p.u.prefix4, + (uint8_t *)&np2->p.u.prefix4) > 0) { *np = np2; *re = re2; return; @@ -298,14 +304,8 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], int i; /* Init index variables */ - - pnt = (uint8_t *)&dest; - for (i = 0; i < 4; i++) - *pnt++ = 0; - - pnt = (uint8_t *)&nexthop; - for (i = 0; i < 4; i++) - *pnt++ = 0; + memset(&dest, 0, sizeof(dest)); + memset(&nexthop, 0, sizeof(nexthop)); proto = 0; policy = 0; @@ -497,23 +497,23 @@ static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len, *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC1: - result = 0; + result = re->metric; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC2: - result = 0; + result = -1; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC3: - result = 0; + result = -1; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC4: - result = 0; + result = -1; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC5: - result = 0; + result = -1; *val_len = sizeof(int); return (uint8_t *)&result; default: diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 501e9d5268..3bf20ff42e 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -4151,12 +4151,6 @@ DEFUN (zebra_show_routing_tables_summary, return CMD_SUCCESS; } -/* Table configuration write function. */ -static int config_write_table(struct vty *vty) -{ - return 0; -} - /* IPForwarding configuration write function. */ static int config_write_forwarding(struct vty *vty) { @@ -4333,14 +4327,6 @@ static struct cmd_node protocol_node = { .prompt = "", .config_write = config_write_protocol, }; -/* table node for routing tables. */ -static int config_write_table(struct vty *vty); -static struct cmd_node table_node = { - .name = "table", - .node = TABLE_NODE, - .prompt = "", - .config_write = config_write_table, -}; static int config_write_forwarding(struct vty *vty); static struct cmd_node forwarding_node = { .name = "forwarding", @@ -4353,7 +4339,6 @@ static struct cmd_node forwarding_node = { void zebra_vty_init(void) { /* Install configuration write function. */ - install_node(&table_node); install_node(&forwarding_node); install_element(VIEW_NODE, &show_ip_forwarding_cmd); |
