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.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 568b398924..eb3d48d784 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -35,6 +35,7 @@
#include "zebra/zebra_mpls.h"
#include "zebra/rt.h"
#include "zebra/debug.h"
+#include "zebra/zebra_pbr.h"
/* Memory type for context blocks */
DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx")
@@ -192,6 +193,36 @@ struct dplane_neigh_info {
};
/*
+ * Policy based routing rule info for the dataplane
+ */
+struct dplane_ctx_rule {
+ uint32_t priority;
+
+ /* The route table pointed by this rule */
+ uint32_t table;
+
+ /* Filter criteria */
+ uint32_t filter_bm;
+ uint32_t fwmark;
+ struct prefix src_ip;
+ struct prefix dst_ip;
+};
+
+struct dplane_rule_info {
+ /*
+ * Originating zclient sock fd, so we can know who to send
+ * back to.
+ */
+ int sock;
+
+ int unique;
+ int seq;
+
+ struct dplane_ctx_rule new;
+ struct dplane_ctx_rule old;
+};
+
+/*
* The context block used to exchange info about route updates across
* the boundary between the zebra main context (and pthread) and the
* dataplane layer (and pthread).
@@ -238,6 +269,7 @@ struct zebra_dplane_ctx {
struct dplane_intf_info intf;
struct dplane_mac_info macinfo;
struct dplane_neigh_info neigh;
+ struct dplane_rule_info rule;
} u;
/* Namespace info, used especially for netlink kernel communication */
@@ -361,6 +393,9 @@ static struct zebra_dplane_globals {
_Atomic uint32_t dg_neighs_in;
_Atomic uint32_t dg_neigh_errors;
+ _Atomic uint32_t dg_rules_in;
+ _Atomic uint32_t dg_rule_errors;
+
_Atomic uint32_t dg_update_yields;
/* Dataplane pthread */
@@ -564,6 +599,9 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
case DPLANE_OP_NEIGH_DELETE:
case DPLANE_OP_VTEP_ADD:
case DPLANE_OP_VTEP_DELETE:
+ case DPLANE_OP_RULE_ADD:
+ case DPLANE_OP_RULE_DELETE:
+ case DPLANE_OP_RULE_UPDATE:
case DPLANE_OP_NONE:
break;
}
@@ -786,6 +824,16 @@ const char *dplane_op2str(enum dplane_op_e op)
case DPLANE_OP_VTEP_DELETE:
ret = "VTEP_DELETE";
break;
+
+ case DPLANE_OP_RULE_ADD:
+ ret = "RULE_ADD";
+ break;
+ case DPLANE_OP_RULE_DELETE:
+ ret = "RULE_DELETE";
+ break;
+ case DPLANE_OP_RULE_UPDATE:
+ ret = "RULE_UPDATE";
+ break;
}
return ret;
@@ -1517,6 +1565,116 @@ uint16_t dplane_ctx_neigh_get_state(const struct zebra_dplane_ctx *ctx)
return ctx->u.neigh.state;
}
+/* Accessors for PBR rule information */
+int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.sock;
+}
+
+int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.unique;
+}
+
+int dplane_ctx_rule_get_seq(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.seq;
+}
+
+uint32_t dplane_ctx_rule_get_priority(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.new.priority;
+}
+
+uint32_t dplane_ctx_rule_get_old_priority(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.old.priority;
+}
+
+uint32_t dplane_ctx_rule_get_table(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.new.table;
+}
+
+uint32_t dplane_ctx_rule_get_old_table(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.old.table;
+}
+
+uint32_t dplane_ctx_rule_get_filter_bm(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.new.filter_bm;
+}
+
+uint32_t dplane_ctx_rule_get_old_filter_bm(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.old.filter_bm;
+}
+
+uint32_t dplane_ctx_rule_get_fwmark(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.new.fwmark;
+}
+
+uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.old.fwmark;
+}
+
+const struct prefix *
+dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rule.new.src_ip);
+}
+
+const struct prefix *
+dplane_ctx_rule_get_old_src_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rule.old.src_ip);
+}
+
+const struct prefix *
+dplane_ctx_rule_get_dst_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rule.new.dst_ip);
+}
+
+const struct prefix *
+dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.rule.old.dst_ip);
+}
+
/*
* End of dplane context accessors
*/
@@ -1913,6 +2071,76 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
return AOK;
}
+/**
+ * dplane_ctx_rule_init_single() - Initialize a dataplane representation of a
+ * PBR rule.
+ *
+ * @dplane_rule: Dataplane internal representation of a rule
+ * @rule: PBR rule
+ */
+static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
+ struct zebra_pbr_rule *rule)
+{
+ dplane_rule->priority = rule->rule.priority;
+ dplane_rule->table = rule->rule.action.table;
+
+ dplane_rule->filter_bm = rule->rule.filter.filter_bm;
+ dplane_rule->fwmark = rule->rule.filter.fwmark;
+ prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip);
+ prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip);
+}
+
+/**
+ * dplane_ctx_rule_init() - Initialize a context block for a PBR rule update.
+ *
+ * @ctx: Dataplane context to init
+ * @op: Operation being performed
+ * @new_rule: PBR rule
+ *
+ * Return: Result status
+ */
+static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op,
+ struct zebra_pbr_rule *new_rule,
+ struct zebra_pbr_rule *old_rule)
+{
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+ char buf1[PREFIX_STRLEN];
+ char buf2[PREFIX_STRLEN];
+
+ zlog_debug(
+ "init dplane ctx %s: IF %s(%u) Prio %u Fwmark %u Src %s Dst %s Table %u",
+ dplane_op2str(op), new_rule->ifname,
+ new_rule->rule.ifindex, new_rule->rule.priority,
+ new_rule->rule.filter.fwmark,
+ prefix2str(&new_rule->rule.filter.src_ip, buf1,
+ sizeof(buf1)),
+ prefix2str(&new_rule->rule.filter.dst_ip, buf2,
+ sizeof(buf2)),
+ new_rule->rule.action.table);
+ }
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT),
+ op == DPLANE_OP_RULE_UPDATE);
+
+ ctx->zd_vrf_id = new_rule->vrf_id;
+ memcpy(ctx->zd_ifname, new_rule->ifname, sizeof(new_rule->ifname));
+ ctx->zd_ifindex = new_rule->rule.ifindex;
+
+ ctx->u.rule.sock = new_rule->sock;
+ ctx->u.rule.unique = new_rule->rule.unique;
+ ctx->u.rule.seq = new_rule->rule.seq;
+
+ dplane_ctx_rule_init_single(&ctx->u.rule.new, new_rule);
+ if (op == DPLANE_OP_RULE_UPDATE)
+ dplane_ctx_rule_init_single(&ctx->u.rule.old, old_rule);
+
+ return AOK;
+}
+
/*
* Enqueue a new update,
* and ensure an event is active for the dataplane pthread.
@@ -2840,6 +3068,56 @@ neigh_update_internal(enum dplane_op_e op,
}
/*
+ * Common helper api for PBR rule updates
+ */
+static enum zebra_dplane_result
+rule_update_internal(enum dplane_op_e op, struct zebra_pbr_rule *new_rule,
+ struct zebra_pbr_rule *old_rule)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ struct zebra_dplane_ctx *ctx;
+ int ret;
+
+ ctx = dplane_ctx_alloc();
+
+ ret = dplane_ctx_rule_init(ctx, op, new_rule, old_rule);
+ if (ret != AOK)
+ goto done;
+
+ ret = dplane_update_enqueue(ctx);
+
+done:
+ atomic_fetch_add_explicit(&zdplane_info.dg_rules_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_rule_errors, 1,
+ memory_order_relaxed);
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
+enum zebra_dplane_result dplane_pbr_rule_add(struct zebra_pbr_rule *rule)
+{
+ return rule_update_internal(DPLANE_OP_RULE_ADD, rule, NULL);
+}
+
+enum zebra_dplane_result dplane_pbr_rule_delete(struct zebra_pbr_rule *rule)
+{
+ return rule_update_internal(DPLANE_OP_RULE_DELETE, rule, NULL);
+}
+
+enum zebra_dplane_result dplane_pbr_rule_update(struct zebra_pbr_rule *old_rule,
+ struct zebra_pbr_rule *new_rule)
+{
+ return rule_update_internal(DPLANE_OP_RULE_UPDATE, new_rule, old_rule);
+}
+
+/*
* Handler for 'show dplane'
*/
int dplane_show_helper(struct vty *vty, bool detailed)
@@ -2909,6 +3187,13 @@ int dplane_show_helper(struct vty *vty, bool detailed)
vty_out(vty, "EVPN neigh updates: %"PRIu64"\n", incoming);
vty_out(vty, "EVPN neigh errors: %"PRIu64"\n", errs);
+ incoming = atomic_load_explicit(&zdplane_info.dg_rules_in,
+ memory_order_relaxed);
+ errs = atomic_load_explicit(&zdplane_info.dg_rule_errors,
+ memory_order_relaxed);
+ vty_out(vty, "Rule updates: %" PRIu64 "\n", incoming);
+ vty_out(vty, "Rule errors: %" PRIu64 "\n", errs);
+
return CMD_SUCCESS;
}
@@ -3398,6 +3683,29 @@ kernel_dplane_neigh_update(struct zebra_dplane_ctx *ctx)
}
/*
+ * Handler for kernel PBR rule updates
+ */
+static enum zebra_dplane_result
+kernel_dplane_rule_update(struct zebra_dplane_ctx *ctx)
+{
+ enum zebra_dplane_result res;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("Dplane rule update op %s, if %s(%u), ctx %p",
+ dplane_op2str(dplane_ctx_get_op(ctx)),
+ dplane_ctx_get_ifname(ctx),
+ dplane_ctx_get_ifindex(ctx), ctx);
+
+ res = kernel_pbr_rule_update(ctx);
+
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(&zdplane_info.dg_rule_errors, 1,
+ memory_order_relaxed);
+
+ return res;
+}
+
+/*
* Kernel provider callback
*/
static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
@@ -3470,6 +3778,12 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
res = kernel_dplane_neigh_update(ctx);
break;
+ case DPLANE_OP_RULE_ADD:
+ case DPLANE_OP_RULE_DELETE:
+ case DPLANE_OP_RULE_UPDATE:
+ res = kernel_dplane_rule_update(ctx);
+ break;
+
/* Ignore 'notifications' - no-op */
case DPLANE_OP_SYS_ROUTE_ADD:
case DPLANE_OP_SYS_ROUTE_DELETE: