diff options
37 files changed, 1029 insertions, 152 deletions
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 563a1faf96..955e73fcf3 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1596,6 +1596,19 @@ DEFPY (no_bgp_norib, return CMD_SUCCESS; } +DEFPY (no_bgp_send_extra_data, + no_bgp_send_extra_data_cmd, + "[no] bgp send-extra-data zebra", + NO_STR + BGP_STR + "Extra data to Zebra for display/use\n" + "To zebra\n") +{ + bgp_option_send_extra_data(!!no); + + return CMD_SUCCESS; +} + DEFUN_YANG(bgp_confederation_identifier, bgp_confederation_identifier_cmd, "bgp confederation identifier (1-4294967295)", @@ -16930,6 +16943,9 @@ int bgp_config_write(struct vty *vty) if (bgp_option_check(BGP_OPT_NO_FIB)) vty_out(vty, "bgp no-rib\n"); + if (bm->send_extra_data_to_zebra) + vty_out(vty, "no bgp send-extra-data zebra\n"); + /* BGP configuration. */ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { @@ -17485,6 +17501,8 @@ void bgp_vty_init(void) install_element(CONFIG_NODE, &bgp_norib_cmd); install_element(CONFIG_NODE, &no_bgp_norib_cmd); + install_element(CONFIG_NODE, &no_bgp_send_extra_data_cmd); + /* "bgp confederation" commands. */ install_element(BGP_NODE, &bgp_confederation_identifier_cmd); install_element(BGP_NODE, &no_bgp_confederation_identifier_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 8c85725bdc..3bd8f7a09b 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -41,6 +41,7 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" +#include "bgpd/bgp_aspath.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_fsm.h" @@ -1409,6 +1410,14 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, is_add = (valid_nh_count || nhg_id) ? true : false; + if (is_add && bm->send_extra_data_to_zebra) { + struct aspath *aspath = info->attr->aspath; + + SET_FLAG(api.message, ZAPI_MESSAGE_OPAQUE); + api.opaque.length = strlen(aspath->str) + 1; + memcpy(api.opaque.data, aspath->str, api.opaque.length); + } + /* * When we create an aggregate route we must also * install a Null0 route in the RIB, so overwrite diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index f1454aaee8..d3db540871 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -7395,6 +7395,11 @@ char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, return buf; } +void bgp_option_send_extra_data(bool send) +{ + bm->send_extra_data_to_zebra = send; +} + void bgp_master_init(struct thread_master *master, const int buffer_size) { qobj_init(); @@ -7413,6 +7418,7 @@ void bgp_master_init(struct thread_master *master, const int buffer_size) bm->v_establish_wait = BGP_UPDATE_DELAY_DEF; bm->terminating = false; bm->socket_buffer = buffer_size; + bm->send_extra_data_to_zebra = true; bgp_mac_init(); /* init the rd id space. diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e867159fa6..3451a616a4 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -169,6 +169,9 @@ struct bgp_master { uint32_t flags; #define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0) + /* Send extra data to zebra like aspath */ + bool send_extra_data_to_zebra; + bool terminating; /* global flag that sigint terminate seen */ QOBJ_FIELDS }; @@ -2246,6 +2249,8 @@ static inline bool bgp_in_graceful_shutdown(struct bgp *bgp) extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t); +extern void bgp_option_send_extra_data(bool send); + /* For benefit of rfapi */ extern struct peer *peer_new(struct bgp *bgp); diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 73c286631a..288b955c27 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -3470,6 +3470,15 @@ starting the daemon and the configuration gets saved, the option will persist unless removed from the configuration with the negating command prior to the configuration write operation. +.. index:: [no] bgp send-extra-data zebra +.. clicmd:: [no] bgp send-extra-data zebra + + This Command turns off the ability of BGP to send extra data to zebra. +In this case it's the AS-Path being used for the path. The default behavior +in BGP is to send this data and to turn it off enter the no form of the command. +If extra data was sent to zebra, and this command is turned on there is no +effort to clean up this data in the rib. + .. _bgp-suppress-fib: Suppressing routes not installed in FIB diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 57ef141c7e..90eae4d65a 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -33,7 +33,7 @@ All sharp commands are under the enable node and preceded by the ``sharp`` keyword. At present, no sharp commands will be preserved in the config. .. index:: sharp install -.. clicmd:: sharp install routes A.B.C.D <nexthop <E.F.G.H|X:X::X:X>|nexthop-group NAME> (1-1000000) [instance (0-255)] [repeat (2-1000)] +.. clicmd:: sharp install routes A.B.C.D <nexthop <E.F.G.H|X:X::X:X>|nexthop-group NAME> (1-1000000) [instance (0-255)] [repeat (2-1000)] [opaque WORD] Install up to 1,000,000 (one million) /32 routes starting at ``A.B.C.D`` with specified nexthop ``E.F.G.H`` or ``X:X::X:X``. The nexthop is @@ -46,7 +46,8 @@ keyword. At present, no sharp commands will be preserved in the config. receives success notifications for all routes this is logged as well. Instance (0-255) if specified causes the routes to be installed in a different instance. If repeat is used then we will install/uninstall the routes the - number of times specified. + number of times specified. If the keyword opaque is specified then the + next word is sent down to zebra as part of the route installation. .. index:: sharp remove .. clicmd:: sharp remove routes A.B.C.D (1-1000000) diff --git a/isisd/isis_ldp_sync.c b/isisd/isis_ldp_sync.c index 45ee976550..00bef5c782 100644 --- a/isisd/isis_ldp_sync.c +++ b/isisd/isis_ldp_sync.c @@ -497,7 +497,7 @@ void isis_ldp_sync_handle_client_close(struct zapi_client_close_info *info) circuit_lookup_by_ifp(ifp, area->circuit_list); if (circuit == NULL) continue; - isis_ldp_sync_if_start(circuit, true); + isis_ldp_sync_ldp_fail(circuit); } } } 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 { diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index a9fc802522..0e419cbff6 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -50,7 +50,8 @@ #include "lib/json.h" static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id); -static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id); +static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6, + struct ospf6_redist *red, int type); unsigned char conf_debug_ospf6_asbr = 0; @@ -844,35 +845,28 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry, /* redistribute function */ - -static void ospf6_asbr_routemap_set(int type, const char *mapname, - uint32_t vrf_id) +static void ospf6_asbr_routemap_set(struct ospf6_redist *red, + const char *mapname) { - struct ospf6 *ospf6 = NULL; - - ospf6 = ospf6_lookup_by_vrf_id(vrf_id); - - if (ospf6 == NULL) - return; - - if (ospf6->rmap[type].name) { - route_map_counter_decrement(ospf6->rmap[type].map); - free(ospf6->rmap[type].name); + if (ROUTEMAP_NAME(red)) { + route_map_counter_decrement(ROUTEMAP(red)); + free(ROUTEMAP_NAME(red)); } - ospf6->rmap[type].name = strdup(mapname); - ospf6->rmap[type].map = route_map_lookup_by_name(mapname); - route_map_counter_increment(ospf6->rmap[type].map); + + ROUTEMAP_NAME(red) = strdup(mapname); + ROUTEMAP(red) = route_map_lookup_by_name(mapname); + route_map_counter_increment(ROUTEMAP(red)); } -static void ospf6_asbr_routemap_unset(int type, struct ospf6 *ospf6) +static void ospf6_asbr_routemap_unset(struct ospf6_redist *red) { - if (ospf6->rmap[type].name) - free(ospf6->rmap[type].name); + if (ROUTEMAP_NAME(red)) + free(ROUTEMAP_NAME(red)); - route_map_counter_decrement(ospf6->rmap[type].map); + route_map_counter_decrement(ROUTEMAP(red)); - ospf6->rmap[type].name = NULL; - ospf6->rmap[type].map = NULL; + ROUTEMAP_NAME(red) = NULL; + ROUTEMAP(red) = NULL; } static int ospf6_asbr_routemap_update_timer(struct thread *thread) @@ -880,6 +874,7 @@ static int ospf6_asbr_routemap_update_timer(struct thread *thread) void **arg; int arg_type; struct ospf6 *ospf6; + struct ospf6_redist *red; arg = THREAD_ARG(thread); ospf6 = (struct ospf6 *)arg[0]; @@ -887,13 +882,14 @@ static int ospf6_asbr_routemap_update_timer(struct thread *thread) ospf6->t_distribute_update = NULL; - if (ospf6->rmap[arg_type].name) - ospf6->rmap[arg_type].map = - route_map_lookup_by_name(ospf6->rmap[arg_type].name); - if (ospf6->rmap[arg_type].map) { + red = ospf6_redist_lookup(ospf6, arg_type, 0); + + if (red && ROUTEMAP_NAME(red)) + ROUTEMAP(red) = route_map_lookup_by_name(ROUTEMAP_NAME(red)); + if (red && ROUTEMAP(red)) { if (IS_OSPF6_DEBUG_ASBR) zlog_debug("%s: route-map %s update, reset redist %s", - __func__, ospf6->rmap[arg_type].name, + __func__, ROUTEMAP_NAME(red), ZROUTE_NAME(arg_type)); ospf6_zebra_no_redistribute(arg_type, ospf6->vrf_id); @@ -931,20 +927,23 @@ static void ospf6_asbr_routemap_update(const char *mapname) int type; struct listnode *node, *nnode; struct ospf6 *ospf6 = NULL; + struct ospf6_redist *red; if (om6 == NULL) return; for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) { for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { - if (ospf6->rmap[type].name == NULL) + red = ospf6_redist_lookup(ospf6, type, 0); + if (!red || (ROUTEMAP_NAME(red) == NULL)) continue; - ospf6->rmap[type].map = route_map_lookup_by_name( - ospf6->rmap[type].name); + ROUTEMAP(red) = + route_map_lookup_by_name(ROUTEMAP_NAME(red)); - if (mapname == NULL || strcmp(ospf6->rmap[type].name, mapname)) + if (mapname == NULL + || strcmp(ROUTEMAP_NAME(red), mapname)) continue; - if (ospf6->rmap[type].map) { + if (ROUTEMAP(red)) { if (IS_OSPF6_DEBUG_ASBR) zlog_debug( "%s: route-map %s update, reset redist %s", @@ -953,11 +952,9 @@ static void ospf6_asbr_routemap_update(const char *mapname) ZROUTE_NAME( type)); - route_map_counter_increment( - ospf6->rmap[type].map); + route_map_counter_increment(ROUTEMAP(red)); - ospf6_asbr_distribute_list_update( - type, ospf6); + ospf6_asbr_distribute_list_update(type, ospf6); } else { /* * if the mapname matches a @@ -973,11 +970,8 @@ static void ospf6_asbr_routemap_update(const char *mapname) mapname, ZROUTE_NAME( type)); - ospf6_asbr_redistribute_unset( - type, ospf6->vrf_id); - ospf6_asbr_routemap_set( - type, mapname, - ospf6->vrf_id); + ospf6_asbr_redistribute_unset(ospf6, red, type); + ospf6_asbr_routemap_set(red, mapname); ospf6_asbr_redistribute_set( type, ospf6->vrf_id); } @@ -990,13 +984,15 @@ static void ospf6_asbr_routemap_event(const char *name) int type; struct listnode *node, *nnode; struct ospf6 *ospf6; + struct ospf6_redist *red; if (om6 == NULL) return; for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) { for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { - if ((ospf6->rmap[type].name) - && (strcmp(ospf6->rmap[type].name, name) == 0)) + red = ospf6_redist_lookup(ospf6, type, 0); + if (red && ROUTEMAP_NAME(red) + && (strcmp(ROUTEMAP_NAME(red), name) == 0)) ospf6_asbr_distribute_list_update(type, ospf6); } } @@ -1007,23 +1003,70 @@ int ospf6_asbr_is_asbr(struct ospf6 *o) return o->external_table->count; } +struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type, + unsigned short instance) +{ + struct list *red_list; + struct listnode *node; + struct ospf6_redist *red; + + red_list = ospf6->redist[type]; + if (!red_list) + return (NULL); + + for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) + if (red->instance == instance) + return red; + + return NULL; +} + +static struct ospf6_redist *ospf6_redist_add(struct ospf6 *ospf6, int type, + uint8_t instance) +{ + struct ospf6_redist *red; + + red = ospf6_redist_lookup(ospf6, type, instance); + if (red) + return red; + + if (!ospf6->redist[type]) + ospf6->redist[type] = list_new(); + + red = XCALLOC(MTYPE_OSPF6_REDISTRIBUTE, sizeof(struct ospf6_redist)); + red->instance = instance; + ROUTEMAP_NAME(red) = NULL; + ROUTEMAP(red) = NULL; + + listnode_add(ospf6->redist[type], red); + + return red; +} + +static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red, + int type) +{ + if (red) { + listnode_delete(ospf6->redist[type], red); + if (!ospf6->redist[type]->count) { + list_delete(&ospf6->redist[type]); + } + XFREE(MTYPE_OSPF6_REDISTRIBUTE, red); + } +} + static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id) { ospf6_zebra_redistribute(type, vrf_id); } -static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id) +static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6, + struct ospf6_redist *red, int type) { struct ospf6_route *route; struct ospf6_external_info *info; - struct ospf6 *ospf6 = NULL; - ospf6 = ospf6_lookup_by_vrf_id(vrf_id); - - if (ospf6 == NULL) - return; - - ospf6_zebra_no_redistribute(type, vrf_id); + ospf6_zebra_no_redistribute(type, ospf6->vrf_id); for (route = ospf6_route_head(ospf6->external_table); route; route = ospf6_route_next(route)) { @@ -1035,7 +1078,7 @@ static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id) ospf6); } - ospf6_asbr_routemap_unset(type, ospf6); + ospf6_asbr_routemap_unset(red); } /* When an area is unstubified, flood all the external LSAs in the area */ @@ -1068,6 +1111,12 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, char ibuf[16]; struct listnode *lnode, *lnnode; struct ospf6_area *oa; + struct ospf6_redist *red; + + red = ospf6_redist_lookup(ospf6, type, 0); + + if (!red) + return; if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id)) return; @@ -1079,28 +1128,28 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, zlog_debug("Redistribute %pFX (%s)", prefix, ZROUTE_NAME(type)); /* if route-map was specified but not found, do not advertise */ - if (ospf6->rmap[type].name) { - if (ospf6->rmap[type].map == NULL) + if (ROUTEMAP_NAME(red)) { + if (ROUTEMAP(red) == NULL) ospf6_asbr_routemap_update(NULL); - if (ospf6->rmap[type].map == NULL) { + if (ROUTEMAP(red) == NULL) { zlog_warn( "route-map \"%s\" not found, suppress redistributing", - ospf6->rmap[type].name); + ROUTEMAP_NAME(red)); return; } } /* apply route-map */ - if (ospf6->rmap[type].map) { + if (ROUTEMAP(red)) { troute.route_option = &tinfo; tinfo.ifindex = ifindex; tinfo.tag = tag; - ret = route_map_apply(ospf6->rmap[type].map, prefix, &troute); + ret = route_map_apply(ROUTEMAP(red), prefix, &troute); if (ret == RMAP_DENYMATCH) { if (IS_OSPF6_DEBUG_ASBR) zlog_debug("Denied by route-map \"%s\"", - ospf6->rmap[type].name); + ROUTEMAP_NAME(red)); ospf6_asbr_redistribute_remove(type, ifindex, prefix, ospf6); return; @@ -1111,7 +1160,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, if (match) { info = match->route_option; /* copy result of route-map */ - if (ospf6->rmap[type].map) { + if (ROUTEMAP(red)) { if (troute.path.metric_type) match->path.metric_type = troute.path.metric_type; @@ -1164,7 +1213,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, info->id = ospf6->external_id++; /* copy result of route-map */ - if (ospf6->rmap[type].map) { + if (ROUTEMAP(red)) { if (troute.path.metric_type) route->path.metric_type = troute.path.metric_type; if (troute.path.cost) @@ -1272,6 +1321,7 @@ DEFUN (ospf6_redistribute, FRR_REDIST_HELP_STR_OSPF6D) { int type; + struct ospf6_redist *red; VTY_DECLVAR_CONTEXT(ospf6, ospf6); OSPF6_CMD_CHECK_RUNNING(ospf6); @@ -1280,8 +1330,13 @@ DEFUN (ospf6_redistribute, if (type < 0) return CMD_WARNING_CONFIG_FAILED; - ospf6_asbr_redistribute_unset(type, ospf6->vrf_id); + red = ospf6_redist_add(ospf6, type, 0); + if (!red) + return CMD_SUCCESS; + + ospf6_asbr_redistribute_unset(ospf6, red, type); ospf6_asbr_redistribute_set(type, ospf6->vrf_id); + return CMD_SUCCESS; } @@ -1296,6 +1351,7 @@ DEFUN (ospf6_redistribute_routemap, int idx_protocol = 1; int idx_word = 3; int type; + struct ospf6_redist *red; VTY_DECLVAR_CONTEXT(ospf6, ospf6); OSPF6_CMD_CHECK_RUNNING(ospf6); @@ -1305,9 +1361,14 @@ DEFUN (ospf6_redistribute_routemap, if (type < 0) return CMD_WARNING_CONFIG_FAILED; - ospf6_asbr_redistribute_unset(type, ospf6->vrf_id); - ospf6_asbr_routemap_set(type, argv[idx_word]->arg, ospf6->vrf_id); + red = ospf6_redist_add(ospf6, type, 0); + if (!red) + return CMD_SUCCESS; + + ospf6_asbr_redistribute_unset(ospf6, red, type); + ospf6_asbr_routemap_set(red, argv[idx_word]->arg); ospf6_asbr_redistribute_set(type, ospf6->vrf_id); + return CMD_SUCCESS; } @@ -1322,6 +1383,7 @@ DEFUN (no_ospf6_redistribute, { int idx_protocol = 2; int type; + struct ospf6_redist *red; VTY_DECLVAR_CONTEXT(ospf6, ospf6); @@ -1332,7 +1394,12 @@ DEFUN (no_ospf6_redistribute, if (type < 0) return CMD_WARNING_CONFIG_FAILED; - ospf6_asbr_redistribute_unset(type, ospf6->vrf_id); + red = ospf6_redist_lookup(ospf6, type, 0); + if (!red) + return CMD_SUCCESS; + + ospf6_asbr_redistribute_unset(ospf6, red, type); + ospf6_redist_del(ospf6, red, type); return CMD_SUCCESS; } @@ -1340,16 +1407,18 @@ DEFUN (no_ospf6_redistribute, int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6) { int type; + struct ospf6_redist *red; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { - if (type == ZEBRA_ROUTE_OSPF6) + red = ospf6_redist_lookup(ospf6, type, 0); + if (!red) continue; - if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id)) + if (type == ZEBRA_ROUTE_OSPF6) continue; - if (ospf6->rmap[type].name) + if (ROUTEMAP_NAME(red)) vty_out(vty, " redistribute %s route-map %s\n", - ZROUTE_NAME(type), ospf6->rmap[type].name); + ZROUTE_NAME(type), ROUTEMAP_NAME(red)); else vty_out(vty, " redistribute %s\n", ZROUTE_NAME(type)); } @@ -1367,6 +1436,7 @@ static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6, struct ospf6_route *route; struct ospf6_external_info *info; json_object *json_route; + struct ospf6_redist *red; total = 0; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) @@ -1384,9 +1454,11 @@ static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6, vty_out(vty, "Redistributing External Routes from:\n"); for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { - if (type == ZEBRA_ROUTE_OSPF6) + red = ospf6_redist_lookup(ospf6, type, 0); + + if (!red) continue; - if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id)) + if (type == ZEBRA_ROUTE_OSPF6) continue; if (use_json) { @@ -1396,25 +1468,24 @@ static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6, nroute[type]); json_object_boolean_add(json_route, "routeMapNamePresent", - ospf6->rmap[type].name); + ROUTEMAP_NAME(red)); } - if (ospf6->rmap[type].name) { + if (ROUTEMAP_NAME(red)) { if (use_json) { json_object_string_add(json_route, "routeMapName", - ospf6->rmap[type].name); + ROUTEMAP_NAME(red)); json_object_boolean_add(json_route, "routeMapFound", - ospf6->rmap[type].map); + ROUTEMAP(red)); } else vty_out(vty, " %d: %s with route-map \"%s\"%s\n", nroute[type], ZROUTE_NAME(type), - ospf6->rmap[type].name, - (ospf6->rmap[type].map - ? "" - : " (not found !)")); + ROUTEMAP_NAME(red), + (ROUTEMAP(red) ? "" + : " (not found !)")); } else { if (!use_json) vty_out(vty, " %d: %s\n", nroute[type], @@ -1980,15 +2051,21 @@ void ospf6_asbr_init(void) install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd); } -void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id) +void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6) { int type; + struct ospf6_redist *red; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { + red = ospf6_redist_lookup(ospf6, type, 0); + if (!red) + continue; if (type == ZEBRA_ROUTE_OSPF6) continue; - if (ospf6_zebra_is_redistribute(type, vrf_id)) - ospf6_asbr_redistribute_unset(type, vrf_id); + if (ospf6_zebra_is_redistribute(type, ospf6->vrf_id)) { + ospf6_asbr_redistribute_unset(ospf6, red, type); + ospf6_redist_del(ospf6, red, type); + } } } diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 24cc6a07b2..fd14610042 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -92,7 +92,7 @@ extern int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6); extern void ospf6_asbr_init(void); -extern void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id); +extern void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6); extern void ospf6_asbr_terminate(void); extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *); @@ -102,5 +102,6 @@ extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, struct ospf6_route *route, struct ospf6 *ospf6); extern void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6); - +struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type, + unsigned short instance); #endif /* OSPF6_ASBR_H */ diff --git a/ospf6d/ospf6_memory.c b/ospf6d/ospf6_memory.c index c008b54ce7..6585fc1580 100644 --- a/ospf6d/ospf6_memory.c +++ b/ospf6d/ospf6_memory.c @@ -44,3 +44,4 @@ DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info") DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path") DEFINE_MTYPE(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments") DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other") +DEFINE_MTYPE(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments") diff --git a/ospf6d/ospf6_memory.h b/ospf6d/ospf6_memory.h index a97d677543..57f0abd9a8 100644 --- a/ospf6d/ospf6_memory.h +++ b/ospf6d/ospf6_memory.h @@ -42,6 +42,7 @@ DECLARE_MTYPE(OSPF6_NEXTHOP) DECLARE_MTYPE(OSPF6_EXTERNAL_INFO) DECLARE_MTYPE(OSPF6_PATH) DECLARE_MTYPE(OSPF6_DIST_ARGS) +DECLARE_MTYPE(OSPF6_REDISTRIBUTE) DECLARE_MTYPE(OSPF6_OTHER) #endif /* _QUAGGA_OSPF6_MEMORY_H */ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 908cda43d0..e461a37923 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -338,7 +338,8 @@ static void ospf6_disable(struct ospf6 *o) ospf6_area_disable(oa); /* XXX: This also changes persistent settings */ - ospf6_asbr_redistribute_reset(o->vrf_id); + /* Unregister redistribution */ + ospf6_asbr_redistribute_reset(o); ospf6_lsdb_remove_all(o->lsdb); ospf6_route_remove_all(o->route_table); diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 52e1d7ee2b..93e25d7599 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -38,6 +38,17 @@ enum { OSPF6_LOG_ADJACENCY_DETAIL = (1 << 1), }; +struct ospf6_redist { + uint8_t instance; + /* For redistribute route map. */ + struct { + char *name; + struct route_map *map; + } route_map; +#define ROUTEMAP_NAME(R) (R->route_map.name) +#define ROUTEMAP(R) (R->route_map.map) +}; + /* OSPFv3 top level data structure */ struct ospf6 { /* The relevant vrf_id */ @@ -71,11 +82,8 @@ struct ospf6 { struct route_table *external_id_table; uint32_t external_id; - /* redistribute route-map */ - struct { - char *name; - struct route_map *map; - } rmap[ZEBRA_ROUTE_MAX]; + /* OSPF6 redistribute configuration */ + struct list *redist[ZEBRA_ROUTE_MAX]; uint8_t flag; diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c index 521b808ecc..b574e2cac8 100644 --- a/ospfd/ospf_ldp_sync.c +++ b/ospfd/ospf_ldp_sync.c @@ -231,7 +231,7 @@ void ospf_ldp_sync_handle_client_close(struct zapi_client_close_info *info) vrf = vrf_lookup_by_id(ospf->vrf_id); FOR_ALL_INTERFACES (vrf, ifp) - ospf_ldp_sync_if_start(ifp, true); + ospf_ldp_sync_ldp_fail(ifp); } void ospf_ldp_sync_ldp_fail(struct interface *ifp) diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h index 0bd47454a9..52561fd451 100644 --- a/sharpd/sharp_globals.h +++ b/sharpd/sharp_globals.h @@ -45,6 +45,8 @@ struct sharp_routes { struct timeval t_start; struct timeval t_end; + + char opaque[ZAPI_MESSAGE_OPAQUE_LENGTH]; }; struct sharp_global { diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 45c0799fa7..a1215835c0 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -163,7 +163,7 @@ DEFPY (install_routes, <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\ nexthop-group NHGNAME$nexthop_group>\ [backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \ - (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", + (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt] [opaque WORD]", "Sharp routing Protocol\n" "install some routes\n" "Routes to install\n" @@ -183,7 +183,9 @@ DEFPY (install_routes, "Instance to use\n" "Instance\n" "Should we repeat this command\n" - "How many times to repeat this command\n") + "How many times to repeat this command\n" + "What opaque data to send down\n" + "The opaque data\n") { struct vrf *vrf; struct prefix prefix; @@ -292,12 +294,17 @@ DEFPY (install_routes, sg.r.backup_nhop_group.nexthop = &sg.r.backup_nhop; } + if (opaque) + strlcpy(sg.r.opaque, opaque, ZAPI_MESSAGE_OPAQUE_LENGTH); + else + sg.r.opaque[0] = '\0'; + sg.r.inst = instance; sg.r.vrf_id = vrf->vrf_id; rts = routes; sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, nhgid, &sg.r.nhop_group, &sg.r.backup_nhop_group, - rts); + rts, sg.r.opaque); return CMD_SUCCESS; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 627caea37d..4445bc0132 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -232,6 +232,7 @@ struct buffer_delay { const struct nexthop_group *nhg; const struct nexthop_group *backup_nhg; enum where_to_restart restart; + char *opaque; } wb; /* @@ -242,7 +243,7 @@ struct buffer_delay { */ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t nhgid, const struct nexthop_group *nhg, - const struct nexthop_group *backup_nhg) + const struct nexthop_group *backup_nhg, char *opaque) { struct zapi_route api; struct zapi_nexthop *api_nh; @@ -290,6 +291,13 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, api.backup_nexthop_num = i; } + if (strlen(opaque)) { + SET_FLAG(api.message, ZAPI_MESSAGE_OPAQUE); + api.opaque.length = strlen(opaque) + 1; + assert(api.opaque.length <= ZAPI_MESSAGE_OPAQUE_LENGTH); + memcpy(api.opaque.data, opaque, api.opaque.length); + } + if (zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api) == ZCLIENT_SEND_BUFFERED) return true; @@ -326,7 +334,7 @@ static void sharp_install_routes_restart(struct prefix *p, uint32_t count, uint32_t nhgid, const struct nexthop_group *nhg, const struct nexthop_group *backup_nhg, - uint32_t routes) + uint32_t routes, char *opaque) { uint32_t temp, i; bool v4 = false; @@ -339,7 +347,7 @@ static void sharp_install_routes_restart(struct prefix *p, uint32_t count, for (i = count; i < routes; i++) { bool buffered = route_add(p, vrf_id, (uint8_t)instance, nhgid, - nhg, backup_nhg); + nhg, backup_nhg, opaque); if (v4) p->u.prefix4.s_addr = htonl(++temp); else @@ -354,6 +362,7 @@ static void sharp_install_routes_restart(struct prefix *p, uint32_t count, wb.nhgid = nhgid; wb.nhg = nhg; wb.backup_nhg = backup_nhg; + wb.opaque = opaque; wb.restart = SHARP_INSTALL_ROUTES_RESTART; return; @@ -365,7 +374,7 @@ void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t nhgid, const struct nexthop_group *nhg, const struct nexthop_group *backup_nhg, - uint32_t routes) + uint32_t routes, char *opaque) { zlog_debug("Inserting %u routes", routes); @@ -375,7 +384,7 @@ void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, monotime(&sg.r.t_start); sharp_install_routes_restart(p, 0, vrf_id, instance, nhgid, nhg, - backup_nhg, routes); + backup_nhg, routes, opaque); } static void sharp_remove_routes_restart(struct prefix *p, uint32_t count, @@ -441,7 +450,7 @@ static void handle_repeated(bool installed) sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst, sg.r.nhgid, &sg.r.nhop_group, &sg.r.backup_nhop_group, - sg.r.total_routes); + sg.r.total_routes, sg.r.opaque); } } @@ -449,9 +458,9 @@ static void sharp_zclient_buffer_ready(void) { switch (wb.restart) { case SHARP_INSTALL_ROUTES_RESTART: - sharp_install_routes_restart(&wb.p, wb.count, wb.vrf_id, - wb.instance, wb.nhgid, wb.nhg, - wb.backup_nhg, wb.routes); + sharp_install_routes_restart( + &wb.p, wb.count, wb.vrf_id, wb.instance, wb.nhgid, + wb.nhg, wb.backup_nhg, wb.routes, wb.opaque); return; case SHARP_DELETE_ROUTES_RESTART: sharp_remove_routes_restart(&wb.p, wb.count, wb.vrf_id, diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 8c5fa5e15e..e7247f5373 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -39,7 +39,7 @@ extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t nhgid, const struct nexthop_group *nhg, const struct nexthop_group *backup_nhg, - uint32_t routes); + uint32_t routes, char *opaque); extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t routes); diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index bd9966c801..261b859bf6 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -1254,6 +1254,15 @@ static int fpm_process_queue(struct thread *t) thread_add_timer(fnc->fthread->master, fpm_process_queue, fnc, 0, &fnc->t_dequeue); + /* + * Let the dataplane thread know if there are items in the + * output queue to be processed. Otherwise they may sit + * until the dataplane thread gets scheduled for new, + * unrelated work. + */ + if (dplane_provider_out_ctx_queue_len(fnc->prov) > 0) + dplane_provider_work_ready(); + return 0; } @@ -1441,7 +1450,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) if (peak_queue < cur_queue) atomic_store_explicit( &fnc->counters.ctxqueue_len_peak, - peak_queue, memory_order_relaxed); + cur_queue, memory_order_relaxed); continue; } diff --git a/zebra/label_manager.c b/zebra/label_manager.c index d312a661f3..feec49ecc2 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -91,8 +91,11 @@ static int label_manager_get_chunk(struct label_manager_chunk **lmc, vrf_id_t vrf_id); static int label_manager_release_label_chunk(struct zserv *client, uint32_t start, uint32_t end); +static int release_label_chunk(uint8_t proto, unsigned short instance, + uint32_t session_id, uint32_t start, + uint32_t end); -void delete_label_chunk(void *val) +static void delete_label_chunk(void *val) { XFREE(MTYPE_LM_CHUNK, val); } @@ -175,11 +178,11 @@ void label_manager_init(void) } /* alloc and fill a label chunk */ -struct label_manager_chunk *create_label_chunk(uint8_t proto, - unsigned short instance, - uint32_t session_id, - uint8_t keep, uint32_t start, - uint32_t end) +static struct label_manager_chunk *create_label_chunk(uint8_t proto, + unsigned short instance, + uint32_t session_id, + uint8_t keep, uint32_t start, + uint32_t end) { /* alloc chunk, fill it and return it */ struct label_manager_chunk *lmc = @@ -302,11 +305,11 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance, * @param base Desired starting label of the chunk; if MPLS_LABEL_BASE_ANY it does not apply * @return Pointer to the assigned label chunk, or NULL if the request could not be satisfied */ -struct label_manager_chunk *assign_label_chunk(uint8_t proto, - unsigned short instance, - uint32_t session_id, - uint8_t keep, uint32_t size, - uint32_t base) +static struct label_manager_chunk *assign_label_chunk(uint8_t proto, + unsigned short instance, + uint32_t session_id, + uint8_t keep, uint32_t size, + uint32_t base) { struct label_manager_chunk *lmc; struct listnode *node; @@ -390,11 +393,12 @@ static int label_manager_release_label_chunk(struct zserv *client, * * @param proto Daemon protocol of client, to identify the owner * @param instance Instance, to identify the owner + * @param session_id Zclient session ID, to identify the zclient session * @param start First label of the chunk * @param end Last label of the chunk * @return 0 on success, -1 otherwise */ -int release_label_chunk(uint8_t proto, unsigned short instance, +static int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t session_id, uint32_t start, uint32_t end) { struct listnode *node; diff --git a/zebra/label_manager.h b/zebra/label_manager.h index 82154982c2..094155f714 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -94,14 +94,6 @@ int lm_client_connect_response(uint8_t proto, uint16_t instance, int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client, vrf_id_t vrf_id); -/* convenience function to allocate an lmc to be consumed by the above API */ -struct label_manager_chunk *create_label_chunk(uint8_t proto, - unsigned short instance, - uint32_t session_id, - uint8_t keep, uint32_t start, - uint32_t end); -void delete_label_chunk(void *val); - /* register/unregister callbacks for hooks */ void lm_hooks_register(void); void lm_hooks_unregister(void); @@ -115,13 +107,6 @@ struct label_manager { }; void label_manager_init(void); -struct label_manager_chunk *assign_label_chunk(uint8_t proto, - unsigned short instance, - uint32_t session_id, - uint8_t keep, uint32_t size, - uint32_t base); -int release_label_chunk(uint8_t proto, unsigned short instance, - uint32_t session_id, uint32_t start, uint32_t end); int lm_client_disconnect_cb(struct zserv *client); int release_daemon_label_chunks(struct zserv *client); void label_manager_close(void); diff --git a/zebra/rib.h b/zebra/rib.h index 3bce62bfa8..fe7073656c 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -84,6 +84,11 @@ struct rnh { PREDECL_LIST(re_list) +struct opaque { + uint16_t length; + uint8_t data[]; +}; + struct route_entry { /* Link list. */ struct re_list_item next; @@ -157,6 +162,8 @@ struct route_entry { /* Distance. */ uint8_t distance; + + struct opaque *opaque; }; #define RIB_SYSTEM_ROUTE(R) RSYSTEM_ROUTE((R)->type) diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 809df0f5a9..f2ff8d53f2 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1973,6 +1973,13 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) if (CHECK_FLAG(api.message, ZAPI_MESSAGE_MTU)) re->mtu = api.mtu; + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_OPAQUE)) { + re->opaque = XMALLOC(MTYPE_OPAQUE, + sizeof(struct opaque) + api.opaque.length); + re->opaque->length = api.opaque.length; + memcpy(re->opaque->data, api.opaque.data, re->opaque->length); + } + afi = family2afi(api.prefix.family); if (afi != AFI_IP6 && CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) { flog_warn(EC_ZEBRA_RX_SRCDEST_WRONG_AFI, diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 8cfe259932..fad3c16244 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -3900,6 +3900,12 @@ int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov, return ret; } +uint32_t dplane_provider_out_ctx_queue_len(struct zebra_dplane_provider *prov) +{ + return atomic_load_explicit(&(prov->dp_out_counter), + memory_order_relaxed); +} + /* * Enqueue and maintain associated counter */ diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 3b4f049068..595d3fe562 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -763,6 +763,9 @@ struct zebra_dplane_ctx *dplane_provider_dequeue_in_ctx( int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov, struct dplane_ctx_q *listp); +/* Current completed work queue length */ +uint32_t dplane_provider_out_ctx_queue_len(struct zebra_dplane_provider *prov); + /* Enqueue completed work, maintain associated counter and locking */ void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov, struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_memory.c b/zebra/zebra_memory.c index da8121774e..17b52a2bcb 100644 --- a/zebra/zebra_memory.c +++ b/zebra/zebra_memory.c @@ -30,3 +30,4 @@ DEFINE_MTYPE(ZEBRA, RE, "Route Entry") DEFINE_MTYPE(ZEBRA, RIB_DEST, "RIB destination") DEFINE_MTYPE(ZEBRA, ZVLAN, "VLAN") DEFINE_MTYPE(ZEBRA, ZVLAN_BITMAP, "VLAN bitmap") +DEFINE_MTYPE(ZEBRA, OPAQUE, "Opaque Data") diff --git a/zebra/zebra_memory.h b/zebra/zebra_memory.h index e15f972493..71901b765f 100644 --- a/zebra/zebra_memory.h +++ b/zebra/zebra_memory.h @@ -32,6 +32,7 @@ DECLARE_MGROUP(ZEBRA) DECLARE_MTYPE(ZEBRA_NS) DECLARE_MTYPE(RE) DECLARE_MTYPE(RIB_DEST) +DECLARE_MTYPE(OPAQUE) #ifdef __cplusplus } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 88f6ec2634..0aea0b6cfa 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2665,6 +2665,8 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) nexthops_free(re->fib_ng.nexthop); + XFREE(MTYPE_OPAQUE, re->opaque); + XFREE(MTYPE_RE, re); } @@ -2748,7 +2750,7 @@ static void _route_entry_dump_nh(const struct route_entry *re, if (nexthop->weight) snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight); - zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s", + zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s%s%s%s", straddr, (nexthop->rparent ? " NH" : "NH"), nhname, nexthop->ifindex, vrf ? vrf->name : "Unknown", nexthop->vrf_id, @@ -2767,7 +2769,13 @@ static void _route_entry_dump_nh(const struct route_entry *re, : ""), (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE) ? "DUPLICATE " - : "")); + : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED) + ? "FILTERED " : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP) + ? "BACKUP " : ""), + (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE) + ? "SRTE " : "")); } diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index b7cbf5262a..be4fb29aae 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -107,6 +107,8 @@ static int zebra_vrf_new(struct vrf *vrf) zvrf = zebra_vrf_alloc(); vrf->info = zvrf; zvrf->vrf = vrf; + if (!vrf_is_backend_netns()) + zvrf->zns = zebra_ns_lookup(NS_DEFAULT); otable_init(&zvrf->other_tables); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index dc43e9a0b1..266050784a 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -419,6 +419,33 @@ static void show_nexthop_detail_helper(struct vty *vty, } } +static void zebra_show_ip_route_opaque(struct vty *vty, struct route_entry *re, + struct json_object *json) +{ + if (!re->opaque) + return; + + switch (re->type) { + case ZEBRA_ROUTE_SHARP: + if (json) + json_object_string_add(json, "opaque", + (char *)re->opaque->data); + else + vty_out(vty, " Opaque Data: %s", + (char *)re->opaque->data); + break; + case ZEBRA_ROUTE_BGP: + if (json) + json_object_string_add(json, "asPath", + (char *)re->opaque->data); + else + vty_out(vty, " AS-Path: %s", + (char *)re->opaque->data); + default: + break; + } +} + /* New RIB. Detailed information for IPv4 route. */ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast, bool use_fib, bool show_ng) @@ -495,6 +522,8 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) show_nh_backup_helper(vty, re, nexthop); } + zebra_show_ip_route_opaque(vty, re, NULL); + vty_out(vty, "\n"); } } @@ -927,6 +956,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_object_add(json_route, "backupNexthops", json_nexthops); } + zebra_show_ip_route_opaque(NULL, re, json_route); json_object_array_add(json, json_route); return; |
