From 13a450e65b727c9559701ea1ac833209b389a3b6 Mon Sep 17 00:00:00 2001 From: "guozhongfeng.gzf" Date: Thu, 14 Nov 2024 10:36:58 +0800 Subject: [PATCH] pathd: Support srv6 te policy Signed-off-by: guozhongfeng.gzf --- bgpd/bgp_nexthop.h | 1 + bgpd/bgp_nht.c | 28 +++--- bgpd/bgp_zebra.c | 102 +++++++++++++--------- lib/log.c | 4 +- lib/prefix.c | 18 ++++ lib/prefix.h | 1 + lib/zclient.c | 82 ++++++++++++++++-- lib/zclient.h | 17 +++- ospf6d/ospf6_zebra.c | 6 +- ospfd/ospf_zebra.c | 6 +- pathd/path_cli.c | 111 +++++++++++++++++------- pathd/path_nb.c | 10 +++ pathd/path_nb.h | 8 ++ pathd/path_nb_config.c | 69 ++++++++++++++- pathd/path_nb_state.c | 30 +++++++ pathd/path_zebra.c | 39 +++++++++ pathd/path_zebra.h | 5 +- pathd/pathd.c | 68 ++++++++++----- pathd/pathd.h | 19 +++++ pbrd/pbr_zebra.c | 5 +- pimd/pim_nht.c | 5 +- sharpd/sharp_zebra.c | 6 +- staticd/static_zebra.c | 5 +- yang/frr-pathd.yang | 144 ++++++++++++++++--------------- zebra/rib.h | 7 ++ zebra/zapi_msg.c | 125 +++++++++++++++++++++++---- zebra/zebra_nhg.c | 36 +++++--- zebra/zebra_rnh.c | 79 ++++++++++++++--- zebra/zebra_rnh.h | 2 +- zebra/zebra_srte.c | 187 +++++++++++++++++++++++++++++++++++++---- zebra/zebra_srte.h | 13 ++- 31 files changed, 983 insertions(+), 255 deletions(-) diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 6a4a02dcc824..e2418dfb5397 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -66,6 +66,7 @@ struct bgp_nexthop_cache { #define BGP_STATIC_ROUTE_EXACT_MATCH (1 << 5) #define BGP_NEXTHOP_LABELED_VALID (1 << 6) #define BGP_NEXTHOP_ULTIMATE (1 << 7) +#define BGP_NEXTHOP_SRV6TE_VALID (1 << 8) /* * This flag is added for EVPN gateway IP nexthops. diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 9b633b7139b2..475e062fddec 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -357,6 +357,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, } srte_color = bgp_attr_get_color(pi->attr); + if (srte_color) + p.u.prefix6 = pi->attr->mp_nexthop_global; } else if (peer) { /* @@ -404,8 +406,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, peer); } else { if (BGP_DEBUG(nht, NHT)) - zlog_debug("Found existing bnc %pFX(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p, resolved prefix %pFX", - &bnc->prefix, bnc->ifindex_ipv6_ll, + zlog_debug("Found existing bnc %pFX(%d)(%u)(%s) flags 0x%x ifindex %d #paths %d peer %p, resolved prefix %pFX", + &bnc->prefix, bnc->ifindex_ipv6_ll, bnc->srte_color, bnc->bgp->name_pretty, bnc->flags, bnc->ifindex_ipv6_ll, bnc->path_count, bnc->nht_info, &bnc->resolved_prefix); @@ -636,6 +638,10 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, if (!bnc->is_evpn_gwip_nexthop) SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + if (nhr->type == ZEBRA_ROUTE_SRTE) + SET_FLAG(bnc->flags, BGP_NEXTHOP_SRV6TE_VALID); + else + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_SRV6TE_VALID); bnc->metric = nhr->metric; bnc->nexthop_num = nhr->nexthop_num; @@ -743,6 +749,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_SRV6TE_VALID); bnc->nexthop_num = nhr->nexthop_num; /* notify bgp fsm if nbr ip goes from valid->invalid */ @@ -1123,9 +1130,8 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) */ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) { - bool exact_match = false; - bool resolve_via_default = false; int ret; + uint32_t flags = 0; if (!zclient) return; @@ -1147,19 +1153,21 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) } if (command == ZEBRA_NEXTHOP_REGISTER) { if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) - exact_match = true; + SET_FLAG(flags, NEXTHOP_REGISTER_FLAG_CONNECTED); if (CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) - resolve_via_default = true; + SET_FLAG(flags, NEXTHOP_REGISTER_FLAG_RESOLVE_VIA_DEFAULT); } if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: sending cmd %s for %pFX (vrf %s)", __func__, + zlog_debug("%s: sending cmd %s for %pFX (vrf %s) color %d", __func__, zserv_command_string(command), &bnc->prefix, - bnc->bgp->name_pretty); + bnc->bgp->name_pretty, bnc->srte_color); + + if (bnc->srte_color) + SET_FLAG(flags, NEXTHOP_REGISTER_FLAG_COLOR); ret = zclient_send_rnh(zclient, command, &bnc->prefix, SAFI_UNICAST, - exact_match, resolve_via_default, - bnc->bgp->vrf_id); + flags, bnc->bgp->vrf_id, bnc->srte_color); if (ret == ZCLIENT_SEND_FAILURE) { flog_warn(EC_BGP_ZEBRA_SEND, "sendmsg_nexthop: zclient_send_message() failed"); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 16f4a0d2df19..7326a840aeef 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1411,41 +1411,49 @@ static void bgp_zebra_announce_parse_nexthop( sizeof(struct ethaddr)); api_nh->weight = nh_weight; + if (CHECK_FLAG(mpinfo->nexthop->flags, BGP_NEXTHOP_SRV6TE_VALID)) { + struct nexthop_srv6 *nh_srv6 = mpinfo->nexthop->nexthop->srv6te; + memcpy(&api_nh->seg6_segs[0], &srv6te->seg6_segs[0], + srv6te->seg_num * sizeof(struct in6_addr)); + api_nh->seg_num = srv6te->seg_num; + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); + } + else { + if (((mpinfo->attr->srv6_l3vpn && + !sid_zero_ipv6(&mpinfo->attr->srv6_l3vpn->sid)) || + (mpinfo->attr->srv6_vpn && + !sid_zero_ipv6(&mpinfo->attr->srv6_vpn->sid))) && + !is_evpn && bgp_is_valid_label(&labels[0])) { + struct in6_addr *sid_tmp = + mpinfo->attr->srv6_l3vpn + ? (&mpinfo->attr->srv6_l3vpn->sid) + : (&mpinfo->attr->srv6_vpn->sid); + + memcpy(&api_nh->seg6_segs[0], sid_tmp, + sizeof(api_nh->seg6_segs[0])); + + if (mpinfo->attr->srv6_l3vpn && + mpinfo->attr->srv6_l3vpn->transposition_len != 0) { + mpls_lse_decode(labels[0], &nh_label, &ttl, + &exp, &bos); + + if (nh_label < MPLS_LABEL_UNRESERVED_MIN) { + if (bgp_debug_zebra(&api->prefix)) + zlog_debug( + "skip invalid SRv6 routes: transposition scheme is used, but label is too small"); + continue; + } - if (((mpinfo->attr->srv6_l3vpn && - !sid_zero_ipv6(&mpinfo->attr->srv6_l3vpn->sid)) || - (mpinfo->attr->srv6_vpn && - !sid_zero_ipv6(&mpinfo->attr->srv6_vpn->sid))) && - !is_evpn && bgp_is_valid_label(&labels[0])) { - struct in6_addr *sid_tmp = - mpinfo->attr->srv6_l3vpn - ? (&mpinfo->attr->srv6_l3vpn->sid) - : (&mpinfo->attr->srv6_vpn->sid); - - memcpy(&api_nh->seg6_segs[0], sid_tmp, - sizeof(api_nh->seg6_segs[0])); - - if (mpinfo->attr->srv6_l3vpn && - mpinfo->attr->srv6_l3vpn->transposition_len != 0) { - mpls_lse_decode(labels[0], &nh_label, &ttl, - &exp, &bos); - - if (nh_label < MPLS_LABEL_UNRESERVED_MIN) { - if (bgp_debug_zebra(&api->prefix)) - zlog_debug( - "skip invalid SRv6 routes: transposition scheme is used, but label is too small"); - continue; + transpose_sid(&api_nh->seg6_segs[0], nh_label, + mpinfo->attr->srv6_l3vpn + ->transposition_offset, + mpinfo->attr->srv6_l3vpn + ->transposition_len); } - transpose_sid(&api_nh->seg6_segs[0], nh_label, - mpinfo->attr->srv6_l3vpn - ->transposition_offset, - mpinfo->attr->srv6_l3vpn - ->transposition_len); + api_nh->seg_num = 1; + SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); } - - api_nh->seg_num = 1; - SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); } (*valid_nh_count)++; @@ -1460,8 +1468,8 @@ static void bgp_debug_zebra_nh(struct zapi_route *api) char eth_buf[ETHER_ADDR_STRLEN + 7] = { '\0' }; char buf1[ETHER_ADDR_STRLEN]; char label_buf[20]; - char sid_buf[20]; - char segs_buf[256]; + char sid_buf[INET6_ADDRSTRLEN]; + char segs_buf[512]; struct zapi_nexthop *api_nh; int count; @@ -1500,20 +1508,32 @@ static void bgp_debug_zebra_nh(struct zapi_route *api) !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) snprintf(label_buf, sizeof(label_buf), "label %u", api_nh->labels[0]); + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) && - !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) { - inet_ntop(AF_INET6, &api_nh->seg6_segs[0], sid_buf, - sizeof(sid_buf)); - snprintf(segs_buf, sizeof(segs_buf), "segs %s", sid_buf); + !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) { + + strlcat(segs_buf, "segs ", sizeof(segs_buf)); + for (int j = 0; j < api_nh->seg_num; j++) { + memset(sid_buf, 0, sizeof(sid_buf)); + inet_ntop(AF_INET6, &api_nh->seg6_segs[j], + sid_buf, sizeof(sid_buf)); + + if (0 > j && j < api_nh->seg_num - 1) + strlcat(segs_buf, "/", sizeof(segs_buf)); + + strlcat(segs_buf, sid_buf, sizeof(segs_buf)); + } } + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN) && !is_zero_mac(&api_nh->rmac)) snprintf(eth_buf, sizeof(eth_buf), " RMAC %s", prefix_mac2str(&api_nh->rmac, buf1, sizeof(buf1))); - zlog_debug(" nhop [%d]: %s if %u VRF %u wt %" PRIu64 + + zlog_debug(" nhop [%d][%u]: %s if %u VRF %u wt %" PRIu64 " %s %s %s", - i + 1, nh_buf, api_nh->ifindex, api_nh->vrf_id, + i + 1, api_nh->srte_color, nh_buf, api_nh->ifindex, api_nh->vrf_id, api_nh->weight, label_buf, segs_buf, eth_buf); } } @@ -1639,9 +1659,9 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, } if (bgp_debug_zebra(p)) { - zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI + zlog_debug("Tx route add %s (table id %u) %pFX color %u metric %u tag %" ROUTE_TAG_PRI " count %d nhg %d", - bgp->name_pretty, api.tableid, &api.prefix, + bgp->name_pretty, api.tableid, &api.prefix, api.srte_color, api.metric, api.tag, api.nexthop_num, nhg_id); bgp_debug_zebra_nh(&api); diff --git a/lib/log.c b/lib/log.c index 2b049cebe41e..449b1c83821b 100644 --- a/lib/log.c +++ b/lib/log.c @@ -464,7 +464,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_TC_FILTER_ADD), DESC_ENTRY(ZEBRA_TC_FILTER_DELETE), DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY), - DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY) + DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY), + DESC_ENTRY(ZEBRA_SRV6_POLICY_SET), + DESC_ENTRY(ZEBRA_SRV6_POLICY_DELETE) }; #undef DESC_ENTRY diff --git a/lib/prefix.c b/lib/prefix.c index 2485c3e61bdd..034a30ce0c68 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1124,6 +1124,24 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) return str; } +int prefix2ipaddr(union prefixconstptr pu, struct ipaddr *ip) +{ + const struct prefix *p = pu.p; + memset(ip, 0, sizeof(struct ipaddr)); + + if (p->family == AF_INET) { + ip->ipa_type = IPADDR_V4; + memcpy(&(ip->ipaddr_v4), &(p->u.prefix4), + sizeof(struct in_addr)); + } else if (p->family == AF_INET6) { + ip->ipa_type = IPADDR_V6; + memcpy(&(ip->ipaddr_v6), &(p->u.prefix6), + sizeof(struct in6_addr)); + } else + return -1; + return 0; +} + void prefix_mcast_ip_dump(const char *onfail, const struct ipaddr *addr, char *buf, int buf_size) { diff --git a/lib/prefix.h b/lib/prefix.h index 2d679d06224f..7baa540899ff 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -422,6 +422,7 @@ extern void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr, extern const char *prefix_sg2str(const struct prefix_sg *sg, char *str); extern const char *prefix2str(union prefixconstptr upfx, char *buffer, int size); +extern int prefix2ipaddr(union prefixconstptr pu, struct ipaddr *ip); extern int evpn_type5_prefix_match(const struct prefix *evpn_pfx, const struct prefix *match_pfx); extern int prefix_match(union prefixconstptr unet, union prefixconstptr upfx); diff --git a/lib/zclient.c b/lib/zclient.c index 557d9c3eb9b4..4e8ab03c7ddf 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -772,17 +772,15 @@ static void zclient_connect(struct event *t) } enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command, - const struct prefix *p, safi_t safi, - bool connected, bool resolve_via_def, - vrf_id_t vrf_id) + const struct prefix *p, safi_t safi, uint32_t flags, + vrf_id_t vrf_id, uint32_t srte_color) { struct stream *s; s = zclient->obuf; stream_reset(s); zclient_create_header(s, command, vrf_id); - stream_putc(s, (connected) ? 1 : 0); - stream_putc(s, (resolve_via_def) ? 1 : 0); + stream_putl(s, flags); stream_putw(s, safi); stream_putw(s, PREFIX_FAMILY(p)); stream_putc(s, p->prefixlen); @@ -796,6 +794,10 @@ enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command, default: break; } + + if (CHECK_FLAG(flags, NEXTHOP_REGISTER_FLAG_COLOR)) + stream_putl(s, srte_color); + stream_putw_at(s, 0, stream_get_endp(s)); return zclient_send_message(zclient); @@ -3847,8 +3849,17 @@ int tm_release_table_chunk(struct zclient *zclient, uint32_t start, enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd, struct zapi_sr_policy *zp) { - if (zapi_sr_policy_encode(zclient->obuf, cmd, zp) < 0) - return ZCLIENT_SEND_FAILURE; + if (cmd == ZEBRA_SR_POLICY_SET || cmd == ZEBRA_SR_POLICY_DELETE) + { + if (zapi_sr_policy_encode(zclient->obuf, cmd, zp) < 0) + return ZCLIENT_SEND_FAILURE; + } + else if (cmd == ZEBRA_SRV6_POLICY_SET || cmd == ZEBRA_SRV6_POLICY_DELETE) + { + if (zapi_srv6_policy_encode(zclient->obuf, cmd, zp) < 0) + return ZCLIENT_SEND_FAILURE; + } + return zclient_send_message(zclient); } @@ -3914,6 +3925,63 @@ int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp) return -1; } +int zapi_srv6_policy_encode(struct stream *s, int cmd, struct zapi_sr_policy *zp) +{ + struct zapi_srv6te_tunnel *zt = &zp->segment_list_v6; + + stream_reset(s); + + zclient_create_header(s, cmd, VRF_DEFAULT); + stream_putl(s, zp->color); + stream_put_ipaddr(s, &zp->endpoint); + stream_write(s, &zp->name, SRTE_POLICY_NAME_MAX_LENGTH); + + if (zt->seg_num > SRV6_MAX_SEGS) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: seg: can't encode %u segs (maximum is %u)", + __func__, zt->seg_num, SRV6_MAX_SEGS); + return -1; + } + stream_putw(s, zt->seg_num); + + for (int i = 0; i < zt->seg_num; i++) + stream_write(s, (uint8_t *)&zt->segs[i], IPV6_MAX_BYTELEN); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return 0; +} + +int zapi_srv6_policy_decode(struct stream *s, struct zapi_sr_policy *zp) +{ + memset(zp, 0, sizeof(*zp)); + + struct zapi_srv6te_tunnel *zt = &zp->segment_list_v6; + + STREAM_GETL(s, zp->color); + STREAM_GET_IPADDR(s, &zp->endpoint); + STREAM_GET(&zp->name, s, SRTE_POLICY_NAME_MAX_LENGTH); + + /* segment list of active candidate path */ + + STREAM_GETW(s, zt->seg_num); + if (zt->seg_num > SRV6_MAX_SEGS) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: seg: can't decode %u segs (maximum is %u)", + __func__, zt->seg_num, SRV6_MAX_SEGS); + return -1; + } + for (int i = 0; i < zt->seg_num; i++) + STREAM_GET(&zt->segs[i], s, IPV6_MAX_BYTELEN); + + return 0; + +stream_failure: + return -1; +} + + int zapi_sr_policy_notify_status_decode(struct stream *s, struct zapi_sr_policy *zp) { diff --git a/lib/zclient.h b/lib/zclient.h index 6da9558aa560..51937fd3bd38 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -70,6 +70,11 @@ typedef uint16_t zebra_size_t; #define ZEBRA_FEC_REGISTER_LABEL 0x1 #define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x2 +#define NEXTHOP_REGISTER_FLAG_CONNECTED (1 << 0) +#define NEXTHOP_REGISTER_FLAG_RESOLVE_VIA_DEFAULT (1 << 1) +#define NEXTHOP_REGISTER_FLAG_COLOR (1 << 2) + + /* Client capabilities */ enum zserv_client_capabilities { ZEBRA_CLIENT_GR_CAPABILITIES = 1, @@ -238,6 +243,8 @@ typedef enum { ZEBRA_TC_FILTER_DELETE, ZEBRA_OPAQUE_NOTIFY, ZEBRA_SRV6_SID_NOTIFY, + ZEBRA_SRV6_POLICY_SET, + ZEBRA_SRV6_POLICY_DELETE, } zebra_message_types_t; /* Zebra message types. Please update the corresponding * command_types array with any changes! @@ -636,11 +643,16 @@ struct zapi_srte_tunnel { mpls_label_t labels[MPLS_MAX_LABELS]; }; +struct zapi_srv6te_tunnel { + uint8_t seg_num; + struct in6_addr segs[SRV6_MAX_SEGS]; +}; struct zapi_sr_policy { uint32_t color; struct ipaddr endpoint; char name[SRTE_POLICY_NAME_MAX_LENGTH]; struct zapi_srte_tunnel segment_list; + struct zapi_srv6te_tunnel segment_list_v6; int status; }; @@ -1106,6 +1118,8 @@ extern int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp); extern int zapi_sr_policy_notify_status_decode(struct stream *s, struct zapi_sr_policy *zp); +extern int zapi_srv6_policy_encode(struct stream *s, int cmd, struct zapi_sr_policy *zp); +extern int zapi_srv6_policy_decode(struct stream *s, struct zapi_sr_policy *zp); extern enum zclient_send_status zebra_send_mpls_labels(struct zclient *zclient, int cmd, struct zapi_labels *zl); @@ -1130,8 +1144,7 @@ extern enum zclient_send_status zclient_route_send(uint8_t, struct zclient *, struct zapi_route *); extern enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command, const struct prefix *p, - safi_t safi, bool connected, bool resolve_via_default, - vrf_id_t vrf_id); + safi_t safi, uint32_t flags, vrf_id_t vrf_id, uint32_t srte_color); int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, uint32_t api_flags, uint32_t api_message); extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 466301309f2a..9937099ad71b 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -121,6 +121,7 @@ void ospf6_zebra_import_default_route(struct ospf6 *ospf6, bool unreg) { struct prefix prefix = {}; int command; + uint32_t flags = 0; if (zclient->sock < 0) { if (IS_OSPF6_DEBUG_ZEBRA(SEND)) @@ -140,9 +141,8 @@ void ospf6_zebra_import_default_route(struct ospf6 *ospf6, bool unreg) zlog_debug("%s: sending cmd %s for %pFX (vrf %u)", __func__, zserv_command_string(command), &prefix, ospf6->vrf_id); - - if (zclient_send_rnh(zclient, command, &prefix, SAFI_UNICAST, false, - true, ospf6->vrf_id) + SET_FLAG(flags, NEXTHOP_REGISTER_FLAG_RESOLVE_VIA_DEFAULT); + if (zclient_send_rnh(zclient, command, &prefix, SAFI_UNICAST, flags, ospf6->vrf_id, 0) == ZCLIENT_SEND_FAILURE) flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_send_rnh() failed", __func__); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index c7cba1e20fee..7a5767fab91d 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1473,6 +1473,7 @@ void ospf_zebra_import_default_route(struct ospf *ospf, bool unreg) { struct prefix prefix = {}; int command; + uint32_t flags = 0; if (zclient->sock < 0) { if (IS_DEBUG_OSPF(zebra, ZEBRA)) @@ -1494,8 +1495,9 @@ void ospf_zebra_import_default_route(struct ospf *ospf, bool unreg) zserv_command_string(command), &prefix, 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) + SET_FLAG(flags, NEXTHOP_REGISTER_FLAG_RESOLVE_VIA_DEFAULT); + if (zclient_send_rnh(zclient, command, &prefix, SAFI_UNICAST, flags, + ospf->vrf_id, 0) == ZCLIENT_SEND_FAILURE) flog_err(EC_LIB_ZAPI_SOCKET, "%s(%s): zclient_send_rnh() failed", __func__, ospf_vrf_id_to_name(ospf->vrf_id)); } diff --git a/pathd/path_cli.c b/pathd/path_cli.c index bf8a9ea02841..fef2a2bcbfd1 100644 --- a/pathd/path_cli.c +++ b/pathd/path_cli.c @@ -106,7 +106,7 @@ DEFPY(show_srte_policy, /* Prepare table. */ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); - ttable_add_row(tt, "Endpoint|Color|Name|BSID|Status"); + ttable_add_row(tt, "Endpoint|Color|Name|BSID|Status|Type"); tt->style.cell.rpad = 2; tt->style.corner = '+'; ttable_restyle(tt); @@ -121,11 +121,12 @@ DEFPY(show_srte_policy, snprintf(binding_sid, sizeof(binding_sid), "%u", policy->binding_sid); - ttable_add_row(tt, "%s|%u|%s|%s|%s", endpoint, policy->color, - policy->name, binding_sid, - policy->status == SRTE_POLICY_STATUS_UP - ? "Active" - : "Inactive"); + ttable_add_row(tt, "%s|%u|%s|%s|%s|%s", endpoint, policy->color, + policy->name, binding_sid, + policy->status == SRTE_POLICY_STATUS_UP ? "Active" : "Inactive", + policy->type == SRTE_POLICY_TYPE_MPLS + ? "MPLS" + : (policy->type == SRTE_POLICY_TYPE_SRV6 ? "SRV6" : "Undefined")); } /* Dump the generated table. */ @@ -172,37 +173,60 @@ DEFPY(show_srte_policy_detail, snprintf(binding_sid, sizeof(binding_sid), "%u", policy->binding_sid); vty_out(vty, - "Endpoint: %s Color: %u Name: %s BSID: %s Status: %s\n", + "Endpoint: %s Color: %u Name: %s BSID: %s Status: %s Type: %s\n", endpoint, policy->color, policy->name, binding_sid, - policy->status == SRTE_POLICY_STATUS_UP ? "Active" - : "Inactive"); + policy->status == SRTE_POLICY_STATUS_UP ? "Active" : "Inactive", + policy->type == SRTE_POLICY_TYPE_MPLS + ? "MPLS" + : (policy->type == SRTE_POLICY_TYPE_SRV6 ? "SRV6" : "Undefined")); RB_FOREACH (candidate, srte_candidate_head, &policy->candidate_paths) { struct srte_segment_list *segment_list; - - segment_list = candidate->lsp->segment_list; - if (segment_list == NULL) - segment_list_info = undefined_info; - else if (segment_list->protocol_origin - == SRTE_ORIGIN_PCEP) - segment_list_info = created_by_pce_info; - else - segment_list_info = - candidate->lsp->segment_list->name; - - vty_out(vty, - " %s Preference: %d Name: %s Type: %s Segment-List: %s Protocol-Origin: %s\n", - CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST) - ? "*" - : " ", - candidate->preference, candidate->name, - candidate->type == SRTE_CANDIDATE_TYPE_EXPLICIT - ? "explicit" - : "dynamic", - segment_list_info, - srte_origin2str( - candidate->lsp->protocol_origin)); + if (policy->type == SRTE_POLICY_TYPE_MPLS) { + segment_list = candidate->lsp->segment_list; + if (segment_list == NULL) + segment_list_info = undefined_info; + else if (segment_list->protocol_origin + == SRTE_ORIGIN_PCEP) + segment_list_info = created_by_pce_info; + else + segment_list_info = + candidate->lsp->segment_list->name; + + vty_out(vty, + " %s Preference: %d Name: %s Type: %s Segment-List: %s Protocol-Origin: %s\n", + CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST) + ? "*" + : " ", + candidate->preference, candidate->name, + candidate->type == SRTE_CANDIDATE_TYPE_EXPLICIT + ? "explicit" + : "dynamic", + segment_list_info, + srte_origin2str( + candidate->lsp->protocol_origin)); + } else if (policy->type == SRTE_POLICY_TYPE_SRV6) { + segment_list = candidate->segment_list; + if (segment_list == NULL) + segment_list_info = undefined_info; + else + segment_list_info = + candidate->segment_list->name; + + vty_out(vty, + " %s Preference: %d Name: %s Type: %s Segment-List: %s Protocol-Origin: %s\n", + CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST) + ? "*" + : " ", + candidate->preference, candidate->name, + candidate->type == SRTE_CANDIDATE_TYPE_EXPLICIT + ? "explicit" + : "dynamic", + segment_list_info, + srte_origin2str( + candidate->protocol_origin)); + } } vty_out(vty, "\n"); @@ -527,6 +551,23 @@ DEFPY(srte_segment_list_segment, srte_segment_list_segment_cmd, return nb_cli_apply_changes(vty, NULL); } +DEFPY_YANG(srv6te_segment_list_segment, srv6te_segment_list_segment_cmd, + "index (0-4294967295)$index ipv6-address X:X::X:X$ipv6_addr", + "Index\n" + "Index Value\n" + IPV6_STR + "IPv6 address\n") +{ + char xpath[XPATH_MAXLEN]; + snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath, sizeof(xpath), + "./segment[index='%s']/srv6-sid-value", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, ipv6_addr_str); + return nb_cli_apply_changes(vty, NULL); +} + DEFPY(srte_segment_list_no_segment, srte_segment_list_no_segment_cmd, "no index (0-4294967295)$index", @@ -547,6 +588,10 @@ void cli_show_srte_segment_list_segment(struct vty *vty, bool show_defaults) { vty_out(vty, " index %s", yang_dnode_get_string(dnode, "index")); + if (yang_dnode_exists(dnode, "srv6-sid-value")) { + vty_out(vty, "ipv6-address %s", + yang_dnode_get_string(dnode, "srv6-sid-value")); + } if (yang_dnode_exists(dnode, "sid-value")) { vty_out(vty, " mpls label %s", yang_dnode_get_string(dnode, "sid-value")); @@ -1331,6 +1376,8 @@ void path_cli_init(void) install_element(SR_TRAFFIC_ENG_NODE, &srte_no_segment_list_cmd); install_element(SR_SEGMENT_LIST_NODE, &srte_segment_list_segment_cmd); + install_element(SR_SEGMENT_LIST_NODE, + &srv6te_segment_list_segment_cmd); install_element(SR_SEGMENT_LIST_NODE, &srte_segment_list_no_segment_cmd); install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd); diff --git a/pathd/path_nb.c b/pathd/path_nb.c index e1c0cc3efa6c..45a41b2d71cc 100644 --- a/pathd/path_nb.c +++ b/pathd/path_nb.c @@ -71,6 +71,7 @@ const struct frr_yang_module_info frr_pathd_info = { .create = pathd_srte_segment_list_segment_create, .cli_show = cli_show_srte_segment_list_segment, .destroy = pathd_srte_segment_list_segment_destroy, + .pre_validate = pathd_srte_segment_list_segment_pre_validate, }, .priority = NB_DFLT_PRIORITY - 1 }, @@ -82,6 +83,14 @@ const struct frr_yang_module_info frr_pathd_info = { }, .priority = NB_DFLT_PRIORITY - 1 }, + { + .xpath = "/frr-pathd:pathd/srte/segment-list/segment/srv6-sid-value", + .cbs = { + .modify = pathd_srte_segment_list_segment_v6_sid_value_modify, + .destroy = pathd_srte_segment_list_segment_v6_sid_value_destroy, + }, + .priority = NB_DFLT_PRIORITY - 1 + }, { .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai", .cbs = { @@ -163,6 +172,7 @@ const struct frr_yang_module_info frr_pathd_info = { .get_next = pathd_srte_policy_candidate_path_get_next, .get_keys = pathd_srte_policy_candidate_path_get_keys, .lookup_entry = pathd_srte_policy_candidate_path_lookup_entry, + .pre_validate = pathd_srte_policy_candidate_path_pre_validate, } }, { diff --git a/pathd/path_nb.h b/pathd/path_nb.h index 21876d788303..c2c565108424 100644 --- a/pathd/path_nb.h +++ b/pathd/path_nb.h @@ -21,6 +21,8 @@ pathd_srte_segment_list_lookup_entry(struct nb_cb_lookup_entry_args *args); int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args); int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args); +int pathd_srte_segment_list_segment_pre_validate( + struct nb_cb_pre_validate_args *args); int pathd_srte_segment_list_protocol_origin_modify( struct nb_cb_modify_args *args); int pathd_srte_segment_list_originator_modify(struct nb_cb_modify_args *args); @@ -32,6 +34,10 @@ void pathd_srte_segment_list_segment_nai_apply_finish( struct nb_cb_apply_finish_args *args); int pathd_srte_segment_list_segment_sid_value_destroy( struct nb_cb_destroy_args *args); +int pathd_srte_segment_list_segment_v6_sid_value_modify( + struct nb_cb_modify_args *args); +int pathd_srte_segment_list_segment_v6_sid_value_destroy( + struct nb_cb_destroy_args *args); int pathd_srte_policy_create(struct nb_cb_create_args *args); int pathd_srte_policy_destroy(struct nb_cb_destroy_args *args); const void *pathd_srte_policy_get_next(struct nb_cb_get_next_args *args); @@ -53,6 +59,8 @@ pathd_srte_policy_candidate_path_get_next(struct nb_cb_get_next_args *args); int pathd_srte_policy_candidate_path_get_keys(struct nb_cb_get_keys_args *args); const void *pathd_srte_policy_candidate_path_lookup_entry( struct nb_cb_lookup_entry_args *args); +int pathd_srte_policy_candidate_path_pre_validate( + struct nb_cb_pre_validate_args *args); void pathd_srte_policy_candidate_path_bandwidth_apply_finish( struct nb_cb_apply_finish_args *args); int pathd_srte_policy_candidate_path_bandwidth_destroy( diff --git a/pathd/path_nb_config.c b/pathd/path_nb_config.c index 48531ba43339..3e0835a5e551 100644 --- a/pathd/path_nb_config.c +++ b/pathd/path_nb_config.c @@ -127,6 +127,29 @@ int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +int pathd_srte_segment_list_segment_pre_validate( + struct nb_cb_pre_validate_args *args) +{ + struct srte_segment_list *segment_list; + segment_list = nb_running_get_entry(args->dnode, NULL, true); + if (yang_dnode_exists(args->dnode, "sid-value")) { + if (segment_list->type == SRTE_SEGMENT_LIST_TYPE_SRV6) { + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "The Segment List Type must be the same!"); + return NB_EV_VALIDATE; + } + } + + if (yang_dnode_exists(args->dnode, "srv6-sid-value")) { + if (segment_list->type == SRTE_SEGMENT_LIST_TYPE_MPLS) { + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "The Segment List Type must be the same!"); + return NB_EV_VALIDATE; + } + } + return NB_OK; +} + /* * XPath: /frr-pathd:pathd/srte/segment-list/segment/sid-value */ @@ -142,6 +165,7 @@ int pathd_srte_segment_list_segment_sid_value_modify( segment = nb_running_get_entry(args->dnode, NULL, true); sid_value = yang_dnode_get_uint32(args->dnode, NULL); segment->sid_value = sid_value; + segment->segment_list->type = SRTE_SEGMENT_LIST_TYPE_MPLS; SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED); return NB_OK; @@ -162,6 +186,43 @@ int pathd_srte_segment_list_segment_sid_value_destroy( return NB_OK; } +/* + * XPath: /frr-pathd:pathd/srte/segment-list/segment/srv6-sid-value + */ +int pathd_srte_segment_list_segment_v6_sid_value_modify( + struct nb_cb_modify_args *args) +{ + struct ipaddr sid_value; + struct srte_segment_entry *segment; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + + segment = nb_running_get_entry(args->dnode, NULL, true); + yang_dnode_get_ip(&sid_value, args->dnode, NULL); + segment->srv6_sid_value = sid_value; + segment->segment_list->type = SRTE_SEGMENT_LIST_TYPE_SRV6; + SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED); + + + return NB_OK; +} + +int pathd_srte_segment_list_segment_v6_sid_value_destroy( + struct nb_cb_destroy_args *args) +{ + struct srte_segment_entry *segment; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + segment = nb_running_get_entry(args->dnode, NULL, true); + memset(&segment->srv6_sid_value, 0, sizeof(struct ipaddr)); + SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED); + + return NB_OK; +} int pathd_srte_segment_list_segment_nai_destroy(struct nb_cb_destroy_args *args) { @@ -703,7 +764,13 @@ int pathd_srte_policy_candidate_path_segment_list_name_modify( segment_list_name = yang_dnode_get_string(args->dnode, NULL); candidate->segment_list = srte_segment_list_find(segment_list_name); - candidate->lsp->segment_list = candidate->segment_list; + if (candidate->segment_list->type == SRTE_SEGMENT_LIST_TYPE_MPLS) { + candidate->lsp->segment_list = candidate->segment_list; + candidate->policy->type = SRTE_POLICY_TYPE_MPLS; + } + else if (candidate->segment_list->type == SRTE_SEGMENT_LIST_TYPE_SRV6) + candidate->policy->type = SRTE_POLICY_TYPE_SRV6; + assert(candidate->segment_list); SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED); diff --git a/pathd/path_nb_state.c b/pathd/path_nb_state.c index 35b9e37c7370..30a8aec29037 100644 --- a/pathd/path_nb_state.c +++ b/pathd/path_nb_state.c @@ -4,6 +4,7 @@ */ #include +#include #include "log.h" #include "prefix.h" @@ -149,6 +150,35 @@ const void *pathd_srte_policy_candidate_path_lookup_entry( return srte_candidate_find(policy, preference); } +int pathd_srte_policy_candidate_path_pre_validate( + struct nb_cb_pre_validate_args *args) +{ + struct srte_segment_list *segment_list; + const char *segment_list_name; + struct srte_policy *policy; + + policy = nb_running_get_entry(args->dnode, NULL, true); + segment_list_name = yang_dnode_get_string(args->dnode, "segment-list-name"); + segment_list = srte_segment_list_find(segment_list_name); + + if (segment_list == NULL) { + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "The Segment List must config frist!"); + return NB_EV_VALIDATE; + } + + if ((segment_list->type == SRTE_SEGMENT_LIST_TYPE_SRV6 + && policy->type == SRTE_POLICY_TYPE_MPLS) + || (segment_list->type == SRTE_SEGMENT_LIST_TYPE_MPLS + && policy->type == SRTE_POLICY_TYPE_SRV6)) { + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "The Segment List type and Policy type must match!"); + return NB_EV_VALIDATE; + } + + return NB_OK; +} + /* * XPath: /frr-pathd:pathd/srte/policy/candidate_path/is-best-candidate-path */ diff --git a/pathd/path_zebra.c b/pathd/path_zebra.c index ba03315c82f7..5d3fab869ec5 100644 --- a/pathd/path_zebra.c +++ b/pathd/path_zebra.c @@ -212,6 +212,45 @@ void path_zebra_delete_sr_policy(struct srte_policy *policy) (void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_DELETE, &zp); } +/** + * Adds a segment routing policy to Zebra. + * + * @param policy The policy to add + * @param segment_list The segment list for the policy + */ +void path_zebra_add_srv6_policy(struct srte_policy *policy, + struct srte_segment_list *segment_list) +{ + struct zapi_sr_policy zp = {}; + struct srte_segment_entry *segment; + + zp.color = policy->color; + zp.endpoint = policy->endpoint; + strlcpy(zp.name, policy->name, sizeof(zp.name)); + zp.segment_list_v6.seg_num = 0; + RB_FOREACH (segment, srte_segment_entry_head, &segment_list->segments) { + memcpy(&zp.segment_list_v6.segs[zp.segment_list_v6.seg_num], + &segment->srv6_sid_value, sizeof(segment->srv6_sid_value)); + zp.segment_list_v6.seg_num++; + } + policy->status = SRTE_POLICY_STATUS_UP; + + (void)zebra_send_sr_policy(zclient, ZEBRA_SRV6_POLICY_SET, &zp); +} + +void path_zebra_delete_srv6_policy(struct srte_policy *policy) +{ + struct zapi_sr_policy zp = {}; + + zp.color = policy->color; + zp.endpoint = policy->endpoint; + strlcpy(zp.name, policy->name, sizeof(zp.name)); + zp.segment_list_v6.seg_num = 0; + policy->status = SRTE_POLICY_STATUS_DOWN; + + (void)zebra_send_sr_policy(zclient, ZEBRA_SRV6_POLICY_DELETE, &zp); +} + /** * Allocates a label from Zebra's label manager. * diff --git a/pathd/path_zebra.h b/pathd/path_zebra.h index 74a62e38b328..11d179d2f4d8 100644 --- a/pathd/path_zebra.h +++ b/pathd/path_zebra.h @@ -12,8 +12,11 @@ bool get_ipv4_router_id(struct in_addr *router_id); bool get_ipv6_router_id(struct in6_addr *router_id); void path_zebra_add_sr_policy(struct srte_policy *policy, - struct srte_segment_list *segment_list); + struct srte_segment_list *segment_list); void path_zebra_delete_sr_policy(struct srte_policy *policy); +void path_zebra_add_srv6_policy(struct srte_policy *policy, + struct srte_segment_list *segment_list); +void path_zebra_delete_srv6_policy(struct srte_policy *policy); int path_zebra_request_label(mpls_label_t label); void path_zebra_release_label(mpls_label_t label); void path_zebra_init(struct event_loop *master); diff --git a/pathd/pathd.c b/pathd/pathd.c index 431fe4d1e31e..e7850dee987d 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -121,6 +121,7 @@ struct srte_segment_list *srte_segment_list_add(const char *name) segment_list = XCALLOC(MTYPE_PATH_SEGMENT_LIST, sizeof(*segment_list)); strlcpy(segment_list->name, name, sizeof(segment_list->name)); + segment_list->type = SRTE_SEGMENT_LIST_TYPE_UNDEFINED; RB_INIT(srte_segment_entry_head, &segment_list->segments); RB_INSERT(srte_segment_list_head, &srte_segment_lists, segment_list); @@ -329,6 +330,7 @@ struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint, policy->endpoint = *endpoint; policy->binding_sid = MPLS_LABEL_NONE; policy->protocol_origin = origin; + policy->type = SRTE_POLICY_TYPE_UNDEFINED; if (originator != NULL) strlcpy(policy->originator, originator, sizeof(policy->originator)); @@ -350,10 +352,15 @@ struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint, void srte_policy_del(struct srte_policy *policy) { struct srte_candidate *candidate; + if (policy->type == SRTE_POLICY_TYPE_MPLS) { + path_zebra_delete_sr_policy(policy); - path_zebra_delete_sr_policy(policy); + path_zebra_release_label(policy->binding_sid); + } - path_zebra_release_label(policy->binding_sid); + if (policy->type == SRTE_POLICY_TYPE_SRV6) { + path_zebra_delete_srv6_policy(policy); + } while (!RB_EMPTY(srte_candidate_head, &policy->candidate_paths)) { candidate = @@ -518,14 +525,23 @@ srte_policy_best_candidate(const struct srte_policy *policy) { struct srte_candidate *candidate; - RB_FOREACH_REVERSE (candidate, srte_candidate_head, - &policy->candidate_paths) { - /* search for highest preference with existing segment list */ - if (!CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED) - && candidate->lsp->segment_list - && (!CHECK_FLAG(candidate->lsp->segment_list->flags, - F_SEGMENT_LIST_SID_CONFLICT))) - return candidate; + if (policy->type == SRTE_POLICY_TYPE_MPLS) { + RB_FOREACH_REVERSE (candidate, srte_candidate_head, + &policy->candidate_paths) { + /* search for highest preference with existing segment list */ + if (!CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED) + && candidate->lsp->segment_list + && (!CHECK_FLAG(candidate->lsp->segment_list->flags, + F_SEGMENT_LIST_SID_CONFLICT))) + return candidate; + } + } else if (policy->type == SRTE_POLICY_TYPE_SRV6) { + RB_FOREACH_REVERSE (candidate, srte_candidate_head, + &policy->candidate_paths) { + if (!CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED) + && candidate->segment_list) + return candidate; + } } return NULL; @@ -598,6 +614,9 @@ void srte_policy_apply_changes(struct srte_policy *policy) struct srte_candidate *new_best_candidate; char endpoint[ENDPOINT_STR_LENGTH]; + if (policy->type != SRTE_POLICY_TYPE_MPLS && policy->type != SRTE_POLICY_TYPE_SRV6) + return; + ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); /* Get old and new best candidate path. */ @@ -621,17 +640,24 @@ void srte_policy_apply_changes(struct srte_policy *policy) * Rely on replace semantics if there's a new best * candidate. */ - if (!new_best_candidate) - path_zebra_delete_sr_policy(policy); + if (!new_best_candidate) { + if (policy->type == SRTE_POLICY_TYPE_MPLS) + path_zebra_delete_sr_policy(policy); + else + path_zebra_delete_srv6_policy(policy); + } } if (new_best_candidate) { policy->best_candidate = new_best_candidate; SET_FLAG(new_best_candidate->flags, F_CANDIDATE_BEST); SET_FLAG(new_best_candidate->flags, F_CANDIDATE_MODIFIED); - - path_zebra_add_sr_policy( - policy, new_best_candidate->lsp->segment_list); + if (policy->type == SRTE_POLICY_TYPE_MPLS) + path_zebra_add_sr_policy( + policy, new_best_candidate->lsp->segment_list); + else + path_zebra_add_srv6_policy( + policy, new_best_candidate->segment_list); } } else if (new_best_candidate) { /* The best candidate path did not change, but some of its @@ -652,8 +678,12 @@ void srte_policy_apply_changes(struct srte_policy *policy) endpoint, policy->color, new_best_candidate->name); - path_zebra_add_sr_policy( - policy, new_best_candidate->lsp->segment_list); + if (policy->type == SRTE_POLICY_TYPE_MPLS) + path_zebra_add_sr_policy( + policy, new_best_candidate->lsp->segment_list); + else + path_zebra_add_srv6_policy( + policy, new_best_candidate->segment_list); } } @@ -734,8 +764,8 @@ void srte_candidate_del(struct srte_candidate *candidate) RB_REMOVE(srte_candidate_head, &srte_policy->candidate_paths, candidate); - - XFREE(MTYPE_PATH_SR_CANDIDATE, candidate->lsp); + if (candidate->lsp) + XFREE(MTYPE_PATH_SR_CANDIDATE, candidate->lsp); XFREE(MTYPE_PATH_SR_CANDIDATE, candidate); } diff --git a/pathd/pathd.h b/pathd/pathd.h index 75e7eff920e7..33e8664d929d 100644 --- a/pathd/pathd.h +++ b/pathd/pathd.h @@ -153,6 +153,17 @@ enum affinity_filter_type { }; #define MAX_AFFINITY_FILTER_TYPE 3 +enum srte_segment_list_type { + SRTE_SEGMENT_LIST_TYPE_UNDEFINED = 0, + SRTE_SEGMENT_LIST_TYPE_MPLS = 1, + SRTE_SEGMENT_LIST_TYPE_SRV6 = 2, +}; + +enum srte_policy_type { + SRTE_POLICY_TYPE_UNDEFINED = 0, + SRTE_POLICY_TYPE_MPLS = 1, + SRTE_POLICY_TYPE_SRV6 = 2, +}; struct srte_segment_list; struct srte_segment_entry { @@ -167,6 +178,9 @@ struct srte_segment_entry { /* Label Value. */ mpls_label_t sid_value; + /*Srv6 Sid*/ + struct ipaddr srv6_sid_value; + /* NAI Type */ enum srte_segment_nai_type nai_type; /* NAI local address when nai type is not NONE */ @@ -201,6 +215,8 @@ struct srte_segment_list { /* Nexthops. */ struct srte_segment_entry_head segments; + enum srte_segment_list_type type; + /* Status flags. */ uint16_t flags; #define F_SEGMENT_LIST_NEW 0x0002 @@ -341,6 +357,9 @@ struct srte_policy { /* Operational Status of the policy */ enum srte_policy_status status; + /* The Type (mpls or srv6) */ + enum srte_policy_type type; + /* Best candidate path. */ struct srte_candidate *best_candidate; diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index dd15beaff440..2ca26cf76ab0 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -425,6 +425,7 @@ void pbr_send_rnh(struct nexthop *nhop, bool reg) { uint32_t command; struct prefix p; + uint32_t flags = 0; command = (reg) ? ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER; @@ -454,8 +455,8 @@ void pbr_send_rnh(struct nexthop *nhop, bool reg) break; } - if (zclient_send_rnh(zclient, command, &p, SAFI_UNICAST, false, false, - nhop->vrf_id) + if (zclient_send_rnh(zclient, command, &p, SAFI_UNICAST, flags, + nhop->vrf_id, 0) == ZCLIENT_SEND_FAILURE) { zlog_warn("%s: Failure to send nexthop to zebra", __func__); } diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index f2dbfa9765c8..06ac0b90814c 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -43,10 +43,11 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, { struct prefix p; int ret; + uint32_t flags = 0; pim_addr_to_prefix(&p, pnc->rpf.rpf_addr); - ret = zclient_send_rnh(zclient, command, &p, SAFI_UNICAST, false, false, - pim->vrf->vrf_id); + ret = zclient_send_rnh(zclient, command, &p, SAFI_UNICAST, flags, + pim->vrf->vrf_id, 0); if (ret == ZCLIENT_SEND_FAILURE) zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 4447b69bf619..8d6f66ee3f91 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -623,13 +623,17 @@ void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, b { int command = ZEBRA_NEXTHOP_REGISTER; safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST; + uint32_t flags = 0; command = ZEBRA_NEXTHOP_REGISTER; if (!watch) command = ZEBRA_NEXTHOP_UNREGISTER; - if (zclient_send_rnh(zclient, command, p, safi, connected, false, vrf_id) == + if (connected) + SET_FLAG(flags, NEXTHOP_REGISTER_FLAG_CONNECTED); + + if (zclient_send_rnh(zclient, command, p, safi, flags, vrf_id, 0) == ZCLIENT_SEND_FAILURE) zlog_warn("%s: Failure to send nexthop to zebra", __func__); } diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index d76befc1318f..bd4bd7f9269a 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -308,6 +308,7 @@ void static_zebra_nht_register(struct static_nexthop *nh, bool reg) struct static_route_info *si = static_route_info_from_rnode(rn); struct static_nht_data *nhtd, lookup = {}; uint32_t cmd; + uint32_t flags = 0; if (!static_zebra_nht_get_prefix(nh, &lookup.nh)) return; @@ -373,8 +374,8 @@ void static_zebra_nht_register(struct static_nexthop *nh, bool reg) "Unregistering nexthop(%pFX) for %pRN", &lookup.nh, rn); } - if (zclient_send_rnh(zclient, cmd, &lookup.nh, si->safi, false, false, - nh->nh_vrf_id) == ZCLIENT_SEND_FAILURE) + if (zclient_send_rnh(zclient, cmd, &lookup.nh, si->safi, flags, + nh->nh_vrf_id, 0) == ZCLIENT_SEND_FAILURE) zlog_warn("%s: Failure to send nexthop %pFX for %pRN to zebra", __func__, &lookup.nh, rn); else if (reg) diff --git a/yang/frr-pathd.yang b/yang/frr-pathd.yang index 5beda769c1a3..82a14d3e7826 100644 --- a/yang/frr-pathd.yang +++ b/yang/frr-pathd.yang @@ -84,84 +84,88 @@ module frr-pathd { leaf index { type uint32; description "Segment index"; - } - leaf sid-value { - type rt-types:mpls-label; - description "MPLS label value"; - } - container nai { - presence "The segment has a Node or Adjacency Identifier"; - leaf type { - description "NAI type"; - mandatory true; - type enumeration { - enum ipv4_node { - value 1; - description "IPv4 node identifier"; - } - enum ipv6_node { - value 2; - description "IPv6 node identifier"; - } - enum ipv4_adjacency { - value 3; - description "IPv4 adjacency"; - } - enum ipv6_adjacency { - value 4; - description "IPv6 adjacency"; - } - enum ipv4_unnumbered_adjacency { - value 5; - description "IPv4 unnumbered adjacency"; - } - enum ipv4_local_iface { - value 7; - description "IPv4 prefix with local interface id"; - } - enum ipv6_local_iface { - value 8; - description "IPv6 prefix with local interface id"; - } - enum ipv4_algo { - value 9; - description "IPv4 prefix with optional algorithm"; - } - enum ipv6_algo { - value 10; - description "IPv6 prefix with optional algorithm"; - } - } - } - leaf local-address { - type inet:ip-address; - mandatory true; - } - leaf local-prefix-len { - type uint8; - mandatory true; - when "../type = 'ipv4_local_iface' or ../type = 'ipv6_local_iface' or ../type = 'ipv4_algo' or ../type = 'ipv6_algo'"; } - leaf local-interface { - type uint32; - mandatory true; - when "../type = 'ipv4_local_iface' or ../type = 'ipv6_local_iface' or ../type = 'ipv4_unnumbered_adjacency'"; + leaf sid-value { + type rt-types:mpls-label; + description "MPLS label value"; } - leaf remote-address { + leaf srv6-sid-value { type inet:ip-address; + description "SRv6 sid value"; + } + container nai { + presence "The segment has a Node or Adjacency Identifier"; + leaf type { + description "NAI type"; + mandatory true; + type enumeration { + enum ipv4_node { + value 1; + description "IPv4 node identifier"; + } + enum ipv6_node { + value 2; + description "IPv6 node identifier"; + } + enum ipv4_adjacency { + value 3; + description "IPv4 adjacency"; + } + enum ipv6_adjacency { + value 4; + description "IPv6 adjacency"; + } + enum ipv4_unnumbered_adjacency { + value 5; + description "IPv4 unnumbered adjacency"; + } + enum ipv4_local_iface { + value 7; + description "IPv4 prefix with local interface id"; + } + enum ipv6_local_iface { + value 8; + description "IPv6 prefix with local interface id"; + } + enum ipv4_algo { + value 9; + description "IPv4 prefix with optional algorithm"; + } + enum ipv6_algo { + value 10; + description "IPv6 prefix with optional algorithm"; + } + } + } + leaf local-address { + type inet:ip-address; + mandatory true; + } + leaf local-prefix-len { + type uint8; mandatory true; - when "../type = 'ipv4_adjacency' or ../type = 'ipv6_adjacency' or ../type = 'ipv4_unnumbered_adjacency'"; + when "../type = 'ipv4_local_iface' or ../type = 'ipv6_local_iface' or ../type = 'ipv4_algo' or ../type = 'ipv6_algo'"; } - leaf remote-interface { + leaf local-interface { type uint32; mandatory true; - when "../type = 'ipv4_unnumbered_adjacency'"; + when "../type = 'ipv4_local_iface' or ../type = 'ipv6_local_iface' or ../type = 'ipv4_unnumbered_adjacency'"; + } + leaf remote-address { + type inet:ip-address; + mandatory true; + when "../type = 'ipv4_adjacency' or ../type = 'ipv6_adjacency' or ../type = 'ipv4_unnumbered_adjacency'"; + } + leaf remote-interface { + type uint32; + mandatory true; + when "../type = 'ipv4_unnumbered_adjacency'"; + } + leaf algorithm { + type uint8; + mandatory true; + when "../type = 'ipv4_algo' or ../type = 'ipv6_algo'"; } - leaf algorithm { - type uint8; - mandatory true; - when "../type = 'ipv4_algo' or ../type = 'ipv6_algo'"; - } } } } diff --git a/zebra/rib.h b/zebra/rib.h index 5fedb07335ef..ace9b2966958 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -22,6 +22,7 @@ #include "mpls.h" #include "srcdest_table.h" #include "zebra/zebra_nhg.h" +#include "srte.h" #ifdef __cplusplus extern "C" { @@ -35,6 +36,10 @@ PREDECL_LIST(rnh_list); /* Nexthop structure. */ struct rnh { + /* For linked list. */ + struct rnh *next; + struct rnh *prev; + uint8_t flags; #define ZEBRA_NHT_CONNECTED 0x1 @@ -64,6 +69,8 @@ struct rnh { int filtered[ZEBRA_ROUTE_MAX]; struct rnh_list_item rnh_list_item; + uint32_t srte_color; + enum zebra_sr_policy_status srp_status; }; #define DISTANCE_INFINITY 255 diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 10acee9be435..35c3514cbb14 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1226,12 +1226,14 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) struct stream *s; struct prefix p; unsigned short l = 0; - uint8_t connected = 0; + uint32_t connected = 0; uint8_t resolve_via_default; bool exist; bool flag_changed = false; uint8_t orig_flags; safi_t safi; + uint32_t flags = 0; + uint32_t srte_color = 0; if (IS_ZEBRA_DEBUG_NHT) zlog_debug( @@ -1245,12 +1247,13 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) client->nh_reg_time = monotime(NULL); while (l < hdr->length) { - STREAM_GETC(s, connected); - STREAM_GETC(s, resolve_via_default); + srte_color = 0; + flags = 0; + STREAM_GETL(s, flags); STREAM_GETW(s, safi); STREAM_GETW(s, p.family); STREAM_GETC(s, p.prefixlen); - l += 7; + l += 9; if (p.family == AF_INET) { client->v4_nh_watch_add_cnt++; if (p.prefixlen > IPV4_MAX_BITLEN) { @@ -1278,10 +1281,25 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) p.family); return; } - rnh = zebra_add_rnh(&p, zvrf_id(zvrf), safi, &exist); + if (CHECK_FLAG(flags, NEXTHOP_REGISTER_FLAG_COLOR)) { + STREAM_GETL(s, srte_color); + l += 4; + } + + rnh = zebra_add_rnh(&p, zvrf_id(zvrf), safi, &exist, srte_color); if (!rnh) return; + if (CHECK_FLAG(flags, NEXTHOP_REGISTER_FLAG_CONNECTED)) + connected = true; + else + connected = false; + + if (CHECK_FLAG(flags, NEXTHOP_REGISTER_FLAG_RESOLVE_VIA_DEFAULT)) + resolve_via_default = true; + else + resolve_via_default = false; + orig_flags = rnh->flags; if (connected && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); @@ -1294,9 +1312,11 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) if (orig_flags != rnh->flags) flag_changed = true; + else + flag_changed = false; /* Anything not AF_INET/INET6 has been filtered out above */ - if (!exist || flag_changed) + if (!srte_color && (!exist || flag_changed)) zebra_evaluate_rnh(zvrf, family2afi(p.family), 1, &p, safi); @@ -1315,6 +1335,8 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS) struct prefix p; unsigned short l = 0; safi_t safi; + uint32_t srte_color = 0; + uint32_t flags = 0; if (IS_ZEBRA_DEBUG_NHT) zlog_debug( @@ -1325,19 +1347,14 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS) s = msg; while (l < hdr->length) { - uint8_t ignore; - - STREAM_GETC(s, ignore); - if (ignore != 0) - goto stream_failure; - STREAM_GETC(s, ignore); - if (ignore != 0) - goto stream_failure; + flags = 0; + srte_color = 0; + STREAM_GETL(s, flags); STREAM_GETW(s, safi); STREAM_GETW(s, p.family); STREAM_GETC(s, p.prefixlen); - l += 7; + l += 9; if (p.family == AF_INET) { client->v4_nh_watch_rem_cnt++; if (p.prefixlen > IPV4_MAX_BITLEN) { @@ -1365,7 +1382,17 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS) p.family); return; } + if (CHECK_FLAG(flags, NEXTHOP_REGISTER_FLAG_COLOR)) { + STREAM_GETL(s, srte_color); + l += 4; + } + rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), safi); + /* check color */ + for (rnh; rnh; rnh = rnh->next) + if (rnh->srte_color == srte_color) + break; + if (rnh) { client->nh_dereg_time = monotime(NULL); zebra_remove_rnh_client(rnh, client); @@ -2131,9 +2158,9 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) vrf_id = zvrf_id(zvrf); if (IS_ZEBRA_DEBUG_RECV) - zlog_debug("%s: p=(%s:%u)%pFX, msg flags=0x%x, flags=0x%x", + zlog_debug("%s: p=(%s:%u)%pFX, msg flags=0x%x, flags=0x%x, color=%u", __func__, zvrf_name(zvrf), api.tableid, &api.prefix, - (int)api.message, api.flags); + (int)api.message, api.flags, api.srte_color); /* Allocate new route. */ re = zebra_rib_route_entry_new( @@ -2673,6 +2700,7 @@ static void zread_sr_policy_set(ZAPI_HANDLER_ARGS) if (!policy) { policy = zebra_sr_policy_add(zp.color, &zp.endpoint, zp.name); policy->sock = client->sock; + policy->type = ZEBRA_SR_POLICY_TYPE_MPLS; } /* TODO: per-VRF list of SR-TE policies. */ policy->zvrf = zvrf; @@ -2708,6 +2736,67 @@ static void zread_sr_policy_delete(ZAPI_HANDLER_ARGS) zebra_sr_policy_del(policy); } +static void zread_srv6_policy_set(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_sr_policy zp; + struct zapi_srv6te_tunnel *zt; + struct zebra_sr_policy *policy; + + /* Get input stream. */ + s = msg; + if (zapi_srv6_policy_decode(s, &zp) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_sr_policy sent", + __func__); + return; + } + zt = &zp.segment_list_v6; + if (zt->seg_num < 1) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug( + "%s: SRV6-TE tunnel must contain at least one sid", + __func__); + return; + } + + policy = zebra_sr_policy_find(zp.color, &zp.endpoint); + if (!policy) { + policy = zebra_sr_policy_add(zp.color, &zp.endpoint, zp.name); + policy->sock = client->sock; + policy->type = ZEBRA_SR_POLICY_TYPE_SRV6; + } + /* TODO: per-VRF list of SR-TE policies. */ + policy->zvrf = zvrf; + + zebra_srv6_policy_validate(policy, &zp.segment_list_v6); +} + +static void zread_srv6_policy_delete(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_sr_policy zp; + struct zebra_sr_policy *policy; + + /* Get input stream. */ + s = msg; + if (zapi_srv6_policy_decode(s, &zp) < 0) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to decode zapi_sr_policy sent", + __func__); + return; + } + + policy = zebra_sr_policy_find(zp.color, &zp.endpoint); + if (!policy) { + if (IS_ZEBRA_DEBUG_RECV) + zlog_debug("%s: Unable to find SRV6-TE policy", __func__); + return; + } + + zebra_sr_policy_del(policy); +} + int zsend_sr_policy_notify_status(uint32_t color, struct ipaddr *endpoint, char *name, int status) { @@ -4113,6 +4202,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_TC_CLASS_DELETE] = zread_tc_class, [ZEBRA_TC_FILTER_ADD] = zread_tc_filter, [ZEBRA_TC_FILTER_DELETE] = zread_tc_filter, + [ZEBRA_SRV6_POLICY_SET] = zread_srv6_policy_set, + [ZEBRA_SRV6_POLICY_DELETE] = zread_srv6_policy_delete, }; /* diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 1519246c179e..c588177a0728 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1861,7 +1861,7 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ONLINK); /* Copy labels of the resolved route and the parent resolving to it */ - if (policy) { + if (policy && policy->type == ZEBRA_SR_POLICY_TYPE_MPLS) { int label_num = 0; /* @@ -1928,7 +1928,11 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, nexthop->nh_srv6->seg6_segs ->num_segs); } - + if (policy && policy->type == ZEBRA_SR_POLICY_TYPE_SRV6) { + nexthop_add_srv6_seg6(resolved_hop, + &policy->segment_list_v6.segs[0], + policy->segment_list_v6.seg_num); + } resolved_hop->rparent = nexthop; _nexthop_add(&nexthop->resolved, resolved_hop); @@ -2332,17 +2336,25 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, policy = zebra_sr_policy_find(nexthop->srte_color, &endpoint); if (policy && policy->status == ZEBRA_SR_POLICY_UP) { resolved = 0; - frr_each_safe (nhlfe_list, &policy->lsp->nhlfe_list, - nhlfe) { - if (!CHECK_FLAG(nhlfe->flags, - NHLFE_FLAG_SELECTED) - || CHECK_FLAG(nhlfe->flags, - NHLFE_FLAG_DELETED)) - continue; + if (policy->type == ZEBRA_SR_POLICY_TYPE_MPLS) { + frr_each_safe (nhlfe_list, &policy->lsp->nhlfe_list, + nhlfe) { + if (!CHECK_FLAG(nhlfe->flags, + NHLFE_FLAG_SELECTED) + || CHECK_FLAG(nhlfe->flags, + NHLFE_FLAG_DELETED)) + continue; + SET_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE); + nexthop_set_resolved(afi, nhlfe->nexthop, + nexthop, policy); + resolved = 1; + } + } else if (policy->type == ZEBRA_SR_POLICY_TYPE_SRV6) { SET_FLAG(nexthop->flags, - NEXTHOP_FLAG_RECURSIVE); - nexthop_set_resolved(afi, nhlfe->nexthop, - nexthop, policy); + NEXTHOP_FLAG_RECURSIVE); + nexthop_set_resolved(afi, nexthop, + nexthop, policy); resolved = 1; } if (resolved) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 640e6551a774..0fdae1034443 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -118,8 +118,33 @@ static void zebra_rnh_store_in_routing_table(struct rnh *rnh) route_unlock_node(rn); } +static void zebra_rnh_info_add(struct route_node *dest, struct rnh *pi) +{ + struct rnh *top; + + top = dest->info; + + pi->next = top; + pi->prev = NULL; + if (top) + top->prev = pi; + dest->info = pi; + + route_lock_node(dest); +} + +static void zebra_rnh_info_del(struct route_node *dest, struct rnh *pi) +{ + if (pi->next) + pi->next->prev = pi->prev; + if (pi->prev) + pi->prev->next = pi->next; + else + dest->info = pi->next; +} + struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, safi_t safi, - bool *exists) + bool *exists, uint32_t srte_color) { struct route_table *table; struct route_node *rn; @@ -129,8 +154,8 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, safi_t safi, if (IS_ZEBRA_DEBUG_NHT) { struct vrf *vrf = vrf_lookup_by_id(vrfid); - zlog_debug("%s(%u): Add RNH %pFX for safi: %u", - VRF_LOGNAME(vrf), vrfid, p, safi); + zlog_debug("%s(%u): Add RNH %pFX for safi: %u, srte_color: %u", + VRF_LOGNAME(vrf), vrfid, p, safi, srte_color); } table = get_rnh_table(vrfid, afi, safi); @@ -150,7 +175,11 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, safi_t safi, /* Lookup (or add) route node.*/ rn = route_node_get(table, p); - if (!rn->info) { + for (rnh = rn->info; rnh; rnh = rnh->next) + if (rnh->srte_color == srte_color) + break; + + if (!rnh) { rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh)); /* @@ -167,16 +196,18 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, safi_t safi, rnh->safi = safi; rnh->zebra_pseudowire_list = list_new(); route_lock_node(rn); - rn->info = rnh; rnh->node = rn; + rnh->srte_color = srte_color; + rnh->srp_status = ZEBRA_SR_POLICY_DOWN; *exists = false; - - zebra_rnh_store_in_routing_table(rnh); + zebra_rnh_info_add(rn, rnh); + if (!srte_color) + zebra_rnh_store_in_routing_table(rnh); } else *exists = true; route_unlock_node(rn); - return (rn->info); + return rnh; } struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, safi_t safi) @@ -247,11 +278,21 @@ static void zebra_delete_rnh(struct rnh *rnh) rnh->vrf_id, rnh->node); } + zebra_rnh_info_del(rn, rnh); zebra_free_rnh(rnh); - rn->info = NULL; route_unlock_node(rn); } +static struct zebra_sr_policy *zebra_sr_policy_find_by_rnh(struct rnh *rnh) +{ + struct ipaddr ip = {0}; + if (!prefix2ipaddr(&rnh->node->p, &ip)) + { + return zebra_sr_policy_find(rnh->srte_color, &ip); + } + return NULL; +} + /* * This code will send to the registering client * the looked up rnh. @@ -263,6 +304,10 @@ static void zebra_delete_rnh(struct rnh *rnh) void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id) { + struct zebra_sr_policy *policy = NULL; + struct ipaddr ip = {0}; + struct prefix *p = &rnh->node->p; + if (IS_ZEBRA_DEBUG_NHT) { struct vrf *vrf = vrf_lookup_by_id(vrf_id); @@ -277,7 +322,19 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, * We always need to respond with known information, * currently multiple daemons expect this behavior */ - zebra_send_rnh_update(rnh, client, vrf_id, 0); + if (!rnh->srte_color) + zebra_send_rnh_update(rnh, client, vrf_id, 0); + else + { + if (!prefix2ipaddr(p, &ip)) + { + policy = zebra_sr_policy_find_by_rnh(rnh); + if (policy) + zebra_sr_policy_notify_update(policy); + else + zebra_sr_policy_notify_unknown(rnh, client); + } + } } void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client) @@ -330,7 +387,7 @@ void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw, return; addr2hostprefix(pw->af, &pw->nexthop, &nh); - rnh = zebra_add_rnh(&nh, vrf_id, SAFI_UNICAST, &exists); + rnh = zebra_add_rnh(&nh, vrf_id, SAFI_UNICAST, &exists, 0); if (!rnh) return; diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index f0b10d825c84..bf2fa3a8ab51 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -17,7 +17,7 @@ extern "C" { extern void zebra_rnh_init(void); extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, safi_t safi, - bool *exists); + bool *exists, uint32_t srte_color); extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, safi_t safi); extern void zebra_free_rnh(struct rnh *rnh); diff --git a/zebra/zebra_srte.c b/zebra/zebra_srte.c index bb8d4b3b4077..d226f3dad9ec 100644 --- a/zebra/zebra_srte.c +++ b/zebra/zebra_srte.c @@ -8,6 +8,7 @@ #include "lib/zclient.h" #include "lib/lib_errors.h" +#include "zebra/debug.h" #include "zebra/zebra_srte.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_rnh.h" @@ -91,6 +92,7 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy, uint8_t num; struct zapi_nexthop znh; int ret; + struct nexthop nh = {0}; /* Get output stream. */ s = stream_new(ZEBRA_MAX_PACKET_SIZ); @@ -133,28 +135,76 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy, } stream_putl(s, policy->color); + if (IS_ZEBRA_DEBUG_SRV6) { + char endpoint[IPADDR_STRING_SIZE]; + ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); + zlog_debug("%s: endpoint %s color %u status %s type %d", + __func__, endpoint, policy->color, policy->status, + policy->type); + } + num = 0; - frr_each (nhlfe_list_const, &policy->lsp->nhlfe_list, nhlfe) { - if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) - || CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)) - continue; + if (policy->type == ZEBRA_SR_POLICY_TYPE_MPLS) { + frr_each (nhlfe_list_const, &policy->lsp->nhlfe_list, nhlfe) { + if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) + || CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED)) + continue; + + if (num == 0) { + stream_putc(s, re_type_from_lsp_type(nhlfe->type)); + stream_putw(s, 0); /* instance - not available */ + stream_putc(s, nhlfe->distance); + stream_putl(s, 0); /* metric - not available */ + nump = stream_get_endp(s); + stream_putw(s, 0); + } + + zapi_nexthop_from_nexthop(&znh, nhlfe->nexthop); + ret = zapi_nexthop_encode(s, &znh, 0, message); + if (ret < 0) + goto failure; - if (num == 0) { - stream_putc(s, re_type_from_lsp_type(nhlfe->type)); - stream_putw(s, 0); /* instance - not available */ - stream_putc(s, nhlfe->distance); - stream_putl(s, 0); /* metric - not available */ - nump = stream_get_endp(s); - stream_putw(s, 0); + num++; } + } else if (policy->type == ZEBRA_SR_POLICY_TYPE_SRV6) { + stream_putc(s, ZEBRA_ROUTE_SRTE); + stream_putw(s, 0); /* instance - not available */ + stream_putc(s, 0); + stream_putl(s, 0); /* metric - not available */ + nump = stream_get_endp(s); + stream_putw(s, 0); + + memset(&nh, 0, sizeof(struct nexthop)); + nh.vrf_id = policy->zvrf->vrf->vrf_id; + + switch (policy->endpoint.ipa_type) { + case IPADDR_V4: + memcpy(&nh.gate.ipv4, &policy->endpoint.ipaddr_v4, sizeof(struct in_addr)); + nh.type = NEXTHOP_TYPE_IPV4; + break; + case IPADDR_V6: + memcpy(&nh.gate.ipv6, &policy->endpoint.ipaddr_v6, sizeof(struct in6_addr)); + nh.type = NEXTHOP_TYPE_IPV6; + break; + case IPADDR_NONE: + flog_warn(EC_LIB_DEVELOPMENT, + "%s: unknown policy endpoint address family: %u", + __func__, policy->endpoint.ipa_type); + exit(1); + } + nexthop_add_srv6_seg6(&nh, &policy->segment_list_v6.segs[0], + policy->segment_list_v6.seg_num); - zapi_nexthop_from_nexthop(&znh, nhlfe->nexthop); + nh.srte_color = policy->color; + zapi_nexthop_from_nexthop(&znh, &nh); + nexthop_del_srv6_seg6(&nh); ret = zapi_nexthop_encode(s, &znh, 0, message); if (ret < 0) goto failure; num++; } + stream_putw_at(s, nump, num); stream_putw_at(s, 0, stream_get_endp(s)); @@ -167,7 +217,7 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy, return -1; } -static void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy) +void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy) { struct rnh *rnh; struct prefix p = {}; @@ -195,9 +245,25 @@ static void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy) } rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), SAFI_UNICAST); + if (!rnh) + return; + + /* check color */ + for (; rnh; rnh = rnh->next) + if (rnh->srte_color == policy->color) + break; if (!rnh) return; + rnh->srp_status = policy->status; + + if (IS_ZEBRA_DEBUG_SRV6) { + char endpoint[IPADDR_STRING_SIZE]; + ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); + zlog_debug("%s: endpoint %s color %u status %s", + __func__, endpoint, policy->color, policy->status); + } + for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) { if (policy->status == ZEBRA_SR_POLICY_UP) zebra_sr_policy_notify_update_client(policy, client); @@ -208,6 +274,65 @@ static void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy) } } +int zebra_sr_policy_notify_unknown(struct rnh *rnh, + struct zserv *client) +{ + struct stream *s; + uint32_t message = 0; + struct route_node *rn; + + rn = rnh->node; + + /* Get output stream. */ + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, ZEBRA_NEXTHOP_UPDATE, rnh->vrf_id); + + /* Message flags. */ + SET_FLAG(message, ZAPI_MESSAGE_SRTE); + stream_putl(s, message); + stream_putw(s, rnh->safi); + + switch (rn->p.family) { + case AF_INET: + stream_putw(s, AF_INET); + stream_putc(s, IPV4_MAX_BITLEN); + stream_put_in_addr(s, &rn->p.u.prefix4); + stream_putw(s, AF_INET); + stream_putc(s, IPV4_MAX_BITLEN); + stream_put_in_addr(s, &rn->p.u.prefix4); + break; + case AF_INET6: + stream_putw(s, AF_INET6); + stream_putc(s, IPV6_MAX_BITLEN); + stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN); + stream_putw(s, AF_INET6); + stream_putc(s, IPV6_MAX_BITLEN); + stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN); + break; + default: + flog_warn(EC_LIB_DEVELOPMENT, + "%s: unknown policy endpoint address family: %u", + __func__, rn->p.family); + exit(1); + } + + stream_putl(s, rnh->srte_color); + + stream_putc(s, ZEBRA_ROUTE_SRTE); + stream_putw(s, 0); /* instance - not available */ + stream_putc(s, 0);/* distance - not available */ + stream_putl(s, 0); /* metric - not available */ + /*set nexthop num to 0 */ + stream_putc(s, 0); + + stream_putw_at(s, 0, stream_get_endp(s)); + client->nh_last_upd_time = monotime(NULL); + client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE; + return zserv_send_message(client, s); + +} + static void zebra_sr_policy_activate(struct zebra_sr_policy *policy, struct zebra_lsp *lsp) { @@ -254,10 +379,12 @@ static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy) { policy->status = ZEBRA_SR_POLICY_DOWN; policy->lsp = NULL; - zebra_sr_policy_bsid_uninstall(policy, - policy->segment_list.local_label); - zsend_sr_policy_notify_status(policy->color, &policy->endpoint, - policy->name, ZEBRA_SR_POLICY_DOWN); + if (policy->type == ZEBRA_SR_POLICY_TYPE_MPLS) { + zebra_sr_policy_bsid_uninstall(policy, + policy->segment_list.local_label); + zsend_sr_policy_notify_status(policy->color, &policy->endpoint, + policy->name, ZEBRA_SR_POLICY_DOWN); + } zebra_sr_policy_notify_update(policy); } @@ -288,6 +415,32 @@ int zebra_sr_policy_validate(struct zebra_sr_policy *policy, return 0; } +int zebra_srv6_policy_validate(struct zebra_sr_policy *policy, + struct zapi_srv6te_tunnel *new_tunnel) +{ + bool segment_list_changed = false; + struct zapi_srv6te_tunnel old_tunnel = policy->segment_list_v6; + + if (new_tunnel) + policy->segment_list_v6 = *new_tunnel; + + + /* First label was resolved successfully. */ + if (policy->status == ZEBRA_SR_POLICY_DOWN) { + policy->status = ZEBRA_SR_POLICY_UP; + segment_list_changed = true; + } else { + segment_list_changed = + policy->segment_list_v6.seg_num != old_tunnel.seg_num + || memcmp(&policy->segment_list_v6.segs[0], &old_tunnel.segs[0], + sizeof(struct in6_addr) * policy->segment_list_v6.seg_num); + } + + if (segment_list_changed) + zebra_sr_policy_notify_update(policy); + + return 0; +} int zebra_sr_policy_bsid_install(struct zebra_sr_policy *policy) { struct zapi_srte_tunnel *zt = &policy->segment_list; diff --git a/zebra/zebra_srte.h b/zebra/zebra_srte.h index 1cdee454048a..bedd3d511b9a 100644 --- a/zebra/zebra_srte.h +++ b/zebra/zebra_srte.h @@ -21,13 +21,21 @@ enum zebra_sr_policy_update_label_mode { ZEBRA_SR_POLICY_LABEL_REMOVED = 3, }; +enum zebra_sr_policy_type { + ZEBRA_SR_POLICY_TYPE_UNDEFINED = 0, + ZEBRA_SR_POLICY_TYPE_MPLS = 1, + ZEBRA_SR_POLICY_TYPE_SRV6 = 2, +}; + struct zebra_sr_policy { RB_ENTRY(zebra_sr_policy) entry; uint32_t color; struct ipaddr endpoint; char name[SRTE_POLICY_NAME_MAX_LENGTH]; enum zebra_sr_policy_status status; + enum zebra_sr_policy_type type; struct zapi_srte_tunnel segment_list; + struct zapi_srv6te_tunnel segment_list_v6; struct zebra_lsp *lsp; struct zebra_vrf *zvrf; int sock; @@ -46,13 +54,16 @@ struct zebra_sr_policy *zebra_sr_policy_find(uint32_t color, struct zebra_sr_policy *zebra_sr_policy_find_by_name(char *name); int zebra_sr_policy_validate(struct zebra_sr_policy *policy, struct zapi_srte_tunnel *new_tunnel); +int zebra_srv6_policy_validate(struct zebra_sr_policy *policy, + struct zapi_srv6te_tunnel *new_tunnel); int zebra_sr_policy_bsid_install(struct zebra_sr_policy *policy); void zebra_sr_policy_bsid_uninstall(struct zebra_sr_policy *policy, mpls_label_t old_bsid); void zebra_srte_init(void); int zebra_sr_policy_label_update(mpls_label_t label, enum zebra_sr_policy_update_label_mode mode); - +extern void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy); +extern int zebra_sr_policy_notify_unknown(struct rnh *rnh, struct zserv *client); #ifdef __cplusplus } #endif