diff options
Diffstat (limited to 'lib')
72 files changed, 2226 insertions, 1043 deletions
@@ -94,7 +94,8 @@ int bfd_validate_param(struct vty *vty, const char *dm_str, const char *rx_str, * bfd_set_param - Set the configured BFD paramter values */ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx, - uint8_t detect_mult, int defaults, int *command) + uint8_t detect_mult, const char *profile, int defaults, + int *command) { if (!*bfd_info) { *bfd_info = bfd_info_create(); @@ -102,7 +103,8 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx, } else { if (((*bfd_info)->required_min_rx != min_rx) || ((*bfd_info)->desired_min_tx != min_tx) - || ((*bfd_info)->detect_mult != detect_mult)) + || ((*bfd_info)->detect_mult != detect_mult) + || (profile && strcmp((*bfd_info)->profile, profile))) *command = ZEBRA_BFD_DEST_UPDATE; } @@ -110,6 +112,11 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx, (*bfd_info)->required_min_rx = min_rx; (*bfd_info)->desired_min_tx = min_tx; (*bfd_info)->detect_mult = detect_mult; + if (profile) + strlcpy((*bfd_info)->profile, profile, + BFD_PROFILE_NAME_LEN); + else + (*bfd_info)->profile[0] = '\0'; } if (!defaults) @@ -121,6 +128,8 @@ void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, uint32_t min_tx, /* * bfd_peer_sendmsg - Format and send a peer register/Unregister * command to Zebra to be forwarded to BFD + * + * DEPRECATED: use zclient_bfd_command instead */ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, int family, void *dst_ip, void *src_ip, char *if_name, @@ -143,8 +152,7 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, if (!zclient || zclient->sock < 0) { if (bfd_debug) zlog_debug( - "%s: Can't send BFD peer register, Zebra client not " - "established", + "%s: Can't send BFD peer register, Zebra client not established", __func__); return; } @@ -162,6 +170,11 @@ void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, args.min_rx = bfd_info->required_min_rx; args.min_tx = bfd_info->desired_min_tx; args.detection_multiplier = bfd_info->detect_mult; + if (bfd_info->profile[0]) { + args.profilelen = strlen(bfd_info->profile); + strlcpy(args.profile, bfd_info->profile, + sizeof(args.profile)); + } } addrlen = family == AF_INET ? sizeof(struct in_addr) @@ -217,8 +230,7 @@ struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, if (ifp == NULL) { if (bfd_debug) zlog_debug( - "zebra_interface_bfd_read: " - "Can't find interface by ifindex: %d ", + "zebra_interface_bfd_read: Can't find interface by ifindex: %d ", ifindex); return NULL; } @@ -320,8 +332,7 @@ void bfd_show_param(struct vty *vty, struct bfd_info *bfd_info, int bfd_tag, json_bfd); } else { vty_out(vty, - " %s%sDetect Multiplier: %d, Min Rx interval: %d," - " Min Tx interval: %d\n", + " %s%sDetect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n", (extra_space) ? " " : "", (bfd_tag) ? "BFD: " : " ", bfd_info->detect_mult, bfd_info->required_min_rx, bfd_info->desired_min_tx); @@ -397,8 +408,7 @@ void bfd_client_sendmsg(struct zclient *zclient, int command, if (!zclient || zclient->sock < 0) { if (bfd_debug) zlog_debug( - "%s: Can't send BFD client register, Zebra client not " - "established", + "%s: Can't send BFD client register, Zebra client not established", __func__); return; } @@ -429,6 +439,15 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args) struct stream *s; size_t addrlen; + /* Individual reg/dereg messages are suppressed during shutdown. */ + if (CHECK_FLAG(bfd_gbl.flags, BFD_GBL_FLAG_IN_SHUTDOWN)) { + if (bfd_debug) + zlog_debug( + "%s: Suppressing BFD peer reg/dereg messages", + __func__); + return -1; + } + /* Check socket. */ if (!zc || zc->sock < 0) { if (bfd_debug) @@ -92,8 +92,8 @@ extern int bfd_validate_param(struct vty *vty, const char *dm_str, uint32_t *tx_val); extern void bfd_set_param(struct bfd_info **bfd_info, uint32_t min_rx, - uint32_t min_tx, uint8_t detect_mult, int defaults, - int *command); + uint32_t min_tx, uint8_t detect_mult, + const char *profile, int defaults, int *command); extern void bfd_peer_sendmsg(struct zclient *zclient, struct bfd_info *bfd_info, int family, void *dst_ip, void *src_ip, char *if_name, int ttl, int multihop, int cbit, diff --git a/lib/bitfield.h b/lib/bitfield.h index 72980165f9..244938933b 100644 --- a/lib/bitfield.h +++ b/lib/bitfield.h @@ -58,7 +58,7 @@ typedef unsigned int word_t; * @n: The current word number that is being used. * @m: total number of words in 'data' */ -#define bitfield_t struct { word_t *data; size_t n, m; } +typedef struct {word_t *data; size_t n, m; } bitfield_t; /** * Initialize the bits. @@ -97,6 +97,16 @@ typedef unsigned int word_t; #define bf_release_index(v, id) \ (v).data[bf_index(id)] &= ~(1 << (bf_offset(id))) +/* check if an id is in use */ +#define bf_test_index(v, id) \ + ((v).data[bf_index(id)] & (1 << (bf_offset(id)))) + +/* check if the bit field has been setup */ +#define bf_is_inited(v) ((v).data) + +/* compare two bitmaps of the same length */ +#define bf_cmp(v1, v2) (memcmp((v1).data, (v2).data, ((v1).m * sizeof(word_t)))) + /* * return 0th index back to bitfield */ @@ -146,6 +156,37 @@ typedef unsigned int word_t; (b) += (w * WORD_SIZE); \ } while (0) +static inline unsigned int bf_find_next_set_bit(bitfield_t v, + word_t start_index) +{ + int start_bit; + unsigned long i, offset; + + start_bit = start_index & (WORD_SIZE - 1); + + for (i = bf_index(start_index); i < v.m; ++i) { + if (v.data[i] == 0) { + /* if the whole word is empty move to the next */ + start_bit = 0; + continue; + } + /* scan one word for set bits */ + for (offset = start_bit; offset < WORD_SIZE; ++offset) { + if ((v.data[i] >> offset) & 1) + return ((i * WORD_SIZE) + offset); + } + /* move to the next word */ + start_bit = 0; + } + return WORD_MAX; +} + +/* iterate through all the set bits */ +#define bf_for_each_set_bit(v, b, max) \ + for ((b) = bf_find_next_set_bit((v), 0); \ + (b) < max; \ + (b) = bf_find_next_set_bit((v), (b) + 1)) + /* * Free the allocated memory for data * @v: an instance of bitfield_t struct. diff --git a/lib/buffer.c b/lib/buffer.c index ff49bc83df..459d98e75d 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -327,8 +327,7 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width, /* This should absolutely never occur. */ flog_err_sys( EC_LIB_SYSTEM_CALL, - "%s: corruption detected: iov_small overflowed; " - "head %p, tail %p, head->next %p", + "%s: corruption detected: iov_small overflowed; head %p, tail %p, head->next %p", __func__, (void *)b->head, (void *)b->tail, (void *)b->head->next); iov = XMALLOC(MTYPE_TMP, diff --git a/lib/command.c b/lib/command.c index fc43cce189..159ed07b38 100644 --- a/lib/command.c +++ b/lib/command.c @@ -841,9 +841,6 @@ enum node_type node_parent(enum node_type node) case BFD_PROFILE_NODE: ret = BFD_NODE; break; - case RPKI_VRF_NODE: - ret = VRF_NODE; - break; default: ret = CONFIG_NODE; break; @@ -907,6 +904,13 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, > vty->candidate_config->version) nb_config_replace(vty->candidate_config, running_config, true); + + /* + * Perform pending commit (if any) before executing + * non-YANG command. + */ + if (matched_element->attr != CMD_ATTR_YANG) + nb_cli_pending_commit_check(vty); } ret = matched_element->func(matched_element, vty, argc, argv); diff --git a/lib/command.h b/lib/command.h index 9e0fc783c7..e20bfe3318 100644 --- a/lib/command.h +++ b/lib/command.h @@ -159,7 +159,6 @@ enum node_type { OPENFABRIC_NODE, /* OpenFabric router configuration node */ VRRP_NODE, /* VRRP node */ BMP_NODE, /* BMP config under router bgp */ - RPKI_VRF_NODE, /* RPKI node for VRF */ NODE_TYPE_MAX, /* maximum */ }; @@ -258,6 +257,12 @@ struct cmd_node { #define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) +#define DEFPY_YANG(funcname, cmdname, cmdstr, helpstr) \ + DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) + +#define DEFPY_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \ + DEFPY_YANG(funcname, cmdname, cmdstr, helpstr) + #define DEFUN(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_FUNC_DECL(funcname) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \ @@ -271,10 +276,16 @@ struct cmd_node { #define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) +#define DEFUN_YANG(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) + /* DEFUN_NOSH for commands that vtysh should ignore */ #define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ DEFUN(funcname, cmdname, cmdstr, helpstr) +#define DEFUN_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_YANG(funcname, cmdname, cmdstr, helpstr) + /* DEFSH for vtysh. */ #define DEFSH(daemon, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon) @@ -283,6 +294,9 @@ struct cmd_node { DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, \ daemon) +#define DEFSH_YANG(daemon, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_YANG, daemon) + /* DEFUN + DEFSH */ #define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_FUNC_DECL(funcname) \ @@ -303,6 +317,9 @@ struct cmd_node { DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, \ CMD_ATTR_DEPRECATED) +#define DEFUNSH_YANG(daemon, funcname, cmdname, cmdstr, helpstr) \ + DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) + /* ALIAS macro which define existing command's alias. */ #define ALIAS(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) @@ -318,6 +335,9 @@ struct cmd_node { DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, \ CMD_ATTR_DEPRECATED, 0) +#define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG, 0) + #define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) @@ -329,18 +349,6 @@ struct cmd_node { DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, \ CMD_ATTR_DEPRECATED, daemon) -#else /* VTYSH_EXTRACT_PL */ -#define DEFPY(funcname, cmdname, cmdstr, helpstr) \ - DEFUN(funcname, cmdname, cmdstr, helpstr) - -#define DEFPY_NOSH(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) - -#define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) - -#define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) #endif /* VTYSH_EXTRACT_PL */ /* Some macroes */ @@ -359,6 +367,8 @@ struct cmd_node { #define SHOW_STR "Show running system information\n" #define IP_STR "IP information\n" #define IPV6_STR "IPv6 information\n" +#define SRTE_STR "SR-TE information\n" +#define SRTE_COLOR_STR "SR-TE Color information\n" #define NO_STR "Negate a command or set its defaults\n" #define REDIST_STR "Redistribute information from another routing protocol\n" #define CLEAR_STR "Reset functions\n" diff --git a/lib/command_graph.h b/lib/command_graph.h index 1efe8b1803..179e104a57 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -74,6 +74,7 @@ enum cmd_token_type { enum { CMD_ATTR_NORMAL, CMD_ATTR_DEPRECATED, CMD_ATTR_HIDDEN, + CMD_ATTR_YANG, }; /* Comamand token struct. */ diff --git a/lib/defun_lex.l b/lib/defun_lex.l index 19b06f51b8..bc5fbd24d9 100644 --- a/lib/defun_lex.l +++ b/lib/defun_lex.l @@ -140,6 +140,8 @@ SPECIAL [(),] "DEFPY_NOSH" value = strdup(yytext); return DEFUNNY; "DEFPY_ATTR" value = strdup(yytext); return DEFUNNY; "DEFPY_HIDDEN" value = strdup(yytext); return DEFUNNY; +"DEFPY_YANG" value = strdup(yytext); return DEFUNNY; +"DEFPY_YANG_NOSH" value = strdup(yytext); return DEFUNNY; "ALIAS" value = strdup(yytext); return DEFUNNY; "ALIAS_HIDDEN" value = strdup(yytext); return DEFUNNY; "install_element" value = strdup(yytext); return INSTALL; diff --git a/lib/ferr.c b/lib/ferr.c index ccf63dea17..7b923da177 100644 --- a/lib/ferr.c +++ b/lib/ferr.c @@ -130,7 +130,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json) if (json) { char key[11]; - snprintf(key, sizeof(key), "%"PRIu32, ref->code); + snprintf(key, sizeof(key), "%u", ref->code); obj = json_object_new_object(); json_object_string_add(obj, "title", ref->title); json_object_string_add(obj, "description", @@ -142,7 +142,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json) char pbuf[256]; char ubuf[256]; - snprintf(pbuf, sizeof(pbuf), "\nError %"PRIu32" - %s", + snprintf(pbuf, sizeof(pbuf), "\nError %u - %s", ref->code, ref->title); memset(ubuf, '=', strlen(pbuf)); ubuf[strlen(pbuf)] = '\0'; diff --git a/lib/filter.h b/lib/filter.h index 76e992bf8e..d41f3b65cd 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -170,11 +170,6 @@ enum yang_prefix_list_action { struct lyd_node; struct vty; -extern void access_list_legacy_show(struct vty *vty, struct lyd_node *dnode, - bool show_defaults); -extern void access_list_legacy_remark_show(struct vty *vty, - struct lyd_node *dnode, - bool show_defaults); extern void access_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); extern void access_list_remark_show(struct vty *vty, struct lyd_node *dnode, diff --git a/lib/filter_cli.c b/lib/filter_cli.c index fe8190d098..8c7a515dc5 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -169,7 +169,7 @@ static long acl_get_seq(struct vty *vty, const char *xpath) /* * Cisco (legacy) access lists. */ -DEFPY( +DEFPY_YANG( access_list_std, access_list_std_cmd, "access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>", ACCESS_LIST_STR @@ -193,7 +193,8 @@ DEFPY( * none given (backward compatibility). */ snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list-legacy[number='%s']", number_str); + "/frr-filter:lib/access-list[type='ipv4'][name='%s']", + number_str); nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); if (seq_str == NULL) { /* Use XPath to find the next sequence number. */ @@ -213,13 +214,13 @@ DEFPY( concat_addr_mask_v4(host_str, mask_str, ipmask, sizeof(ipmask)); nb_cli_enqueue_change(vty, "./network", NB_OP_MODIFY, ipmask); } else { - nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./source-any", NB_OP_CREATE, NULL); } return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_access_list_std, no_access_list_std_cmd, "no access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>", NO_STR @@ -244,7 +245,7 @@ DEFPY( if (seq_str != NULL) { snprintf( xpath, sizeof(xpath), - "/frr-filter:lib/access-list-legacy[number='%s']/entry[sequence='%s']", + "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']", number_str, seq_str); nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -252,7 +253,8 @@ DEFPY( /* Otherwise, to keep compatibility, we need to figure it out. */ snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list-legacy[number='%s']", number_str); + "/frr-filter:lib/access-list[type='ipv4'][name='%s']", + number_str); /* Access-list must exist before entries. */ if (yang_dnode_exists(running_config->dnode, xpath) == false) @@ -278,7 +280,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( access_list_ext, access_list_ext_cmd, "access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>", ACCESS_LIST_STR @@ -308,7 +310,8 @@ DEFPY( * none given (backward compatibility). */ snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list-legacy[number='%s']", number_str); + "/frr-filter:lib/access-list[type='ipv4'][name='%s']", + number_str); nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); if (seq_str == NULL) { /* Use XPath to find the next sequence number. */ @@ -329,7 +332,7 @@ DEFPY( sizeof(ipmask)); nb_cli_enqueue_change(vty, "./network", NB_OP_MODIFY, ipmask); } else { - nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL); + nb_cli_enqueue_change(vty, "./source-any", NB_OP_CREATE, NULL); } if (dst_str != NULL && dst_mask_str == NULL) { @@ -348,7 +351,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_access_list_ext, no_access_list_ext_cmd, "no access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>", NO_STR @@ -379,7 +382,7 @@ DEFPY( if (seq_str != NULL) { snprintfrr( xpath, sizeof(xpath), - "/frr-filter:lib/access-list-legacy[number='%s']/entry[sequence='%s']", + "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']", number_str, seq_str); nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -387,7 +390,8 @@ DEFPY( /* Otherwise, to keep compatibility, we need to figure it out. */ snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list-legacy[number='%s']", number_str); + "/frr-filter:lib/access-list[type='ipv4'][name='%s']", + number_str); /* Access-list must exist before entries. */ if (yang_dnode_exists(running_config->dnode, xpath) == false) @@ -429,131 +433,10 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( - no_access_list_legacy, no_access_list_legacy_cmd, - "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number", - NO_STR - ACCESS_LIST_STR - ACCESS_LIST_XLEG_STR) -{ - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list-legacy[number='%s']", number_str); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -void access_list_legacy_show(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) -{ - uint16_t number = yang_dnode_get_uint16(dnode, "../number"); - bool extended; - struct prefix p; - struct in_addr mask; - - vty_out(vty, "access-list %d seq %s %s", number, - yang_dnode_get_string(dnode, "./sequence"), - yang_dnode_get_string(dnode, "./action")); - - extended = (number >= 100 && number <= 199) - || (number >= 2000 && number <= 2699); - if (extended) - vty_out(vty, " ip"); - - if (yang_dnode_exists(dnode, "./network")) { - yang_dnode_get_prefix(&p, dnode, "./network"); - masklen2ip(p.prefixlen, &mask); - vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask); - } else if (yang_dnode_exists(dnode, "./host")) { - if (extended) - vty_out(vty, " host"); - - vty_out(vty, " %s", yang_dnode_get_string(dnode, "./host")); - } else if (yang_dnode_exists(dnode, "./any")) - vty_out(vty, " any"); - - if (extended) { - if (yang_dnode_exists(dnode, "./destination-network")) { - yang_dnode_get_prefix(&p, dnode, - "./destination-network"); - masklen2ip(p.prefixlen, &mask); - vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask); - } else if (yang_dnode_exists(dnode, "./destination-host")) - vty_out(vty, " host %s", - yang_dnode_get_string(dnode, - "./destination-host")); - else if (yang_dnode_exists(dnode, "./destination-any")) - vty_out(vty, " any"); - } - - vty_out(vty, "\n"); -} - -DEFPY( - access_list_legacy_remark, access_list_legacy_remark_cmd, - "access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark LINE...", - ACCESS_LIST_STR - ACCESS_LIST_XLEG_STR - ACCESS_LIST_REMARK_STR - ACCESS_LIST_REMARK_LINE_STR) -{ - int rv; - char *remark; - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list-legacy[number='%s']", number_str); - nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - - remark = argv_concat(argv, argc, 3); - nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark); - rv = nb_cli_apply_changes(vty, xpath); - XFREE(MTYPE_TMP, remark); - - return rv; -} - -DEFPY( - no_access_list_legacy_remark, no_access_list_legacy_remark_cmd, - "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark", - NO_STR - ACCESS_LIST_STR - ACCESS_LIST_XLEG_STR - ACCESS_LIST_REMARK_STR) -{ - char xpath[XPATH_MAXLEN]; - - snprintf(xpath, sizeof(xpath), - "/frr-filter:lib/access-list-legacy[number='%s']/remark", - number_str); - nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - - return nb_cli_apply_changes(vty, NULL); -} - -ALIAS( - no_access_list_legacy_remark, no_access_list_legacy_remark_line_cmd, - "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark LINE...", - NO_STR - ACCESS_LIST_STR - ACCESS_LIST_XLEG_STR - ACCESS_LIST_REMARK_STR - ACCESS_LIST_REMARK_LINE_STR) - -void access_list_legacy_remark_show(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) -{ - vty_out(vty, "access-list %s remark %s\n", - yang_dnode_get_string(dnode, "../number"), - yang_dnode_get_string(dnode, NULL)); -} - /* * Zebra access lists. */ -DEFPY( +DEFPY_YANG( access_list, access_list_cmd, "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>", ACCESS_LIST_STR @@ -599,7 +482,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_access_list, no_access_list_cmd, "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>", NO_STR @@ -656,7 +539,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_access_list_all, no_access_list_all_cmd, "no access-list WORD$name", NO_STR @@ -672,7 +555,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( access_list_remark, access_list_remark_cmd, "access-list WORD$name remark LINE...", ACCESS_LIST_STR @@ -696,7 +579,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_access_list_remark, no_access_list_remark_cmd, "no access-list WORD$name remark", NO_STR @@ -723,7 +606,7 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) -DEFPY( +DEFPY_YANG( ipv6_access_list, ipv6_access_list_cmd, "ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>", IPV6_STR @@ -770,7 +653,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_ipv6_access_list, no_ipv6_access_list_cmd, "no ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>", NO_STR @@ -828,7 +711,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_ipv6_access_list_all, no_ipv6_access_list_all_cmd, "no ipv6 access-list WORD$name", NO_STR @@ -845,7 +728,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( ipv6_access_list_remark, ipv6_access_list_remark_cmd, "ipv6 access-list WORD$name remark LINE...", IPV6_STR @@ -870,7 +753,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_ipv6_access_list_remark, no_ipv6_access_list_remark_cmd, "no ipv6 access-list WORD$name remark", NO_STR @@ -899,7 +782,7 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) -DEFPY( +DEFPY_YANG( mac_access_list, mac_access_list_cmd, "mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", MAC_STR @@ -942,7 +825,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_mac_access_list, no_mac_access_list_cmd, "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$prefix|any>", NO_STR @@ -999,7 +882,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_mac_access_list_all, no_mac_access_list_all_cmd, "no mac access-list WORD$name", NO_STR @@ -1016,7 +899,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( mac_access_list_remark, mac_access_list_remark_cmd, "mac access-list WORD$name remark LINE...", MAC_STR @@ -1041,7 +924,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_mac_access_list_remark, no_mac_access_list_remark_cmd, "no mac access-list WORD$name remark", NO_STR @@ -1077,6 +960,9 @@ void access_list_show(struct vty *vty, struct lyd_node *dnode, struct prefix p; bool is_any; bool is_exact = false; + bool cisco_style = false; + bool cisco_extended = false; + struct in_addr mask; char macstr[PREFIX2STR_BUFFER]; is_any = yang_dnode_exists(dnode, "./any"); @@ -1085,8 +971,19 @@ void access_list_show(struct vty *vty, struct lyd_node *dnode, if (is_any) break; - yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix"); - is_exact = yang_dnode_get_bool(dnode, "./ipv4-exact-match"); + if (yang_dnode_exists(dnode, "./host") + || yang_dnode_exists(dnode, "./network") + || yang_dnode_exists(dnode, "./source-any")) { + cisco_style = true; + if (yang_dnode_exists(dnode, "./destination-host") + || yang_dnode_exists(dnode, "./destination-network") + || yang_dnode_exists(dnode, "./destination-any")) + cisco_extended = true; + } else { + yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix"); + is_exact = yang_dnode_get_bool(dnode, + "./ipv4-exact-match"); + } break; case YALT_IPV6: /* ipv6 */ vty_out(vty, "ipv6 "); @@ -1110,6 +1007,48 @@ void access_list_show(struct vty *vty, struct lyd_node *dnode, yang_dnode_get_string(dnode, "./sequence"), yang_dnode_get_string(dnode, "./action")); + /* Handle Cisco style access lists. */ + if (cisco_style) { + if (cisco_extended) + vty_out(vty, " ip"); + + if (yang_dnode_exists(dnode, "./network")) { + yang_dnode_get_prefix(&p, dnode, "./network"); + masklen2ip(p.prefixlen, &mask); + vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask); + } else if (yang_dnode_exists(dnode, "./host")) { + if (cisco_extended) + vty_out(vty, " host"); + + vty_out(vty, " %s", + yang_dnode_get_string(dnode, "./host")); + } else if (yang_dnode_exists(dnode, "./source-any")) + vty_out(vty, " any"); + + /* Not extended, exit earlier. */ + if (!cisco_extended) { + vty_out(vty, "\n"); + return; + } + + /* Handle destination address. */ + if (yang_dnode_exists(dnode, "./destination-network")) { + yang_dnode_get_prefix(&p, dnode, + "./destination-network"); + masklen2ip(p.prefixlen, &mask); + vty_out(vty, " %pI4 %pI4", &p.u.prefix4, &mask); + } else if (yang_dnode_exists(dnode, "./destination-host")) + vty_out(vty, " host %s", + yang_dnode_get_string(dnode, + "./destination-host")); + else if (yang_dnode_exists(dnode, "./destination-any")) + vty_out(vty, " any"); + + vty_out(vty, "\n"); + return; + } + + /* Zebra style access list. */ if (!is_any) { /* If type is MAC don't show '/mask'. */ if (type == 2 /* mac */) { @@ -1243,7 +1182,7 @@ static int plist_remove(struct vty *vty, const char *iptype, const char *name, return rv; } -DEFPY( +DEFPY_YANG( ip_prefix_list, ip_prefix_list_cmd, "ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)$ge|le (0-32)$le}]>", IP_STR @@ -1300,7 +1239,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_ip_prefix_list, no_ip_prefix_list_cmd, "no ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)|le (0-32)}]>", NO_STR @@ -1320,7 +1259,7 @@ DEFPY( (struct prefix *)prefix, ge, le); } -DEFPY( +DEFPY_YANG( no_ip_prefix_list_seq, no_ip_prefix_list_seq_cmd, "no ip prefix-list WORD$name seq (1-4294967295)$seq", NO_STR @@ -1332,7 +1271,7 @@ DEFPY( return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, 0, 0); } -DEFPY( +DEFPY_YANG( no_ip_prefix_list_all, no_ip_prefix_list_all_cmd, "no ip prefix-list WORD$name", NO_STR @@ -1349,7 +1288,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( ip_prefix_list_remark, ip_prefix_list_remark_cmd, "ip prefix-list WORD$name description LINE...", IP_STR @@ -1374,7 +1313,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_ip_prefix_list_remark, no_ip_prefix_list_remark_cmd, "no ip prefix-list WORD$name description", NO_STR @@ -1403,7 +1342,7 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) -DEFPY( +DEFPY_YANG( ipv6_prefix_list, ipv6_prefix_list_cmd, "ipv6 prefix-list WORD$name [seq (1-4294967295)] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>", IPV6_STR @@ -1460,7 +1399,7 @@ DEFPY( return nb_cli_apply_changes(vty, xpath_entry); } -DEFPY( +DEFPY_YANG( no_ipv6_prefix_list, no_ipv6_prefix_list_cmd, "no ipv6 prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>", NO_STR @@ -1480,7 +1419,7 @@ DEFPY( (struct prefix *)prefix, ge, le); } -DEFPY( +DEFPY_YANG( no_ipv6_prefix_list_seq, no_ipv6_prefix_list_seq_cmd, "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq", NO_STR @@ -1492,7 +1431,7 @@ DEFPY( return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, 0, 0); } -DEFPY( +DEFPY_YANG( no_ipv6_prefix_list_all, no_ipv6_prefix_list_all_cmd, "no ipv6 prefix-list WORD$name", NO_STR @@ -1509,7 +1448,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( ipv6_prefix_list_remark, ipv6_prefix_list_remark_cmd, "ipv6 prefix-list WORD$name description LINE...", IPV6_STR @@ -1534,7 +1473,7 @@ DEFPY( return rv; } -DEFPY( +DEFPY_YANG( no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_cmd, "no ipv6 prefix-list WORD$name description", NO_STR @@ -1648,10 +1587,6 @@ void filter_cli_init(void) install_element(CONFIG_NODE, &no_access_list_std_cmd); install_element(CONFIG_NODE, &access_list_ext_cmd); install_element(CONFIG_NODE, &no_access_list_ext_cmd); - install_element(CONFIG_NODE, &no_access_list_legacy_cmd); - install_element(CONFIG_NODE, &access_list_legacy_remark_cmd); - install_element(CONFIG_NODE, &no_access_list_legacy_remark_cmd); - install_element(CONFIG_NODE, &no_access_list_legacy_remark_line_cmd); /* access-list zebra-style. */ install_element(CONFIG_NODE, &access_list_cmd); diff --git a/lib/filter_nb.c b/lib/filter_nb.c index 83cf586ed3..91691d2f1d 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -24,6 +24,7 @@ #include "lib/northbound.h" #include "lib/prefix.h" +#include "lib/printfrr.h" #include "lib/filter.h" #include "lib/plist.h" @@ -39,20 +40,19 @@ ipv4_network_addr(in_addr_t hostaddr, int masklen) return hostaddr & mask.s_addr; } -static enum nb_error -prefix_list_length_validate(const struct lyd_node *dnode) +static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args) { - int type = yang_dnode_get_enum(dnode, "../../type"); + int type = yang_dnode_get_enum(args->dnode, "../../type"); const char *xpath_le = NULL, *xpath_ge = NULL; struct prefix p; uint8_t le, ge; if (type == YPLT_IPV4) { - yang_dnode_get_prefix(&p, dnode, "../ipv4-prefix"); + yang_dnode_get_prefix(&p, args->dnode, "../ipv4-prefix"); xpath_le = "../ipv4-prefix-length-lesser-or-equal"; xpath_ge = "../ipv4-prefix-length-greater-or-equal"; } else { - yang_dnode_get_prefix(&p, dnode, "../ipv6-prefix"); + yang_dnode_get_prefix(&p, args->dnode, "../ipv6-prefix"); xpath_le = "../ipv6-prefix-length-lesser-or-equal"; xpath_ge = "../ipv6-prefix-length-greater-or-equal"; } @@ -61,19 +61,18 @@ prefix_list_length_validate(const struct lyd_node *dnode) * Check rule: * prefix length <= le. */ - if (yang_dnode_exists(dnode, xpath_le)) { - le = yang_dnode_get_uint8(dnode, xpath_le); + if (yang_dnode_exists(args->dnode, xpath_le)) { + le = yang_dnode_get_uint8(args->dnode, xpath_le); if (p.prefixlen > le) goto log_and_fail; - } /* * Check rule: * prefix length < ge. */ - if (yang_dnode_exists(dnode, xpath_ge)) { - ge = yang_dnode_get_uint8(dnode, xpath_ge); + if (yang_dnode_exists(args->dnode, xpath_ge)) { + ge = yang_dnode_get_uint8(args->dnode, xpath_ge); if (p.prefixlen >= ge) goto log_and_fail; } @@ -82,19 +81,21 @@ prefix_list_length_validate(const struct lyd_node *dnode) * Check rule: * ge <= le. */ - if (yang_dnode_exists(dnode, xpath_le) && - yang_dnode_exists(dnode, xpath_ge)) { - le = yang_dnode_get_uint8(dnode, xpath_le); - ge = yang_dnode_get_uint8(dnode, xpath_ge); + if (yang_dnode_exists(args->dnode, xpath_le) + && yang_dnode_exists(args->dnode, xpath_ge)) { + le = yang_dnode_get_uint8(args->dnode, xpath_le); + ge = yang_dnode_get_uint8(args->dnode, xpath_ge); if (ge > le) goto log_and_fail; } return NB_OK; - log_and_fail: - zlog_info("prefix-list: invalid prefix range for %pFX: " - "Make sure that mask length < ge <= le", &p); +log_and_fail: + snprintfrr( + args->errmsg, args->errmsg_len, + "Invalid prefix range for %pFX: Make sure that mask length < ge <= le", + &p); return NB_ERR_VALIDATION; } @@ -112,24 +113,38 @@ static void prefix_list_entry_set_empty(struct prefix_list_entry *ple) } /* - * XPath: /frr-filter:lib/access-list-legacy + * XPath: /frr-filter:lib/access-list */ -static int lib_access_list_legacy_create(struct nb_cb_create_args *args) +static int lib_access_list_create(struct nb_cb_create_args *args) { - struct access_list *acl; + struct access_list *acl = NULL; const char *acl_name; + int type; if (args->event != NB_EV_APPLY) return NB_OK; - acl_name = yang_dnode_get_string(args->dnode, "./number"); - acl = access_list_get(AFI_IP, acl_name); + type = yang_dnode_get_enum(args->dnode, "./type"); + acl_name = yang_dnode_get_string(args->dnode, "./name"); + + switch (type) { + case YALT_IPV4: + acl = access_list_get(AFI_IP, acl_name); + break; + case YALT_IPV6: + acl = access_list_get(AFI_IP6, acl_name); + break; + case YALT_MAC: + acl = access_list_get(AFI_L2VPN, acl_name); + break; + } + nb_running_set_entry(args->dnode, acl); return NB_OK; } -static int lib_access_list_legacy_destroy(struct nb_cb_destroy_args *args) +static int lib_access_list_destroy(struct nb_cb_destroy_args *args) { struct access_master *am; struct access_list *acl; @@ -148,9 +163,9 @@ static int lib_access_list_legacy_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-filter:lib/access-list-legacy/remark + * XPath: /frr-filter:lib/access-list/remark */ -static int lib_access_list_legacy_remark_modify(struct nb_cb_modify_args *args) +static int lib_access_list_remark_modify(struct nb_cb_modify_args *args) { struct access_list *acl; const char *remark; @@ -169,7 +184,7 @@ static int lib_access_list_legacy_remark_modify(struct nb_cb_modify_args *args) } static int -lib_access_list_legacy_remark_destroy(struct nb_cb_destroy_args *args) +lib_access_list_remark_destroy(struct nb_cb_destroy_args *args) { struct access_list *acl; @@ -183,31 +198,20 @@ lib_access_list_legacy_remark_destroy(struct nb_cb_destroy_args *args) return NB_OK; } + /* - * XPath: /frr-filter:lib/access-list-legacy/entry + * XPath: /frr-filter:lib/access-list/entry */ -static int lib_access_list_legacy_entry_create(struct nb_cb_create_args *args) +static int lib_access_list_entry_create(struct nb_cb_create_args *args) { - struct filter_cisco *fc; struct access_list *acl; struct filter *f; - uint32_t aclno; - - /* TODO: validate `filter_lookup_cisco` returns NULL. */ if (args->event != NB_EV_APPLY) return NB_OK; - aclno = yang_dnode_get_uint16(args->dnode, "../number"); - f = filter_new(); - f->cisco = 1; f->seq = yang_dnode_get_uint32(args->dnode, "./sequence"); - fc = &f->u.cfilter; - if ((aclno >= 1 && aclno <= 99) || (aclno >= 1300 && aclno <= 1999)) - fc->extended = 0; - else - fc->extended = 1; acl = nb_running_get_entry(args->dnode, NULL, true); f->acl = acl; @@ -217,7 +221,7 @@ static int lib_access_list_legacy_entry_create(struct nb_cb_create_args *args) return NB_OK; } -static int lib_access_list_legacy_entry_destroy(struct nb_cb_destroy_args *args) +static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args) { struct access_list *acl; struct filter *f; @@ -233,10 +237,10 @@ static int lib_access_list_legacy_entry_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-filter:lib/access-list-legacy/entry/action + * XPath: /frr-filter:lib/access-list/entry/action */ static int -lib_access_list_legacy_entry_action_modify(struct nb_cb_modify_args *args) +lib_access_list_entry_action_modify(struct nb_cb_modify_args *args) { const char *filter_type; struct filter *f; @@ -255,86 +259,81 @@ lib_access_list_legacy_entry_action_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-filter:lib/access-list-legacy/entry/host + * XPath: /frr-filter:lib/access-list/entry/ipv4-prefix */ static int -lib_access_list_legacy_entry_host_modify(struct nb_cb_modify_args *args) +lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) { - struct filter_cisco *fc; + struct filter_zebra *fz; struct filter *f; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); - fc = &f->u.cfilter; - yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL); - fc->addr_mask.s_addr = INADDR_ANY; + f->cisco = 0; + fz = &f->u.zfilter; + yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL); return NB_OK; } static int -lib_access_list_legacy_entry_host_destroy(struct nb_cb_destroy_args *args) +lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args) { - struct filter_cisco *fc; + struct filter_zebra *fz; struct filter *f; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); - fc = &f->u.cfilter; - fc->addr.s_addr = INADDR_ANY; - fc->addr_mask.s_addr = INADDR_NONE; + fz = &f->u.zfilter; + memset(&fz->prefix, 0, sizeof(fz->prefix)); return NB_OK; } /* - * XPath: /frr-filter:lib/access-list-legacy/entry/network + * XPath: /frr-filter:lib/access-list/entry/ipv4-exact-match */ static int -lib_access_list_legacy_entry_network_modify(struct nb_cb_modify_args *args) +lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args) { - struct filter_cisco *fc; + struct filter_zebra *fz; struct filter *f; - struct prefix p; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); - fc = &f->u.cfilter; - yang_dnode_get_prefix(&p, args->dnode, NULL); - fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen); - masklen2ip(p.prefixlen, &fc->addr_mask); + fz = &f->u.zfilter; + fz->exact = yang_dnode_get_bool(args->dnode, NULL); return NB_OK; } static int -lib_access_list_legacy_entry_network_destroy(struct nb_cb_destroy_args *args) +lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args) { - struct filter_cisco *fc; + struct filter_zebra *fz; struct filter *f; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); - fc = &f->u.cfilter; - fc->addr.s_addr = INADDR_ANY; - fc->addr_mask.s_addr = INADDR_NONE; + fz = &f->u.zfilter; + fz->exact = 0; return NB_OK; } /* - * XPath: /frr-filter:lib/access-list-legacy/entry/any + * XPath: /frr-filter:lib/access-list/entry/host */ static int -lib_access_list_legacy_entry_any_create(struct nb_cb_create_args *args) +lib_access_list_entry_host_modify(struct nb_cb_modify_args *args) { struct filter_cisco *fc; struct filter *f; @@ -343,15 +342,16 @@ lib_access_list_legacy_entry_any_create(struct nb_cb_create_args *args) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); + f->cisco = 1; fc = &f->u.cfilter; - fc->addr.s_addr = INADDR_ANY; - fc->addr_mask.s_addr = INADDR_NONE; + yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL); + fc->addr_mask.s_addr = INADDR_ANY; return NB_OK; } static int -lib_access_list_legacy_entry_any_destroy(struct nb_cb_destroy_args *args) +lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args) { struct filter_cisco *fc; struct filter *f; @@ -368,27 +368,30 @@ lib_access_list_legacy_entry_any_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-filter:lib/access-list-legacy/entry/destination-host + * XPath: /frr-filter:lib/access-list/entry/network */ -static int lib_access_list_legacy_entry_destination_host_modify( - struct nb_cb_modify_args *args) +static int +lib_access_list_entry_network_modify(struct nb_cb_modify_args *args) { struct filter_cisco *fc; struct filter *f; + struct prefix p; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); + f->cisco = 1; fc = &f->u.cfilter; - yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL); - fc->mask_mask.s_addr = INADDR_ANY; + yang_dnode_get_prefix(&p, args->dnode, NULL); + fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen); + masklen2ip(p.prefixlen, &fc->addr_mask); return NB_OK; } -static int lib_access_list_legacy_entry_destination_host_destroy( - struct nb_cb_destroy_args *args) +static int +lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args) { struct filter_cisco *fc; struct filter *f; @@ -398,36 +401,35 @@ static int lib_access_list_legacy_entry_destination_host_destroy( f = nb_running_get_entry(args->dnode, NULL, true); fc = &f->u.cfilter; - fc->mask.s_addr = INADDR_ANY; - fc->mask_mask.s_addr = INADDR_NONE; + fc->addr.s_addr = INADDR_ANY; + fc->addr_mask.s_addr = INADDR_NONE; return NB_OK; } /* - * XPath: /frr-filter:lib/access-list-legacy/entry/destination-network + * XPath: /frr-filter:lib/access-list/entry/source-any */ -static int lib_access_list_legacy_entry_destination_network_modify( - struct nb_cb_modify_args *args) +static int +lib_access_list_entry_source_any_create(struct nb_cb_create_args *args) { struct filter_cisco *fc; struct filter *f; - struct prefix p; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); + f->cisco = 1; fc = &f->u.cfilter; - yang_dnode_get_prefix(&p, args->dnode, NULL); - fc->mask.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen); - masklen2ip(p.prefixlen, &fc->mask_mask); + fc->addr.s_addr = INADDR_ANY; + fc->addr_mask.s_addr = INADDR_NONE; return NB_OK; } -static int lib_access_list_legacy_entry_destination_network_destroy( - struct nb_cb_destroy_args *args) +static int +lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args) { struct filter_cisco *fc; struct filter *f; @@ -437,17 +439,17 @@ static int lib_access_list_legacy_entry_destination_network_destroy( f = nb_running_get_entry(args->dnode, NULL, true); fc = &f->u.cfilter; - fc->mask.s_addr = INADDR_ANY; - fc->mask_mask.s_addr = INADDR_NONE; + fc->addr.s_addr = INADDR_ANY; + fc->addr_mask.s_addr = INADDR_NONE; return NB_OK; } /* - * XPath: /frr-filter:lib/access-list-legacy/entry/destination-any + * XPath: /frr-filter:lib/access-list/entry/destination-host */ -static int lib_access_list_legacy_entry_destination_any_create( - struct nb_cb_create_args *args) +static int lib_access_list_entry_destination_host_modify( + struct nb_cb_modify_args *args) { struct filter_cisco *fc; struct filter *f; @@ -457,13 +459,14 @@ static int lib_access_list_legacy_entry_destination_any_create( f = nb_running_get_entry(args->dnode, NULL, true); fc = &f->u.cfilter; - fc->mask.s_addr = INADDR_ANY; - fc->mask_mask.s_addr = INADDR_NONE; + fc->extended = 1; + yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL); + fc->mask_mask.s_addr = INADDR_ANY; return NB_OK; } -static int lib_access_list_legacy_entry_destination_any_destroy( +static int lib_access_list_entry_destination_host_destroy( struct nb_cb_destroy_args *args) { struct filter_cisco *fc; @@ -474,6 +477,7 @@ static int lib_access_list_legacy_entry_destination_any_destroy( f = nb_running_get_entry(args->dnode, NULL, true); fc = &f->u.cfilter; + fc->extended = 0; fc->mask.s_addr = INADDR_ANY; fc->mask_mask.s_addr = INADDR_NONE; @@ -481,160 +485,81 @@ static int lib_access_list_legacy_entry_destination_any_destroy( } /* - * XPath: /frr-filter:lib/access-list + * XPath: /frr-filter:lib/access-list/entry/destination-network */ -static int lib_access_list_create(struct nb_cb_create_args *args) -{ - struct access_list *acl = NULL; - const char *acl_name; - int type; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - type = yang_dnode_get_enum(args->dnode, "./type"); - acl_name = yang_dnode_get_string(args->dnode, "./name"); - - switch (type) { - case YALT_IPV4: - acl = access_list_get(AFI_IP, acl_name); - break; - case YALT_IPV6: - acl = access_list_get(AFI_IP6, acl_name); - break; - case YALT_MAC: - acl = access_list_get(AFI_L2VPN, acl_name); - break; - } - - nb_running_set_entry(args->dnode, acl); - - return NB_OK; -} - -static int lib_access_list_destroy(struct nb_cb_destroy_args *args) -{ - struct access_master *am; - struct access_list *acl; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - acl = nb_running_unset_entry(args->dnode); - am = acl->master; - if (am->delete_hook) - am->delete_hook(acl); - - access_list_delete(acl); - - return NB_OK; -} - -/* - * XPath: /frr-filter:lib/access-list/entry - */ -static int lib_access_list_entry_create(struct nb_cb_create_args *args) -{ - struct access_list *acl; - struct filter *f; - - /* TODO: validate `filter_lookup_zebra` returns NULL. */ - - if (args->event != NB_EV_APPLY) - return NB_OK; - - f = filter_new(); - f->seq = yang_dnode_get_uint32(args->dnode, "./sequence"); - - acl = nb_running_get_entry(args->dnode, NULL, true); - f->acl = acl; - access_list_filter_add(acl, f); - nb_running_set_entry(args->dnode, f); - - return NB_OK; -} - -static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args) -{ - struct access_list *acl; - struct filter *f; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - f = nb_running_unset_entry(args->dnode); - acl = f->acl; - access_list_filter_delete(acl, f); - - return NB_OK; -} - -/* - * XPath: /frr-filter:lib/access-list/entry/ipv4-prefix - */ -static int -lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) +static int lib_access_list_entry_destination_network_modify( + struct nb_cb_modify_args *args) { - struct filter_zebra *fz; + struct filter_cisco *fc; struct filter *f; + struct prefix p; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); - fz = &f->u.zfilter; - yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL); + fc = &f->u.cfilter; + fc->extended = 1; + yang_dnode_get_prefix(&p, args->dnode, NULL); + fc->mask.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen); + masklen2ip(p.prefixlen, &fc->mask_mask); return NB_OK; } -static int -lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args) +static int lib_access_list_entry_destination_network_destroy( + struct nb_cb_destroy_args *args) { - struct filter_zebra *fz; + struct filter_cisco *fc; struct filter *f; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); - fz = &f->u.zfilter; - memset(&fz->prefix, 0, sizeof(fz->prefix)); + fc = &f->u.cfilter; + fc->extended = 0; + fc->mask.s_addr = INADDR_ANY; + fc->mask_mask.s_addr = INADDR_NONE; return NB_OK; } /* - * XPath: /frr-filter:lib/access-list/entry/ipv4-exact-match + * XPath: /frr-filter:lib/access-list/entry/destination-any */ -static int -lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args) +static int lib_access_list_entry_destination_any_create( + struct nb_cb_create_args *args) { - struct filter_zebra *fz; + struct filter_cisco *fc; struct filter *f; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); - fz = &f->u.zfilter; - fz->exact = yang_dnode_get_bool(args->dnode, NULL); + fc = &f->u.cfilter; + fc->extended = 1; + fc->mask.s_addr = INADDR_ANY; + fc->mask_mask.s_addr = INADDR_NONE; return NB_OK; } -static int -lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args) +static int lib_access_list_entry_destination_any_destroy( + struct nb_cb_destroy_args *args) { - struct filter_zebra *fz; + struct filter_cisco *fc; struct filter *f; if (args->event != NB_EV_APPLY) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); - fz = &f->u.zfilter; - fz->exact = 0; + fc = &f->u.cfilter; + fc->extended = 0; + fc->mask.s_addr = INADDR_ANY; + fc->mask_mask.s_addr = INADDR_NONE; return NB_OK; } @@ -652,6 +577,7 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args) return NB_OK; f = nb_running_get_entry(args->dnode, NULL, true); + f->cisco = 0; fz = &f->u.zfilter; memset(&fz->prefix, 0, sizeof(fz->prefix)); @@ -905,7 +831,7 @@ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify( struct prefix_list_entry *ple; if (args->event == NB_EV_VALIDATE && - prefix_list_length_validate(args->dnode) != NB_OK) + prefix_list_length_validate(args) != NB_OK) return NB_ERR_VALIDATION; if (args->event != NB_EV_APPLY) @@ -954,7 +880,7 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify( struct prefix_list_entry *ple; if (args->event == NB_EV_VALIDATE && - prefix_list_length_validate(args->dnode) != NB_OK) + prefix_list_length_validate(args) != NB_OK) return NB_ERR_VALIDATION; if (args->event != NB_EV_APPLY) @@ -1060,117 +986,88 @@ const struct frr_yang_module_info frr_filter_info = { .name = "frr-filter", .nodes = { { - .xpath = "/frr-filter:lib/access-list-legacy", - .cbs = { - .create = lib_access_list_legacy_create, - .destroy = lib_access_list_legacy_destroy, - } - }, - { - .xpath = "/frr-filter:lib/access-list-legacy/remark", - .cbs = { - .modify = lib_access_list_legacy_remark_modify, - .destroy = lib_access_list_legacy_remark_destroy, - .cli_show = access_list_legacy_remark_show, - } - }, - { - .xpath = "/frr-filter:lib/access-list-legacy/entry", - .cbs = { - .create = lib_access_list_legacy_entry_create, - .destroy = lib_access_list_legacy_entry_destroy, - .cli_show = access_list_legacy_show, - } - }, - { - .xpath = "/frr-filter:lib/access-list-legacy/entry/action", - .cbs = { - .modify = lib_access_list_legacy_entry_action_modify, - } - }, - { - .xpath = "/frr-filter:lib/access-list-legacy/entry/host", + .xpath = "/frr-filter:lib/access-list", .cbs = { - .modify = lib_access_list_legacy_entry_host_modify, - .destroy = lib_access_list_legacy_entry_host_destroy, + .create = lib_access_list_create, + .destroy = lib_access_list_destroy, } }, { - .xpath = "/frr-filter:lib/access-list-legacy/entry/network", + .xpath = "/frr-filter:lib/access-list/remark", .cbs = { - .modify = lib_access_list_legacy_entry_network_modify, - .destroy = lib_access_list_legacy_entry_network_destroy, + .modify = lib_access_list_remark_modify, + .destroy = lib_access_list_remark_destroy, + .cli_show = access_list_remark_show, } }, { - .xpath = "/frr-filter:lib/access-list-legacy/entry/any", + .xpath = "/frr-filter:lib/access-list/entry", .cbs = { - .create = lib_access_list_legacy_entry_any_create, - .destroy = lib_access_list_legacy_entry_any_destroy, + .create = lib_access_list_entry_create, + .destroy = lib_access_list_entry_destroy, + .cli_show = access_list_show, } }, { - .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-host", + .xpath = "/frr-filter:lib/access-list/entry/action", .cbs = { - .modify = lib_access_list_legacy_entry_destination_host_modify, - .destroy = lib_access_list_legacy_entry_destination_host_destroy, + .modify = lib_access_list_entry_action_modify, } }, { - .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-network", + .xpath = "/frr-filter:lib/access-list/entry/ipv4-prefix", .cbs = { - .modify = lib_access_list_legacy_entry_destination_network_modify, - .destroy = lib_access_list_legacy_entry_destination_network_destroy, + .modify = lib_access_list_entry_ipv4_prefix_modify, + .destroy = lib_access_list_entry_ipv4_prefix_destroy, } }, { - .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-any", + .xpath = "/frr-filter:lib/access-list/entry/ipv4-exact-match", .cbs = { - .create = lib_access_list_legacy_entry_destination_any_create, - .destroy = lib_access_list_legacy_entry_destination_any_destroy, + .modify = lib_access_list_entry_ipv4_exact_match_modify, + .destroy = lib_access_list_entry_ipv4_exact_match_destroy, } }, { - .xpath = "/frr-filter:lib/access-list", + .xpath = "/frr-filter:lib/access-list/entry/host", .cbs = { - .create = lib_access_list_create, - .destroy = lib_access_list_destroy, + .modify = lib_access_list_entry_host_modify, + .destroy = lib_access_list_entry_host_destroy, } }, { - .xpath = "/frr-filter:lib/access-list/remark", + .xpath = "/frr-filter:lib/access-list/entry/network", .cbs = { - .modify = lib_access_list_legacy_remark_modify, - .destroy = lib_access_list_legacy_remark_destroy, - .cli_show = access_list_remark_show, + .modify = lib_access_list_entry_network_modify, + .destroy = lib_access_list_entry_network_destroy, } }, { - .xpath = "/frr-filter:lib/access-list/entry", + .xpath = "/frr-filter:lib/access-list/entry/source-any", .cbs = { - .create = lib_access_list_entry_create, - .destroy = lib_access_list_entry_destroy, - .cli_show = access_list_show, + .create = lib_access_list_entry_source_any_create, + .destroy = lib_access_list_entry_source_any_destroy, } }, { - .xpath = "/frr-filter:lib/access-list/entry/action", + .xpath = "/frr-filter:lib/access-list/entry/destination-host", .cbs = { - .modify = lib_access_list_legacy_entry_action_modify, + .modify = lib_access_list_entry_destination_host_modify, + .destroy = lib_access_list_entry_destination_host_destroy, } }, { - .xpath = "/frr-filter:lib/access-list/entry/ipv4-prefix", + .xpath = "/frr-filter:lib/access-list/entry/destination-network", .cbs = { - .modify = lib_access_list_entry_ipv4_prefix_modify, - .destroy = lib_access_list_entry_ipv4_prefix_destroy, + .modify = lib_access_list_entry_destination_network_modify, + .destroy = lib_access_list_entry_destination_network_destroy, } }, { - .xpath = "/frr-filter:lib/access-list/entry/ipv4-exact-match", + .xpath = "/frr-filter:lib/access-list/entry/destination-any", .cbs = { - .modify = lib_access_list_entry_ipv4_exact_match_modify, - .destroy = lib_access_list_entry_ipv4_exact_match_destroy, + .create = lib_access_list_entry_destination_any_create, + .destroy = lib_access_list_entry_destination_any_destroy, } }, { diff --git a/lib/id_alloc.c b/lib/id_alloc.c index 7c7f2c4689..95096fa5f0 100644 --- a/lib/id_alloc.c +++ b/lib/id_alloc.c @@ -108,7 +108,7 @@ static struct id_alloc_page *find_or_create_page(struct id_alloc *alloc, } else if (page != NULL && create) { flog_err( EC_LIB_ID_CONSISTENCY, - "ID Allocator %s attempt to re-create page at %" PRIu32, + "ID Allocator %s attempt to re-create page at %u", alloc->name, id); } @@ -131,8 +131,7 @@ void idalloc_free(struct id_alloc *alloc, uint32_t id) page = find_or_create_page(alloc, id, 0); if (!page) { flog_err(EC_LIB_ID_CONSISTENCY, - "ID Allocator %s cannot free #%" PRIu32 - ". ID Block does not exist.", + "ID Allocator %s cannot free #%u. ID Block does not exist.", alloc->name, id); return; } @@ -142,8 +141,7 @@ void idalloc_free(struct id_alloc *alloc, uint32_t id) if ((page->allocated_mask[word] & (1 << offset)) == 0) { flog_err(EC_LIB_ID_CONSISTENCY, - "ID Allocator %s cannot free #%" PRIu32 - ". ID was not allocated at the time of free.", + "ID Allocator %s cannot free #%u. ID was not allocated at the time of free.", alloc->name, id); return; } @@ -285,8 +283,7 @@ uint32_t idalloc_reserve(struct id_alloc *alloc, uint32_t id) if (page->allocated_mask[word] & (((uint32_t)1) << offset)) { flog_err(EC_LIB_ID_CONSISTENCY, - "ID Allocator %s could not reserve %" PRIu32 - " because it is already allocated.", + "ID Allocator %s could not reserve %u because it is already allocated.", alloc->name, id); return IDALLOC_INVALID; } @@ -217,16 +217,14 @@ struct interface *if_create_name(const char *name, vrf_id_t vrf_id) return ifp; } -struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id, - char *optional_name) +struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) { struct interface *ifp; ifp = if_new(vrf_id); if_set_index(ifp, ifindex); - if (optional_name) - if_set_name(ifp, optional_name); + hook_call(if_add, ifp); return ifp; } @@ -573,8 +571,7 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id) return NULL; } -struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id, - char *optional_name) +struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) { struct interface *ifp; @@ -584,7 +581,7 @@ struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id, ifp = if_lookup_by_ifindex(ifindex, vrf_id); if (ifp) return ifp; - return if_create_ifindex(ifindex, vrf_id, optional_name); + return if_create_ifindex(ifindex, vrf_id); case VRF_BACKEND_VRF_LITE: ifp = if_lookup_by_index_all_vrf(ifindex); if (ifp) { @@ -596,7 +593,7 @@ struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id, if_update_to_new_vrf(ifp, vrf_id); return ifp; } - return if_create_ifindex(ifindex, vrf_id, optional_name); + return if_create_ifindex(ifindex, vrf_id); } return NULL; @@ -785,8 +782,7 @@ static void if_dump(const struct interface *ifp) struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); zlog_info( - "Interface %s vrf %s(%u) index %d metric %d mtu %d " - "mtu6 %d %s", + "Interface %s vrf %s(%u) index %d metric %d mtu %d mtu6 %d %s", ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, ifp->metric, ifp->mtu, ifp->mtu6, if_flag_dump(ifp->flags)); @@ -1322,7 +1318,7 @@ void if_link_params_free(struct interface *ifp) /* * XPath: /frr-interface:lib/interface */ -DEFPY_NOSH (interface, +DEFPY_YANG_NOSH (interface, interface_cmd, "interface IFNAME [vrf NAME$vrf_name]", "Select an interface to configure\n" @@ -1385,6 +1381,7 @@ DEFPY_NOSH (interface, * all interface-level commands are converted to the new * northbound model. */ + nb_cli_pending_commit_check(vty); ifp = if_lookup_by_name(ifname, vrf_id); if (ifp) VTY_PUSH_CONTEXT(INTERFACE_NODE, ifp); @@ -1393,7 +1390,7 @@ DEFPY_NOSH (interface, return ret; } -DEFPY (no_interface, +DEFPY_YANG (no_interface, no_interface_cmd, "no interface IFNAME [vrf NAME$vrf_name]", NO_STR @@ -1428,7 +1425,7 @@ static void cli_show_interface(struct vty *vty, struct lyd_node *dnode, /* * XPath: /frr-interface:lib/interface/description */ -DEFPY (interface_desc, +DEFPY_YANG (interface_desc, interface_desc_cmd, "description LINE...", "Interface specific description\n" @@ -1445,7 +1442,7 @@ DEFPY (interface_desc, return ret; } -DEFPY (no_interface_desc, +DEFPY_YANG (no_interface_desc, no_interface_desc_cmd, "no description", NO_STR @@ -509,8 +509,7 @@ extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id); extern struct interface *if_create_name(const char *name, vrf_id_t vrf_id); /* Create new interface, adds to index list only */ -extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id, - char *name); +extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id); extern struct interface *if_lookup_by_index_all_vrf(ifindex_t); extern struct interface *if_lookup_exact_address(const void *matchaddr, @@ -527,8 +526,8 @@ extern struct interface *if_lookup_by_name_all_vrf(const char *ifname); extern struct interface *if_lookup_by_name_vrf(const char *name, struct vrf *vrf); extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id); extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id); -extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id, - char *optional_name); +extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); + /* Sets the index and adds to index list */ extern int if_set_index(struct interface *ifp, ifindex_t ifindex); /* Sets the name and adds to name list */ diff --git a/lib/ipaddr.h b/lib/ipaddr.h index cd7f79a04e..730c7ce130 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -25,6 +25,8 @@ #include <zebra.h> +#include "lib/log.h" + #ifdef __cplusplus extern "C" { #endif @@ -33,9 +35,9 @@ extern "C" { * Generic IP address - union of IPv4 and IPv6 address. */ enum ipaddr_type_t { - IPADDR_NONE = 0, - IPADDR_V4 = 1, /* IPv4 */ - IPADDR_V6 = 2, /* IPv6 */ + IPADDR_NONE = AF_UNSPEC, + IPADDR_V4 = AF_INET, + IPADDR_V6 = AF_INET6, }; struct ipaddr { @@ -59,6 +61,18 @@ struct ipaddr { #define IPADDRSZ(p) \ (IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr)) +static inline int ipaddr_family(const struct ipaddr *ip) +{ + switch (ip->ipa_type) { + case IPADDR_V4: + return AF_INET; + case IPADDR_V6: + return AF_INET6; + default: + return AF_UNSPEC; + } +} + static inline int str2ipaddr(const char *str, struct ipaddr *ip) { int ret; @@ -84,15 +98,18 @@ static inline int str2ipaddr(const char *str, struct ipaddr *ip) static inline char *ipaddr2str(const struct ipaddr *ip, char *buf, int size) { buf[0] = '\0'; - if (ip) { - if (IS_IPADDR_V4(ip)) - inet_ntop(AF_INET, &ip->ip.addr, buf, size); - else if (IS_IPADDR_V6(ip)) - inet_ntop(AF_INET6, &ip->ip.addr, buf, size); - } + if (ip) + inet_ntop(ip->ipa_type, &ip->ip.addr, buf, size); return buf; } +#define IS_MAPPED_IPV6(A) \ + ((A)->s6_addr32[0] == 0x00000000 \ + ? ((A)->s6_addr32[1] == 0x00000000 \ + ? (ntohl((A)->s6_addr32[2]) == 0xFFFF ? 1 : 0) \ + : 0) \ + : 0) + /* * Convert IPv4 address to IPv4-mapped IPv6 address which is of the * form ::FFFF:<IPv4 address> (RFC 4291). This IPv6 address can then @@ -128,6 +145,35 @@ static inline bool ipaddr_isset(struct ipaddr *ip) return (0 != memcmp(&a, ip, sizeof(struct ipaddr))); } +/* + * generic ordering comparison between IP addresses + */ +static inline int ipaddr_cmp(const struct ipaddr *a, const struct ipaddr *b) +{ + uint32_t va, vb; + va = a->ipa_type; + vb = b->ipa_type; + if (va != vb) + return (va < vb) ? -1 : 1; + switch (a->ipa_type) { + case IPADDR_V4: + va = ntohl(a->ipaddr_v4.s_addr); + vb = ntohl(b->ipaddr_v4.s_addr); + if (va != vb) + return (va < vb) ? -1 : 1; + return 0; + case IPADDR_V6: + return memcmp((void *)&a->ipaddr_v6, (void *)&b->ipaddr_v6, + sizeof(a->ipaddr_v6)); + default: + return 0; + } +} + +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pIA" (struct ipaddr *) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/libfrr.c b/lib/libfrr.c index b3df7de6d3..2597eb61e2 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -105,6 +105,7 @@ static const struct option lo_always[] = { {"daemon", no_argument, NULL, 'd'}, {"module", no_argument, NULL, 'M'}, {"profile", required_argument, NULL, 'F'}, + {"pathspace", required_argument, NULL, 'N'}, {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, {"log", required_argument, NULL, OPTION_LOG}, @@ -113,12 +114,13 @@ static const struct option lo_always[] = { {"command-log-always", no_argument, NULL, OPTION_LOGGING}, {NULL}}; static const struct optspec os_always = { - "hvdM:F:", + "hvdM:F:N:", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" " -M, --module Load specified module\n" " -F, --profile Use specified configuration profile\n" + " -N, --pathspace Insert prefix into config & socket paths\n" " --vty_socket Override vty socket path\n" " --moduledir Override modules directory\n" " --log Set Logging to stdout, syslog, or file:<name>\n" @@ -133,18 +135,16 @@ static const struct option lo_cfg_pid_dry[] = { #ifdef HAVE_SQLITE3 {"db_file", required_argument, NULL, OPTION_DB_FILE}, #endif - {"pathspace", required_argument, NULL, 'N'}, {"dryrun", no_argument, NULL, 'C'}, {"terminal", no_argument, NULL, 't'}, {NULL}}; static const struct optspec os_cfg_pid_dry = { - "f:i:CtN:", + "f:i:Ct", " -f, --config_file Set configuration file name\n" " -i, --pid_file Set process identifier file name\n" #ifdef HAVE_SQLITE3 " --db_file Set database file name\n" #endif - " -N, --pathspace Insert prefix into config & socket paths\n" " -C, --dryrun Check configuration for validity and exit\n" " -t, --terminal Open terminal session on stdio\n" " -d -t Daemonize after terminal session ends\n", @@ -428,8 +428,6 @@ static int frr_opt(int opt) di->config_file = optarg; break; case 'N': - if (di->flags & FRR_NO_CFG_PID_DRY) - return 1; if (di->pathspace) { fprintf(stderr, "-N/--pathspace option specified more than once!\n"); diff --git a/lib/linklist.c b/lib/linklist.c index 272e153276..84dc6e1419 100644 --- a/lib/linklist.c +++ b/lib/linklist.c @@ -38,16 +38,30 @@ static void list_free_internal(struct list *l) XFREE(MTYPE_LINK_LIST, l); } + /* Allocate new listnode. Internal use only. */ -static struct listnode *listnode_new(void) +static struct listnode *listnode_new(struct list *list, void *val) { - return XCALLOC(MTYPE_LINK_NODE, sizeof(struct listnode)); + struct listnode *node; + + /* if listnode memory is managed by the app then the val + * passed in is the listnode + */ + if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) { + node = val; + node->prev = node->next = NULL; + } else { + node = XCALLOC(MTYPE_LINK_NODE, sizeof(struct listnode)); + node->data = val; + } + return node; } /* Free listnode. */ -static void listnode_free(struct listnode *node) +static void listnode_free(struct list *list, struct listnode *node) { - XFREE(MTYPE_LINK_NODE, node); + if (!(list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP)) + XFREE(MTYPE_LINK_NODE, node); } struct listnode *listnode_add(struct list *list, void *val) @@ -56,10 +70,9 @@ struct listnode *listnode_add(struct list *list, void *val) assert(val != NULL); - node = listnode_new(); + node = listnode_new(list, val); node->prev = list->tail; - node->data = val; if (list->head == NULL) list->head = node; @@ -78,10 +91,9 @@ void listnode_add_head(struct list *list, void *val) assert(val != NULL); - node = listnode_new(); + node = listnode_new(list, val); node->next = list->head; - node->data = val; if (list->head == NULL) list->head = node; @@ -97,15 +109,22 @@ bool listnode_add_sort_nodup(struct list *list, void *val) struct listnode *n; struct listnode *new; int ret; + void *data; assert(val != NULL); + if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) { + n = val; + data = n->data; + } else { + data = val; + } + if (list->cmp) { for (n = list->head; n; n = n->next) { - ret = (*list->cmp)(val, n->data); + ret = (*list->cmp)(data, n->data); if (ret < 0) { - new = listnode_new(); - new->data = val; + new = listnode_new(list, val); new->next = n; new->prev = n->prev; @@ -124,14 +143,30 @@ bool listnode_add_sort_nodup(struct list *list, void *val) } } - new = listnode_new(); - new->data = val; + new = listnode_new(list, val); LISTNODE_ATTACH(list, new); return true; } +struct list *list_dup(struct list *list) +{ + struct list *dup; + struct listnode *node; + void *data; + + assert(list); + + dup = list_new(); + dup->cmp = list->cmp; + dup->del = list->del; + for (ALL_LIST_ELEMENTS_RO(list, node, data)) + listnode_add(dup, data); + + return dup; +} + void listnode_add_sort(struct list *list, void *val) { struct listnode *n; @@ -139,8 +174,8 @@ void listnode_add_sort(struct list *list, void *val) assert(val != NULL); - new = listnode_new(); - new->data = val; + new = listnode_new(list, val); + val = new->data; if (list->cmp) { for (n = list->head; n; n = n->next) { @@ -177,8 +212,7 @@ struct listnode *listnode_add_after(struct list *list, struct listnode *pp, assert(val != NULL); - nn = listnode_new(); - nn->data = val; + nn = listnode_new(list, val); if (pp == NULL) { if (list->head) @@ -212,8 +246,7 @@ struct listnode *listnode_add_before(struct list *list, struct listnode *pp, assert(val != NULL); - nn = listnode_new(); - nn->data = val; + nn = listnode_new(list, val); if (pp == NULL) { if (list->tail) @@ -276,7 +309,7 @@ void list_delete_all_node(struct list *list) next = node->next; if (*list->del) (*list->del)(node->data); - listnode_free(node); + listnode_free(list, node); } list->head = list->tail = NULL; list->count = 0; @@ -336,7 +369,7 @@ void list_delete_node(struct list *list, struct listnode *node) else list->tail = node->prev; list->count--; - listnode_free(node); + listnode_free(list, node); } void list_sort(struct list *list, int (*cmp)(const void **, const void **)) diff --git a/lib/linklist.h b/lib/linklist.h index 00cb9f8714..d8820c924d 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -43,6 +43,12 @@ struct list { /* invariant: count is the number of listnodes in the list */ unsigned int count; + uint8_t flags; +/* Indicates that listnode memory is managed by the application and + * doesn't need to be freed by this library via listnode_delete etc. + */ +#define LINKLIST_FLAG_NODE_MEM_BY_APP (1 << 0) + /* * Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2. * Used as definition of sorted for listnode_add_sort @@ -60,10 +66,14 @@ struct list { #define listhead(X) ((X) ? ((X)->head) : NULL) #define listhead_unchecked(X) ((X)->head) #define listtail(X) ((X) ? ((X)->tail) : NULL) +#define listtail_unchecked(X) ((X)->tail) #define listcount(X) ((X)->count) #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL) /* return X->data only if X and X->data are not NULL */ #define listgetdata(X) (assert(X), assert((X)->data != NULL), (X)->data) +/* App is going to manage listnode memory */ +#define listset_app_node_mem(X) ((X)->flags |= LINKLIST_FLAG_NODE_MEM_BY_APP) +#define listnode_init(X, val) ((X)->data = (val)) /* * Create a new linked list. @@ -95,7 +105,7 @@ extern struct listnode *listnode_add(struct list *list, void *data); * list to operate on * * data - * element to add + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. */ extern void listnode_add_head(struct list *list, void *data); @@ -112,7 +122,7 @@ extern void listnode_add_head(struct list *list, void *data); * list to operate on * * val - * element to add + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. */ extern void listnode_add_sort(struct list *list, void *val); @@ -128,7 +138,7 @@ extern void listnode_add_sort(struct list *list, void *val); * listnode to insert after * * data - * data to insert + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. * * Returns: * pointer to newly created listnode that contains the inserted data @@ -148,7 +158,7 @@ extern struct listnode *listnode_add_after(struct list *list, * listnode to insert before * * data - * data to insert + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. * * Returns: * pointer to newly created listnode that contains the inserted data @@ -313,10 +323,23 @@ extern void list_filter_out_nodes(struct list *list, bool (*cond)(void *data)); * list to operate on * * val - * element to add + * If MEM_BY_APP is set this is listnode. Otherwise it is element to add. */ extern bool listnode_add_sort_nodup(struct list *list, void *val); + +/* + * Duplicate the specified list, creating a shallow copy of each of its + * elements. + * + * list + * list to duplicate + * + * Returns: + * the duplicated list + */ +extern struct list *list_dup(struct list *list); + /* List iteration macro. * Usage: for (ALL_LIST_ELEMENTS (...) { ... } * It is safe to delete the listnode using this macro. @@ -273,8 +273,7 @@ void zlog_backtrace(int priority) if (size <= 0 || (size_t)size > array_size(array)) { flog_err_sys( EC_LIB_SYSTEM_CALL, - "Cannot get backtrace, returned invalid # of frames %d " - "(valid range is between 1 and %lu)", + "Cannot get backtrace, returned invalid # of frames %d (valid range is between 1 and %lu)", size, (unsigned long)(array_size(array))); return; } @@ -301,8 +300,7 @@ void zlog_thread_info(int log_level) if (tc) zlog(log_level, - "Current thread function %s, scheduled from " - "file %s, line %u", + "Current thread function %s, scheduled from file %s, line %u", tc->funcname, tc->schedfrom, tc->schedfrom_line); else zlog(log_level, "Current thread not known/applicable"); @@ -386,6 +384,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD), DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE), DESC_ENTRY(ZEBRA_MPLS_LABELS_REPLACE), + DESC_ENTRY(ZEBRA_SR_POLICY_SET), + DESC_ENTRY(ZEBRA_SR_POLICY_DELETE), + DESC_ENTRY(ZEBRA_SR_POLICY_NOTIFY_STATUS), DESC_ENTRY(ZEBRA_IPMR_ROUTE_STATS), DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT), DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC), @@ -400,6 +401,10 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET), DESC_ENTRY(ZEBRA_LOCAL_ES_ADD), DESC_ENTRY(ZEBRA_LOCAL_ES_DEL), + DESC_ENTRY(ZEBRA_REMOTE_ES_VTEP_ADD), + DESC_ENTRY(ZEBRA_REMOTE_ES_VTEP_DEL), + DESC_ENTRY(ZEBRA_LOCAL_ES_EVI_ADD), + DESC_ENTRY(ZEBRA_LOCAL_ES_EVI_DEL), DESC_ENTRY(ZEBRA_VNI_ADD), DESC_ENTRY(ZEBRA_VNI_DEL), DESC_ENTRY(ZEBRA_L3VNI_ADD), @@ -446,7 +451,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES), DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE), DESC_ENTRY(ZEBRA_OPAQUE_REGISTER), - DESC_ENTRY(ZEBRA_OPAQUE_UNREGISTER)}; + DESC_ENTRY(ZEBRA_OPAQUE_UNREGISTER), + DESC_ENTRY(ZEBRA_NEIGH_DISCOVER)}; #undef DESC_ENTRY static const struct zebra_desc_table unknown = {0, "unknown", '?'}; @@ -465,8 +471,7 @@ static const struct zebra_desc_table *zroute_lookup(unsigned int zroute) for (i = 0; i < array_size(route_types); i++) { if (zroute == route_types[i].type) { zlog_warn( - "internal error: route type table out of order " - "while searching for %u, please notify developers", + "internal error: route type table out of order while searching for %u, please notify developers", zroute); return &route_types[i]; } @@ -64,13 +64,13 @@ struct message { /* For logs which have error codes associated with them */ #define flog_err(ferr_id, format, ...) \ - zlog_err("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__) + zlog_err("[EC %u] " format, ferr_id, ##__VA_ARGS__) #define flog_err_sys(ferr_id, format, ...) \ flog_err(ferr_id, format, ##__VA_ARGS__) #define flog_warn(ferr_id, format, ...) \ - zlog_warn("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__) + zlog_warn("[EC %u] " format, ferr_id, ##__VA_ARGS__) #define flog(priority, ferr_id, format, ...) \ - zlog(priority, "[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__) + zlog(priority, "[EC %u] " format, ferr_id, ##__VA_ARGS__) extern void zlog_thread_info(int log_level); diff --git a/lib/memory.c b/lib/memory.c index 3a29404827..2c902d123b 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -157,8 +157,7 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt) if (!mt) { fprintf(eda->fp, - "%s: showing active allocations in " - "memory group %s\n", + "%s: showing active allocations in memory group %s\n", eda->prefix, mg->name); } else if (mt->n_alloc) { diff --git a/lib/mpls.h b/lib/mpls.h index 126dbf753d..8922a36664 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -129,6 +129,7 @@ enum lsp_types_t { ZEBRA_LSP_OSPF_SR = 4,/* OSPF Segment Routing LSP. */ ZEBRA_LSP_ISIS_SR = 5,/* IS-IS Segment Routing LSP. */ ZEBRA_LSP_SHARP = 6, /* Identifier for test protocol */ + ZEBRA_LSP_SRTE = 7, /* SR-TE LSP */ }; /* Functions for basic label operations. */ diff --git a/lib/netns_linux.c b/lib/netns_linux.c index e1c0159fc5..98f359401e 100644 --- a/lib/netns_linux.c +++ b/lib/netns_linux.c @@ -379,20 +379,12 @@ struct ns *ns_lookup(ns_id_t ns_id) return ns_lookup_internal(ns_id); } -void ns_walk_func(int (*func)(struct ns *, - void *param_in, - void **param_out), - void *param_in, - void **param_out) +void ns_walk_func(int (*func)(struct ns *)) { struct ns *ns = NULL; - int ret; - RB_FOREACH (ns, ns_head, &ns_tree) { - ret = func(ns, param_in, param_out); - if (ret == NS_WALK_STOP) - return; - } + RB_FOREACH (ns, ns_head, &ns_tree) + func(ns); } const char *ns_get_name(struct ns *ns) @@ -592,33 +584,9 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id) return ret; } -/* if relative link_nsid matches default netns, - * then return default absolute netns value - * otherwise, return NS_UNKNOWN - */ -ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid) -{ - struct ns *ns; - - ns = ns_lookup(ns_id_reference); - if (!ns) - return NS_UNKNOWN; - if (ns->relative_default_ns != link_nsid) - return NS_UNKNOWN; - ns = ns_get_default(); - assert(ns); - return ns->ns_id; -} - ns_id_t ns_get_default_id(void) { if (default_ns) return default_ns->ns_id; return NS_DEFAULT_INTERNAL; } - -struct ns *ns_get_default(void) -{ - return default_ns; -} - diff --git a/lib/nexthop.c b/lib/nexthop.c index 3496081d47..0ea72d03e1 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -152,11 +152,20 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1, break; } + if (next1->srte_color < next2->srte_color) + return -1; + if (next1->srte_color > next2->srte_color) + return 1; + ret = _nexthop_source_cmp(next1, next2); if (ret != 0) goto done; if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) && + !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) + return 0; + + if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) && CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) return -1; @@ -164,12 +173,18 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1, !CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP)) return 1; - if (next1->backup_idx < next2->backup_idx) + if (next1->backup_num == 0 && next2->backup_num == 0) + goto done; + + if (next1->backup_num < next2->backup_num) return -1; - if (next1->backup_idx > next2->backup_idx) + if (next1->backup_num > next2->backup_num) return 1; + ret = memcmp(next1->backup_idx, + next2->backup_idx, next1->backup_num); + done: return ret; } @@ -515,11 +530,12 @@ struct nexthop *nexthop_next_active_resolved(const struct nexthop *nexthop) return next; } -unsigned int nexthop_level(struct nexthop *nexthop) +unsigned int nexthop_level(const struct nexthop *nexthop) { unsigned int rv = 0; - for (struct nexthop *par = nexthop->rparent; par; par = par->rparent) + for (const struct nexthop *par = nexthop->rparent; + par; par = par->rparent) rv++; return rv; @@ -529,14 +545,15 @@ unsigned int nexthop_level(struct nexthop *nexthop) uint32_t nexthop_hash_quick(const struct nexthop *nexthop) { uint32_t key = 0x45afe398; - uint32_t val; + int i; key = jhash_3words(nexthop->type, nexthop->vrf_id, nexthop->nh_label_type, key); if (nexthop->nh_label) { int labels = nexthop->nh_label->num_labels; - int i = 0; + + i = 0; while (labels >= 3) { key = jhash_3words(nexthop->nh_label->label[i], @@ -559,14 +576,35 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop) key = jhash_1word(nexthop->nh_label->label[i], key); } - val = 0; - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) - val = (uint32_t)nexthop->backup_idx; - - key = jhash_3words(nexthop->ifindex, - CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), val, + key = jhash_2words(nexthop->ifindex, + CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), key); + /* Include backup nexthops, if present */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + int backups = nexthop->backup_num; + + i = 0; + + while (backups >= 3) { + key = jhash_3words(nexthop->backup_idx[i], + nexthop->backup_idx[i + 1], + nexthop->backup_idx[i + 2], key); + backups -= 3; + i += 3; + } + + while (backups >= 2) { + key = jhash_2words(nexthop->backup_idx[i], + nexthop->backup_idx[i + 1], key); + backups -= 2; + i += 2; + } + + if (backups >= 1) + key = jhash_1word(nexthop->backup_idx[i], key); + } + return key; } @@ -604,7 +642,13 @@ void nexthop_copy_no_recurse(struct nexthop *copy, copy->type = nexthop->type; copy->flags = nexthop->flags; copy->weight = nexthop->weight; - copy->backup_idx = nexthop->backup_idx; + + assert(nexthop->backup_num < NEXTHOP_MAX_BACKUPS); + copy->backup_num = nexthop->backup_num; + if (copy->backup_num > 0) + memcpy(copy->backup_idx, nexthop->backup_idx, copy->backup_num); + + copy->srte_color = nexthop->srte_color; memcpy(©->gate, &nexthop->gate, sizeof(nexthop->gate)); memcpy(©->src, &nexthop->src, sizeof(nexthop->src)); memcpy(©->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src)); @@ -621,7 +665,7 @@ void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, nexthop_copy_no_recurse(copy, nexthop, rparent); /* Bit of a special case here, we need to handle the case - * of a nexthop resolving to agroup. Hence, we need to + * of a nexthop resolving to a group. Hence, we need to * use a nexthop_group API. */ if (CHECK_FLAG(copy->flags, NEXTHOP_FLAG_RECURSIVE)) @@ -647,6 +691,67 @@ struct nexthop *nexthop_dup(const struct nexthop *nexthop, } /* + * Parse one or more backup index values, as comma-separated numbers, + * into caller's array of uint8_ts. The array must be NEXTHOP_MAX_BACKUPS + * in size. Mails back the number of values converted, and returns 0 on + * success, <0 if an error in parsing. + */ +int nexthop_str2backups(const char *str, int *num_backups, + uint8_t *backups) +{ + char *ostr; /* copy of string (start) */ + char *lstr; /* working copy of string */ + char *nump; /* pointer to next segment */ + char *endp; /* end pointer */ + int i, ret; + uint8_t tmp[NEXTHOP_MAX_BACKUPS]; + uint32_t lval; + + /* Copy incoming string; the parse is destructive */ + lstr = ostr = XSTRDUP(MTYPE_TMP, str); + *num_backups = 0; + ret = 0; + + for (i = 0; i < NEXTHOP_MAX_BACKUPS && lstr; i++) { + nump = strsep(&lstr, ","); + lval = strtoul(nump, &endp, 10); + + /* Format check */ + if (*endp != '\0') { + ret = -1; + break; + } + + /* Empty value */ + if (endp == nump) { + ret = -1; + break; + } + + /* Limit to one octet */ + if (lval > 255) { + ret = -1; + break; + } + + tmp[i] = lval; + } + + /* Excess values */ + if (ret == 0 && i == NEXTHOP_MAX_BACKUPS && lstr) + ret = -1; + + if (ret == 0) { + *num_backups = i; + memcpy(backups, tmp, i); + } + + XFREE(MTYPE_TMP, ostr); + + return ret; +} + +/* * nexthop printing variants: * %pNHvv * via 1.2.3.4 diff --git a/lib/nexthop.h b/lib/nexthop.h index eda88efc08..cadcea1f41 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -65,6 +65,12 @@ enum nh_encap_type { NET_VXLAN = 100, /* value copied from FPM_NH_ENCAP_VXLAN. */ }; +/* Fixed limit on the number of backup nexthops per primary nexthop */ +#define NEXTHOP_MAX_BACKUPS 8 + +/* Backup index value is limited */ +#define NEXTHOP_BACKUP_IDX_MAX 255 + /* Nexthop structure. */ struct nexthop { struct nexthop *next; @@ -92,6 +98,7 @@ struct nexthop { */ #define NEXTHOP_FLAG_RNH_FILTERED (1 << 5) /* rmap filtered, used by rnh */ #define NEXTHOP_FLAG_HAS_BACKUP (1 << 6) /* Backup nexthop index is set */ +#define NEXTHOP_FLAG_SRTE (1 << 7) /* SR-TE color used for BGP traffic */ #define NEXTHOP_IS_ACTIVE(flags) \ (CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \ @@ -124,20 +131,21 @@ struct nexthop { /* Weight of the nexthop ( for unequal cost ECMP ) */ uint8_t weight; - /* Index of a corresponding backup nexthop in a backup list; + /* Count and index of corresponding backup nexthop(s) in a backup list; * only meaningful if the HAS_BACKUP flag is set. */ - uint8_t backup_idx; + uint8_t backup_num; + uint8_t backup_idx[NEXTHOP_MAX_BACKUPS]; /* Encapsulation information. */ enum nh_encap_type nh_encap_type; union { vni_t vni; } nh_encap; -}; -/* Backup index value is limited */ -#define NEXTHOP_BACKUP_IDX_MAX 255 + /* SR-TE color used for matching SR-TE policies */ + uint32_t srte_color; +}; /* Utility to append one nexthop to another. */ #define NEXTHOP_APPEND(to, new) \ @@ -216,7 +224,7 @@ extern const char *nexthop2str(const struct nexthop *nexthop, extern struct nexthop *nexthop_next(const struct nexthop *nexthop); extern struct nexthop * nexthop_next_active_resolved(const struct nexthop *nexthop); -extern unsigned int nexthop_level(struct nexthop *nexthop); +extern unsigned int nexthop_level(const struct nexthop *nexthop); /* Copies to an already allocated nexthop struct */ extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop, struct nexthop *rparent); @@ -231,6 +239,15 @@ extern struct nexthop *nexthop_dup(const struct nexthop *nexthop, extern struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop, struct nexthop *rparent); +/* + * Parse one or more backup index values, as comma-separated numbers, + * into caller's array of uint8_ts. The array must be NEXTHOP_MAX_BACKUPS + * in size. Mails back the number of values converted, and returns 0 on + * success, <0 if an error in parsing. + */ +int nexthop_str2backups(const char *str, int *num_backups, + uint8_t *backups); + #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pNH" (struct nexthop *) #endif diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 4f0c72af27..8ae001e42a 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -43,12 +43,9 @@ struct nexthop_hold { char *intf; char *labels; uint32_t weight; - int backup_idx; /* Index of backup nexthop, if >= 0 */ + char *backup_str; }; -/* Invalid/unset value for nexthop_hold's backup_idx */ -#define NHH_BACKUP_IDX_INVALID -1 - struct nexthop_group_hooks { void (*new)(const char *name); void (*add_nexthop)(const struct nexthop_group_cmd *nhg, @@ -677,7 +674,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, const char *nhvrf_name, const union sockunion *addr, const char *intf, const char *labels, - const uint32_t weight, int backup_idx) + const uint32_t weight, + const char *backup_str) { struct nexthop_hold *nh; @@ -694,7 +692,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc, nh->weight = weight; - nh->backup_idx = backup_idx; + if (backup_str) + nh->backup_str = XSTRDUP(MTYPE_TMP, backup_str); listnode_add_sort(nhgc->nhg_list, nh); } @@ -741,10 +740,11 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, const union sockunion *addr, const char *intf, const char *name, const char *labels, int *lbl_ret, - uint32_t weight, int backup_idx) + uint32_t weight, const char *backup_str) { int ret = 0; struct vrf *vrf; + int num; memset(nhop, 0, sizeof(*nhop)); @@ -800,13 +800,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop, nhop->weight = weight; - if (backup_idx != NHH_BACKUP_IDX_INVALID) { - /* Validate index value */ - if (backup_idx > NEXTHOP_BACKUP_IDX_MAX) + if (backup_str) { + /* Parse backup indexes */ + ret = nexthop_str2backups(backup_str, + &num, nhop->backup_idx); + if (ret == 0) { + SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP); + nhop->backup_num = num; + } else return false; - - SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP); - nhop->backup_idx = backup_idx; } return true; @@ -820,7 +822,7 @@ static bool nexthop_group_parse_nhh(struct nexthop *nhop, { return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf, nhh->nhvrf_name, nhh->labels, NULL, - nhh->weight, nhh->backup_idx)); + nhh->weight, nhh->backup_str)); } DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, @@ -833,7 +835,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, nexthop-vrf NAME$vrf_name \ |label WORD \ |weight (1-255) \ - |backup-idx$bi_str (0-254)$idx \ + |backup-idx WORD \ }]", NO_STR "Specify one of the nexthops in this ECMP group\n" @@ -847,19 +849,26 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, "One or more labels in the range (16-1048575) separated by '/'\n" "Weight to be used by the nexthop for purposes of ECMP\n" "Weight value to be used\n" - "Backup nexthop index in another group\n" - "Nexthop index value\n") + "Specify backup nexthop indexes in another group\n" + "One or more indexes in the range (0-254) separated by ','\n") { VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc); struct nexthop nhop; struct nexthop *nh; int lbl_ret = 0; bool legal; - int backup_idx = idx; + int num; + uint8_t backups[NEXTHOP_MAX_BACKUPS]; bool yes = !no; - if (bi_str == NULL) - backup_idx = NHH_BACKUP_IDX_INVALID; + /* Pre-parse backup string to validate */ + if (backup_idx) { + lbl_ret = nexthop_str2backups(backup_idx, &num, backups); + if (lbl_ret < 0) { + vty_out(vty, "%% Invalid backups\n"); + return CMD_WARNING_CONFIG_FAILED; + } + } legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label, &lbl_ret, weight, backup_idx); @@ -943,10 +952,11 @@ static struct cmd_node nexthop_group_node = { .config_write = nexthop_group_write, }; -void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh) +void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh) { char buf[100]; struct vrf *vrf; + int i; vty_out(vty, "nexthop "); @@ -976,7 +986,7 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh) if (nh->vrf_id != VRF_DEFAULT) { vrf = vrf_lookup_by_id(nh->vrf_id); - vty_out(vty, " nexthop-vrf %s", vrf->name); + vty_out(vty, " nexthop-vrf %s", VRF_LOGNAME(vrf)); } if (nh->nh_label && nh->nh_label->num_labels > 0) { @@ -991,16 +1001,22 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh) if (nh->weight) vty_out(vty, " weight %u", nh->weight); - if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) - vty_out(vty, " backup-idx %d", nh->backup_idx); + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + vty_out(vty, " backup-idx %d", nh->backup_idx[0]); + + for (i = 1; i < nh->backup_num; i++) + vty_out(vty, ",%d", nh->backup_idx[i]); + } vty_out(vty, "\n"); } -void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh) +void nexthop_group_json_nexthop(json_object *j, const struct nexthop *nh) { char buf[100]; struct vrf *vrf; + json_object *json_backups = NULL; + int i; switch (nh->type) { case NEXTHOP_TYPE_IFINDEX: @@ -1047,12 +1063,19 @@ void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh) if (nh->weight) json_object_int_add(j, "weight", nh->weight); - if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) - json_object_int_add(j, "backupIdx", nh->backup_idx); + if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + json_backups = json_object_new_array(); + for (i = 0; i < nh->backup_num; i++) + json_object_array_add( + json_backups, + json_object_new_int(nh->backup_idx[i])); + + json_object_object_add(j, "backupIdx", json_backups); + } } static void nexthop_group_write_nexthop_internal(struct vty *vty, - struct nexthop_hold *nh) + const struct nexthop_hold *nh) { char buf[100]; @@ -1073,8 +1096,8 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty, if (nh->weight) vty_out(vty, " weight %u", nh->weight); - if (nh->backup_idx != NHH_BACKUP_IDX_INVALID) - vty_out(vty, " backup-idx %d", nh->backup_idx); + if (nh->backup_str) + vty_out(vty, " backup-idx %s", nh->backup_str); vty_out(vty, "\n"); } diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 9888dad982..0b5ac91bb2 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -135,9 +135,11 @@ extern bool nexthop_group_equal(const struct nexthop_group *nhg1, extern struct nexthop_group_cmd *nhgc_find(const char *name); -extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh); +extern void nexthop_group_write_nexthop(struct vty *vty, + const struct nexthop *nh); -extern void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh); +extern void nexthop_group_json_nexthop(json_object *j, + const struct nexthop *nh); /* Return the number of nexthops in this nhg */ extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg); diff --git a/lib/northbound.c b/lib/northbound.c index 48b8499bfc..29e843a84e 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -680,8 +680,12 @@ int nb_candidate_commit_prepare(struct nb_context *context, RB_INIT(nb_config_cbs, &changes); nb_config_diff(running_config, candidate, &changes); - if (RB_EMPTY(nb_config_cbs, &changes)) + if (RB_EMPTY(nb_config_cbs, &changes)) { + snprintf( + errmsg, errmsg_len, + "No changes to apply were found during preparation phase"); return NB_ERR_NO_CHANGES; + } if (nb_candidate_validate_code(context, candidate, &changes, errmsg, errmsg_len) @@ -707,23 +711,21 @@ int nb_candidate_commit_prepare(struct nb_context *context, errmsg_len); } -void nb_candidate_commit_abort(struct nb_transaction *transaction) +void nb_candidate_commit_abort(struct nb_transaction *transaction, char *errmsg, + size_t errmsg_len) { - char errmsg[BUFSIZ] = {0}; - (void)nb_transaction_process(NB_EV_ABORT, transaction, errmsg, - sizeof(errmsg)); + errmsg_len); nb_transaction_free(transaction); } void nb_candidate_commit_apply(struct nb_transaction *transaction, - bool save_transaction, uint32_t *transaction_id) + bool save_transaction, uint32_t *transaction_id, + char *errmsg, size_t errmsg_len) { - char errmsg[BUFSIZ] = {0}; - (void)nb_transaction_process(NB_EV_APPLY, transaction, errmsg, - sizeof(errmsg)); - nb_transaction_apply_finish(transaction, errmsg, sizeof(errmsg)); + errmsg_len); + nb_transaction_apply_finish(transaction, errmsg, errmsg_len); /* Replace running by candidate. */ transaction->config->version++; @@ -754,9 +756,9 @@ int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate, */ if (ret == NB_OK) nb_candidate_commit_apply(transaction, save_transaction, - transaction_id); + transaction_id, errmsg, errmsg_len); else if (transaction != NULL) - nb_candidate_commit_abort(transaction); + nb_candidate_commit_abort(transaction, errmsg, errmsg_len); return ret; } @@ -2046,18 +2048,21 @@ void *nb_running_unset_entry(const struct lyd_node *dnode) return entry; } -void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath, - bool abort_if_not_found) +static void *nb_running_get_entry_worker(const struct lyd_node *dnode, + const char *xpath, + bool abort_if_not_found, + bool rec_search) { const struct lyd_node *orig_dnode = dnode; char xpath_buf[XPATH_MAXLEN]; + bool rec_flag = true; assert(dnode || xpath); if (!dnode) dnode = yang_dnode_get(running_config->dnode, xpath); - while (dnode) { + while (rec_flag && dnode) { struct nb_config_entry *config, s; yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath)); @@ -2065,6 +2070,8 @@ void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath, if (config) return config->entry; + rec_flag = rec_search; + dnode = dnode->parent; } @@ -2078,6 +2085,20 @@ void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath, abort(); } +void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath, + bool abort_if_not_found) +{ + return nb_running_get_entry_worker(dnode, xpath, abort_if_not_found, + true); +} + +void *nb_running_get_entry_non_rec(const struct lyd_node *dnode, + const char *xpath, bool abort_if_not_found) +{ + return nb_running_get_entry_worker(dnode, xpath, abort_if_not_found, + false); +} + /* Logging functions. */ const char *nb_event_name(enum nb_event event) { diff --git a/lib/northbound.h b/lib/northbound.h index bd57013f59..fa5ac5616c 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -910,8 +910,15 @@ extern int nb_candidate_commit_prepare(struct nb_context *context, * * transaction * Candidate configuration to abort. It's consumed by this function. + * + * errmsg + * Buffer to store human-readable error message in case of error. + * + * errmsg_len + * Size of errmsg. */ -extern void nb_candidate_commit_abort(struct nb_transaction *transaction); +extern void nb_candidate_commit_abort(struct nb_transaction *transaction, + char *errmsg, size_t errmsg_len); /* * Commit a previously created configuration transaction. @@ -925,10 +932,17 @@ extern void nb_candidate_commit_abort(struct nb_transaction *transaction); * * transaction_id * Optional output parameter providing the ID of the committed transaction. + * + * errmsg + * Buffer to store human-readable error message in case of error. + * + * errmsg_len + * Size of errmsg. */ extern void nb_candidate_commit_apply(struct nb_transaction *transaction, bool save_transaction, - uint32_t *transaction_id); + uint32_t *transaction_id, char *errmsg, + size_t errmsg_len); /* * Create a new transaction to commit a candidate configuration. This is a @@ -1165,6 +1179,14 @@ extern void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath, bool abort_if_not_found); /* + * Same as 'nb_running_get_entry', but doesn't search within parent nodes + * recursively if an user point is not found. + */ +extern void *nb_running_get_entry_non_rec(const struct lyd_node *dnode, + const char *xpath, + bool abort_if_not_found); + +/* * Return a human-readable string representing a northbound event. * * event diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 105fc83cef..2f6aef5398 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -53,6 +53,108 @@ static void vty_show_nb_errors(struct vty *vty, int error, const char *errmsg) vty_out(vty, "Error description: %s\n", errmsg); } +static int nb_cli_classic_commit(struct vty *vty) +{ + struct nb_context context = {}; + char errmsg[BUFSIZ] = {0}; + int ret; + + context.client = NB_CLIENT_CLI; + context.user = vty; + ret = nb_candidate_commit(&context, vty->candidate_config, true, NULL, + NULL, errmsg, sizeof(errmsg)); + if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) { + vty_out(vty, "%% Configuration failed.\n\n"); + vty_show_nb_errors(vty, ret, errmsg); + if (vty->t_pending_commit) + vty_out(vty, + "The following commands were dynamically grouped into the same transaction and rejected:\n%s", + vty->pending_cmds_buf); + + /* Regenerate candidate for consistency. */ + nb_config_replace(vty->candidate_config, running_config, true); + return CMD_WARNING_CONFIG_FAILED; + } else if (strlen(errmsg) > 0) + /* Successful commit. Print warnings (if any). */ + vty_out(vty, "%s\n", errmsg); + + return CMD_SUCCESS; +} + +static void nb_cli_pending_commit_clear(struct vty *vty) +{ + THREAD_TIMER_OFF(vty->t_pending_commit); + vty->backoff_cmd_count = 0; + XFREE(MTYPE_TMP, vty->pending_cmds_buf); + vty->pending_cmds_buflen = 0; + vty->pending_cmds_bufpos = 0; +} + +static int nb_cli_pending_commit_cb(struct thread *thread) +{ + struct vty *vty = THREAD_ARG(thread); + + (void)nb_cli_classic_commit(vty); + nb_cli_pending_commit_clear(vty); + + return 0; +} + +void nb_cli_pending_commit_check(struct vty *vty) +{ + if (vty->t_pending_commit) { + (void)nb_cli_classic_commit(vty); + nb_cli_pending_commit_clear(vty); + } +} + +static bool nb_cli_backoff_start(struct vty *vty) +{ + struct timeval now, delta; + + /* + * Start the configuration backoff timer only if 100 YANG-modeled + * commands or more were entered within the last second. + */ + monotime(&now); + if (monotime_since(&vty->backoff_start, &delta) >= 1000000) { + vty->backoff_start = now; + vty->backoff_cmd_count = 1; + return false; + } + if (++vty->backoff_cmd_count < 100) + return false; + + return true; +} + +static int nb_cli_schedule_command(struct vty *vty) +{ + /* Append command to dynamically sized buffer of scheduled commands. */ + if (!vty->pending_cmds_buf) { + vty->pending_cmds_buflen = 4096; + vty->pending_cmds_buf = + XCALLOC(MTYPE_TMP, vty->pending_cmds_buflen); + } + if ((strlen(vty->buf) + 3) + > (vty->pending_cmds_buflen - vty->pending_cmds_bufpos)) { + vty->pending_cmds_buflen *= 2; + vty->pending_cmds_buf = + XREALLOC(MTYPE_TMP, vty->pending_cmds_buf, + vty->pending_cmds_buflen); + } + strlcat(vty->pending_cmds_buf, "- ", vty->pending_cmds_buflen); + vty->pending_cmds_bufpos = strlcat(vty->pending_cmds_buf, vty->buf, + vty->pending_cmds_buflen); + + /* Schedule the commit operation. */ + THREAD_TIMER_OFF(vty->t_pending_commit); + thread_add_timer_msec(master, nb_cli_pending_commit_cb, vty, 100, + &vty->t_pending_commit); + + return CMD_SUCCESS; +} + void nb_cli_enqueue_change(struct vty *vty, const char *xpath, enum nb_operation operation, const char *value) { @@ -76,7 +178,6 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) { char xpath_base[XPATH_MAXLEN] = {}; bool error = false; - int ret; VTY_CHECK_XPATH; @@ -95,6 +196,7 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) struct nb_node *nb_node; char xpath[XPATH_MAXLEN]; struct yang_data *data; + int ret; /* Handle relative XPaths. */ memset(xpath, 0, sizeof(xpath)); @@ -158,25 +260,19 @@ int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) yang_print_errors(ly_native_ctx, buf, sizeof(buf))); } - /* Do an implicit "commit" when using the classic CLI mode. */ + /* + * Do an implicit commit when using the classic CLI mode. + * + * NOTE: the implicit commit might be scheduled to run later when + * too many commands are being sent at the same time. This is a + * protection mechanism where multiple commands are grouped into the + * same configuration transaction, allowing them to be processed much + * faster. + */ if (frr_get_cli_mode() == FRR_CLI_CLASSIC) { - struct nb_context context = {}; - char errmsg[BUFSIZ] = {0}; - - context.client = NB_CLIENT_CLI; - context.user = vty; - ret = nb_candidate_commit(&context, vty->candidate_config, - false, NULL, NULL, errmsg, - sizeof(errmsg)); - if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) { - vty_out(vty, "%% Configuration failed.\n\n"); - vty_show_nb_errors(vty, ret, errmsg); - - /* Regenerate candidate for consistency. */ - nb_config_replace(vty->candidate_config, running_config, - true); - return CMD_WARNING_CONFIG_FAILED; - } + if (vty->t_pending_commit || nb_cli_backoff_start(vty)) + return nb_cli_schedule_command(vty); + return nb_cli_classic_commit(vty); } return CMD_SUCCESS; @@ -224,11 +320,14 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty) &context, vty->confirmed_commit_rollback, true, "Rollback to previous configuration - confirmed commit has timed out", &transaction_id, errmsg, sizeof(errmsg)); - if (ret == NB_OK) + if (ret == NB_OK) { vty_out(vty, "Rollback performed successfully (Transaction ID #%u).\n", transaction_id); - else { + /* Print warnings (if any). */ + if (strlen(errmsg) > 0) + vty_out(vty, "%s\n", errmsg); + } else { vty_out(vty, "Failed to rollback to previous configuration.\n\n"); vty_show_nb_errors(vty, ret, errmsg); @@ -313,6 +412,9 @@ static int nb_cli_commit(struct vty *vty, bool force, vty_out(vty, "%% Configuration committed successfully (Transaction ID #%u).\n\n", transaction_id); + /* Print warnings (if any). */ + if (strlen(errmsg) > 0) + vty_out(vty, "%s\n", errmsg); return CMD_SUCCESS; case NB_ERR_NO_CHANGES: vty_out(vty, "%% No configuration changes to commit.\n\n"); @@ -1572,6 +1674,9 @@ static int nb_cli_rollback_configuration(struct vty *vty, case NB_OK: vty_out(vty, "%% Configuration was successfully rolled back.\n\n"); + /* Print warnings (if any). */ + if (strlen(errmsg) > 0) + vty_out(vty, "%s\n", errmsg); return CMD_SUCCESS; case NB_ERR_NO_CHANGES: vty_out(vty, diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index b2d8c8f035..112d62efda 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -108,6 +108,14 @@ extern int nb_cli_rpc(const char *xpath, struct list *input, extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +/* + * Perform pending commit, if any. + * + * vty + * The vty context. + */ +extern void nb_cli_pending_commit_check(struct vty *vty); + /* Prototypes of internal functions. */ extern void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults); diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index a3aaf02f08..1f480f3d02 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -375,8 +375,10 @@ static int frr_confd_cdb_read_cb_commit(int fd, int *subp, int reslen) /* Apply the transaction. */ if (transaction) { struct nb_config *candidate = transaction->config; + char errmsg[BUFSIZ] = {0}; - nb_candidate_commit_apply(transaction, true, NULL); + nb_candidate_commit_apply(transaction, true, NULL, errmsg, + sizeof(errmsg)); nb_config_free(candidate); } @@ -400,8 +402,9 @@ static int frr_confd_cdb_read_cb_abort(int fd, int *subp, int reslen) /* Abort the transaction. */ if (transaction) { struct nb_config *candidate = transaction->config; + char errmsg[BUFSIZ] = {0}; - nb_candidate_commit_abort(transaction); + nb_candidate_commit_abort(transaction, errmsg, sizeof(errmsg)); nb_config_free(candidate); } diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index 83d7e0ce95..f35b4bb31b 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -677,11 +677,13 @@ class NorthboundImpl switch (phase) { case frr::CommitRequest::VALIDATE: + zlog_debug("`-> Performing VALIDATE"); ret = nb_candidate_validate( &context, candidate->config, errmsg, sizeof(errmsg)); break; case frr::CommitRequest::PREPARE: + zlog_debug("`-> Performing PREPARE"); ret = nb_candidate_commit_prepare( &context, candidate->config, comment.c_str(), @@ -689,15 +691,20 @@ class NorthboundImpl sizeof(errmsg)); break; case frr::CommitRequest::ABORT: + zlog_debug("`-> Performing ABORT"); nb_candidate_commit_abort( - candidate->transaction); + candidate->transaction, errmsg, + sizeof(errmsg)); break; case frr::CommitRequest::APPLY: + zlog_debug("`-> Performing ABORT"); nb_candidate_commit_apply( candidate->transaction, true, - &transaction_id); + &transaction_id, errmsg, + sizeof(errmsg)); break; case frr::CommitRequest::ALL: + zlog_debug("`-> Performing ALL"); ret = nb_candidate_commit( &context, candidate->config, true, comment.c_str(), &transaction_id, @@ -735,12 +742,20 @@ class NorthboundImpl grpc::StatusCode::INTERNAL, errmsg); break; } + + if (nb_dbg_client_grpc) + zlog_debug("`-> Result: %s (message: '%s')", + nb_err_name((enum nb_error)ret), + errmsg); + if (ret == NB_OK) { // Response: uint32 transaction_id = 1; if (transaction_id) tag->response.set_transaction_id( transaction_id); } + if (strlen(errmsg) > 0) + tag->response.set_error_message(errmsg); tag->responder.Finish(tag->response, status, tag); tag->state = FINISH; @@ -1281,10 +1296,13 @@ class NorthboundImpl void delete_candidate(struct candidate *candidate) { + char errmsg[BUFSIZ] = {0}; + _candidates.erase(candidate->id); nb_config_free(candidate->config); if (candidate->transaction) - nb_candidate_commit_abort(candidate->transaction); + nb_candidate_commit_abort(candidate->transaction, + errmsg, sizeof(errmsg)); } struct candidate *get_candidate(uint32_t candidate_id) diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index 500203173c..2209b19c14 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -329,8 +329,10 @@ static int frr_sr_config_change_cb_apply(sr_session_ctx_t *session, /* Apply the transaction. */ if (transaction) { struct nb_config *candidate = transaction->config; + char errmsg[BUFSIZ] = {0}; - nb_candidate_commit_apply(transaction, true, NULL); + nb_candidate_commit_apply(transaction, true, NULL, errmsg, + sizeof(errmsg)); nb_config_free(candidate); } @@ -343,8 +345,9 @@ static int frr_sr_config_change_cb_abort(sr_session_ctx_t *session, /* Abort the transaction. */ if (transaction) { struct nb_config *candidate = transaction->config; + char errmsg[BUFSIZ] = {0}; - nb_candidate_commit_abort(transaction); + nb_candidate_commit_abort(transaction, errmsg, sizeof(errmsg)); nb_config_free(candidate); } @@ -53,11 +53,6 @@ struct ns { /* Identifier, mapped on the NSID value */ ns_id_t internal_ns_id; - /* Identifier, value of NSID of default netns, - * relative value in that local netns - */ - ns_id_t relative_default_ns; - /* Name */ char *name; @@ -125,14 +120,7 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id); extern char *ns_netns_pathname(struct vty *vty, const char *name); /* Parse and execute a function on all the NETNS */ -#define NS_WALK_CONTINUE 0 -#define NS_WALK_STOP 1 - -extern void ns_walk_func(int (*func)(struct ns *, - void *, - void **), - void *param_in, - void **param_out); +extern void ns_walk_func(int (*func)(struct ns *)); /* API to get the NETNS name, from the ns pointer */ extern const char *ns_get_name(struct ns *ns); @@ -186,9 +174,7 @@ extern struct ns *ns_lookup_name(const char *name); */ extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *)); extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id); -extern ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid); extern void ns_disable(struct ns *ns); -extern struct ns *ns_get_default(void); #ifdef __cplusplus } @@ -49,6 +49,10 @@ struct pbr_filter { #define PBR_FILTER_PROTO (1 << 5) #define PBR_FILTER_SRC_PORT_RANGE (1 << 6) #define PBR_FILTER_DST_PORT_RANGE (1 << 7) +#define PBR_FILTER_DSFIELD (1 << 8) + +#define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */ +#define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */ /* Source and Destination IP address with masks. */ struct prefix src_ip; @@ -58,6 +62,9 @@ struct pbr_filter { uint16_t src_port; uint16_t dst_port; + /* Filter by Differentiated Services field */ + uint8_t dsfield; /* DSCP (6 bits) & ECN (2 bits) */ + /* Filter with fwmark */ uint32_t fwmark; }; diff --git a/lib/prefix.c b/lib/prefix.c index 0900100be3..697e1a6239 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -22,6 +22,7 @@ #include <zebra.h> #include "prefix.h" +#include "ipaddr.h" #include "vty.h" #include "sockunion.h" #include "memory.h" @@ -1316,6 +1317,26 @@ char *esi_to_str(const esi_t *esi, char *buf, int size) return ptr; } +printfrr_ext_autoreg_p("EA", printfrr_ea) +static ssize_t printfrr_ea(char *buf, size_t bsz, const char *fmt, + int prec, const void *ptr) +{ + const struct ethaddr *mac = ptr; + + prefix_mac2str(mac, buf, bsz); + return 2; +} + +printfrr_ext_autoreg_p("IA", printfrr_ia) +static ssize_t printfrr_ia(char *buf, size_t bsz, const char *fmt, + int prec, const void *ptr) +{ + const struct ipaddr *ipa = ptr; + + ipaddr2str(ipa, buf, bsz); + return 2; +} + printfrr_ext_autoreg_p("I4", printfrr_i4) static ssize_t printfrr_i4(char *buf, size_t bsz, const char *fmt, int prec, const void *ptr) diff --git a/lib/prefix.h b/lib/prefix.h index 0bd457cc23..400f07386f 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -43,9 +43,36 @@ extern "C" { #define ETH_ALEN 6 #endif +/* EVPN route types. */ +typedef enum { + BGP_EVPN_AD_ROUTE = 1, /* Ethernet Auto-Discovery (A-D) route */ + BGP_EVPN_MAC_IP_ROUTE, /* MAC/IP Advertisement route */ + BGP_EVPN_IMET_ROUTE, /* Inclusive Multicast Ethernet Tag route */ + BGP_EVPN_ES_ROUTE, /* Ethernet Segment route */ + BGP_EVPN_IP_PREFIX_ROUTE, /* IP Prefix route */ +} bgp_evpn_route_type; + +/* value of first byte of ESI */ +#define ESI_TYPE_ARBITRARY 0 /* */ +#define ESI_TYPE_LACP 1 /* <> */ +#define ESI_TYPE_BRIDGE 2 /* <Root bridge Mac-6B>:<Root Br Priority-2B>:00 */ +#define ESI_TYPE_MAC 3 /* <Syst Mac Add-6B>:<Local Discriminator Value-3B> */ +#define ESI_TYPE_ROUTER 4 /* <RouterId-4B>:<Local Discriminator Value-4B> */ +#define ESI_TYPE_AS 5 /* <AS-4B>:<Local Discriminator Value-4B> */ + +#define MAX_ESI {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + + +#define EVPN_ETH_TAG_BYTES 4 #define ESI_BYTES 10 #define ESI_STR_LEN (3 * ESI_BYTES) +/* Maximum number of VTEPs per-ES - + * XXX - temporary limit for allocating strings etc. + */ +#define ES_VTEP_MAX_CNT 10 +#define ES_VTEP_LIST_STR_SZ (ES_VTEP_MAX_CNT * 16) + #define ETHER_ADDR_STRLEN (3*ETH_ALEN) /* * there isn't a portable ethernet address type. We define our @@ -64,12 +91,13 @@ struct ethaddr { #define PREFIX_LEN_ROUTE_TYPE_5_IPV6 (30*8) typedef struct esi_t_ { - uint8_t val[10]; + uint8_t val[ESI_BYTES]; } esi_t; struct evpn_ead_addr { esi_t esi; uint32_t eth_tag; + struct ipaddr ip; }; struct evpn_macip_addr { @@ -217,39 +245,45 @@ struct prefix_evpn { static inline int is_evpn_prefix_ipaddr_none(const struct prefix_evpn *evp) { - if (evp->prefix.route_type == 2) + if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) + return IS_IPADDR_NONE(&(evp)->prefix.ead_addr.ip); + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) return IS_IPADDR_NONE(&(evp)->prefix.macip_addr.ip); - if (evp->prefix.route_type == 3) + if (evp->prefix.route_type == BGP_EVPN_IMET_ROUTE) return IS_IPADDR_NONE(&(evp)->prefix.imet_addr.ip); - if (evp->prefix.route_type == 4) + if (evp->prefix.route_type == BGP_EVPN_ES_ROUTE) return IS_IPADDR_NONE(&(evp)->prefix.es_addr.ip); - if (evp->prefix.route_type == 5) + if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) return IS_IPADDR_NONE(&(evp)->prefix.prefix_addr.ip); return 0; } static inline int is_evpn_prefix_ipaddr_v4(const struct prefix_evpn *evp) { - if (evp->prefix.route_type == 2) + if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) + return IS_IPADDR_V4(&(evp)->prefix.ead_addr.ip); + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) return IS_IPADDR_V4(&(evp)->prefix.macip_addr.ip); - if (evp->prefix.route_type == 3) + if (evp->prefix.route_type == BGP_EVPN_IMET_ROUTE) return IS_IPADDR_V4(&(evp)->prefix.imet_addr.ip); - if (evp->prefix.route_type == 4) + if (evp->prefix.route_type == BGP_EVPN_ES_ROUTE) return IS_IPADDR_V4(&(evp)->prefix.es_addr.ip); - if (evp->prefix.route_type == 5) + if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) return IS_IPADDR_V4(&(evp)->prefix.prefix_addr.ip); return 0; } static inline int is_evpn_prefix_ipaddr_v6(const struct prefix_evpn *evp) { - if (evp->prefix.route_type == 2) + if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) + return IS_IPADDR_V6(&(evp)->prefix.ead_addr.ip); + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) return IS_IPADDR_V6(&(evp)->prefix.macip_addr.ip); - if (evp->prefix.route_type == 3) + if (evp->prefix.route_type == BGP_EVPN_IMET_ROUTE) return IS_IPADDR_V6(&(evp)->prefix.imet_addr.ip); - if (evp->prefix.route_type == 4) + if (evp->prefix.route_type == BGP_EVPN_ES_ROUTE) return IS_IPADDR_V6(&(evp)->prefix.es_addr.ip); - if (evp->prefix.route_type == 5) + if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) return IS_IPADDR_V6(&(evp)->prefix.prefix_addr.ip); return 0; } @@ -555,6 +589,8 @@ static inline int is_default_host_route(const struct prefix *p) } #ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pEA" (struct ethaddr *) + #pragma FRR printfrr_ext "%pI4" (struct in_addr *) #pragma FRR printfrr_ext "%pI4" (in_addr_t *) diff --git a/lib/privs.c b/lib/privs.c index eb0dbe0783..5c7e1240e2 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -558,8 +558,7 @@ static void zprivs_caps_init(struct zebra_privs_t *zprivs) /* nonsensical to have gotten here but not have capabilities */ if (!zprivs_state.syscaps_p) { fprintf(stderr, - "%s: capabilities enabled, " - "but no valid capabilities supplied\n", + "%s: capabilities enabled, but no valid capabilities supplied\n", __func__); } diff --git a/lib/privs.h b/lib/privs.h index db5707d675..18ba8e8888 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -24,6 +24,7 @@ #define _ZEBRA_PRIVS_H #include <pthread.h> +#include <stdint.h> #include "lib/queue.h" #ifdef __cplusplus diff --git a/lib/route_types.pl b/lib/route_types.pl index f297096633..e007de4d69 100755 --- a/lib/route_types.pl +++ b/lib/route_types.pl @@ -121,7 +121,7 @@ sub codelist { } $str =~ s/ $//; push @lines, $str . "\\n\" \\\n"; - push @lines, " \" > - selected route, * - FIB route, q - queued route, r - rejected route\\n\\n\""; + push @lines, " \" > - selected route, * - FIB route, q - queued, r - rejected, b - backup\\n\\n\""; return join("", @lines); } diff --git a/lib/route_types.txt b/lib/route_types.txt index 71d0a46449..b549c11cfc 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -85,6 +85,7 @@ ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD" ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric" ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP" ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group" +ZEBRA_ROUTE_SRTE, srte, none, '-', 0, 0, 0, "SR-TE" ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-" diff --git a/lib/routemap.c b/lib/routemap.c index 7749ea4cc7..fb70860024 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -263,6 +263,24 @@ void route_map_no_match_tag_hook(int (*func)( rmap_match_set_hook.no_match_tag = func; } +/* set sr-te color */ +void route_map_set_srte_color_hook(int (*func)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg)) +{ + rmap_match_set_hook.set_srte_color = func; +} + +/* no set sr-te color */ +void route_map_no_set_srte_color_hook(int (*func)(struct vty *vty, + struct route_map_index *index, + const char *command, + const char *arg)) +{ + rmap_match_set_hook.no_set_srte_color = func; +} + /* set ip nexthop */ void route_map_set_ip_nexthop_hook(int (*func)(struct vty *vty, struct route_map_index *index, @@ -353,8 +371,7 @@ int generic_match_add(struct vty *vty, struct route_map_index *index, "%% [%s] Argument form is unsupported or malformed.\n", frr_protonameinst); else - zlog_warn("Argument form is unsupported or malformed: " - "%s %s", command, arg); + zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_SUCCESS: /* @@ -405,8 +422,7 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, "%% [%s] Argument form is unsupported or malformed.\n", frr_protonameinst); else - zlog_warn("Argument form is unsupported or malformed: " - "%s %s", command, arg); + zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg); retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: @@ -441,8 +457,7 @@ int generic_set_add(struct vty *vty, struct route_map_index *index, "%% [%s] Argument form is unsupported or malformed.\n", frr_protonameinst); else - zlog_warn("Argument form is unsupported or malformed: " - "%s %s", command, arg); + zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_SUCCESS: break; @@ -470,8 +485,7 @@ int generic_set_delete(struct vty *vty, struct route_map_index *index, "%% [%s] Argument form is unsupported or malformed.\n", frr_protonameinst); else - zlog_warn("Argument form is unsupported or malformed: " - "%s %s", command, arg); + zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_SUCCESS: break; @@ -825,9 +839,10 @@ static void vty_show_route_map_entry(struct vty *vty, struct route_map *map) struct route_map_index *index; struct route_map_rule *rule; - vty_out(vty, "route-map: %s Invoked: %" PRIu64 " Optimization: %s\n", + vty_out(vty, "route-map: %s Invoked: %" PRIu64 " Optimization: %s Processed Change: %s\n", map->name, map->applied - map->applied_clear, - map->optimization_disabled ? "disabled" : "enabled"); + map->optimization_disabled ? "disabled" : "enabled", + map->to_be_processed ? "true" : "false"); for (index = map->head; index; index = index->next) { vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n", @@ -1692,14 +1707,19 @@ route_map_get_index(struct route_map *map, const struct prefix *prefix, * more noops, we retain this return value and * return this eventually if there are no * matches. + * If a best match route-map index already + * exists, do not reset the match_ret. */ - if (*match_ret != RMAP_NOMATCH) + if (!best_index && (*match_ret != RMAP_NOMATCH)) *match_ret = ret; } else { /* * ret is RMAP_NOMATCH. + * If a best match route-map index already + * exists, do not reset the match_ret. */ - *match_ret = ret; + if (!best_index) + *match_ret = ret; } } @@ -2411,6 +2431,7 @@ route_map_result_t route_map_apply(struct route_map *map, for (; index; index = index->next) { if (!skip_match_clause) { + index->applied++; /* Apply this index. */ match_ret = route_map_apply_match(&index->match_list, prefix, type, object); @@ -2610,6 +2631,47 @@ static unsigned int route_map_dep_data_hash_make_key(const void *p) return string_hash_make(dep_data->rname); } +DEFUN (set_srte_color, + set_srte_color_cmd, + "set sr-te color [(1-4294967295)]", + SET_STR + SRTE_STR + SRTE_COLOR_STR + "Color of the SR-TE Policies to match with\n") +{ + VTY_DECLVAR_CONTEXT(route_map_index, index); + int idx = 0; + char *arg = argv_find(argv, argc, "(1-4294967295)", &idx) + ? argv[idx]->arg + : NULL; + + if (rmap_match_set_hook.set_srte_color) + return rmap_match_set_hook.set_srte_color(vty, index, + "sr-te color", arg); + return CMD_SUCCESS; +} + +DEFUN (no_set_srte_color, + no_set_srte_color_cmd, + "no set sr-te color [(1-4294967295)]", + NO_STR + SET_STR + SRTE_STR + SRTE_COLOR_STR + "Color of the SR-TE Policies to match with\n") +{ + VTY_DECLVAR_CONTEXT(route_map_index, index); + int idx = 0; + char *arg = argv_find(argv, argc, "(1-4294967295)", &idx) + ? argv[idx]->arg + : NULL; + + if (rmap_match_set_hook.no_set_srte_color) + return rmap_match_set_hook.no_set_srte_color( + vty, index, "sr-te color", arg); + return CMD_SUCCESS; +} + static void *route_map_dep_hash_alloc(void *p) { char *dep_name = (char *)p; @@ -3234,5 +3296,8 @@ void route_map_init(void) install_element(RMAP_NODE, &routemap_optimization_cmd); install_element(RMAP_NODE, &no_routemap_optimization_cmd); + install_element(RMAP_NODE, &set_srte_color_cmd); + install_element(RMAP_NODE, &no_set_srte_color_cmd); + install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd); } diff --git a/lib/routemap.h b/lib/routemap.h index 62195b8349..64da4b87ef 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -424,6 +424,14 @@ extern void route_map_match_tag_hook(int (*func)( extern void route_map_no_match_tag_hook(int (*func)( struct vty *vty, struct route_map_index *index, const char *command, const char *arg, route_map_event_t type)); +/* set sr-te color */ +extern void route_map_set_srte_color_hook( + int (*func)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg)); +/* no set sr-te color */ +extern void route_map_no_set_srte_color_hook( + int (*func)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg)); /* set ip nexthop */ extern void route_map_set_ip_nexthop_hook( int (*func)(struct vty *vty, struct route_map_index *index, @@ -606,6 +614,14 @@ struct route_map_match_set_hooks { const char *command, const char *arg, route_map_event_t type); + /* set sr-te color */ + int (*set_srte_color)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg); + + /* no set sr-te color */ + int (*no_set_srte_color)(struct vty *vty, struct route_map_index *index, + const char *command, const char *arg); + /* set ip nexthop */ int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index, const char *command, const char *arg); diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 2c45f09751..836be38113 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -39,7 +39,7 @@ #define ROUTE_MAP_SEQUENCE_CMD_STR \ "Sequence to insert to/delete from existing route-map entry\n" -DEFPY_NOSH( +DEFPY_YANG_NOSH( route_map, route_map_cmd, "route-map WORD$name <deny|permit>$action (1-65535)$sequence", ROUTE_MAP_CMD_STR @@ -70,6 +70,7 @@ DEFPY_NOSH( VTY_PUSH_XPATH(RMAP_NODE, xpath_index); /* Add support for non-migrated route map users. */ + nb_cli_pending_commit_check(vty); rm = route_map_get(name); action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY; rmi = route_map_index_get(rm, action_type, sequence); @@ -79,7 +80,7 @@ DEFPY_NOSH( return rv; } -DEFPY( +DEFPY_YANG( no_route_map_all, no_route_map_all_cmd, "no route-map WORD$name", NO_STR @@ -94,7 +95,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_route_map, no_route_map_cmd, "no route-map WORD$name <deny|permit>$action (1-65535)$sequence", NO_STR @@ -179,7 +180,7 @@ void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode) vty_out(vty, "!\n"); } -DEFPY( +DEFPY_YANG( match_interface, match_interface_cmd, "match interface IFNAME", MATCH_STR @@ -196,7 +197,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_interface, no_match_interface_cmd, "no match interface [IFNAME]", NO_STR @@ -211,9 +212,9 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_address, match_ip_address_cmd, - "match ip address <(1-199)$acll|(1300-2699)$aclh|WORD$name>", + "match ip address <(1-199)|(1300-2699)|WORD>$name", MATCH_STR IP_STR "Match address of route\n" @@ -223,34 +224,15 @@ DEFPY( { const char *xpath = "./match-condition[condition='ipv4-address-list']"; char xpath_value[XPATH_MAXLEN + 32]; - int acln = acll ? acll : aclh; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - if (name) { - snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); - } else /* if (acll || aclh) */ { - if ((acln >= 1 && acln <= 99) - || (acln >= 1300 && acln <= 1999)) { - snprintf(xpath_value, sizeof(xpath_value), - "%s/access-list-num", xpath); - } else { - /* - * if ((acln >= 100 && acln <= 199) - * || (acln >= 2000 && acln <= 2699)) - */ - snprintf(xpath_value, sizeof(xpath_value), - "%s/access-list-num-extended", xpath); - } - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - acll_str ? acll_str : aclh_str); - } + snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_address, no_match_ip_address_cmd, "no match ip address [<(1-199)|(1300-2699)|WORD>]", NO_STR @@ -268,7 +250,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, "match ip address prefix-list WORD$name", @@ -288,7 +270,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, "no match ip address prefix-list [WORD]", NO_STR @@ -305,9 +287,9 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_next_hop, match_ip_next_hop_cmd, - "match ip next-hop <(1-199)$acll|(1300-2699)$aclh|WORD$name>", + "match ip next-hop <(1-199)|(1300-2699)|WORD>$name", MATCH_STR IP_STR "Match next-hop address of route\n" @@ -317,34 +299,15 @@ DEFPY( { const char *xpath = "./match-condition[condition='ipv4-next-hop-list']"; char xpath_value[XPATH_MAXLEN + 32]; - int acln = acll ? acll : aclh; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - if (name) { - snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", - xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); - } else /* if (acll || aclh) */ { - if ((acln >= 1 && acln <= 99) - || (acln >= 1300 && acln <= 1999)) { - snprintf(xpath_value, sizeof(xpath_value), - "%s/access-list-num", xpath); - } else { - /* - * if ((acln >= 100 && acln <= 199) - * || (acln >= 2000 && acln <= 2699)) - */ - snprintf(xpath_value, sizeof(xpath_value), - "%s/access-list-num-extended", xpath); - } - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, - acll_str ? acll_str : aclh_str); - } + snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_next_hop, no_match_ip_next_hop_cmd, "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]", NO_STR @@ -362,7 +325,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, "match ip next-hop prefix-list WORD$name", @@ -383,7 +346,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_cmd, "no match ip next-hop prefix-list [WORD]", @@ -402,7 +365,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ip_next_hop_type, match_ip_next_hop_type_cmd, "match ip next-hop type <blackhole>$type", MATCH_STR @@ -422,7 +385,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ip_next_hop_type, no_match_ip_next_hop_type_cmd, "no match ip next-hop type [<blackhole>]", NO_STR MATCH_STR IP_STR @@ -437,7 +400,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ipv6_address, match_ipv6_address_cmd, "match ipv6 address WORD$name", MATCH_STR @@ -455,7 +418,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ipv6_address, no_match_ipv6_address_cmd, "no match ipv6 address [WORD]", NO_STR @@ -471,7 +434,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd, "match ipv6 address prefix-list WORD$name", MATCH_STR @@ -490,7 +453,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ipv6_address_prefix_list, no_match_ipv6_address_prefix_list_cmd, "no match ipv6 address prefix-list [WORD]", @@ -508,7 +471,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_ipv6_next_hop_type, match_ipv6_next_hop_type_cmd, "match ipv6 next-hop type <blackhole>$type", MATCH_STR IPV6_STR @@ -527,7 +490,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_ipv6_next_hop_type, no_match_ipv6_next_hop_type_cmd, "no match ipv6 next-hop type [<blackhole>]", NO_STR MATCH_STR IPV6_STR @@ -542,7 +505,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_metric, match_metric_cmd, "match metric (0-4294967295)$metric", MATCH_STR @@ -559,7 +522,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_metric, no_match_metric_cmd, "no match metric [(0-4294967295)]", NO_STR @@ -574,7 +537,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( match_tag, match_tag_cmd, "match tag (1-4294967295)$tag", MATCH_STR @@ -591,7 +554,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_match_tag, no_match_tag_cmd, "no match tag [(1-4294967295)]", NO_STR @@ -610,8 +573,6 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { int condition = yang_dnode_get_enum(dnode, "./condition"); - struct lyd_node *ln; - const char *acl; switch (condition) { case 0: /* interface */ @@ -620,25 +581,14 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, break; case 1: /* ipv4-address-list */ case 3: /* ipv4-next-hop-list */ - acl = NULL; - if ((ln = yang_dnode_get(dnode, "./list-name")) != NULL) - acl = yang_dnode_get_string(ln, NULL); - else if ((ln = yang_dnode_get(dnode, "./access-list-num")) - != NULL) - acl = yang_dnode_get_string(ln, NULL); - else if ((ln = yang_dnode_get(dnode, - "./access-list-num-extended")) - != NULL) - acl = yang_dnode_get_string(ln, NULL); - - assert(acl); - switch (condition) { case 1: - vty_out(vty, " match ip address %s\n", acl); + vty_out(vty, " match ip address %s\n", + yang_dnode_get_string(dnode, "./list-name")); break; case 3: - vty_out(vty, " match ip next-hop %s\n", acl); + vty_out(vty, " match ip next-hop %s\n", + yang_dnode_get_string(dnode, "./list-name")); break; } break; @@ -697,7 +647,7 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, } } -DEFPY( +DEFPY_YANG( set_ip_nexthop, set_ip_nexthop_cmd, "set ip next-hop A.B.C.D$addr", SET_STR @@ -715,7 +665,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_set_ip_nexthop, no_set_ip_nexthop_cmd, "no set ip next-hop [A.B.C.D]", NO_STR @@ -731,7 +681,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd, "set ipv6 next-hop local X:X::X:X$addr", SET_STR @@ -750,7 +700,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd, "no set ipv6 next-hop local [X:X::X:X]", NO_STR @@ -767,7 +717,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( set_metric, set_metric_cmd, "set metric <(0-4294967295)$metric|rtt$rtt|+rtt$artt|-rtt$srtt|+metric$ametric|-metric$smetric>", SET_STR @@ -813,7 +763,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_set_metric, no_set_metric_cmd, "no set metric [(0-4294967295)]", NO_STR @@ -827,7 +777,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( set_tag, set_tag_cmd, "set tag (1-4294967295)$tag", SET_STR @@ -844,7 +794,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_set_tag, no_set_tag_cmd, "no set tag [(1-4294967295)]", NO_STR @@ -904,7 +854,7 @@ void route_map_action_show(struct vty *vty, struct lyd_node *dnode, } } -DEFPY( +DEFPY_YANG( rmap_onmatch_next, rmap_onmatch_next_cmd, "on-match next", "Exit policy on matches\n" @@ -915,7 +865,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_rmap_onmatch_next, no_rmap_onmatch_next_cmd, "no on-match next", @@ -928,7 +878,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( rmap_onmatch_goto, rmap_onmatch_goto_cmd, "on-match goto (1-65535)$rm_num", "Exit policy on matches\n" @@ -941,7 +891,7 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_rmap_onmatch_goto, no_rmap_onmatch_goto_cmd, "no on-match goto", NO_STR @@ -954,13 +904,13 @@ DEFPY( } /* Cisco/GNU Zebra compatibility aliases */ -ALIAS( +ALIAS_YANG( rmap_onmatch_goto, rmap_continue_cmd, "continue (1-65535)$rm_num", "Continue on a different entry within the route-map\n" "Route-map entry sequence number\n") -ALIAS( +ALIAS_YANG( no_rmap_onmatch_goto, no_rmap_continue_cmd, "no continue [(1-65535)]", NO_STR @@ -986,7 +936,7 @@ void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode, } } -DEFPY( +DEFPY_YANG( rmap_call, rmap_call_cmd, "call WORD$name", "Jump to another Route-Map after match+set\n" @@ -997,11 +947,12 @@ DEFPY( return nb_cli_apply_changes(vty, NULL); } -DEFPY( +DEFPY_YANG( no_rmap_call, no_rmap_call_cmd, - "no call", + "no call [NAME]", NO_STR - "Jump to another Route-Map after match+set\n") + "Jump to another Route-Map after match+set\n" + "Target route-map name\n") { nb_cli_enqueue_change(vty, "./call", NB_OP_DESTROY, NULL); @@ -1014,7 +965,7 @@ void route_map_call_show(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL)); } -DEFPY( +DEFPY_YANG( rmap_description, rmap_description_cmd, "description LINE...", "Route-map comment\n" @@ -1031,7 +982,7 @@ DEFPY( return rv; } -DEFUN (no_rmap_description, +DEFUN_YANG (no_rmap_description, no_rmap_description_cmd, "no description", NO_STR diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index f500a6c408..967f3fd4d4 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -516,77 +516,6 @@ static int lib_route_map_entry_match_condition_interface_destroy( } /* - * XPath: /frr-route-map:lib/route-map/entry/match-condition/access-list-num - */ -static int lib_route_map_entry_match_condition_access_list_num_modify( - struct nb_cb_modify_args *args) -{ - struct routemap_hook_context *rhc; - const char *acl; - int condition, rv; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - /* Check for hook function. */ - rv = CMD_SUCCESS; - acl = yang_dnode_get_string(args->dnode, NULL); - rhc = nb_running_get_entry(args->dnode, NULL, true); - condition = yang_dnode_get_enum(args->dnode, "../condition"); - switch (condition) { - case 1: /* ipv4-address-list */ - if (rmap_match_set_hook.match_ip_address == NULL) - break; - rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address; - rhc->rhc_rule = "ip address"; - rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; - rv = rmap_match_set_hook.match_ip_address( - NULL, rhc->rhc_rmi, "ip address", acl, - RMAP_EVENT_FILTER_ADDED); - break; - case 3: /* ipv4-next-hop-list */ - if (rmap_match_set_hook.match_ip_next_hop == NULL) - break; - rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop; - rhc->rhc_rule = "ip next-hop"; - rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; - rv = rmap_match_set_hook.match_ip_next_hop( - NULL, rhc->rhc_rmi, "ip next-hop", acl, - RMAP_EVENT_FILTER_ADDED); - break; - } - if (rv != CMD_SUCCESS) { - rhc->rhc_mhook = NULL; - return NB_ERR_INCONSISTENCY; - } - - return NB_OK; -} - -static int lib_route_map_entry_match_condition_access_list_num_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_match_destroy(args); -} - -/* - * XPath: - * /frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended - */ -static int lib_route_map_entry_match_condition_access_list_num_extended_modify( - struct nb_cb_modify_args *args) -{ - return lib_route_map_entry_match_condition_access_list_num_modify(args); -} - -static int lib_route_map_entry_match_condition_access_list_num_extended_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_match_condition_access_list_num_destroy( - args); -} - -/* * XPath: /frr-route-map:lib/route-map/entry/match-condition/list-name */ static int lib_route_map_entry_match_condition_list_name_modify( @@ -1245,20 +1174,6 @@ const struct frr_yang_module_info frr_route_map_info = { } }, { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num", - .cbs = { - .modify = lib_route_map_entry_match_condition_access_list_num_modify, - .destroy = lib_route_map_entry_match_condition_access_list_num_destroy, - } - }, - { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/access-list-num-extended", - .cbs = { - .modify = lib_route_map_entry_match_condition_access_list_num_extended_modify, - .destroy = lib_route_map_entry_match_condition_access_list_num_extended_destroy, - } - }, - { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/list-name", .cbs = { .modify = lib_route_map_entry_match_condition_list_name_modify, diff --git a/lib/routing_nb.c b/lib/routing_nb.c new file mode 100644 index 0000000000..0160354a7e --- /dev/null +++ b/lib/routing_nb.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018 Vmware + * Vishal Dhingra + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "northbound.h" +#include "libfrr.h" +#include "routing_nb.h" + + + +/* clang-format off */ +const struct frr_yang_module_info frr_routing_info = { + .name = "frr-routing", + .nodes = { + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/lib/routing_nb.h b/lib/routing_nb.h new file mode 100644 index 0000000000..d1b59ea29e --- /dev/null +++ b/lib/routing_nb.h @@ -0,0 +1,24 @@ +#ifndef _FRR_ROUTING_NB_H_ +#define _FRR_ROUTING_NB_H_ + +extern const struct frr_yang_module_info frr_routing_info; + +/* Mandatory callbacks. */ +int routing_control_plane_protocols_control_plane_protocol_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_destroy( + struct nb_cb_destroy_args *args); + +#define FRR_ROUTING_XPATH \ + "/frr-routing:routing/control-plane-protocols/control-plane-protocol" + +#define FRR_ROUTING_KEY_XPATH \ + "/frr-routing:routing/control-plane-protocols/" \ + "control-plane-protocol[type='%s'][name='%s'][vrf='%s']" +/* + * callbacks for routing to handle configuration events + * based on the control plane protocol + */ +DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args)) + +#endif /* _FRR_ROUTING_NB_H_ */ diff --git a/lib/routing_nb_config.c b/lib/routing_nb_config.c new file mode 100644 index 0000000000..b789e8494e --- /dev/null +++ b/lib/routing_nb_config.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 Vmware + * Vishal Dhingra + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "northbound.h" +#include "libfrr.h" +#include "vrf.h" +#include "lib_errors.h" +#include "routing_nb.h" + + +DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args)) + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol + */ + +int routing_control_plane_protocols_control_plane_protocol_create( + struct nb_cb_create_args *args) +{ + struct vrf *vrf; + const char *vrfname; + + switch (args->event) { + case NB_EV_VALIDATE: + if (hook_call(routing_conf_event, args)) + return NB_ERR_VALIDATION; + break; + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + vrfname = yang_dnode_get_string(args->dnode, "./vrf"); + vrf = vrf_lookup_by_name(vrfname); + vrf = vrf ? vrf : vrf_get(VRF_UNKNOWN, vrfname); + if (!vrf) { + flog_warn(EC_LIB_NB_CB_CONFIG_APPLY, + "vrf creation %s failed", vrfname); + return NB_ERR; + } + nb_running_set_entry(args->dnode, vrf); + break; + }; + + return NB_OK; +} + +int routing_control_plane_protocols_control_plane_protocol_destroy( + struct nb_cb_destroy_args *args) +{ + struct vrf *vrf __attribute__((unused)); + + if (args->event != NB_EV_APPLY) + return NB_OK; + + vrf = nb_running_unset_entry(args->dnode); + + return NB_OK; +} diff --git a/lib/sockopt.c b/lib/sockopt.c index 45d9008796..21fddcd01d 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -264,8 +264,7 @@ int setsockopt_ipv4_multicast(int sock, int optname, struct in_addr if_addr, * up */ char buf[1][INET_ADDRSTRLEN]; zlog_info( - "setsockopt_ipv4_multicast attempting to drop and " - "re-add (fd %d, mcast %s, ifindex %u)", + "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %s, ifindex %u)", sock, inet_ntop(AF_INET, &mreqn.imr_multiaddr, buf[0], sizeof(buf[0])), ifindex); @@ -306,8 +305,7 @@ int setsockopt_ipv4_multicast(int sock, int optname, struct in_addr if_addr, * up */ char buf[1][INET_ADDRSTRLEN]; zlog_info( - "setsockopt_ipv4_multicast attempting to drop and " - "re-add (fd %d, mcast %s, ifindex %u)", + "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %s, ifindex %u)", sock, inet_ntop(AF_INET, &mreq.imr_multiaddr, buf[0], sizeof(buf[0])), ifindex); diff --git a/lib/sockunion.c b/lib/sockunion.c index 63d8a8c69b..d77229797c 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -27,6 +27,7 @@ #include "log.h" #include "jhash.h" #include "lib_errors.h" +#include "printfrr.h" DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union") @@ -406,8 +407,7 @@ int sockopt_v6only(int family, int sock) sizeof(int)); if (ret < 0) { flog_err(EC_LIB_SOCKET, - "can't set sockopt IPV6_V6ONLY " - "to socket %d", + "can't set sockopt IPV6_V6ONLY to socket %d", sock); return -1; } @@ -666,3 +666,49 @@ void sockunion_init(union sockunion *su) { memset(su, 0, sizeof(union sockunion)); } + +printfrr_ext_autoreg_p("SU", printfrr_psu) +static ssize_t printfrr_psu(char *buf, size_t bsz, const char *fmt, + int prec, const void *ptr) +{ + const union sockunion *su = ptr; + struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 }; + bool include_port = false; + bool endflags = false; + ssize_t consumed = 2; + + while (!endflags) { + switch (fmt[consumed++]) { + case 'p': + include_port = true; + break; + default: + consumed--; + endflags = true; + break; + } + }; + + switch (sockunion_family(su)) { + case AF_UNSPEC: + bprintfrr(&fb, "(unspec)"); + break; + case AF_INET: + inet_ntop(AF_INET, &su->sin.sin_addr, buf, bsz); + fb.pos += strlen(fb.buf); + if (include_port) + bprintfrr(&fb, ":%d", su->sin.sin_port); + break; + case AF_INET6: + inet_ntop(AF_INET6, &su->sin6.sin6_addr, buf, bsz); + fb.pos += strlen(fb.buf); + if (include_port) + bprintfrr(&fb, ":%d", su->sin6.sin6_port); + break; + default: + bprintfrr(&fb, "(af %d)", sockunion_family(su)); + } + + fb.pos[0] = '\0'; + return consumed; +} diff --git a/lib/sockunion.h b/lib/sockunion.h index 7091c1b5e7..72f12b77ca 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -103,6 +103,10 @@ extern union sockunion *sockunion_dup(const union sockunion *); extern void sockunion_free(union sockunion *); extern void sockunion_init(union sockunion *); +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pSU" (union sockunion *) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c index 66b735919b..8ffa0e9709 100644 --- a/lib/srcdest_table.c +++ b/lib/srcdest_table.c @@ -317,3 +317,13 @@ static ssize_t printfrr_rn(char *buf, size_t bsz, const char *fmt, srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, buf, bsz); return 2; } + +struct route_table *srcdest_srcnode_table(struct route_node *rn) +{ + if (rnode_is_dstnode(rn)) { + struct srcdest_rnode *srn = srcdest_rnode_from_rnode(rn); + + return srn->src_table; + } + return NULL; +} diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h index 7982260777..79afef9bb0 100644 --- a/lib/srcdest_table.h +++ b/lib/srcdest_table.h @@ -100,6 +100,8 @@ static inline void *srcdest_rnode_table_info(struct route_node *rn) return route_table_get_info(srcdest_rnode_table(rn)); } +extern struct route_table *srcdest_srcnode_table(struct route_node *rn); + #ifdef __cplusplus } #endif diff --git a/lib/srte.h b/lib/srte.h new file mode 100644 index 0000000000..d468c1cac9 --- /dev/null +++ b/lib/srte.h @@ -0,0 +1,56 @@ +/* + * SR-TE definitions + * Copyright 2020 NetDef Inc. + * Sascha Kattelmann + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _FRR_SRTE_H +#define _FRR_SRTE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SRTE_POLICY_NAME_MAX_LENGTH 64 + +enum zebra_sr_policy_status { + ZEBRA_SR_POLICY_UP = 0, + ZEBRA_SR_POLICY_DOWN, +}; + +static inline int sr_policy_compare(const struct ipaddr *a_endpoint, + const struct ipaddr *b_endpoint, + uint32_t a_color, uint32_t b_color) +{ + int ret; + + ret = ipaddr_cmp(a_endpoint, b_endpoint); + if (ret < 0) + return -1; + if (ret > 0) + return 1; + + return a_color - b_color; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _FRR_SRTE_H */ diff --git a/lib/stream.c b/lib/stream.c index 17520f978e..768114e69b 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -55,15 +55,19 @@ DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO") * using stream_put..._at() functions. */ #define STREAM_WARN_OFFSETS(S) \ - flog_warn(EC_LIB_STREAM, \ - "&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \ - (void *)(S), (unsigned long)(S)->size, \ - (unsigned long)(S)->getp, (unsigned long)(S)->endp) + do { \ + flog_warn(EC_LIB_STREAM, \ + "&(struct stream): %p, size: %lu, getp: %lu, endp: %lu\n", \ + (void *)(S), (unsigned long)(S)->size, \ + (unsigned long)(S)->getp, (unsigned long)(S)->endp); \ + zlog_backtrace(LOG_WARNING); \ + } while (0) #define STREAM_VERIFY_SANE(S) \ do { \ - if (!(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp))) \ + if (!(GETP_VALID(S, (S)->getp) && ENDP_VALID(S, (S)->endp))) { \ STREAM_WARN_OFFSETS(S); \ + } \ assert(GETP_VALID(S, (S)->getp)); \ assert(ENDP_VALID(S, (S)->endp)); \ } while (0) @@ -582,6 +586,43 @@ uint32_t stream_get_ipv4(struct stream *s) return l; } +bool stream_get_ipaddr(struct stream *s, struct ipaddr *ip) +{ + uint16_t ipa_len; + + STREAM_VERIFY_SANE(s); + + /* Get address type. */ + if (STREAM_READABLE(s) < sizeof(uint16_t)) { + STREAM_BOUND_WARN2(s, "get ipaddr"); + return false; + } + ip->ipa_type = stream_getw(s); + + /* Get address value. */ + switch (ip->ipa_type) { + case IPADDR_V4: + ipa_len = IPV4_MAX_BYTELEN; + break; + case IPADDR_V6: + ipa_len = IPV6_MAX_BYTELEN; + break; + default: + flog_err(EC_LIB_DEVELOPMENT, + "%s: unknown ip address-family: %u", __func__, + ip->ipa_type); + return false; + } + if (STREAM_READABLE(s) < ipa_len) { + STREAM_BOUND_WARN2(s, "get ipaddr"); + return false; + } + memcpy(&ip->ip, s->data + s->getp, ipa_len); + s->getp += ipa_len; + + return true; +} + float stream_getf(struct stream *s) { union { @@ -848,6 +889,27 @@ int stream_put_in_addr(struct stream *s, const struct in_addr *addr) return sizeof(uint32_t); } +bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip) +{ + stream_putw(s, ip->ipa_type); + + switch (ip->ipa_type) { + case IPADDR_V4: + stream_put_in_addr(s, &ip->ipaddr_v4); + break; + case IPADDR_V6: + stream_write(s, (uint8_t *)&ip->ipaddr_v6, 16); + break; + default: + flog_err(EC_LIB_DEVELOPMENT, + "%s: unknown ip address-family: %u", __func__, + ip->ipa_type); + return false; + } + + return true; +} + /* Put in_addr at location in the stream. */ int stream_put_in_addr_at(struct stream *s, size_t putp, const struct in_addr *addr) diff --git a/lib/stream.h b/lib/stream.h index 245f35db51..1250b6944d 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -189,6 +189,7 @@ extern int stream_putq(struct stream *, uint64_t); extern int stream_putq_at(struct stream *, size_t, uint64_t); extern int stream_put_ipv4(struct stream *, uint32_t); extern int stream_put_in_addr(struct stream *s, const struct in_addr *addr); +extern bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip); extern int stream_put_in_addr_at(struct stream *s, size_t putp, const struct in_addr *addr); extern int stream_put_in6_addr_at(struct stream *s, size_t putp, @@ -219,6 +220,7 @@ extern uint64_t stream_getq(struct stream *); extern uint64_t stream_getq_from(struct stream *, size_t); bool stream_getq2(struct stream *s, uint64_t *q); extern uint32_t stream_get_ipv4(struct stream *); +extern bool stream_get_ipaddr(struct stream *s, struct ipaddr *ip); /* IEEE-754 floats */ extern float stream_getf(struct stream *); @@ -439,6 +441,12 @@ static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out) (P) = _pval; \ } while (0) +#define STREAM_GET_IPADDR(S, P) \ + do { \ + if (!stream_get_ipaddr((S), (P))) \ + goto stream_failure; \ + } while (0) + #define STREAM_GET(P, STR, SIZE) \ do { \ if (!stream_get2((P), (STR), (SIZE))) \ diff --git a/lib/subdir.am b/lib/subdir.am index 57b2cea832..1feaa56d13 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -108,6 +108,8 @@ lib_libfrr_la_SOURCES = \ lib/printf/printf-pos.c \ lib/printf/vfprintf.c \ lib/printf/glue.c \ + lib/routing_nb.c \ + lib/routing_nb_config.c \ # end nodist_lib_libfrr_la_SOURCES = \ @@ -117,13 +119,11 @@ nodist_lib_libfrr_la_SOURCES = \ yang/frr-route-types.yang.c \ yang/frr-vrf.yang.c \ yang/frr-routing.yang.c \ + yang/frr-nexthop.yang.c \ yang/ietf/ietf-routing-types.yang.c \ yang/ietf/ietf-interfaces.yang.c \ yang/frr-module-translator.yang.c \ yang/frr-nexthop.yang.c \ - yang/frr-igmp.yang.c \ - yang/frr-pim.yang.c \ - yang/frr-pim-rp.yang.c \ # end vtysh_scan += \ @@ -242,6 +242,7 @@ pkginclude_HEADERS += \ lib/sockunion.h \ lib/spf_backoff.h \ lib/srcdest_table.h \ + lib/srte.h \ lib/stream.h \ lib/systemd.h \ lib/table.h \ @@ -266,6 +267,7 @@ pkginclude_HEADERS += \ lib/zlog.h \ lib/zlog_targets.h \ lib/pbr.h \ + lib/routing_nb.h \ # end diff --git a/lib/thread.c b/lib/thread.c index 9b2f5661ac..19e4827283 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -305,8 +305,7 @@ DEFUN (show_thread_cpu, filter = parse_filter(argv[idx]->arg); if (!filter) { vty_out(vty, - "Invalid filter \"%s\" specified; must contain at least" - "one of 'RWTEXB'\n", + "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n", argv[idx]->arg); return CMD_WARNING; } @@ -393,8 +392,7 @@ DEFUN (clear_thread_cpu, filter = parse_filter(argv[idx]->arg); if (!filter) { vty_out(vty, - "Invalid filter \"%s\" specified; must contain at least" - "one of 'RWTEXB'\n", + "Invalid filter \"%s\" specified; must contain at leastone of 'RWTEXB'\n", argv[idx]->arg); return CMD_WARNING; } @@ -636,6 +634,36 @@ struct timeval thread_timer_remain(struct thread *thread) return remain; } +static int time_hhmmss(char *buf, int buf_size, long sec) +{ + long hh; + long mm; + int wr; + + zassert(buf_size >= 8); + + hh = sec / 3600; + sec %= 3600; + mm = sec / 60; + sec %= 60; + + wr = snprintf(buf, buf_size, "%02ld:%02ld:%02ld", hh, mm, sec); + + return wr != 8; +} + +char *thread_timer_to_hhmmss(char *buf, int buf_size, + struct thread *t_timer) +{ + if (t_timer) { + time_hhmmss(buf, buf_size, + thread_timer_remain_second(t_timer)); + } else { + snprintf(buf, buf_size, "--:--:--"); + } + return buf; +} + /* Get new thread. */ static struct thread *thread_get(struct thread_master *m, uint8_t type, int (*func)(struct thread *), void *arg, @@ -698,17 +726,16 @@ static void thread_free(struct thread_master *master, struct thread *thread) static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize, nfds_t count, const struct timeval *timer_wait) { - /* If timer_wait is null here, that means poll() should block - * indefinitely, - * unless the thread_master has overridden it by setting + /* + * If timer_wait is null here, that means poll() should block + * indefinitely, unless the thread_master has overridden it by setting * ->selectpoll_timeout. + * * If the value is positive, it specifies the maximum number of - * milliseconds - * to wait. If the timeout is -1, it specifies that we should never wait - * and - * always return immediately even if no event is detected. If the value - * is - * zero, the behavior is default. */ + * milliseconds to wait. If the timeout is -1, it specifies that + * we should never wait and always return immediately even if no + * event is detected. If the value is zero, the behavior is default. + */ int timeout = -1; /* number of file descriptors with events */ @@ -832,7 +859,7 @@ funcname_thread_add_timer_timeval(struct thread_master *m, frr_with_mutex(&m->mtx) { if (t_ptr && *t_ptr) - // thread is already scheduled; don't reschedule + /* thread is already scheduled; don't reschedule */ return NULL; thread = thread_get(m, type, func, arg, debugargpass); @@ -912,7 +939,7 @@ struct thread *funcname_thread_add_event(struct thread_master *m, frr_with_mutex(&m->mtx) { if (t_ptr && *t_ptr) - // thread is already scheduled; don't reschedule + /* thread is already scheduled; don't reschedule */ break; thread = thread_get(m, THREAD_EVENT, func, arg, debugargpass); @@ -1019,11 +1046,12 @@ static void do_thread_cancel(struct thread_master *master) struct cancel_req *cr; struct listnode *ln; for (ALL_LIST_ELEMENTS_RO(master->cancel_req, ln, cr)) { - /* If this is an event object cancellation, linear search - * through event - * list deleting any events which have the specified argument. - * We also - * need to check every thread in the ready queue. */ + /* + * If this is an event object cancellation, linear search + * through event list deleting any events which have the + * specified argument. We also need to check every thread + * in the ready queue. + */ if (cr->eventobj) { struct thread *t; @@ -1047,11 +1075,12 @@ static void do_thread_cancel(struct thread_master *master) continue; } - /* The pointer varies depending on whether the cancellation - * request was - * made asynchronously or not. If it was, we need to check - * whether the - * thread even exists anymore before cancelling it. */ + /* + * The pointer varies depending on whether the cancellation + * request was made asynchronously or not. If it was, we + * need to check whether the thread even exists anymore + * before cancelling it. + */ thread = (cr->thread) ? cr->thread : *cr->threadref; if (!thread) @@ -1276,18 +1305,21 @@ static void thread_process_io(struct thread_master *m, unsigned int num) ready++; - /* Unless someone has called thread_cancel from another pthread, - * the only - * thing that could have changed in m->handler.pfds while we - * were - * asleep is the .events field in a given pollfd. Barring - * thread_cancel() - * that value should be a superset of the values we have in our - * copy, so - * there's no need to update it. Similarily, barring deletion, - * the fd - * should still be a valid index into the master's pfds. */ - if (pfds[i].revents & (POLLIN | POLLHUP)) { + /* + * Unless someone has called thread_cancel from another + * pthread, the only thing that could have changed in + * m->handler.pfds while we were asleep is the .events + * field in a given pollfd. Barring thread_cancel() that + * value should be a superset of the values we have in our + * copy, so there's no need to update it. Similarily, + * barring deletion, the fd should still be a valid index + * into the master's pfds. + * + * We are including POLLERR here to do a READ event + * this is because the read should fail and the + * read function should handle it appropriately + */ + if (pfds[i].revents & (POLLIN | POLLHUP | POLLERR)) { thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN, pfds[i].revents, i); } @@ -1399,11 +1431,10 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) * * - If there are events pending, set the poll() timeout to zero * - If there are no events pending, but there are timers - * pending, set the - * timeout to the smallest remaining time on any timer + * pending, set the timeout to the smallest remaining time on + * any timer. * - If there are neither timers nor events pending, but there - * are file - * descriptors pending, block indefinitely in poll() + * are file descriptors pending, block indefinitely in poll() * - If nothing is pending, it's time for the application to die * * In every case except the last, we need to hit poll() at least diff --git a/lib/thread.h b/lib/thread.h index 412a4d93bf..c22b2105cd 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -140,6 +140,8 @@ struct cpu_thread_history { /* Thread yield time. */ #define THREAD_YIELD_TIME_SLOT 10 * 1000L /* 10ms */ +#define THREAD_TIMER_STRLEN 12 + /* Macros. */ #define THREAD_ARG(X) ((X)->arg) #define THREAD_FD(X) ((X)->u.fd) @@ -228,6 +230,8 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before, /* only for use in logging functions! */ extern pthread_key_t thread_current; +extern char *thread_timer_to_hhmmss(char *buf, int buf_size, + struct thread *t_timer); #ifdef __cplusplus } @@ -638,6 +638,7 @@ int vrf_handler_create(struct vty *vty, const char *vrfname, ret = nb_cli_apply_changes(vty, xpath_list); if (ret == CMD_SUCCESS) { VTY_PUSH_XPATH(VRF_NODE, xpath_list); + nb_cli_pending_commit_check(vty); vrfp = vrf_lookup_by_name(vrfname); if (vrfp) VTY_PUSH_CONTEXT(VRF_NODE, vrfp); @@ -652,8 +653,7 @@ int vrf_handler_create(struct vty *vty, const char *vrfname, } int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, - ns_id_t ns_id, ns_id_t internal_ns_id, - ns_id_t rel_def_ns_id) + ns_id_t ns_id, ns_id_t internal_ns_id) { struct ns *ns = NULL; @@ -691,8 +691,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, return CMD_SUCCESS; if (vty) vty_out(vty, - "NS %s is already configured" - " with VRF %u(%s)\n", + "NS %s is already configured with VRF %u(%s)\n", ns->name, vrf2->vrf_id, vrf2->name); else zlog_info("NS %s is already configured with VRF %u(%s)", @@ -701,7 +700,6 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, } ns = ns_get_created(ns, pathname, ns_id); ns->internal_ns_id = internal_ns_id; - ns->relative_default_ns = rel_def_ns_id; ns->vrf_ctxt = (void *)vrf; vrf->ns_ctxt = (void *)ns; /* update VRF netns NAME */ @@ -732,7 +730,7 @@ DEFUN_NOSH(vrf_exit, return CMD_SUCCESS; } -DEFUN_NOSH (vrf, +DEFUN_YANG_NOSH (vrf, vrf_cmd, "vrf NAME", "Select a VRF to configure\n" @@ -744,7 +742,7 @@ DEFUN_NOSH (vrf, return vrf_handler_create(vty, vrfname, NULL); } -DEFUN (no_vrf, +DEFUN_YANG (no_vrf, no_vrf_cmd, "no vrf NAME", NO_STR @@ -758,10 +756,8 @@ DEFUN (no_vrf, vrfp = vrf_lookup_by_name(vrfname); - if (vrfp == NULL) { - vty_out(vty, "%% VRF %s does not exist\n", vrfname); - return CMD_WARNING_CONFIG_FAILED; - } + if (vrfp == NULL) + return CMD_SUCCESS; if (CHECK_FLAG(vrfp->status, VRF_ACTIVE)) { vty_out(vty, "%% Only inactive VRFs can be deleted\n"); @@ -799,9 +795,7 @@ DEFUN_NOSH (vrf_netns, frr_with_privs(vrf_daemon_privs) { ret = vrf_netns_handler_create(vty, vrf, pathname, - NS_UNKNOWN, - NS_UNKNOWN, - NS_UNKNOWN); + NS_UNKNOWN, NS_UNKNOWN); } return ret; } @@ -315,7 +315,7 @@ extern int vrf_handler_create(struct vty *vty, const char *name, */ extern int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, ns_id_t ext_ns_id, - ns_id_t ns_id, ns_id_t rel_def_ns_id); + ns_id_t ns_id); /* used internally to enable or disable VRF. * Notify a change in the VRF ID of the VRF @@ -1244,8 +1244,7 @@ static int vty_telnet_option(struct vty *vty, unsigned char *buf, int nbytes) if (vty->sb_len != TELNET_NAWS_SB_LEN) flog_err( EC_LIB_SYSTEM_CALL, - "RFC 1073 violation detected: telnet NAWS option " - "should send %d characters, but we received %lu", + "RFC 1073 violation detected: telnet NAWS option should send %d characters, but we received %lu", TELNET_NAWS_SB_LEN, (unsigned long)vty->sb_len); else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN) @@ -1261,8 +1260,7 @@ static int vty_telnet_option(struct vty *vty, unsigned char *buf, int nbytes) | vty->sb_buf[4]); #ifdef TELNET_OPTION_DEBUG vty_out(vty, - "TELNET NAWS window size negotiation completed: " - "width %d, height %d\n", + "TELNET NAWS window size negotiation completed: width %d, height %d\n", vty->width, vty->height); #endif } @@ -2633,6 +2631,9 @@ int vty_config_node_exit(struct vty *vty) { vty->xpath_index = 0; + /* Perform pending commit if any. */ + nb_cli_pending_commit_check(vty); + /* Check if there's a pending confirmed commit. */ if (vty->t_confirmed_commit_timeout) { vty_out(vty, @@ -134,6 +134,14 @@ struct vty { /* Base candidate configuration. */ struct nb_config *candidate_config_base; + /* Dynamic transaction information. */ + struct timeval backoff_start; + size_t backoff_cmd_count; + struct thread *t_pending_commit; + char *pending_cmds_buf; + size_t pending_cmds_buflen; + size_t pending_cmds_bufpos; + /* Confirmed-commit timeout and rollback configuration. */ struct thread *t_confirmed_commit_timeout; struct nb_config *confirmed_commit_rollback; diff --git a/lib/yang.c b/lib/yang.c index 0714ddf7bb..6ab9492d52 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -53,22 +53,30 @@ static const char *yang_module_imp_clb(const char *mod_name, { struct yang_module_embed *e; - if (submod_name || submod_rev) - return NULL; - for (e = embeds; e; e = e->next) { - if (strcmp(e->mod_name, mod_name)) - continue; - if (mod_rev && strcmp(e->mod_rev, mod_rev)) - continue; + if (e->sub_mod_name && submod_name) { + if (strcmp(e->sub_mod_name, submod_name)) + continue; + + if (submod_rev && strcmp(e->sub_mod_rev, submod_rev)) + continue; + } else { + if (strcmp(e->mod_name, mod_name)) + continue; + + if (mod_rev && strcmp(e->mod_rev, mod_rev)) + continue; + } *format = e->format; return e->data; } - flog_warn(EC_LIB_YANG_MODULE_LOAD, - "YANG model \"%s@%s\" not embedded, trying external file", - mod_name, mod_rev ? mod_rev : "*"); + flog_warn( + EC_LIB_YANG_MODULE_LOAD, + "YANG model \"%s@%s\" \"%s@%s\"not embedded, trying external file", + mod_name, mod_rev ? mod_rev : "*", + submod_name ? submod_name : "*", submod_rev ? submod_rev : "*"); return NULL; } @@ -749,3 +757,147 @@ void yang_terminate(void) ly_ctx_destroy(ly_native_ctx, NULL); } + +const struct lyd_node *yang_dnode_get_parent(const struct lyd_node *dnode, + const char *name) +{ + const struct lyd_node *orig_dnode = dnode; + + while (orig_dnode) { + switch (orig_dnode->schema->nodetype) { + case LYS_LIST: + case LYS_CONTAINER: + if (!strcmp(orig_dnode->schema->name, name)) + return orig_dnode; + break; + default: + break; + } + + orig_dnode = orig_dnode->parent; + } + + return NULL; +} + +/* API to check if the given node is last node in the list */ +static bool yang_is_last_list_dnode(const struct lyd_node *dnode) +{ + return (((dnode->next == NULL) + || (dnode->next + && (strcmp(dnode->next->schema->name, dnode->schema->name) + != 0))) + && dnode->prev + && ((dnode->prev == dnode) + || (strcmp(dnode->prev->schema->name, dnode->schema->name) + != 0))); +} + +/* API to check if the given node is last node in the data tree level */ +static bool yang_is_last_level_dnode(const struct lyd_node *dnode) +{ + const struct lyd_node *parent; + const struct lys_node_list *snode; + const struct lyd_node *key_leaf; + uint8_t keys_size; + + switch (dnode->schema->nodetype) { + case LYS_LIST: + assert(dnode->parent); + parent = dnode->parent; + snode = (struct lys_node_list *)parent->schema; + key_leaf = dnode->prev; + for (keys_size = 1; keys_size < snode->keys_size; keys_size++) + key_leaf = key_leaf->prev; + if (key_leaf->prev == dnode) + return true; + break; + case LYS_CONTAINER: + return true; + default: + break; + } + + return false; +} + + +const struct lyd_node * +yang_get_subtree_with_no_sibling(const struct lyd_node *dnode) +{ + bool parent = true; + const struct lyd_node *node; + const struct lys_node_container *snode; + + node = dnode; + if (node->schema->nodetype != LYS_LIST) + return node; + + while (parent) { + switch (node->schema->nodetype) { + case LYS_CONTAINER: + snode = (struct lys_node_container *)node->schema; + if ((!snode->presence) + && yang_is_last_level_dnode(node)) { + if (node->parent + && (node->parent->schema->module + == dnode->schema->module)) + node = node->parent; + else + parent = false; + } else + parent = false; + break; + case LYS_LIST: + if (yang_is_last_list_dnode(node) + && yang_is_last_level_dnode(node)) { + if (node->parent + && (node->parent->schema->module + == dnode->schema->module)) + node = node->parent; + else + parent = false; + } else + parent = false; + break; + default: + parent = false; + break; + } + } + return node; +} + +uint32_t yang_get_list_pos(const struct lyd_node *node) +{ + return lyd_list_pos(node); +} + +uint32_t yang_get_list_elements_count(const struct lyd_node *node) +{ + unsigned int count; + struct lys_node *schema; + + if (!node + || ((node->schema->nodetype != LYS_LIST) + && (node->schema->nodetype != LYS_LEAFLIST))) { + return 0; + } + + schema = node->schema; + count = 0; + do { + if (node->schema == schema) + ++count; + node = node->next; + } while (node); + return count; +} + + +const struct lyd_node *yang_dnode_get_child(const struct lyd_node *dnode) +{ + if (dnode) + return dnode->child; + return NULL; +} diff --git a/lib/yang.h b/lib/yang.h index 85ef0d758c..cc048c44e8 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -34,7 +34,7 @@ extern "C" { #endif /* Maximum XPath length. */ -#define XPATH_MAXLEN 512 +#define XPATH_MAXLEN 1024 /* Maximum list key length. */ #define LIST_MAXKEYS 8 @@ -48,6 +48,8 @@ extern "C" { struct yang_module_embed { struct yang_module_embed *next; const char *mod_name, *mod_rev; + const char *sub_mod_name; + const char *sub_mod_rev; const char *data; LYS_INFORMAT format; }; @@ -551,6 +553,57 @@ extern void yang_init(bool embedded_modules); */ extern void yang_terminate(void); +/* + * API to return the parent dnode having a given schema-node name + * Use case: One has to access the parent dnode's private pointer + * for a given child node. + * For that there is a need to find parent dnode first. + * + * dnode The starting node to work on + * + * name The name of container/list schema-node + * + * Returns The dnode matched with the given name + */ +extern const struct lyd_node * +yang_dnode_get_parent(const struct lyd_node *dnode, const char *name); + + +/* + * In some cases there is a need to auto delete the parent nodes + * if the given node is last in the list. + * It tries to delete all the parents in a given tree in a given module. + * The use case is with static routes and route maps + * example : ip route 1.1.1.1/32 ens33 + * ip route 1.1.1.1/32 ens34 + * After this no ip route 1.1.1.1/32 ens34 came, now staticd + * has to find out upto which level it has to delete the dnodes. + * For this case it has to send delete nexthop + * After this no ip route 1.1.1.1/32 ens33 came, now staticd has to + * clear nexthop, path and route nodes. + * The same scheme is required for routemaps also + * dnode The starting node to work on + * + * Returns The final parent node selected for deletion + */ +extern const struct lyd_node * +yang_get_subtree_with_no_sibling(const struct lyd_node *dnode); + +/* To get the relative position of a node in list */ +extern uint32_t yang_get_list_pos(const struct lyd_node *node); + +/* To get the number of elements in a list + * + * dnode : The head of list + * Returns : The number of dnodes present in the list + */ +extern uint32_t yang_get_list_elements_count(const struct lyd_node *node); + + +/* To get the immediate child of a dnode */ +const struct lyd_node *yang_dnode_get_child(const struct lyd_node *dnode); + + #ifdef __cplusplus } #endif diff --git a/lib/yang_wrappers.c b/lib/yang_wrappers.c index c31ba3fcc0..4c658c1bfb 100644 --- a/lib/yang_wrappers.c +++ b/lib/yang_wrappers.c @@ -792,6 +792,29 @@ struct yang_data *yang_data_new_empty(const char *xpath) return yang_data_new(xpath, NULL); } +bool yang_dnode_get_empty(const struct lyd_node *dnode, const char *xpath_fmt, + ...) +{ + va_list ap; + char xpath[XPATH_MAXLEN]; + const struct lyd_node_leaf_list *dleaf; + + assert(dnode); + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + dnode = yang_dnode_get(dnode, xpath); + if (dnode) { + dleaf = (const struct lyd_node_leaf_list *)dnode; + if (dleaf->value_type == LY_TYPE_EMPTY) + return true; + } + + return false; +} + /* * Derived type: IP prefix. */ @@ -1191,3 +1214,63 @@ const char *yang_nexthop_type2str(uint32_t ntype) break; } } + + +const char *yang_afi_safi_value2identity(afi_t afi, safi_t safi) +{ + if (afi == AFI_IP && safi == SAFI_UNICAST) + return "frr-routing:ipv4-unicast"; + if (afi == AFI_IP6 && safi == SAFI_UNICAST) + return "frr-routing:ipv6-unicast"; + if (afi == AFI_IP && safi == SAFI_MULTICAST) + return "frr-routing:ipv4-multicast"; + if (afi == AFI_IP6 && safi == SAFI_MULTICAST) + return "frr-routing:ipv6-multicast"; + if (afi == AFI_IP && safi == SAFI_MPLS_VPN) + return "frr-routing:l3vpn-ipv4-unicast"; + if (afi == AFI_IP6 && safi == SAFI_MPLS_VPN) + return "frr-routing:l3vpn-ipv6-unicast"; + if (afi == AFI_L2VPN && safi == SAFI_EVPN) + return "frr-routing:l2vpn-evpn"; + if (afi == AFI_IP && safi == SAFI_LABELED_UNICAST) + return "frr-routing:ipv4-labeled-unicast"; + if (afi == AFI_IP6 && safi == SAFI_LABELED_UNICAST) + return "frr-routing:ipv6-labeled-unicast"; + + return NULL; +} + +void yang_afi_safi_identity2value(const char *key, afi_t *afi, safi_t *safi) +{ + if (strmatch(key, "frr-routing:ipv4-unicast")) { + *afi = AFI_IP; + *safi = SAFI_UNICAST; + } else if (strmatch(key, "frr-routing:ipv6-unicast")) { + *afi = AFI_IP6; + *safi = SAFI_UNICAST; + } else if (strmatch(key, "frr-routing:ipv4-multicast")) { + *afi = AFI_IP; + *safi = SAFI_MULTICAST; + } else if (strmatch(key, "frr-routing:ipv6-multicast")) { + *afi = AFI_IP6; + *safi = SAFI_MULTICAST; + } else if (strmatch(key, "frr-routing:l3vpn-ipv4-unicast")) { + *afi = AFI_IP; + *safi = SAFI_MPLS_VPN; + } else if (strmatch(key, "frr-routing:l3vpn-ipv6-unicast")) { + *afi = AFI_IP6; + *safi = SAFI_MPLS_VPN; + } else if (strmatch(key, "frr-routing:ipv4-labeled-unicast")) { + *afi = AFI_IP; + *safi = SAFI_LABELED_UNICAST; + } else if (strmatch(key, "frr-routing:ipv6-labeled-unicast")) { + *afi = AFI_IP6; + *safi = SAFI_LABELED_UNICAST; + } else if (strmatch(key, "frr-routing:l2vpn-evpn")) { + *afi = AFI_L2VPN; + *safi = SAFI_EVPN; + } else { + *afi = AFI_UNSPEC; + *safi = SAFI_UNSPEC; + } +} diff --git a/lib/yang_wrappers.h b/lib/yang_wrappers.h index ba2cf5139c..d781dfb1e4 100644 --- a/lib/yang_wrappers.h +++ b/lib/yang_wrappers.h @@ -120,6 +120,8 @@ extern void yang_get_default_string_buf(char *buf, size_t size, /* empty */ extern struct yang_data *yang_data_new_empty(const char *xpath); +extern bool yang_dnode_get_empty(const struct lyd_node *dnode, + const char *xpath_fmt, ...); /* ip prefix */ extern void yang_str2prefix(const char *value, union prefixptr prefix); @@ -191,6 +193,9 @@ extern struct yang_data *yang_data_new_date_and_time(const char *xpath, /* nexthop enum2str */ extern const char *yang_nexthop_type2str(uint32_t ntype); +const char *yang_afi_safi_value2identity(afi_t afi, safi_t safi); +void yang_afi_safi_identity2value(const char *key, afi_t *afi, safi_t *safi); + #ifdef __cplusplus } #endif diff --git a/lib/zclient.c b/lib/zclient.c index 793864243c..808aa18bbe 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -39,6 +39,7 @@ #include "pbr.h" #include "nexthop_group.h" #include "lib_errors.h" +#include "srte.h" DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient") DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs") @@ -436,7 +437,8 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) vrf_id); /* We need router-id information. */ - zebra_message_send(zclient, ZEBRA_ROUTER_ID_ADD, vrf_id); + zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP, + vrf_id); /* We need interface information. */ zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, vrf_id); @@ -503,7 +505,8 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) vrf_id); /* We need router-id information. */ - zebra_message_send(zclient, ZEBRA_ROUTER_ID_DELETE, vrf_id); + zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_DELETE, AFI_IP, + vrf_id); zebra_message_send(zclient, ZEBRA_INTERFACE_DELETE, vrf_id); @@ -554,6 +557,18 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) } } +int zclient_send_router_id_update(struct zclient *zclient, + zebra_message_types_t type, afi_t afi, + vrf_id_t vrf_id) +{ + struct stream *s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, type, vrf_id); + stream_putw(s, afi); + stream_putw_at(s, 0, stream_get_endp(s)); + return zclient_send_message(zclient); +} + /* Send request to zebra daemon to start or stop RA. */ void zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id, struct interface *ifp, int enable, @@ -886,9 +901,9 @@ static void zapi_nexthop_group_sort(struct zapi_nexthop *nh_grp, * Encode a single zapi nexthop */ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, - uint32_t api_flags) + uint32_t api_flags, uint32_t api_message) { - int ret = 0; + int i, ret = 0; int nh_flags = api_nh->flags; stream_putl(s, api_nh->vrf_id); @@ -950,9 +965,22 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, stream_put(s, &(api_nh->rmac), sizeof(struct ethaddr)); + /* Color for Segment Routing TE. */ + if (CHECK_FLAG(api_message, ZAPI_MESSAGE_SRTE)) + stream_putl(s, api_nh->srte_color); + /* Index of backup nexthop */ - if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) - stream_putc(s, api_nh->backup_idx); + if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { + /* Validate backup count */ + if (api_nh->backup_num > NEXTHOP_MAX_BACKUPS) { + ret = -1; + goto done; + } + + stream_putc(s, api_nh->backup_num); + for (i = 0; i < api_nh->backup_num; i++) + stream_putc(s, api_nh->backup_idx[i]); + } done: return ret; @@ -977,7 +1005,7 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) stream_putw(s, api->instance); stream_putl(s, api->flags); - stream_putc(s, api->message); + stream_putl(s, api->message); if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) { flog_err(EC_LIB_ZAPI_ENCODE, @@ -1038,7 +1066,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) return -1; } - if (zapi_nexthop_encode(s, api_nh, api->flags) != 0) + if (zapi_nexthop_encode(s, api_nh, api->flags, + api->message) + != 0) return -1; } } @@ -1082,7 +1112,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) return -1; } - if (zapi_nexthop_encode(s, api_nh, api->flags) != 0) + if (zapi_nexthop_encode(s, api_nh, api->flags, + api->message) + != 0) return -1; } } @@ -1109,9 +1141,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) * Decode a single zapi nexthop object */ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, - uint32_t api_flags) + uint32_t api_flags, uint32_t api_message) { - int ret = -1; + int i, ret = -1; STREAM_GETL(s, api_nh->vrf_id); STREAM_GETC(s, api_nh->type); @@ -1162,9 +1194,20 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh, STREAM_GET(&(api_nh->rmac), s, sizeof(struct ethaddr)); + /* Color for Segment Routing TE. */ + if (CHECK_FLAG(api_message, ZAPI_MESSAGE_SRTE)) + STREAM_GETL(s, api_nh->srte_color); + /* Backup nexthop index */ - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) - STREAM_GETC(s, api_nh->backup_idx); + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { + STREAM_GETC(s, api_nh->backup_num); + + if (api_nh->backup_num > NEXTHOP_MAX_BACKUPS) + return -1; + + for (i = 0; i < api_nh->backup_num; i++) + STREAM_GETC(s, api_nh->backup_idx[i]); + } /* Success */ ret = 0; @@ -1192,7 +1235,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) STREAM_GETW(s, api->instance); STREAM_GETL(s, api->flags); - STREAM_GETC(s, api->message); + STREAM_GETL(s, api->message); STREAM_GETC(s, api->safi); if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) { flog_err(EC_LIB_ZAPI_ENCODE, @@ -1267,7 +1310,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) for (i = 0; i < api->nexthop_num; i++) { api_nh = &api->nexthops[i]; - if (zapi_nexthop_decode(s, api_nh, api->flags) != 0) + if (zapi_nexthop_decode(s, api_nh, api->flags, + api->message) + != 0) return -1; } } @@ -1285,7 +1330,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) for (i = 0; i < api->backup_nexthop_num; i++) { api_nh = &api->backup_nexthops[i]; - if (zapi_nexthop_decode(s, api_nh, api->flags) != 0) + if (zapi_nexthop_decode(s, api_nh, api->flags, + api->message) + != 0) return -1; } } @@ -1472,6 +1519,7 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) n->vrf_id = znh->vrf_id; n->ifindex = znh->ifindex; n->gate = znh->gate; + n->srte_color = znh->srte_color; /* * This function currently handles labels @@ -1483,7 +1531,8 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP); - n->backup_idx = znh->backup_idx; + n->backup_num = znh->backup_num; + memcpy(n->backup_idx, znh->backup_idx, n->backup_num); } return n; @@ -1519,8 +1568,12 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh, } if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) { + if (nh->backup_num > NEXTHOP_MAX_BACKUPS) + return -1; + SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP); - znh->backup_idx = nh->backup_idx; + znh->backup_num = nh->backup_num; + memcpy(znh->backup_idx, nh->backup_idx, znh->backup_num); } return 0; @@ -1584,6 +1637,7 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) memset(nhr, 0, sizeof(*nhr)); + STREAM_GETL(s, nhr->message); STREAM_GETW(s, nhr->prefix.family); STREAM_GETC(s, nhr->prefix.prefixlen); switch (nhr->prefix.family) { @@ -1596,6 +1650,8 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) default: break; } + if (CHECK_FLAG(nhr->message, ZAPI_MESSAGE_SRTE)) + STREAM_GETL(s, nhr->srte_color); STREAM_GETC(s, nhr->type); STREAM_GETW(s, nhr->instance); @@ -1604,7 +1660,7 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) STREAM_GETC(s, nhr->nexthop_num); for (i = 0; i < nhr->nexthop_num; i++) { - if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0) != 0) + if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0, 0) != 0) return -1; } @@ -1924,8 +1980,7 @@ static int link_params_set_value(struct stream *s, struct if_link_params *iflp) if (i < bwclassnum) flog_err( EC_LIB_ZAPI_MISSMATCH, - "%s: received %d > %d (MAX_CLASS_TYPE) bw entries" - " - outdated library?", + "%s: received %d > %d (MAX_CLASS_TYPE) bw entries - outdated library?", __func__, bwclassnum, MAX_CLASS_TYPE); } STREAM_GETL(s, iflp->admin_grp); @@ -2801,6 +2856,92 @@ int tm_release_table_chunk(struct zclient *zclient, uint32_t start, return zclient_send_message(zclient); } +int 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 -1; + return zclient_send_message(zclient); +} + +int zapi_sr_policy_encode(struct stream *s, int cmd, struct zapi_sr_policy *zp) +{ + struct zapi_srte_tunnel *zt = &zp->segment_list; + + 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); + + stream_putc(s, zt->type); + stream_putl(s, zt->local_label); + + if (zt->label_num > MPLS_MAX_LABELS) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: label %u: can't encode %u labels (maximum is %u)", + __func__, zt->local_label, zt->label_num, + MPLS_MAX_LABELS); + return -1; + } + stream_putw(s, zt->label_num); + + for (int i = 0; i < zt->label_num; i++) + stream_putl(s, zt->labels[i]); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return 0; +} + +int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp) +{ + memset(zp, 0, sizeof(*zp)); + + struct zapi_srte_tunnel *zt = &zp->segment_list; + + 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_GETC(s, zt->type); + STREAM_GETL(s, zt->local_label); + STREAM_GETW(s, zt->label_num); + if (zt->label_num > MPLS_MAX_LABELS) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: label %u: can't decode %u labels (maximum is %u)", + __func__, zt->local_label, zt->label_num, + MPLS_MAX_LABELS); + return -1; + } + for (int i = 0; i < zt->label_num; i++) + STREAM_GETL(s, zt->labels[i]); + + return 0; + +stream_failure: + return -1; +} + +int zapi_sr_policy_notify_status_decode(struct stream *s, + struct zapi_sr_policy *zp) +{ + memset(zp, 0, sizeof(*zp)); + + STREAM_GETL(s, zp->color); + STREAM_GET_IPADDR(s, &zp->endpoint); + STREAM_GET(&zp->name, s, SRTE_POLICY_NAME_MAX_LENGTH); + STREAM_GETL(s, zp->status); + + return 0; + +stream_failure: + return -1; +} + int zebra_send_mpls_labels(struct zclient *zclient, int cmd, struct zapi_labels *zl) { @@ -2840,7 +2981,7 @@ int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl) for (int i = 0; i < zl->nexthop_num; i++) { znh = &zl->nexthops[i]; - if (zapi_nexthop_encode(s, znh, 0) < 0) + if (zapi_nexthop_encode(s, znh, 0, 0) < 0) return -1; } @@ -2859,7 +3000,7 @@ int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl) for (int i = 0; i < zl->backup_nexthop_num; i++) { znh = &zl->backup_nexthops[i]; - if (zapi_nexthop_encode(s, znh, 0) < 0) + if (zapi_nexthop_encode(s, znh, 0, 0) < 0) return -1; } @@ -2935,7 +3076,7 @@ int zapi_labels_decode(struct stream *s, struct zapi_labels *zl) for (int i = 0; i < zl->nexthop_num; i++) { znh = &zl->nexthops[i]; - if (zapi_nexthop_decode(s, znh, 0) < 0) + if (zapi_nexthop_decode(s, znh, 0, 0) < 0) return -1; } @@ -2956,7 +3097,7 @@ int zapi_labels_decode(struct stream *s, struct zapi_labels *zl) for (int i = 0; i < zl->backup_nexthop_num; i++) { znh = &zl->backup_nexthops[i]; - if (zapi_nexthop_decode(s, znh, 0) < 0) + if (zapi_nexthop_decode(s, znh, 0, 0) < 0) return -1; } } @@ -3499,6 +3640,16 @@ static int zclient_read(struct thread *thread) (*zclient->local_es_del)(command, zclient, length, vrf_id); break; + case ZEBRA_LOCAL_ES_EVI_ADD: + if (zclient->local_es_evi_add) + (*zclient->local_es_evi_add)(command, zclient, length, + vrf_id); + break; + case ZEBRA_LOCAL_ES_EVI_DEL: + if (zclient->local_es_evi_del) + (*zclient->local_es_evi_del)(command, zclient, length, + vrf_id); + break; case ZEBRA_VNI_ADD: if (zclient->local_vni_add) (*zclient->local_vni_add)(command, zclient, length, @@ -3613,6 +3764,10 @@ static int zclient_read(struct thread *thread) (*zclient->opaque_unregister_handler)(command, zclient, length, vrf_id); break; + case ZEBRA_SR_POLICY_NOTIFY_STATUS: + if (zclient->sr_policy_notify_status) + (*zclient->sr_policy_notify_status)(command, zclient, + length, vrf_id); default: break; } @@ -3798,3 +3953,23 @@ int32_t zapi_capabilities_decode(struct stream *s, struct zapi_cap *api) stream_failure: return 0; } + +int zclient_send_neigh_discovery_req(struct zclient *zclient, + const struct interface *ifp, + const struct prefix *p) +{ + struct stream *s; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_NEIGH_DISCOVER, ifp->vrf_id); + stream_putl(s, ifp->ifindex); + + stream_putc(s, p->family); + stream_putc(s, p->prefixlen); + stream_put(s, &p->u.prefix, prefix_blen(p)); + + stream_putw_at(s, 0, stream_get_endp(s)); + return zclient_send_message(zclient); +} diff --git a/lib/zclient.h b/lib/zclient.h index 3ded2f55d7..dab384d5ec 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -37,6 +37,7 @@ #include "pw.h" #include "mlag.h" +#include "srte.h" #ifdef __cplusplus extern "C" { @@ -89,6 +90,8 @@ enum zserv_client_capabilities { /* Macro to check if there GR enabled. */ #define ZEBRA_CLIENT_GR_ENABLED(X) (X == ZEBRA_CLIENT_GR_CAPABILITIES) +#define ZEBRA_SR_POLICY_NAME_MAX_LENGTH 100 + extern struct sockaddr_storage zclient_addr; extern socklen_t zclient_addr_len; @@ -143,6 +146,9 @@ typedef enum { ZEBRA_MPLS_LABELS_ADD, ZEBRA_MPLS_LABELS_DELETE, ZEBRA_MPLS_LABELS_REPLACE, + ZEBRA_SR_POLICY_SET, + ZEBRA_SR_POLICY_DELETE, + ZEBRA_SR_POLICY_NOTIFY_STATUS, ZEBRA_IPMR_ROUTE_STATS, ZEBRA_LABEL_MANAGER_CONNECT, ZEBRA_LABEL_MANAGER_CONNECT_ASYNC, @@ -157,6 +163,10 @@ typedef enum { ZEBRA_ADVERTISE_ALL_VNI, ZEBRA_LOCAL_ES_ADD, ZEBRA_LOCAL_ES_DEL, + ZEBRA_REMOTE_ES_VTEP_ADD, + ZEBRA_REMOTE_ES_VTEP_DEL, + ZEBRA_LOCAL_ES_EVI_ADD, + ZEBRA_LOCAL_ES_EVI_DEL, ZEBRA_VNI_ADD, ZEBRA_VNI_DEL, ZEBRA_L3VNI_ADD, @@ -204,6 +214,7 @@ typedef enum { ZEBRA_OPAQUE_MESSAGE, ZEBRA_OPAQUE_REGISTER, ZEBRA_OPAQUE_UNREGISTER, + ZEBRA_NEIGH_DISCOVER, } zebra_message_types_t; enum zebra_error_types { @@ -321,6 +332,8 @@ struct zclient { int (*fec_update)(int, struct zclient *, uint16_t); int (*local_es_add)(ZAPI_CALLBACK_ARGS); int (*local_es_del)(ZAPI_CALLBACK_ARGS); + int (*local_es_evi_add)(ZAPI_CALLBACK_ARGS); + int (*local_es_evi_del)(ZAPI_CALLBACK_ARGS); int (*local_vni_add)(ZAPI_CALLBACK_ARGS); int (*local_vni_del)(ZAPI_CALLBACK_ARGS); int (*local_l3vni_add)(ZAPI_CALLBACK_ARGS); @@ -345,6 +358,7 @@ struct zclient { int (*opaque_msg_handler)(ZAPI_CALLBACK_ARGS); int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS); int (*opaque_unregister_handler)(ZAPI_CALLBACK_ARGS); + int (*sr_policy_notify_status)(ZAPI_CALLBACK_ARGS); }; /* Zebra API message flag. */ @@ -362,7 +376,8 @@ struct zclient { * the table being used is not in the VRF. You must pass the * default vrf, else this will be ignored. */ -#define ZAPI_MESSAGE_TABLEID 0x80 +#define ZAPI_MESSAGE_TABLEID 0x0080 +#define ZAPI_MESSAGE_SRTE 0x0100 #define ZSERV_VERSION 6 /* Zserv protocol message header */ @@ -394,8 +409,12 @@ struct zapi_nexthop { uint32_t weight; - /* Index of backup nexthop */ - uint8_t backup_idx; + /* Backup nexthops, for IP-FRR, TI-LFA, etc */ + uint8_t backup_num; + uint8_t backup_idx[NEXTHOP_MAX_BACKUPS]; + + /* SR-TE color. */ + uint32_t srte_color; }; /* @@ -458,7 +477,7 @@ struct zapi_route { #define ZEBRA_FLAG_RR_USE_DISTANCE 0x40 /* The older XXX_MESSAGE flags live here */ - uint8_t message; + uint32_t message; /* * This is an enum but we are going to treat it as a uint8_t @@ -487,6 +506,9 @@ struct zapi_route { vrf_id_t vrf_id; uint32_t tableid; + + /* SR-TE color (used for nexthop updates only). */ + uint32_t srte_color; }; struct zapi_labels { @@ -509,6 +531,21 @@ struct zapi_labels { struct zapi_nexthop backup_nexthops[MULTIPATH_NUM]; }; +struct zapi_srte_tunnel { + enum lsp_types_t type; + mpls_label_t local_label; + uint8_t label_num; + mpls_label_t labels[MPLS_MAX_LABELS]; +}; + +struct zapi_sr_policy { + uint32_t color; + struct ipaddr endpoint; + char name[SRTE_POLICY_NAME_MAX_LENGTH]; + struct zapi_srte_tunnel segment_list; + int status; +}; + struct zapi_pw { char ifname[IF_NAMESIZE]; ifindex_t ifindex; @@ -600,6 +637,11 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note) #define ZEBRA_MACIP_TYPE_ROUTER_FLAG 0x04 /* Router Flag - proxy NA */ #define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG 0x08 /* Override Flag */ #define ZEBRA_MACIP_TYPE_SVI_IP 0x10 /* SVI MAC-IP */ +#define ZEBRA_MACIP_TYPE_PROXY_ADVERT 0x20 /* Not locally active */ +#define ZEBRA_MACIP_TYPE_SYNC_PATH 0x40 /* sync path */ +/* XXX - flags is an u8; that needs to be changed to u32 if you need + * to allocate past 0x80 + */ enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 }; @@ -647,6 +689,9 @@ extern void zclient_send_vrf_label(struct zclient *zclient, vrf_id_t vrf_id, extern void zclient_send_reg_requests(struct zclient *, vrf_id_t); extern void zclient_send_dereg_requests(struct zclient *, vrf_id_t); +extern int zclient_send_router_id_update(struct zclient *zclient, + zebra_message_types_t type, afi_t afi, + vrf_id_t vrf_id); extern void zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id, @@ -763,6 +808,14 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start, uint32_t end); +extern int zebra_send_sr_policy(struct zclient *zclient, int cmd, + struct zapi_sr_policy *zp); +extern int zapi_sr_policy_encode(struct stream *s, int cmd, + struct zapi_sr_policy *zp); +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 zebra_send_mpls_labels(struct zclient *zclient, int cmd, struct zapi_labels *zl); extern int zapi_labels_encode(struct stream *s, int cmd, @@ -779,7 +832,7 @@ extern int zclient_send_rnh(struct zclient *zclient, int command, const struct prefix *p, bool exact_match, vrf_id_t vrf_id); int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, - uint32_t api_flags); + uint32_t api_flags, uint32_t api_message); extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *); extern int zapi_route_decode(struct stream *, struct zapi_route *); bool zapi_route_notify_decode(struct stream *s, struct prefix *p, @@ -904,6 +957,10 @@ enum zapi_opaque_registry { */ extern int zclient_send_hello(struct zclient *client); +extern int zclient_send_neigh_discovery_req(struct zclient *zclient, + const struct interface *ifp, + const struct prefix *p); + #ifdef __cplusplus } #endif diff --git a/lib/zlog.c b/lib/zlog.c index 45726755f8..8dfd20371b 100644 --- a/lib/zlog.c +++ b/lib/zlog.c @@ -246,10 +246,10 @@ void zlog_tls_buffer_init(void) fchown(mmfd, zlog_uid, zlog_gid); #ifdef HAVE_POSIX_FALLOCATE - if (posix_fallocate(mmfd, 0, TLS_LOG_BUF_SIZE) < 0) { -#else - if (ftruncate(mmfd, TLS_LOG_BUF_SIZE) < 0) { + if (posix_fallocate(mmfd, 0, TLS_LOG_BUF_SIZE) != 0) + /* note next statement is under above if() */ #endif + if (ftruncate(mmfd, TLS_LOG_BUF_SIZE) < 0) { zlog_err("failed to allocate thread log buffer \"%s\": %s", mmpath, strerror(errno)); goto out_anon_unlink; |
