diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/filter.h | 54 | ||||
| -rw-r--r-- | lib/filter_cli.c | 218 | ||||
| -rw-r--r-- | lib/filter_nb.c | 386 | ||||
| -rw-r--r-- | lib/hash.h | 2 | ||||
| -rw-r--r-- | lib/yang.c | 2 | ||||
| -rw-r--r-- | lib/zclient.c | 13 | ||||
| -rw-r--r-- | lib/zclient.h | 12 |
7 files changed, 673 insertions, 14 deletions
diff --git a/lib/filter.h b/lib/filter.h index 623fb94527..091a5197f6 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -176,6 +176,60 @@ enum yang_prefix_list_action { YPLA_PERMIT = 1, }; +struct acl_dup_args { + /** Access list type ("ipv4", "ipv6" or "mac"). */ + const char *ada_type; + /** Access list name. */ + const char *ada_name; + +#define ADA_MAX_VALUES 4 + /** Entry XPath for value. */ + const char *ada_xpath[ADA_MAX_VALUES]; + /** Entry value to match. */ + const char *ada_value[ADA_MAX_VALUES]; + + /** Duplicated entry found in list? */ + bool ada_found; + + /** (Optional) Already existing `dnode`. */ + const struct lyd_node *ada_entry_dnode; +}; + +/** + * Check for duplicated entries using the candidate configuration. + * + * \param vty so we can get the candidate config. + * \param ada the arguments to check. + */ +bool acl_is_dup(const struct lyd_node *dnode, struct acl_dup_args *ada); + +struct plist_dup_args { + /** Access list type ("ipv4" or "ipv6"). */ + const char *pda_type; + /** Access list name. */ + const char *pda_name; + +#define PDA_MAX_VALUES 4 + /** Entry XPath for value. */ + const char *pda_xpath[PDA_MAX_VALUES]; + /** Entry value to match. */ + const char *pda_value[PDA_MAX_VALUES]; + + /** Duplicated entry found in list? */ + bool pda_found; + + /** (Optional) Already existing `dnode`. */ + const struct lyd_node *pda_entry_dnode; +}; + +/** + * Check for duplicated entries using the candidate configuration. + * + * \param vty so we can get the candidate config. + * \param pda the arguments to check. + */ +bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda); + /* filter_cli.c */ struct lyd_node; struct vty; diff --git a/lib/filter_cli.c b/lib/filter_cli.c index a8230f3a9a..54b6cda9a5 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -162,10 +162,36 @@ DEFPY_YANG( "Wildcard bits\n") { int64_t sseq; + struct acl_dup_args ada = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 128]; /* + * Backward compatibility: don't complain about duplicated values, + * just silently accept. + */ + if (seq_str == NULL) { + ada.ada_type = "ipv4"; + ada.ada_name = name; + if (host_str && mask_str == NULL) { + ada.ada_xpath[0] = "./host"; + ada.ada_value[0] = host_str; + } else if (host_str && mask_str) { + ada.ada_xpath[0] = "./network/address"; + ada.ada_value[0] = host_str; + ada.ada_xpath[1] = "./network/mask"; + ada.ada_value[1] = mask_str; + } else { + ada.ada_xpath[0] = "./source-any"; + ada.ada_value[0] = "true"; + } + + /* Duplicated entry without sequence, just quit. */ + if (acl_is_dup(vty->candidate_config->dnode, &ada)) + return CMD_SUCCESS; + } + + /* * Create the access-list first, so we can generate sequence if * none given (backward compatibility). */ @@ -270,11 +296,59 @@ DEFPY_YANG( "Destination address to match\n" "Any destination host\n") { + int idx = 0; int64_t sseq; + struct acl_dup_args ada = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 128]; /* + * Backward compatibility: don't complain about duplicated values, + * just silently accept. + */ + if (seq_str == NULL) { + ada.ada_type = "ipv4"; + ada.ada_name = name; + if (src_str && src_mask_str == NULL) { + ada.ada_xpath[idx] = "./host"; + ada.ada_value[idx] = src_str; + idx++; + } else if (src_str && src_mask_str) { + ada.ada_xpath[idx] = "./network/address"; + ada.ada_value[idx] = src_str; + idx++; + ada.ada_xpath[idx] = "./network/mask"; + ada.ada_value[idx] = src_mask_str; + idx++; + } else { + ada.ada_xpath[idx] = "./source-any"; + ada.ada_value[idx] = "true"; + idx++; + } + + if (dst_str && dst_mask_str == NULL) { + ada.ada_xpath[idx] = "./destination-host"; + ada.ada_value[idx] = dst_str; + idx++; + } else if (dst_str && dst_mask_str) { + ada.ada_xpath[idx] = "./destination-network/address"; + ada.ada_value[idx] = dst_str; + idx++; + ada.ada_xpath[idx] = "./destination-network/mask"; + ada.ada_value[idx] = dst_mask_str; + idx++; + } else { + ada.ada_xpath[idx] = "./destination-any"; + ada.ada_value[idx] = "true"; + idx++; + } + + /* Duplicated entry without sequence, just quit. */ + if (acl_is_dup(vty->candidate_config->dnode, &ada)) + return CMD_SUCCESS; + } + + /* * Create the access-list first, so we can generate sequence if * none given (backward compatibility). */ @@ -419,10 +493,36 @@ DEFPY_YANG( "Match any IPv4\n") { int64_t sseq; + struct acl_dup_args ada = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 128]; /* + * Backward compatibility: don't complain about duplicated values, + * just silently accept. + */ + if (seq_str == NULL) { + ada.ada_type = "ipv4"; + ada.ada_name = name; + + if (prefix_str) { + ada.ada_xpath[0] = "./ipv4-prefix"; + ada.ada_value[0] = prefix_str; + if (exact) { + ada.ada_xpath[1] = "./ipv4-exact-match"; + ada.ada_value[1] = "true"; + } + } else { + ada.ada_xpath[0] = "./any"; + ada.ada_value[0] = "true"; + } + + /* Duplicated entry without sequence, just quit. */ + if (acl_is_dup(vty->candidate_config->dnode, &ada)) + return CMD_SUCCESS; + } + + /* * Create the access-list first, so we can generate sequence if * none given (backward compatibility). */ @@ -590,10 +690,36 @@ DEFPY_YANG( "Match any IPv6\n") { int64_t sseq; + struct acl_dup_args ada = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 128]; /* + * Backward compatibility: don't complain about duplicated values, + * just silently accept. + */ + if (seq_str == NULL) { + ada.ada_type = "ipv6"; + ada.ada_name = name; + + if (prefix_str) { + ada.ada_xpath[0] = "./ipv6-prefix"; + ada.ada_value[0] = prefix_str; + if (exact) { + ada.ada_xpath[1] = "./ipv6-exact-match"; + ada.ada_value[1] = "true"; + } + } else { + ada.ada_xpath[0] = "./any"; + ada.ada_value[0] = "true"; + } + + /* Duplicated entry without sequence, just quit. */ + if (acl_is_dup(vty->candidate_config->dnode, &ada)) + return CMD_SUCCESS; + } + + /* * Create the access-list first, so we can generate sequence if * none given (backward compatibility). */ @@ -765,10 +891,32 @@ DEFPY_YANG( "Match any MAC address\n") { int64_t sseq; + struct acl_dup_args ada = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 128]; /* + * Backward compatibility: don't complain about duplicated values, + * just silently accept. + */ + if (seq_str == NULL) { + ada.ada_type = "mac"; + ada.ada_name = name; + + if (mac_str) { + ada.ada_xpath[0] = "./mac"; + ada.ada_value[0] = mac_str; + } else { + ada.ada_xpath[0] = "./any"; + ada.ada_value[0] = "true"; + } + + /* Duplicated entry without sequence, just quit. */ + if (acl_is_dup(vty->candidate_config->dnode, &ada)) + return CMD_SUCCESS; + } + + /* * Create the access-list first, so we can generate sequence if * none given (backward compatibility). */ @@ -1171,10 +1319,45 @@ DEFPY_YANG( "Maximum prefix length\n") { int64_t sseq; + int arg_idx = 0; + struct plist_dup_args pda = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 128]; /* + * Backward compatibility: don't complain about duplicated values, + * just silently accept. + */ + if (seq_str == NULL) { + pda.pda_type = "ipv4"; + pda.pda_name = name; + if (prefix_str) { + pda.pda_xpath[arg_idx] = "./ipv4-prefix"; + pda.pda_value[arg_idx] = prefix_str; + arg_idx++; + if (ge_str) { + pda.pda_xpath[arg_idx] = + "./ipv4-prefix-length-greater-or-equal"; + pda.pda_value[arg_idx] = ge_str; + arg_idx++; + } + if (le_str) { + pda.pda_xpath[arg_idx] = + "./ipv4-prefix-length-lesser-or-equal"; + pda.pda_value[arg_idx] = le_str; + arg_idx++; + } + } else { + pda.pda_xpath[0] = "./any"; + pda.pda_value[0] = ""; + } + + /* Duplicated entry without sequence, just quit. */ + if (plist_is_dup(vty->candidate_config->dnode, &pda)) + return CMD_SUCCESS; + } + + /* * Create the prefix-list first, so we can generate sequence if * none given (backward compatibility). */ @@ -1331,10 +1514,45 @@ DEFPY_YANG( "Minimum prefix length\n") { int64_t sseq; + int arg_idx = 0; + struct plist_dup_args pda = {}; char xpath[XPATH_MAXLEN]; char xpath_entry[XPATH_MAXLEN + 128]; /* + * Backward compatibility: don't complain about duplicated values, + * just silently accept. + */ + if (seq_str == NULL) { + pda.pda_type = "ipv6"; + pda.pda_name = name; + if (prefix_str) { + pda.pda_xpath[arg_idx] = "./ipv6-prefix"; + pda.pda_value[arg_idx] = prefix_str; + arg_idx++; + if (ge_str) { + pda.pda_xpath[arg_idx] = + "./ipv6-prefix-length-greater-or-equal"; + pda.pda_value[arg_idx] = ge_str; + arg_idx++; + } + if (le_str) { + pda.pda_xpath[arg_idx] = + "./ipv6-prefix-length-lesser-or-equal"; + pda.pda_value[arg_idx] = le_str; + arg_idx++; + } + } else { + pda.pda_xpath[0] = "./any"; + pda.pda_value[0] = ""; + } + + /* Duplicated entry without sequence, just quit. */ + if (plist_is_dup(vty->candidate_config->dnode, &pda)) + return CMD_SUCCESS; + } + + /* * Create the prefix-list first, so we can generate sequence if * none given (backward compatibility). */ diff --git a/lib/filter_nb.c b/lib/filter_nb.c index 1d522bdbec..2007b37cdf 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -133,6 +133,220 @@ static void cisco_unset_addr_mask(struct in_addr *addr, struct in_addr *mask) mask->s_addr = CISCO_BIN_HOST_WILDCARD_MASK; } +static int _acl_is_dup(const struct lyd_node *dnode, void *arg) +{ + struct acl_dup_args *ada = arg; + int idx; + + /* This entry is the caller, so skip it. */ + if (ada->ada_entry_dnode + && ada->ada_entry_dnode == dnode) + return YANG_ITER_CONTINUE; + + /* Check if all values match. */ + for (idx = 0; idx < ADA_MAX_VALUES; idx++) { + /* No more values. */ + if (ada->ada_xpath[idx] == NULL) + break; + + /* Not same type, just skip it. */ + if (!yang_dnode_exists(dnode, ada->ada_xpath[idx])) + return YANG_ITER_CONTINUE; + + /* Check if different value. */ + if (strcmp(yang_dnode_get_string(dnode, ada->ada_xpath[idx]), + ada->ada_value[idx])) + return YANG_ITER_CONTINUE; + } + + ada->ada_found = true; + + return YANG_ITER_STOP; +} + +bool acl_is_dup(const struct lyd_node *dnode, struct acl_dup_args *ada) +{ + ada->ada_found = false; + + yang_dnode_iterate( + _acl_is_dup, ada, dnode, + "/frr-filter:lib/access-list[type='%s'][name='%s']/entry", + ada->ada_type, ada->ada_name); + + return ada->ada_found; +} + +static bool acl_cisco_is_dup(const struct lyd_node *dnode) +{ + const struct lyd_node *entry_dnode = + yang_dnode_get_parent(dnode, "entry"); + struct acl_dup_args ada = {}; + int idx = 0, arg_idx = 0; + static const char *cisco_entries[] = { + "./host", + "./network/address", + "./network/mask", + "./source-any", + "./destination-host", + "./destination-network/address", + "./destination-network/mask", + "./destination-any", + NULL + }; + + /* Initialize. */ + ada.ada_type = "ipv4"; + ada.ada_name = yang_dnode_get_string(entry_dnode, "../name"); + ada.ada_entry_dnode = entry_dnode; + + /* Load all values/XPaths. */ + while (cisco_entries[idx] != NULL) { + if (!yang_dnode_exists(entry_dnode, cisco_entries[idx])) { + idx++; + continue; + } + + ada.ada_xpath[arg_idx] = cisco_entries[idx]; + ada.ada_value[arg_idx] = + yang_dnode_get_string(entry_dnode, cisco_entries[idx]); + arg_idx++; + idx++; + } + + return acl_is_dup(entry_dnode, &ada); +} + +static bool acl_zebra_is_dup(const struct lyd_node *dnode, + enum yang_access_list_type type) +{ + const struct lyd_node *entry_dnode = + yang_dnode_get_parent(dnode, "entry"); + struct acl_dup_args ada = {}; + int idx = 0, arg_idx = 0; + static const char *zebra_entries[] = { + "./ipv4-prefix", + "./ipv4-exact-match", + "./ipv6-prefix", + "./ipv6-exact-match", + "./mac", + "./any", + NULL + }; + + /* Initialize. */ + switch (type) { + case YALT_IPV4: + ada.ada_type = "ipv4"; + break; + case YALT_IPV6: + ada.ada_type = "ipv6"; + break; + case YALT_MAC: + ada.ada_type = "mac"; + break; + } + ada.ada_name = yang_dnode_get_string(entry_dnode, "../name"); + ada.ada_entry_dnode = entry_dnode; + + /* Load all values/XPaths. */ + while (zebra_entries[idx] != NULL) { + if (!yang_dnode_exists(entry_dnode, zebra_entries[idx])) { + idx++; + continue; + } + + ada.ada_xpath[arg_idx] = zebra_entries[idx]; + ada.ada_value[arg_idx] = + yang_dnode_get_string(entry_dnode, zebra_entries[idx]); + arg_idx++; + idx++; + } + + return acl_is_dup(entry_dnode, &ada); +} + +static int _plist_is_dup(const struct lyd_node *dnode, void *arg) +{ + struct plist_dup_args *pda = arg; + int idx; + + /* This entry is the caller, so skip it. */ + if (pda->pda_entry_dnode + && pda->pda_entry_dnode == dnode) + return YANG_ITER_CONTINUE; + + /* Check if all values match. */ + for (idx = 0; idx < PDA_MAX_VALUES; idx++) { + /* No more values. */ + if (pda->pda_xpath[idx] == NULL) + break; + + /* Not same type, just skip it. */ + if (!yang_dnode_exists(dnode, pda->pda_xpath[idx])) + return YANG_ITER_CONTINUE; + + /* Check if different value. */ + if (strcmp(yang_dnode_get_string(dnode, pda->pda_xpath[idx]), + pda->pda_value[idx])) + return YANG_ITER_CONTINUE; + } + + pda->pda_found = true; + + return YANG_ITER_STOP; +} + +bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda) +{ + pda->pda_found = false; + + yang_dnode_iterate( + _plist_is_dup, pda, dnode, + "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry", + pda->pda_type, pda->pda_name); + + return pda->pda_found; +} + +static bool plist_is_dup_nb(const struct lyd_node *dnode) +{ + const struct lyd_node *entry_dnode = + yang_dnode_get_parent(dnode, "entry"); + struct plist_dup_args pda = {}; + int idx = 0, arg_idx = 0; + static const char *entries[] = { + "./ipv4-prefix", + "./ipv4-prefix-length-greater-or-equal", + "./ipv4-prefix-length-lesser-or-equal", + "./ipv6-prefix", + "./ipv6-prefix-length-greater-or-equal", + "./ipv6-prefix-length-lesser-or-equal", + "./any", + NULL + }; + + /* Initialize. */ + pda.pda_type = yang_dnode_get_string(entry_dnode, "../type"); + pda.pda_name = yang_dnode_get_string(entry_dnode, "../name"); + pda.pda_entry_dnode = entry_dnode; + + /* Load all values/XPaths. */ + while (entries[idx] != NULL) { + if (!yang_dnode_exists(entry_dnode, entries[idx])) { + idx++; + continue; + } + + pda.pda_xpath[arg_idx] = entries[idx]; + pda.pda_value[arg_idx] = + yang_dnode_get_string(entry_dnode, entries[idx]); + arg_idx++; + idx++; + } + + return plist_is_dup(entry_dnode, &pda); +} + /* * XPath: /frr-filter:lib/access-list */ @@ -290,6 +504,19 @@ lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) struct filter_zebra *fz; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_zebra_is_dup( + args->dnode, + yang_dnode_get_enum(args->dnode, "../../type"))) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -330,6 +557,19 @@ lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args) struct filter_zebra *fz; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_zebra_is_dup( + args->dnode, + yang_dnode_get_enum(args->dnode, "../../type"))) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -369,6 +609,17 @@ lib_access_list_entry_host_modify(struct nb_cb_modify_args *args) struct filter_cisco *fc; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_cisco_is_dup(args->dnode)) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -410,6 +661,17 @@ lib_access_list_entry_network_address_modify(struct nb_cb_modify_args *args) struct filter_cisco *fc; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_cisco_is_dup(args->dnode)) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -432,6 +694,17 @@ lib_access_list_entry_network_mask_modify(struct nb_cb_modify_args *args) struct filter_cisco *fc; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_cisco_is_dup(args->dnode)) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -454,6 +727,17 @@ lib_access_list_entry_source_any_create(struct nb_cb_create_args *args) struct filter_cisco *fc; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_cisco_is_dup(args->dnode)) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -495,6 +779,17 @@ static int lib_access_list_entry_destination_host_modify( struct filter_cisco *fc; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_cisco_is_dup(args->dnode)) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -537,6 +832,17 @@ static int lib_access_list_entry_destination_network_address_modify( struct filter_cisco *fc; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_cisco_is_dup(args->dnode)) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -559,6 +865,17 @@ static int lib_access_list_entry_destination_network_mask_modify( struct filter_cisco *fc; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_cisco_is_dup(args->dnode)) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -581,6 +898,17 @@ static int lib_access_list_entry_destination_any_create( struct filter_cisco *fc; struct filter *f; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_cisco_is_dup(args->dnode)) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -623,6 +951,19 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args) struct filter *f; int type; + /* Don't allow duplicated values. */ + if (args->event == NB_EV_VALIDATE) { + if (acl_zebra_is_dup( + args->dnode, + yang_dnode_get_enum(args->dnode, "../../type"))) { + snprintfrr(args->errmsg, args->errmsg_len, + "duplicated access list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -817,15 +1158,12 @@ lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) struct prefix p; if (args->event == NB_EV_VALIDATE) { - /* - * TODO: validate prefix_entry_dup_check() passes. - * - * This needs to be implemented using YANG lyd_node - * navigation, because the `priv` data structures are not - * available at `NB_EV_VALIDATE` phase. An easier - * alternative would be mark `ipvx-prefix` as unique - * (see RFC 7950, Section 7.8.3. The list "unique" Statement). - */ + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } return NB_OK; } @@ -888,6 +1226,16 @@ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify( prefix_list_length_validate(args) != NB_OK) return NB_ERR_VALIDATION; + if (args->event == NB_EV_VALIDATE) { + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -937,6 +1285,16 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify( prefix_list_length_validate(args) != NB_OK) return NB_ERR_VALIDATION; + if (args->event == NB_EV_VALIDATE) { + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -982,6 +1340,16 @@ static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args) struct prefix_list_entry *ple; int type; + if (args->event == NB_EV_VALIDATE) { + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; diff --git a/lib/hash.h b/lib/hash.h index 6fbdc67cc4..23e93b6d7d 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -137,7 +137,7 @@ extern struct hash *hash_create(unsigned int (*hash_key)(const void *), * * hash_cmp * comparison function used for resolving collisions; when called with two - * data items, should return nonzero if the two items are equal and 0 + * data items, should return true if the two items are equal and false * otherwise * * name diff --git a/lib/yang.c b/lib/yang.c index 22fe938e4c..a3e2a395d7 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -468,7 +468,7 @@ void yang_dnode_iterate(yang_dnode_iter_cb cb, void *arg, dnode = set->set.d[i]; ret = (*cb)(dnode, arg); if (ret == YANG_ITER_STOP) - return; + break; } ly_set_free(set); diff --git a/lib/zclient.c b/lib/zclient.c index ba94b7fb99..cb4555650d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1182,6 +1182,12 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api) if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID)) stream_putl(s, api->tableid); + if (CHECK_FLAG(api->message, ZAPI_MESSAGE_OPAQUE)) { + assert(api->opaque.length <= ZAPI_MESSAGE_OPAQUE_LENGTH); + + stream_putw(s, api->opaque.length); + stream_write(s, api->opaque.data, api->opaque.length); + } /* Put length at the first point of the stream. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -1403,6 +1409,13 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TABLEID)) STREAM_GETL(s, api->tableid); + if (CHECK_FLAG(api->message, ZAPI_MESSAGE_OPAQUE)) { + STREAM_GETW(s, api->opaque.length); + assert(api->opaque.length < ZAPI_MESSAGE_OPAQUE_LENGTH); + + STREAM_GET(api->opaque.data, s, api->opaque.length); + } + return 0; stream_failure: return -1; diff --git a/lib/zclient.h b/lib/zclient.h index af4707289f..2af448a20c 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -391,14 +391,14 @@ struct zclient { /* Backup nexthops are present */ #define ZAPI_MESSAGE_BACKUP_NEXTHOPS 0x40 #define ZAPI_MESSAGE_NHG 0x80 - /* * This should only be used by a DAEMON that needs to communicate * the table being used is not in the VRF. You must pass the * default vrf, else this will be ignored. */ -#define ZAPI_MESSAGE_TABLEID 0x0080 -#define ZAPI_MESSAGE_SRTE 0x0100 +#define ZAPI_MESSAGE_TABLEID 0x0100 +#define ZAPI_MESSAGE_SRTE 0x0200 +#define ZAPI_MESSAGE_OPAQUE 0x0400 #define ZSERV_VERSION 6 /* Zserv protocol message header */ @@ -572,6 +572,12 @@ struct zapi_route { /* SR-TE color (used for nexthop updates only). */ uint32_t srte_color; + +#define ZAPI_MESSAGE_OPAQUE_LENGTH 1024 + struct { + uint16_t length; + uint8_t data[ZAPI_MESSAGE_OPAQUE_LENGTH]; + } opaque; }; struct zapi_labels { |
