From bed448b17786c97b210e761c6c9d122421a1a5f0 Mon Sep 17 00:00:00 2001 From: "guozhongfeng.gzf" <guozhongfeng.gzf@alibaba-inc.com> Date: Sat, 7 Dec 2024 11:33:31 +0800 Subject: [PATCH] pathd: pathd support IPv6 address SID list command: router2(config-sr-te)# segment-list test_srv6 router2(config-sr-te-segment-list)# index 10 ipv6-address X:X::X:X IPv6 address router2(config-sr-te-segment-list)# index 10 ipv6-address 100:1::1 router2(config-sr-te-segment-list)# index 20 ipv6-address 200:1::1 router2(config-sr-te-segment-list)# index 30 mpls label (16-1048575) Label Value router2(config-sr-te-segment-list)# index 30 mpls label 100 % Configuration failed. Error type: validation Error description: The Segment List(test_srv6) Type must be SRv6! router2(config-sr-te-segment-list)# router2(config-sr-te)# segment-list test_mpls router2(config-sr-te-segment-list)# index 10 mpls label 100 router2(config-sr-te-segment-list)# index 20 mpls label 200 router2(config-sr-te-segment-list)# index 30 ipv6-address 1:1::1 % Configuration failed. Error type: validation Error description: The Segment List(test_mpls) Type must be MPLS! router2(config-sr-te-segment-list)# router2# configure router2(config)# seg router2(config-sr)# traffic-eng router2(config-sr-te)# policy color 100 endpoint A.B.C.D SR Policy endpoint IPv4 address X:X::X:X SR Policy endpoint IPv6 address router2(config-sr-te)# policy color 100 endpoint 1.1.1.1 <cr> router2(config-sr-te)# policy color 100 endpoint 1.1.1.1 router2(config-sr-te-policy)# candidate-path preference 1 name mpls explicit segment-list test_mpls <cr> router2(config-sr-te-policy)# candidate-path preference 1 name mpls explicit segment-list test_mpls router2(config-sr-te-policy)# candidate-path preference 2 name srv6 explicit segment-list test_srv6 % Configuration failed. Error type: validation Error description: The Segment List type(2) and Policy type(1) must match! router2(config-sr-te-policy)# exit router2(config-sr-te)# policy color 200 endpoint 1:1::1 router2(config-sr-te-policy)# candidate-path preference 1 name srv6 explicit segment-list test_srv6 router2(config-sr-te-policy)# candidate-path preference 2 name mpls explicit segment-list test_mpls % Configuration failed. Error type: validation Error description: The Segment List type(1) and Policy type(2) must match! config: segment-routing traffic-eng segment-list test_srv6 index 10 ipv6-address 100:1::1 index 20 ipv6-address 200:1::1 exit segment-list test_mpls index 10 mpls label 100 index 20 mpls label 200 exit policy color 100 endpoint 1.1.1.1 candidate-path preference 1 name mpls explicit segment-list test_mpls exit policy color 200 endpoint 1:1::1 candidate-path preference 1 name srv6 explicit segment-list test_srv6 exit exit exit ! end show: router2# show sr-te policy detail Endpoint: 1.1.1.1 Color: 100 Name: BSID: - Status: Inactive Type: MPLS * Preference: 1 Name: mpls Type: explicit Segment-List: test_mpls Protocol-Origin: Local Endpoint: 1:1::1 Color: 200 Name: BSID: - Status: Active Type: SRV6 * Preference: 1 Name: srv6 Type: explicit Segment-List: test_srv6 Protocol-Origin: Local router2# Signed-off-by: guozhongfeng.gzf <guozhongfeng.gzf@alibaba-inc.com> --- lib/log.c | 4 +- lib/prefix.c | 18 ++++++ lib/prefix.h | 1 + lib/srv6.c | 15 +++++ lib/srv6.h | 3 +- lib/zclient.c | 69 +++++++++++++++++++- lib/zclient.h | 10 +++ pathd/path_cli.c | 116 ++++++++++++++++++++++++--------- pathd/path_nb.c | 8 +++ pathd/path_nb.h | 7 ++ pathd/path_nb_config.c | 66 +++++++++++++++++-- pathd/path_nb_state.c | 63 ++++++++++++++++++ pathd/path_zebra.c | 39 +++++++++++ pathd/path_zebra.h | 5 +- pathd/pathd.c | 68 +++++++++++++------ pathd/pathd.h | 19 ++++++ yang/frr-pathd.yang | 144 +++++++++++++++++++++-------------------- zebra/zapi_msg.c | 12 ++++ zebra/zebra_srte.h | 8 +++ 19 files changed, 545 insertions(+), 130 deletions(-) diff --git a/lib/log.c b/lib/log.c index bc1ed5c5ccae..6050464feea3 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..eb16d3662d5a 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; + IPV4_ADDR_COPY(&ip->ipaddr_v4, &p->u.prefix4); + } else if (p->family == AF_INET6) { + ip->ipa_type = IPADDR_V6; + IPV6_ADDR_COPY(&ip->ipaddr_v6, &p->u.prefix6); + } 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/srv6.c b/lib/srv6.c index e6fc375fbb11..37d8f020066e 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -71,6 +71,21 @@ int snprintf_seg6_segs(char *str, return strlen(str); } +int snprintf_seg6_seg_stack(char *str, + size_t size, const struct seg6_seg_stack *segs) +{ + str[0] = '\0'; + for (size_t i = 0; i < segs->num_segs; i++) { + char addr[INET6_ADDRSTRLEN]; + bool not_last = (i + 1) < segs->num_segs; + + inet_ntop(AF_INET6, &segs->seg[i], addr, sizeof(addr)); + strlcat(str, addr, size); + strlcat(str, not_last ? "," : "", size); + } + return strlen(str); +} + void seg6local_context2json(const struct seg6local_context *ctx, uint32_t action, json_object *json) { diff --git a/lib/srv6.h b/lib/srv6.h index 9a041e3d85b2..ee69f41eed1b 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -375,7 +375,8 @@ static inline const char *srv6_sid_ctx2str(char *str, size_t size, int snprintf_seg6_segs(char *str, size_t size, const struct seg6_segs *segs); - +int snprintf_seg6_seg_stack(char *str, + size_t size, const struct seg6_seg_stack *segs); extern struct srv6_locator *srv6_locator_alloc(const char *name); extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void); extern void srv6_locator_free(struct srv6_locator *locator); diff --git a/lib/zclient.c b/lib/zclient.c index 55bbc18a87eb..46d2208d7ba0 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -3849,8 +3849,14 @@ 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); } @@ -3916,6 +3922,65 @@ 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_put_ipaddr(s, &zt->segs[i]); + + /* 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_IPADDR(s, &zt->segs[i]); + + 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 8cac6969ee5c..360ee78b467d 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -74,6 +74,7 @@ typedef uint16_t zebra_size_t; #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, @@ -242,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! @@ -640,11 +643,16 @@ struct zapi_srte_tunnel { mpls_label_t labels[MPLS_MAX_LABELS]; }; +struct zapi_srv6te_tunnel { + uint8_t seg_num; + struct ipaddr 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; }; @@ -1110,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); diff --git a/pathd/path_cli.c b/pathd/path_cli.c index bf8a9ea02841..dbd54ffdeac1 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"); @@ -308,6 +332,7 @@ static int segment_list_has_src_dst( struct ipaddr ip_src = {}; struct ipaddr ip_dst = {}; + if (adj_src_ipv4_str != NULL) { ip_src.ipa_type = IPADDR_V4; ip_src.ip._v4_addr = adj_src_ipv4; @@ -527,6 +552,24 @@ 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,10 +590,17 @@ 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")); } + if (yang_dnode_exists(dnode, "nai")) { struct ipaddr addr; struct ipaddr addr_rmt; @@ -1331,6 +1381,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..523d3152434a 100644 --- a/pathd/path_nb.c +++ b/pathd/path_nb.c @@ -82,6 +82,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 = { diff --git a/pathd/path_nb.h b/pathd/path_nb.h index 21876d788303..4d1895cc3a3e 100644 --- a/pathd/path_nb.h +++ b/pathd/path_nb.h @@ -20,6 +20,7 @@ const void * 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_check_validate(struct nb_cb_create_args *args); int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args); int pathd_srte_segment_list_protocol_origin_modify( struct nb_cb_modify_args *args); @@ -32,6 +33,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 +58,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_check_validate( + struct nb_cb_create_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..912c0587ff8d 100644 --- a/pathd/path_nb_config.c +++ b/pathd/path_nb_config.c @@ -96,9 +96,16 @@ int pathd_srte_segment_list_originator_modify(struct nb_cb_modify_args *args) */ int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args) { - struct srte_segment_list *segment_list; struct srte_segment_entry *segment; + struct srte_segment_list *segment_list; uint32_t index; + enum nb_error nb_code = NB_OK; + + if (args->event == NB_EV_VALIDATE) { + nb_code = pathd_srte_segment_list_segment_check_validate(args); + if (nb_code != NB_OK) + return nb_code; + } if (args->event != NB_EV_APPLY) return NB_OK; @@ -142,6 +149,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 +170,41 @@ 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) { @@ -235,11 +278,14 @@ void pathd_srte_segment_list_segment_nai_apply_finish( zlog_debug(" Segment list name (%d) index (%s) ", segment->index, segment->segment_list->name); + if (srte_segment_entry_set_nai(segment, type, &local_addr, local_iface, - &remote_addr, remote_iface, algo, - local_prefix_len)) + &remote_addr, remote_iface, algo, + local_prefix_len)) { SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_SID_CONFLICT); + segment->segment_list->type = SRTE_SEGMENT_LIST_TYPE_MPLS; + } } /* @@ -372,7 +418,13 @@ int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args) struct srte_policy *policy; struct srte_candidate *candidate; uint32_t preference; + enum nb_error nb_code = NB_OK; + if (args->event == NB_EV_VALIDATE) { + nb_code = pathd_srte_policy_candidate_path_check_validate(args); + if (nb_code != NB_OK) + return nb_code; + } if (args->event != NB_EV_APPLY) return NB_OK; @@ -703,7 +755,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..d5a4d1460acf 100644 --- a/pathd/path_nb_state.c +++ b/pathd/path_nb_state.c @@ -4,6 +4,7 @@ */ #include <zebra.h> +#include <lib_errors.h> #include "log.h" #include "prefix.h" @@ -149,6 +150,68 @@ const void *pathd_srte_policy_candidate_path_lookup_entry( return srte_candidate_find(policy, preference); } +int pathd_srte_segment_list_segment_check_validate(struct nb_cb_create_args *args) +{ + struct srte_segment_list *segment_list; + + segment_list = nb_running_get_entry(args->dnode, NULL, false); + if (segment_list == NULL) + return NB_OK; + + if (yang_dnode_exists(args->dnode, "sid-value") || yang_dnode_exists(args->dnode, "nai")) { + if (segment_list->type == SRTE_SEGMENT_LIST_TYPE_SRV6) { + snprintf(args->errmsg, args->errmsg_len, + "The Segment List(%s) Type must be SRv6!", segment_list->name); + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "The Segment List(%s) Type must be SRv6!", segment_list->name); + return NB_ERR_VALIDATION; + } else + return NB_OK; + } + + if (yang_dnode_exists(args->dnode, "srv6-sid-value")) { + if (segment_list->type == SRTE_SEGMENT_LIST_TYPE_MPLS) { + snprintf(args->errmsg, args->errmsg_len, + "The Segment List(%s) Type must be MPLS!", segment_list->name); + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "The Segment List(%s) Type must be MPLS!", segment_list->name); + return NB_ERR_VALIDATION; + } else + return NB_OK; + } + return NB_OK; +} + +int pathd_srte_policy_candidate_path_check_validate( + struct nb_cb_create_args *args) +{ + struct srte_policy *policy; + const char *segment_list_name; + struct srte_segment_list *segment_list; + + policy = nb_running_get_entry(args->dnode, NULL, false); + 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) + return NB_OK; + + 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)) { + snprintf(args->errmsg, args->errmsg_len, + "The Segment List type(%d) and Policy type(%d) must match!", + segment_list->type, policy->type); + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "The Segment List type(%d) and Policy type(%d) must match!", + segment_list->type, policy->type); + return NB_ERR_VALIDATION; + } + + 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..6beb791e3984 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(struct ipaddr)); + 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..469b91143d68 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)); @@ -351,9 +353,14 @@ void srte_policy_del(struct srte_policy *policy) { struct srte_candidate *candidate; - path_zebra_delete_sr_policy(policy); + if (policy->type == SRTE_POLICY_TYPE_MPLS) { + 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/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/zapi_msg.c b/zebra/zapi_msg.c index 198715a657ce..0f0fd74f51c2 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2741,6 +2741,16 @@ static void zread_sr_policy_delete(ZAPI_HANDLER_ARGS) zebra_sr_policy_del(policy); } +static void zread_srv6_policy_set(ZAPI_HANDLER_ARGS) +{ + +} + +static void zread_srv6_policy_delete(ZAPI_HANDLER_ARGS) +{ + +} + int zsend_sr_policy_notify_status(uint32_t color, struct ipaddr *endpoint, char *name, int status) { @@ -4145,6 +4155,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_srte.h b/zebra/zebra_srte.h index 1cdee454048a..66b6a30d093a 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;