diff --git a/pathd/path_cli.c b/pathd/path_cli.c index ecb667f985..7a28449e4e 100644 --- a/pathd/path_cli.c +++ b/pathd/path_cli.c @@ -34,6 +34,7 @@ #ifndef VTYSH_EXTRACT_PL #include "pathd/path_cli_clippy.c" #endif +#include "pathd/path_ted.h" #define XPATH_MAXATTRSIZE 64 #define XPATH_MAXKEYSIZE 42 @@ -47,6 +48,18 @@ static int config_write_segment_routing(struct vty *vty); static int config_write_traffic_eng(struct vty *vty); static int config_write_segment_lists(struct vty *vty); static int config_write_sr_policies(struct vty *vty); +static int segment_list_has_src_dst( + struct vty *vty, char *xpath, long index, const char *index_str, + struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4, + struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6, + const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str, + const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str); +static int segment_list_has_prefix( + struct vty *vty, char *xpath, long index, const char *index_str, + const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str, + const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str, + const char *has_algo, long algo, const char *algo_str, + const char *has_iface_id, long iface_id, const char *iface_id_str); DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client"); @@ -144,6 +157,7 @@ DEFPY(show_srte_policy, return CMD_SUCCESS; } + /* * Show detailed SR-TE info */ @@ -295,56 +309,227 @@ void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode, yang_dnode_get_string(dnode, "./name")); } +static int segment_list_has_src_dst( + struct vty *vty, char *xpath, long index, const char *index_str, + struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4, + struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6, + const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str, + const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str) +{ + const char *node_src_id; + uint32_t ted_sid = MPLS_LABEL_NONE; + + 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; + ip_dst.ipa_type = IPADDR_V4; + ip_dst.ip._v4_addr = adj_dst_ipv4; + } else if (adj_src_ipv6_str != NULL) { + ip_src.ipa_type = IPADDR_V6; + ip_src.ip._v6_addr = adj_src_ipv6; + ip_dst.ipa_type = IPADDR_V6; + ip_dst.ip._v6_addr = adj_dst_ipv6; + } else { + return CMD_ERR_NO_MATCH; + } + ted_sid = path_ted_query_type_f(&ip_src, &ip_dst); + if (ted_sid == MPLS_LABEL_NONE) { + zlog_warn( + "%s: [rcv ted] CLI NOT FOUND Continue query_type_f SRC (%pIA) DST (%pIA)!", + __func__, &ip_src, &ip_dst); + } + /* type */ + snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type", + index_str); + if (adj_src_ipv4_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv4_adjacency"); + node_src_id = adj_src_ipv4_str; + } else if (adj_src_ipv6_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv6_adjacency"); + node_src_id = adj_src_ipv6_str; + } else { + return CMD_ERR_NO_MATCH; + } + /* addresses */ + snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, node_src_id); + snprintf(xpath, XPATH_MAXLEN, + "./segment[index='%s']/nai/remote-address", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + adj_dst_ipv4_str ? adj_dst_ipv4_str + : adj_dst_ipv6_str); + return CMD_SUCCESS; +} +int segment_list_has_prefix( + struct vty *vty, char *xpath, long index, const char *index_str, + const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str, + const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str, + const char *has_algo, long algo, const char *algo_str, + const char *has_iface_id, long iface_id, const char *iface_id_str) +{ + char buf_prefix[INET6_ADDRSTRLEN]; + + uint32_t ted_sid = MPLS_LABEL_NONE; + struct prefix prefix_cli = {}; + struct ipaddr pre_ipaddr = {}; + /* prefix with algorithm or local interface id */ + /* Type */ + snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type", + index_str); + if (has_iface_id != NULL) { + if (prefix_ipv4_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv4_local_iface"); + } else if (prefix_ipv6_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv6_local_iface"); + } else { + return CMD_ERR_NO_MATCH; + } + } else { + if (prefix_ipv4_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv4_algo"); + } else if (prefix_ipv6_str != NULL) { + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + "ipv6_algo"); + } else { + return CMD_ERR_NO_MATCH; + } + } + /* Prefix */ + if (prefix_ipv4_str != NULL) { + if (!str2prefix(prefix_ipv4_str, &prefix_cli)) { + vty_out(vty, "%% Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + inet_ntop(AF_INET, &prefix_cli.u.prefix4, buf_prefix, + sizeof(buf_prefix)); + pre_ipaddr.ipa_type = IPADDR_V4; + pre_ipaddr.ip._v4_addr = prefix_cli.u.prefix4; + } else if (prefix_ipv6_str != NULL) { + if (!str2prefix(prefix_ipv6_str, &prefix_cli)) { + vty_out(vty, "%% Malformed prefix\n"); + return CMD_WARNING_CONFIG_FAILED; + } + inet_ntop(AF_INET6, &prefix_cli.u.prefix6, buf_prefix, + sizeof(buf_prefix)); + pre_ipaddr.ipa_type = IPADDR_V6; + pre_ipaddr.ip._v6_addr = prefix_cli.u.prefix6; + } else { + return CMD_ERR_NO_MATCH; + } + snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, buf_prefix); + snprintf(xpath, XPATH_MAXLEN, + "./segment[index='%s']/nai/local-prefix-len", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + prefix_ipv4_str + ? strchr(prefix_ipv4_str, '/') + 1 + : strchr(prefix_ipv6_str, '/') + 1); + /* Alg / Iface */ + if (has_algo != NULL) { + snprintf(xpath, XPATH_MAXLEN, + "./segment[index='%s']/nai/algorithm", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, algo_str); + } else { + if (has_iface_id != NULL) { + snprintf(xpath, XPATH_MAXLEN, + "./segment[index='%s']/nai/local-interface", + index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + iface_id_str); + } + } + if (has_algo != NULL) { + ted_sid = path_ted_query_type_c(&prefix_cli, algo); + if (ted_sid == MPLS_LABEL_NONE) { + zlog_err( + "%s: [rcv ted] CLI NOT FOUND Continue query_type_c PREFIX (%pIA/%d) ALGO (%ld) sid:(%d)!", + __func__, &pre_ipaddr, prefix_cli.prefixlen, + algo, ted_sid); + } + } + if (has_iface_id != NULL) { + ted_sid = path_ted_query_type_e(&prefix_cli, iface_id); + if (ted_sid == MPLS_LABEL_NONE) { + zlog_err( + "%s: [rcv ted] CLI NOT FOUND Continue query_type_e PREFIX (%pIA/%d) IFACE (%ld) sid:(%d)!", + __func__, &pre_ipaddr, prefix_cli.prefixlen, + iface_id, ted_sid); + } + } + return CMD_SUCCESS; +} /* * XPath: /frr-pathd:pathd/srte/segment-list/segment */ -DEFPY(srte_segment_list_segment, - srte_segment_list_segment_cmd, - "index (0-4294967295)$index mpls label (16-1048575)$label " +/* clang-format off */ +DEFPY(srte_segment_list_segment, srte_segment_list_segment_cmd, + "index (0-4294967295)$index <[mpls$has_mpls_label label (16-1048575)$label] " + "|" "[nai$has_nai <" - "node " - ">]", + "prefix " + "" + "| adjacency$has_adj " + "" + ">]" + ">", "Index\n" "Index Value\n" "MPLS or IP Label\n" "Label\n" "Label Value\n" "Segment NAI\n" - "NAI node identifier\n" - "NAI IPv4 node identifier\n" - "NAI IPv6 node identifier\n") + "NAI prefix identifier\n" + "NAI IPv4 prefix identifier\n" + "NAI IPv6 prefix identifier\n" + "IGP Algorithm\n" + "Algorithm Value SPF or Strict-SPF\n" + "Interface Id\n" + "Interface Value\n" + "ADJ identifier\n" + "ADJ IPv4 src identifier\n" + "ADJ IPv4 dst identifier\n" + "ADJ IPv6 src identifier\n" + "ADJ IPv6 dst identifier\n") +/* clang-format on */ { char xpath[XPATH_MAXLEN]; - const char *node_id; + int status = CMD_SUCCESS; + 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']/sid-value", - index_str); - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, label_str); - - if (has_nai != NULL) { - snprintf(xpath, sizeof(xpath), "./segment[index='%s']/nai/type", - index_str); - if (node_ipv4_str != NULL) { - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, - "ipv4_node"); - node_id = node_ipv4_str; - } else if (node_ipv6_str != NULL) { - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, - "ipv6_node"); - node_id = node_ipv6_str; - } else { - return CMD_ERR_NO_MATCH; - } + if (has_mpls_label != NULL) { snprintf(xpath, sizeof(xpath), - "./segment[index='%s']/nai/local-address", index_str); - nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, node_id); + "./segment[index='%s']/sid-value", index_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, label_str); + return nb_cli_apply_changes(vty, NULL); + } + + if (has_adj != NULL) { + status = segment_list_has_src_dst(vty, xpath, index, index_str, + adj_src_ipv4, adj_dst_ipv4, + adj_src_ipv6, adj_dst_ipv6, + adj_src_ipv4_str, adj_dst_ipv4_str, + adj_dst_ipv6_str, adj_src_ipv6_str); + if (status != CMD_SUCCESS) + return status; } else { - snprintf(xpath, sizeof(xpath), "./segment[index='%s']/nai", - index_str); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + segment_list_has_prefix( + vty, xpath, index, index_str, prefix_ipv4, + prefix_ipv4_str, prefix_ipv6, prefix_ipv6_str, has_algo, + algo, algo_str, has_iface_id, iface_id, iface_id_str); + if (status != CMD_SUCCESS) + return status; } return nb_cli_apply_changes(vty, NULL); @@ -369,23 +554,60 @@ void cli_show_srte_segment_list_segment(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - vty_out(vty, " index %s mpls label %s", - yang_dnode_get_string(dnode, "./index"), - yang_dnode_get_string(dnode, "./sid-value")); + vty_out(vty, " index %s ", yang_dnode_get_string(dnode, "./index")); + 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; + switch (yang_dnode_get_enum(dnode, "./nai/type")) { case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: + case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: + case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); - vty_out(vty, " nai node %pI4", &addr.ipaddr_v4); + vty_out(vty, " nai prefix %pI4", &addr.ipaddr_v4); break; case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE: + case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE: + case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM: yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); - vty_out(vty, " nai node %pI6", &addr.ipaddr_v6); + vty_out(vty, " nai prefix %pI6", &addr.ipaddr_v6); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY: + yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + yang_dnode_get_ip(&addr_rmt, dnode, + "./nai/remote-address"); + vty_out(vty, " nai adjacency %pI4", &addr.ipaddr_v4); + vty_out(vty, " %pI4", &addr_rmt.ipaddr_v4); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY: + yang_dnode_get_ip(&addr, dnode, "./nai/local-address"); + yang_dnode_get_ip(&addr_rmt, dnode, + "./nai/remote-address"); + vty_out(vty, " nai adjacency %pI6", &addr.ipaddr_v6); + vty_out(vty, " %pI6", &addr_rmt.ipaddr_v6); break; default: break; } + if (yang_dnode_exists(dnode, "./nai/local-prefix-len")) { + vty_out(vty, "/%s", + yang_dnode_get_string( + dnode, "./nai/local-prefix-len")); + } + if (yang_dnode_exists(dnode, "./nai/local-interface")) { + vty_out(vty, " iface %s", + yang_dnode_get_string(dnode, + "./nai/local-interface")); + } + if (yang_dnode_exists(dnode, "./nai/algorithm")) { + vty_out(vty, " algorithm %s", + yang_dnode_get_string(dnode, + "./nai/algorithm")); + } } vty_out(vty, "\n"); } @@ -1038,6 +1260,7 @@ int config_write_segment_routing(struct vty *vty) int config_write_traffic_eng(struct vty *vty) { vty_out(vty, " traffic-eng\n"); + path_ted_config_write(vty); return 1; } diff --git a/pathd/path_nb.c b/pathd/path_nb.c index a210e31b9c..9c622883bc 100644 --- a/pathd/path_nb.c +++ b/pathd/path_nb.c @@ -90,6 +90,7 @@ const struct frr_yang_module_info frr_pathd_info = { .xpath = "/frr-pathd:pathd/srte/segment-list/segment/sid-value", .cbs = { .modify = pathd_srte_segment_list_segment_sid_value_modify, + .destroy = pathd_srte_segment_list_segment_sid_value_destroy, }, .priority = NB_DFLT_PRIORITY - 1 }, @@ -114,6 +115,10 @@ const struct frr_yang_module_info frr_pathd_info = { .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-interface", .cbs = {.modify = dummy_modify, .destroy = dummy_destroy} }, + { + .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-prefix-len", + .cbs = {.modify = dummy_modify, .destroy = dummy_destroy} + }, { .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-address", .cbs = {.modify = dummy_modify, .destroy = dummy_destroy} @@ -122,6 +127,10 @@ const struct frr_yang_module_info frr_pathd_info = { .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-interface", .cbs = {.modify = dummy_modify, .destroy = dummy_destroy} }, + { + .xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/algorithm", + .cbs = {.modify = dummy_modify, .destroy = dummy_destroy} + }, { .xpath = "/frr-pathd:pathd/srte/policy", .cbs = { diff --git a/pathd/path_nb.h b/pathd/path_nb.h index 3a0b3863ce..caeadd9ccc 100644 --- a/pathd/path_nb.h +++ b/pathd/path_nb.h @@ -43,6 +43,8 @@ int pathd_srte_segment_list_segment_nai_destroy( struct nb_cb_destroy_args *args); 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_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); diff --git a/pathd/path_nb_config.c b/pathd/path_nb_config.c index af54f5bce2..5b0f5b44e5 100644 --- a/pathd/path_nb_config.c +++ b/pathd/path_nb_config.c @@ -160,6 +160,22 @@ int pathd_srte_segment_list_segment_sid_value_modify( return NB_OK; } +int pathd_srte_segment_list_segment_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); + segment->sid_value = MPLS_LABEL_NONE; + 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) { struct srte_segment_entry *segment; @@ -184,6 +200,8 @@ void pathd_srte_segment_list_segment_nai_apply_finish( enum srte_segment_nai_type type; struct ipaddr local_addr, remote_addr; uint32_t local_iface = 0, remote_iface = 0; + uint8_t algo = 0, local_prefix_len = 0; + const char *algo_buf, *local_prefix_len_buf; segment = nb_running_get_entry(args->dnode, NULL, true); type = yang_dnode_get_enum(args->dnode, "./type"); @@ -207,12 +225,31 @@ void pathd_srte_segment_list_segment_nai_apply_finish( remote_iface = yang_dnode_get_uint32(args->dnode, "./remote-interface"); break; + case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: + algo_buf = yang_dnode_get_string(args->dnode, "./algorithm"); + algo = atoi(algo_buf); + local_prefix_len_buf = yang_dnode_get_string( + args->dnode, "./local-prefix-len"); + local_prefix_len = atoi(local_prefix_len_buf); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: + local_iface = + yang_dnode_get_uint32(args->dnode, "./local-interface"); + local_prefix_len_buf = yang_dnode_get_string( + args->dnode, "./local-prefix-len"); + local_prefix_len = atoi(local_prefix_len_buf); + break; default: break; } - srte_segment_entry_set_nai(segment, type, &local_addr, local_iface, - &remote_addr, remote_iface); + 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)) + SET_FLAG(segment->segment_list->flags, + F_SEGMENT_LIST_SID_CONFLICT); } /* diff --git a/pathd/path_pcep_config.c b/pathd/path_pcep_config.c index aacbca4ae9..609f091559 100644 --- a/pathd/path_pcep_config.c +++ b/pathd/path_pcep_config.c @@ -246,6 +246,10 @@ path_pcep_config_list_path_hops(struct srte_segment_list *segment_list) switch (segment->nai_type) { case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE: + case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: + case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE: + case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: + case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM: memcpy(&hop->nai.local_addr, &segment->nai_local_addr, sizeof(struct ipaddr)); break; @@ -278,6 +282,7 @@ int path_pcep_config_update_path(struct path *path) assert(path->nbkey.preference != 0); assert(path->nbkey.endpoint.ipa_type == IPADDR_V4); + int number_of_sid_clashed = 0; struct path_hop *hop; struct path_metric *metric; int index; @@ -297,40 +302,44 @@ int path_pcep_config_update_path(struct path *path) if (candidate->lsp->segment_list) { SET_FLAG(candidate->lsp->segment_list->flags, F_SEGMENT_LIST_DELETED); + srte_segment_list_del(candidate->lsp->segment_list); candidate->lsp->segment_list = NULL; } - if (path->first_hop != NULL) { - snprintf(segment_list_name_buff, sizeof(segment_list_name_buff), - "%s-%u", path->name, path->plsp_id); - segment_list_name = segment_list_name_buff; + if (path->first_hop == NULL) + return PATH_NB_ERR; - segment_list = srte_segment_list_add(segment_list_name); - segment_list->protocol_origin = path->update_origin; - strlcpy(segment_list->originator, path->originator, - sizeof(segment_list->originator)); - SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW); - SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED); + snprintf(segment_list_name_buff, sizeof(segment_list_name_buff), + "%s-%u", path->name, path->plsp_id); + segment_list_name = segment_list_name_buff; - for (hop = path->first_hop, index = 10; hop != NULL; - hop = hop->next, index += 10) { - assert(hop->has_sid); - assert(hop->is_mpls); + segment_list = srte_segment_list_add(segment_list_name); + segment_list->protocol_origin = path->update_origin; + strlcpy(segment_list->originator, path->originator, + sizeof(segment_list->originator)); + SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW); + SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED); - segment = srte_segment_entry_add(segment_list, index); + for (hop = path->first_hop, index = 10; hop != NULL; + hop = hop->next, index += 10) { + assert(hop->has_sid); + assert(hop->is_mpls); - segment->sid_value = (mpls_label_t)hop->sid.mpls.label; - SET_FLAG(segment->segment_list->flags, - F_SEGMENT_LIST_MODIFIED); + segment = srte_segment_entry_add(segment_list, index); - if (hop->has_nai) - srte_segment_entry_set_nai( - segment, srte_nai_type(hop->nai.type), - &hop->nai.local_addr, - hop->nai.local_iface, - &hop->nai.remote_addr, - hop->nai.remote_iface); - } + segment->sid_value = (mpls_label_t)hop->sid.mpls.label; + SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED); + + if (!hop->has_nai) + continue; + if (srte_segment_entry_set_nai( + segment, srte_nai_type(hop->nai.type), + &hop->nai.local_addr, hop->nai.local_iface, + &hop->nai.remote_addr, hop->nai.remote_iface, 0, 0) + == PATH_SID_ERROR) + /* TED queries don't match PCE */ + /* Don't apply srte,zebra changes */ + number_of_sid_clashed++; } candidate->lsp->segment_list = segment_list; @@ -352,7 +361,11 @@ int path_pcep_config_update_path(struct path *path) candidate->lsp->objfun = path->pce_objfun; } - srte_apply_changes(); + if (number_of_sid_clashed) + SET_FLAG(segment->segment_list->flags, + F_SEGMENT_LIST_SID_CONFLICT); + else + srte_apply_changes(); return 0; } @@ -402,6 +415,16 @@ enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type) return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY; case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY: return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY; + case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES: + return PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY; + case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: + return PCEP_SR_SUBOBJ_NAI_IPV4_NODE; + case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE: + return PCEP_SR_SUBOBJ_NAI_IPV6_NODE; + case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: + return PCEP_SR_SUBOBJ_NAI_IPV4_NODE; + case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM: + return PCEP_SR_SUBOBJ_NAI_IPV6_NODE; default: return PCEP_SR_SUBOBJ_NAI_UNKNOWN; } diff --git a/pathd/pathd.c b/pathd/pathd.c index 62785333ec..2462b08306 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -189,14 +189,20 @@ void srte_segment_entry_del(struct srte_segment_entry *segment) * @param type The remote address of the adjacency * @param type The remote interface index of the unumbered adjacency */ -void srte_segment_entry_set_nai(struct srte_segment_entry *segment, - enum srte_segment_nai_type type, - struct ipaddr *local_ip, uint32_t local_iface, - struct ipaddr *remote_ip, uint32_t remote_iface) +int srte_segment_entry_set_nai(struct srte_segment_entry *segment, + enum srte_segment_nai_type type, + struct ipaddr *local_ip, uint32_t local_iface, + struct ipaddr *remote_ip, uint32_t remote_iface, + uint8_t algo, uint8_t pref_len) { + int32_t status = 0; + struct prefix pre = {0}; segment->nai_type = type; memcpy(&segment->nai_local_addr, local_ip, sizeof(struct ipaddr)); + if (!segment || !local_ip || !remote_ip) + return 1; + switch (type) { case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE: @@ -205,6 +211,7 @@ void srte_segment_entry_set_nai(struct srte_segment_entry *segment, case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY: memcpy(&segment->nai_remote_addr, remote_ip, sizeof(struct ipaddr)); + status = srte_ted_do_query_type_f(segment, local_ip, remote_ip); break; case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY: memcpy(&segment->nai_remote_addr, remote_ip, @@ -212,12 +219,68 @@ void srte_segment_entry_set_nai(struct srte_segment_entry *segment, segment->nai_local_iface = local_iface; segment->nai_remote_iface = remote_iface; break; + case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM: + pre.family = AF_INET6; + pre.prefixlen = pref_len; + pre.u.prefix6 = local_ip->ip._v6_addr; + segment->nai_local_prefix_len = pref_len; + segment->nai_algorithm = algo; + status = srte_ted_do_query_type_c(segment, &pre, algo); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: + pre.family = AF_INET; + pre.prefixlen = pref_len; + pre.u.prefix4 = local_ip->ip._v4_addr; + segment->nai_local_prefix_len = pref_len; + segment->nai_algorithm = algo; + status = srte_ted_do_query_type_c(segment, &pre, algo); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE: + pre.family = AF_INET6; + pre.prefixlen = pref_len; + pre.u.prefix6 = local_ip->ip._v6_addr; + segment->nai_local_prefix_len = pref_len; + segment->nai_local_iface = local_iface; + status = srte_ted_do_query_type_e(segment, &pre, local_iface); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: + pre.family = AF_INET; + pre.prefixlen = pref_len; + pre.u.prefix4 = local_ip->ip._v4_addr; + segment->nai_local_prefix_len = pref_len; + segment->nai_local_iface = local_iface; + status = srte_ted_do_query_type_e(segment, &pre, local_iface); + break; default: segment->nai_local_addr.ipa_type = IPADDR_NONE; segment->nai_local_iface = 0; segment->nai_remote_addr.ipa_type = IPADDR_NONE; segment->nai_remote_iface = 0; } + return status; +} + +/** + * Mark segment as modified depending in protocol and sid conditions + * + * @param protocol_origin Origin of the segment list + * @param s_list Ptr to segment list with flags,sid to modidy + * @param s_entry Ptr to segment entry with sid to modidy + * @param ted_sid The sid from ted query + * @return void + */ +void srte_segment_set_local_modification(struct srte_segment_list *s_list, + struct srte_segment_entry *s_entry, + uint32_t ted_sid) +{ + if (!s_list || !s_entry) + return; + + if (s_list->protocol_origin == SRTE_ORIGIN_LOCAL + && s_entry->sid_value != ted_sid) { + s_entry->sid_value = ted_sid; + SET_FLAG(s_list->flags, F_SEGMENT_LIST_MODIFIED); + } } /** @@ -288,6 +351,105 @@ struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint) return RB_FIND(srte_policy_head, &srte_policies, &search); } +/* + * After new data from igp,local and pce the segment list : + * Mark as invalid for origin pce if cannot be validated + * Updated for origin local + */ +int srte_policy_update_ted_sid(void) +{ + + int number_of_sid_clashed = 0; + struct srte_segment_list *s_list; + struct srte_segment_entry *s_entry; + + if (!path_ted_is_initialized()) + return 0; + if (RB_EMPTY(srte_segment_list_head, &srte_segment_lists)) + return 0; + + RB_FOREACH (s_list, srte_segment_list_head, &srte_segment_lists) { + if (CHECK_FLAG(s_list->flags, F_SEGMENT_LIST_DELETED)) + continue; + RB_FOREACH (s_entry, srte_segment_entry_head, + &s_list->segments) { + PATH_TED_DEBUG( + "%s:PATHD-TED: SL: Name: %s index:(%d) sid:(%d) prefix_len:(%d) local iface:(%d) algorithm:(%d)", + __func__, s_list->name, s_entry->index, + s_entry->sid_value, + s_entry->nai_local_prefix_len, + s_entry->nai_local_iface, + s_entry->nai_algorithm); + struct prefix prefix_cli = {0}; + + switch (s_entry->nai_type) { + case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY: + case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY: + number_of_sid_clashed += + srte_ted_do_query_type_f( + s_entry, + &s_entry->nai_local_addr, + &s_entry->nai_remote_addr); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE: + prefix_cli.family = AF_INET6; + prefix_cli.prefixlen = + s_entry->nai_local_prefix_len; + prefix_cli.u.prefix6 = + s_entry->nai_local_addr.ip._v6_addr; + number_of_sid_clashed += + srte_ted_do_query_type_e( + s_entry, &prefix_cli, + s_entry->nai_local_iface); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: + prefix_cli.family = AF_INET; + prefix_cli.prefixlen = + s_entry->nai_local_prefix_len; + prefix_cli.u.prefix4 = + s_entry->nai_local_addr.ip._v4_addr; + number_of_sid_clashed += + srte_ted_do_query_type_e( + s_entry, &prefix_cli, + s_entry->nai_local_iface); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM: + prefix_cli.family = AF_INET6; + prefix_cli.prefixlen = + s_entry->nai_local_prefix_len; + prefix_cli.u.prefix6 = + s_entry->nai_local_addr.ip._v6_addr; + number_of_sid_clashed += + srte_ted_do_query_type_c( + s_entry, &prefix_cli, + s_entry->nai_algorithm); + break; + case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: + prefix_cli.family = AF_INET; + prefix_cli.prefixlen = + s_entry->nai_local_prefix_len; + prefix_cli.u.prefix4 = + s_entry->nai_local_addr.ip._v4_addr; + number_of_sid_clashed += + srte_ted_do_query_type_c( + s_entry, &prefix_cli, + s_entry->nai_algorithm); + break; + default: + break; + } + } + if (number_of_sid_clashed) { + SET_FLAG(s_list->flags, F_SEGMENT_LIST_SID_CONFLICT); + number_of_sid_clashed = 0; + } else + UNSET_FLAG(s_list->flags, F_SEGMENT_LIST_SID_CONFLICT); + } + srte_apply_changes(); + + return 0; +} + /** * Update a policy binding SID. * @@ -323,7 +485,9 @@ srte_policy_best_candidate(const struct srte_policy *policy) &policy->candidate_paths) { /* search for highest preference with existing segment list */ if (!CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED) - && candidate->lsp->segment_list) + && candidate->lsp->segment_list + && (!CHECK_FLAG(candidate->lsp->segment_list->flags, + F_SEGMENT_LIST_SID_CONFLICT))) return candidate; } @@ -535,6 +699,7 @@ void srte_candidate_set_bandwidth(struct srte_candidate *candidate, { struct srte_policy *policy = candidate->policy; char endpoint[46]; + ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint)); zlog_debug( "SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s", @@ -1139,3 +1304,91 @@ const char *srte_candidate_metric_name(enum srte_candidate_metric_type type) return "UNKNOWN"; } } + +int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry, + struct prefix *prefix_cli, uint32_t algo) +{ + int32_t status = 0; + uint32_t ted_sid = MPLS_LABEL_NONE; + + if (!entry || !prefix_cli) + return 0; + + if (!path_ted_is_initialized()) + return 0; + + ted_sid = path_ted_query_type_c(prefix_cli, algo); + if (ted_sid == MPLS_LABEL_NONE) { + zlog_warn(" %s: PATHD-TED: SL: ERROR query C : ted-sid (%d)", + __func__, ted_sid); + } else { + zlog_debug("%s: PATHD-TED: SL: Sucess query C : ted-sid (%d)", + __func__, ted_sid); + } + if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid, + entry->sid_value)) { + status = PATH_SID_ERROR; + } else + srte_segment_set_local_modification(entry->segment_list, entry, + ted_sid); + return status; +} + +int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry, + struct prefix *prefix_cli, + uint32_t local_iface) +{ + int32_t status = 0; + uint32_t ted_sid = MPLS_LABEL_NONE; + + if (!entry || !prefix_cli) + return 0; + + if (!path_ted_is_initialized()) + return 0; + + ted_sid = path_ted_query_type_e(prefix_cli, local_iface); + if (ted_sid == MPLS_LABEL_NONE) { + zlog_warn(" %s: PATHD-TED: SL: ERROR query E : ted-sid (%d)", + __func__, ted_sid); + } else { + zlog_debug("%s: PATHD-TED: SL: Sucess query E : ted-sid (%d)", + __func__, ted_sid); + } + if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid, + entry->sid_value)) { + status = PATH_SID_ERROR; + } else + srte_segment_set_local_modification(entry->segment_list, entry, + ted_sid); + return status; +} + +int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry, + struct ipaddr *local, struct ipaddr *remote) +{ + int32_t status = 0; + uint32_t ted_sid = MPLS_LABEL_NONE; + + if (!entry || !local || !remote) + return 0; + + if (!path_ted_is_initialized()) + return status; + + ted_sid = path_ted_query_type_f(local, remote); + if (ted_sid == MPLS_LABEL_NONE) { + zlog_warn("%s:SL: ERROR query F : ted-sid (%d)", __func__, + ted_sid); + } else { + zlog_debug("%s:SL: Sucess query F : ted-sid (%d)", __func__, + ted_sid); + } + if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid, + entry->sid_value)) { + status = PATH_SID_ERROR; + } else + srte_segment_set_local_modification(entry->segment_list, entry, + ted_sid); + return status; +} diff --git a/pathd/pathd.h b/pathd/pathd.h index 6a5fdb3c24..7d38272e85 100644 --- a/pathd/pathd.h +++ b/pathd/pathd.h @@ -24,6 +24,13 @@ #include "lib/ipaddr.h" #include "lib/srte.h" #include "lib/hook.h" +#include "lib/prefix.h" + +#define PATH_SID_ERROR 1 +#define PATH_SID_NO_ERROR 0 +#define CHECK_SID(or, ts, es) \ + ((or == SRTE_ORIGIN_PCEP && (ts == MPLS_LABEL_NONE || es != ts)) \ + || (or == SRTE_ORIGIN_LOCAL && ts == MPLS_LABEL_NONE)) DECLARE_MGROUP(PATHD); @@ -100,7 +107,12 @@ enum srte_segment_nai_type { SRTE_SEGMENT_NAI_TYPE_IPV6_NODE = 2, SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY = 3, SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY = 4, - SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY = 5 + SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY = 5, + SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES = 6, + SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE = 7, + SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE = 8, + SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM = 9, + SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM = 10 }; enum objfun_type { @@ -175,6 +187,9 @@ struct srte_segment_entry { /* NAI remote interface when nai type is not IPv4 unnumbered adjacency */ uint32_t nai_remote_iface; + /* Support draft-ietf-spring-segment-routing-policy sl types queries*/ + uint8_t nai_local_prefix_len; + uint8_t nai_algorithm; }; RB_HEAD(srte_segment_entry_head, srte_segment_entry); RB_PROTOTYPE(srte_segment_entry_head, srte_segment_entry, entry, @@ -200,6 +215,7 @@ struct srte_segment_list { #define F_SEGMENT_LIST_NEW 0x0002 #define F_SEGMENT_LIST_MODIFIED 0x0004 #define F_SEGMENT_LIST_DELETED 0x0008 +#define F_SEGMENT_LIST_SID_CONFLICT 0x0010 }; RB_HEAD(srte_segment_list_head, srte_segment_list); RB_PROTOTYPE(srte_segment_list_head, srte_segment_list, entry, @@ -361,14 +377,18 @@ struct srte_segment_list *srte_segment_list_find(const char *name); struct srte_segment_entry * srte_segment_entry_add(struct srte_segment_list *segment_list, uint32_t index); void srte_segment_entry_del(struct srte_segment_entry *segment); -void srte_segment_entry_set_nai(struct srte_segment_entry *segment, - enum srte_segment_nai_type type, - struct ipaddr *local_ip, uint32_t local_iface, - struct ipaddr *remote_ip, - uint32_t remote_iface); +int srte_segment_entry_set_nai(struct srte_segment_entry *segment, + enum srte_segment_nai_type type, + struct ipaddr *local_ip, uint32_t local_iface, + struct ipaddr *remote_ip, uint32_t remote_iface, + uint8_t algo, uint8_t pref_len); +void srte_segment_set_local_modification(struct srte_segment_list *s_list, + struct srte_segment_entry *s_entry, + uint32_t ted_sid); struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint); void srte_policy_del(struct srte_policy *policy); struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint); +int srte_policy_update_ted_sid(void); void srte_policy_update_binding_sid(struct srte_policy *policy, uint32_t binding_sid); void srte_apply_changes(void); @@ -414,4 +434,40 @@ void pathd_shutdown(void); /* path_cli.c */ void path_cli_init(void); + +/** + * Search for sid based in prefix and algorithm + * + * @param Prefix The prefix to use + * @param algo Algorithm we want to query for + * @param ted_sid Sid to query + * + * @return void + */ +int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry, + struct prefix *prefix_cli, uint32_t algo); + +/** + * Search for sid based in prefix and interface id + * + * @param Prefix The prefix to use + * @param local_iface The id of interface + * @param ted_sid Sid to query + * + * @return void + */ +int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry, + struct prefix *prefix_cli, + uint32_t local_iface); +/** + * Search for sid based in local and remote ip + * + * @param entry entry to update + * @param local Local addr for query + * @param remote Local addr for query + * + * @return void + */ +int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry, + struct ipaddr *local, struct ipaddr *remote); #endif /* _FRR_PATHD_H_ */ diff --git a/yang/frr-pathd.yang b/yang/frr-pathd.yang index 03f0d3b024..30f9875a6d 100644 --- a/yang/frr-pathd.yang +++ b/yang/frr-pathd.yang @@ -84,51 +84,71 @@ module frr-pathd { leaf index { type uint32; description "Segment index"; - } - leaf sid-value { - type rt-types:mpls-label; + } + 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; - description "MPLS label value"; - } - container nai { - presence "The segement 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"; - } + 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-interface { - type uint32; - mandatory true; - when "../type = 'ipv4_unnumbered_adjacency'"; - } - leaf remote-address { - type inet:ip-address; + } + 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 remote-address { + type inet:ip-address; mandatory true; when "../type = 'ipv4_adjacency' or ../type = 'ipv6_adjacency' or ../type = 'ipv4_unnumbered_adjacency'"; } @@ -137,6 +157,11 @@ module frr-pathd { mandatory true; when "../type = 'ipv4_unnumbered_adjacency'"; } + leaf algorithm { + type uint8; + mandatory true; + when "../type = 'ipv4_algo' or ../type = 'ipv6_algo'"; + } } } }