diff options
Diffstat (limited to 'zebra/zebra_dplane.c')
| -rw-r--r-- | zebra/zebra_dplane.c | 314 |
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: |
