summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_vty.c18
-rw-r--r--bgpd/bgp_zebra.c9
-rw-r--r--bgpd/bgpd.c6
-rw-r--r--bgpd/bgpd.h5
-rw-r--r--doc/user/bgp.rst9
-rw-r--r--doc/user/sharp.rst5
-rw-r--r--isisd/isis_ldp_sync.c2
-rw-r--r--lib/filter.h54
-rw-r--r--lib/filter_cli.c218
-rw-r--r--lib/filter_nb.c386
-rw-r--r--lib/hash.h2
-rw-r--r--lib/yang.c2
-rw-r--r--lib/zclient.c13
-rw-r--r--lib/zclient.h12
-rw-r--r--ospf6d/ospf6_asbr.c243
-rw-r--r--ospf6d/ospf6_asbr.h5
-rw-r--r--ospf6d/ospf6_memory.c1
-rw-r--r--ospf6d/ospf6_memory.h1
-rw-r--r--ospf6d/ospf6_top.c3
-rw-r--r--ospf6d/ospf6_top.h18
-rw-r--r--ospfd/ospf_ldp_sync.c2
-rw-r--r--sharpd/sharp_globals.h2
-rw-r--r--sharpd/sharp_vty.c13
-rw-r--r--sharpd/sharp_zebra.c27
-rw-r--r--sharpd/sharp_zebra.h2
-rw-r--r--zebra/dplane_fpm_nl.c11
-rw-r--r--zebra/label_manager.c28
-rw-r--r--zebra/label_manager.h15
-rw-r--r--zebra/rib.h7
-rw-r--r--zebra/zapi_msg.c7
-rw-r--r--zebra/zebra_dplane.c6
-rw-r--r--zebra/zebra_dplane.h3
-rw-r--r--zebra/zebra_memory.c1
-rw-r--r--zebra/zebra_memory.h1
-rw-r--r--zebra/zebra_rib.c12
-rw-r--r--zebra/zebra_vrf.c2
-rw-r--r--zebra/zebra_vty.c30
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;