summaryrefslogtreecommitdiff
path: root/zebra/zebra_dplane.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_dplane.c')
-rw-r--r--zebra/zebra_dplane.c253
1 files changed, 245 insertions, 8 deletions
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 39f865fbfc..ab06ea6438 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -37,11 +37,12 @@
#include "zebra/zebra_pbr.h"
#include "printfrr.h"
-/* Memory type for context blocks */
+/* Memory types */
DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx");
DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf");
DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider");
DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object");
+DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes");
#ifndef AOK
# define AOK 0
@@ -402,6 +403,19 @@ struct zebra_dplane_provider {
TAILQ_ENTRY(zebra_dplane_provider) dp_prov_link;
};
+/* Declare types for list of zns info objects */
+PREDECL_DLIST(zns_info_list);
+
+struct dplane_zns_info {
+ struct zebra_dplane_info info;
+
+ /* Read event */
+ struct thread *t_read;
+
+ /* List linkage */
+ struct zns_info_list_item link;
+};
+
/*
* Globals
*/
@@ -424,6 +438,9 @@ static struct zebra_dplane_globals {
/* Ordered list of providers */
TAILQ_HEAD(zdg_prov_q, zebra_dplane_provider) dg_providers_q;
+ /* List of info about each zns */
+ struct zns_info_list_head dg_zns_list;
+
/* Counter used to assign internal ids to providers */
uint32_t dg_provider_id;
@@ -498,6 +515,9 @@ static struct zebra_dplane_globals {
} zdplane_info;
+/* Instantiate zns list type */
+DECLARE_DLIST(zns_info_list, struct dplane_zns_info, link);
+
/*
* Lock and unlock for interactions with the zebra 'core' pthread
*/
@@ -690,6 +710,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_ADDR_INSTALL:
case DPLANE_OP_ADDR_UNINSTALL:
+ case DPLANE_OP_INTF_ADDR_ADD:
+ case DPLANE_OP_INTF_ADDR_DEL:
/* Maybe free label string, if allocated */
if (ctx->u.intf.label != NULL &&
ctx->u.intf.label != ctx->u.intf.label_buf) {
@@ -1011,6 +1033,12 @@ const char *dplane_op2str(enum dplane_op_e op)
case DPLANE_OP_GRE_SET:
ret = "GRE_SET";
break;
+
+ case DPLANE_OP_INTF_ADDR_ADD:
+ return "INTF_ADDR_ADD";
+
+ case DPLANE_OP_INTF_ADDR_DEL:
+ return "INTF_ADDR_DEL";
}
return ret;
@@ -1108,6 +1136,21 @@ vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
return ctx->zd_vrf_id;
}
+/* In some paths we have only a namespace id */
+void dplane_ctx_set_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t nsid)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->zd_ns_info.ns_id = nsid;
+}
+
+ns_id_t dplane_ctx_get_ns_id(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->zd_ns_info.ns_id;
+}
+
bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@@ -1154,6 +1197,13 @@ ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx)
return ctx->zd_ifindex;
}
+void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->zd_ifindex = ifindex;
+}
+
void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type)
{
DPLANE_CTX_VALID(ctx);
@@ -1669,6 +1719,13 @@ uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx)
return ctx->u.intf.metric;
}
+void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.intf.metric = metric;
+}
+
/* Is interface addr p2p? */
bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
{
@@ -1691,6 +1748,27 @@ bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx)
return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST);
}
+void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.intf.flags |= DPLANE_INTF_CONNECTED;
+}
+
+void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
+}
+
+void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
+}
+
const struct prefix *dplane_ctx_get_intf_addr(
const struct zebra_dplane_ctx *ctx)
{
@@ -1699,6 +1777,14 @@ const struct prefix *dplane_ctx_get_intf_addr(
return &(ctx->u.intf.prefix);
}
+void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx,
+ const struct prefix *p)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ prefix_copy(&(ctx->u.intf.prefix), p);
+}
+
bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@@ -1711,10 +1797,15 @@ const struct prefix *dplane_ctx_get_intf_dest(
{
DPLANE_CTX_VALID(ctx);
- if (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST)
- return &(ctx->u.intf.dest_prefix);
- else
- return NULL;
+ return &(ctx->u.intf.dest_prefix);
+}
+
+void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx,
+ const struct prefix *p)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ prefix_copy(&(ctx->u.intf.dest_prefix), p);
}
bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx)
@@ -1731,6 +1822,35 @@ const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx)
return ctx->u.intf.label;
}
+void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label)
+{
+ size_t len;
+
+ DPLANE_CTX_VALID(ctx);
+
+ if (ctx->u.intf.label && ctx->u.intf.label != ctx->u.intf.label_buf)
+ free(ctx->u.intf.label);
+
+ ctx->u.intf.label = NULL;
+
+ if (label) {
+ ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
+
+ /* Use embedded buffer if it's adequate; else allocate. */
+ len = strlen(label);
+
+ if (len < sizeof(ctx->u.intf.label_buf)) {
+ strlcpy(ctx->u.intf.label_buf, label,
+ sizeof(ctx->u.intf.label_buf));
+ ctx->u.intf.label = ctx->u.intf.label_buf;
+ } else {
+ ctx->u.intf.label = strdup(label);
+ }
+ } else {
+ ctx->u.intf.flags &= ~DPLANE_INTF_HAS_LABEL;
+ }
+}
+
/* Accessors for MAC information */
vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx)
{
@@ -2177,9 +2297,9 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
* two messages in some 'update' cases.
*/
if (is_update)
- zns->netlink_dplane.seq += 2;
+ zns->netlink_dplane_out.seq += 2;
else
- zns->netlink_dplane.seq++;
+ zns->netlink_dplane_out.seq++;
#endif /* HAVE_NETLINK */
return AOK;
@@ -4709,10 +4829,92 @@ static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
#if defined(HAVE_NETLINK)
ns_info->is_cmd = true;
- ns_info->nls = zns->netlink_dplane;
+ ns_info->nls = zns->netlink_dplane_out;
#endif /* NETLINK */
}
+#ifdef HAVE_NETLINK
+/*
+ * Callback when an OS (netlink) incoming event read is ready. This runs
+ * in the dplane pthread.
+ */
+static int dplane_incoming_read(struct thread *event)
+{
+ struct dplane_zns_info *zi = THREAD_ARG(event);
+
+ kernel_dplane_read(&zi->info);
+
+ /* Re-start read task */
+ thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi,
+ zi->info.nls.sock, &zi->t_read);
+
+ return 0;
+}
+#endif /* HAVE_NETLINK */
+
+/*
+ * Notify dplane when namespaces are enabled and disabled. The dplane
+ * needs to start and stop reading incoming events from the zns. In the
+ * common case where vrfs are _not_ namespaces, there will only be one
+ * of these.
+ *
+ * This is called in the main pthread.
+ */
+void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled)
+{
+ struct dplane_zns_info *zi;
+
+ if (IS_ZEBRA_DEBUG_DPLANE)
+ zlog_debug("%s: %s for nsid %u", __func__,
+ (enabled ? "ENABLED" : "DISABLED"), zns->ns_id);
+
+ /* Search for an existing zns info entry */
+ frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
+ if (zi->info.ns_id == zns->ns_id)
+ break;
+ }
+
+ if (enabled) {
+ /* Create a new entry if necessary; start reading. */
+ if (zi == NULL) {
+ zi = XCALLOC(MTYPE_DP_NS, sizeof(*zi));
+
+ zi->info.ns_id = zns->ns_id;
+
+ zns_info_list_add_tail(&zdplane_info.dg_zns_list, zi);
+
+ if (IS_ZEBRA_DEBUG_DPLANE)
+ zlog_debug("%s: nsid %u, new zi %p", __func__,
+ zns->ns_id, zi);
+ }
+
+ /* Make sure we're up-to-date with the zns object */
+#if defined(HAVE_NETLINK)
+ zi->info.is_cmd = false;
+ zi->info.nls = zns->netlink_dplane_in;
+
+ /* Start read task for the dplane pthread. */
+ if (zdplane_info.dg_master)
+ thread_add_read(zdplane_info.dg_master,
+ dplane_incoming_read, zi,
+ zi->info.nls.sock, &zi->t_read);
+#endif
+ } else if (zi) {
+ if (IS_ZEBRA_DEBUG_DPLANE)
+ zlog_debug("%s: nsid %u, deleting zi %p", __func__,
+ zns->ns_id, zi);
+
+ /* Stop reading, free memory */
+ zns_info_list_del(&zdplane_info.dg_zns_list, zi);
+
+ if (zdplane_info.dg_master)
+ thread_cancel_async(zdplane_info.dg_master, &zi->t_read,
+ NULL);
+
+ XFREE(MTYPE_DP_NS, zi);
+ }
+}
+
/*
* Provider api to signal that work/events are available
* for the dataplane pthread.
@@ -4878,6 +5080,14 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
dplane_ctx_get_ifname(ctx),
ctx->u.gre.link_ifindex);
break;
+
+ case DPLANE_OP_INTF_ADDR_ADD:
+ case DPLANE_OP_INTF_ADDR_DEL:
+ zlog_debug("Dplane incoming op %s, intf %s, addr %pFX",
+ dplane_op2str(dplane_ctx_get_op(ctx)),
+ dplane_ctx_get_ifname(ctx),
+ dplane_ctx_get_intf_addr(ctx));
+ break;
}
}
@@ -5020,6 +5230,11 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_BR_PORT_UPDATE:
break;
+ /* TODO -- error counters for incoming events? */
+ case DPLANE_OP_INTF_ADDR_ADD:
+ case DPLANE_OP_INTF_ADDR_DEL:
+ break;
+
case DPLANE_OP_NONE:
if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
atomic_fetch_add_explicit(&zdplane_info.dg_other_errors,
@@ -5355,9 +5570,21 @@ done:
*/
static int dplane_check_shutdown_status(struct thread *event)
{
+ struct dplane_zns_info *zi;
+
if (IS_ZEBRA_DEBUG_DPLANE)
zlog_debug("Zebra dataplane shutdown status check called");
+ /* Remove any zns info entries as we stop the dplane pthread. */
+ frr_each_safe (zns_info_list, &zdplane_info.dg_zns_list, zi) {
+ zns_info_list_del(&zdplane_info.dg_zns_list, zi);
+
+ if (zdplane_info.dg_master)
+ thread_cancel(&zi->t_read);
+
+ XFREE(MTYPE_DP_NS, zi);
+ }
+
if (dplane_work_pending()) {
/* Reschedule dplane check on a short timer */
thread_add_timer_msec(zdplane_info.dg_master,
@@ -5652,6 +5879,7 @@ static void zebra_dplane_init_internal(void)
TAILQ_INIT(&zdplane_info.dg_update_ctx_q);
TAILQ_INIT(&zdplane_info.dg_providers_q);
+ zns_info_list_init(&zdplane_info.dg_zns_list);
zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK;
@@ -5667,6 +5895,7 @@ static void zebra_dplane_init_internal(void)
*/
void zebra_dplane_start(void)
{
+ struct dplane_zns_info *zi;
struct zebra_dplane_provider *prov;
struct frr_pthread_attr pattr = {
.start = frr_pthread_attr_default.start,
@@ -5686,6 +5915,14 @@ void zebra_dplane_start(void)
thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0,
&zdplane_info.dg_t_update);
+ /* Enqueue reads if necessary */
+ frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
+#if defined(HAVE_NETLINK)
+ thread_add_read(zdplane_info.dg_master, dplane_incoming_read,
+ zi, zi->info.nls.sock, &zi->t_read);
+#endif
+ }
+
/* Call start callbacks for registered providers */
DPLANE_LOCK();