diff options
Diffstat (limited to 'zebra/zebra_dplane.c')
| -rw-r--r-- | zebra/zebra_dplane.c | 501 |
1 files changed, 478 insertions, 23 deletions
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index db2b9e002e..18fe0a7e85 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -28,7 +28,6 @@ #include "lib/memory.h" #include "lib/queue.h" #include "lib/zebra.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_router.h" #include "zebra/zebra_dplane.h" #include "zebra/zebra_vxlan_private.h" @@ -39,9 +38,10 @@ #include "printfrr.h" /* Memory type for context blocks */ -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_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"); #ifndef AOK # define AOK 0 @@ -307,6 +307,12 @@ struct zebra_dplane_ctx { struct dplane_mac_info macinfo; struct dplane_neigh_info neigh; struct dplane_rule_info rule; + struct zebra_pbr_iptable iptable; + struct zebra_pbr_ipset ipset; + union { + struct zebra_pbr_ipset_entry entry; + struct zebra_pbr_ipset_info info; + } ipset_entry; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -438,6 +444,14 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_update_yields; + _Atomic uint32_t dg_iptable_in; + _Atomic uint32_t dg_iptable_errors; + + _Atomic uint32_t dg_ipset_in; + _Atomic uint32_t dg_ipset_errors; + _Atomic uint32_t dg_ipset_entry_in; + _Atomic uint32_t dg_ipset_entry_errors; + /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -656,7 +670,29 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NONE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + break; + + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: break; + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + if (ctx->u.iptable.interface_name_list) { + struct listnode *node, *nnode; + char *ifname; + + for (ALL_LIST_ELEMENTS( + ctx->u.iptable.interface_name_list, node, + nnode, ifname)) { + LISTNODE_DETACH( + ctx->u.iptable.interface_name_list, + node); + XFREE(MTYPE_DP_NETFILTER, ifname); + } + list_delete(&ctx->u.iptable.interface_name_list); + } } } @@ -895,6 +931,25 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_NEIGH_DISCOVER: ret = "NEIGH_DISCOVER"; break; + + case DPLANE_OP_IPTABLE_ADD: + ret = "IPTABLE_ADD"; + break; + case DPLANE_OP_IPTABLE_DELETE: + ret = "IPTABLE_DELETE"; + break; + case DPLANE_OP_IPSET_ADD: + ret = "IPSET_ADD"; + break; + case DPLANE_OP_IPSET_DELETE: + ret = "IPSET_DELETE"; + break; + case DPLANE_OP_IPSET_ENTRY_ADD: + ret = "IPSET_ENTRY_ADD"; + break; + case DPLANE_OP_IPSET_ENTRY_DELETE: + ret = "IPSET_ENTRY_DELETE"; + break; } return ret; @@ -1843,6 +1898,46 @@ dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx) return ctx->u.br_port.backup_nhg_id; } +/* Accessors for PBR iptable information */ +bool +dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_iptable *table) +{ + DPLANE_CTX_VALID(ctx); + + memcpy(table, &ctx->u.iptable, sizeof(struct zebra_pbr_iptable)); + return true; +} + +bool dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset *ipset) +{ + DPLANE_CTX_VALID(ctx); + + if (!ipset) + return false; + if (ctx->zd_op == DPLANE_OP_IPSET_ENTRY_ADD || + ctx->zd_op == DPLANE_OP_IPSET_ENTRY_DELETE) { + memset(ipset, 0, sizeof(struct zebra_pbr_ipset)); + ipset->type = ctx->u.ipset_entry.info.type; + memcpy(&ipset->ipset_name, &ctx->u.ipset_entry.info.ipset_name, + ZEBRA_IPSET_NAME_SIZE); + } else + memcpy(ipset, &ctx->u.ipset, sizeof(struct zebra_pbr_ipset)); + return true; +} + +bool dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset_entry *entry) +{ + DPLANE_CTX_VALID(ctx); + + if (!entry) + return false; + memcpy(entry, &ctx->u.ipset_entry.entry, sizeof(struct zebra_pbr_ipset_entry)); + return true; +} + /* * End of dplane context accessors */ @@ -2398,6 +2493,126 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx, return AOK; } +/** + * dplane_ctx_iptable_init() - Initialize a context block for a PBR iptable + * update. + * + * @ctx: Dataplane context to init + * @op: Operation being performed + * @new_rule: PBR iptable + * + * Return: Result status + */ +static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, + struct zebra_pbr_iptable *iptable) +{ + char *ifname; + struct listnode *node; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug( + "init dplane ctx %s: Unique %u Fwmark %u Family %s Action %s", + dplane_op2str(op), iptable->unique, iptable->fwmark, + family2str(iptable->family), + iptable->action == ZEBRA_IPTABLES_DROP ? "Drop" + : "Forward"); + } + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); + ctx->zd_is_update = false; + + ctx->zd_vrf_id = iptable->vrf_id; + memcpy(&ctx->u.iptable, iptable, sizeof(struct zebra_pbr_iptable)); + ctx->u.iptable.interface_name_list = NULL; + if (iptable->nb_interface > 0) { + ctx->u.iptable.interface_name_list = list_new(); + for (ALL_LIST_ELEMENTS_RO(iptable->interface_name_list, node, + ifname)) { + listnode_add(ctx->u.iptable.interface_name_list, + XSTRDUP(MTYPE_DP_NETFILTER, ifname)); + } + } + return AOK; +} + +/** + * dplane_ctx_ipset_init() - Initialize a context block for a PBR ipset update. + * + * @ctx: Dataplane context to init + * @op: Operation being performed + * @new_rule: PBR ipset + * + * Return: Result status + */ +static int dplane_ctx_ipset_init(struct zebra_dplane_ctx *ctx, + enum dplane_op_e op, + struct zebra_pbr_ipset *ipset) +{ + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("init dplane ctx %s: %s Unique %u Family %s Type %s", + dplane_op2str(op), ipset->ipset_name, ipset->unique, + family2str(ipset->family), + zebra_pbr_ipset_type2str(ipset->type)); + } + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); + ctx->zd_is_update = false; + + ctx->zd_vrf_id = ipset->vrf_id; + + memcpy(&ctx->u.ipset, ipset, sizeof(struct zebra_pbr_ipset)); + return AOK; +} + +/** + * dplane_ctx_ipset_entry_init() - Initialize a context block for a PBR ipset + * update. + * + * @ctx: Dataplane context to init + * @op: Operation being performed + * @new_rule: PBR ipset + * + * Return: Result status + */ +static int +dplane_ctx_ipset_entry_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, + struct zebra_pbr_ipset_entry *ipset_entry) +{ + struct zebra_pbr_ipset *ipset; + + ipset = ipset_entry->backpointer; + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("init dplane ctx %s: %s Unique %u filter %u", + dplane_op2str(op), ipset->ipset_name, + ipset_entry->unique, ipset_entry->filter_bm); + } + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false); + ctx->zd_is_update = false; + + ctx->zd_vrf_id = ipset->vrf_id; + + memcpy(&ctx->u.ipset_entry.entry, ipset_entry, + sizeof(struct zebra_pbr_ipset_entry)); + ctx->u.ipset_entry.entry.backpointer = NULL; + ctx->u.ipset_entry.info.type = ipset->type; + memcpy(&ctx->u.ipset_entry.info.ipset_name, &ipset->ipset_name, + ZEBRA_IPSET_NAME_SIZE); + + return AOK; +} + + /* * Enqueue a new update, * and ensure an event is active for the dataplane pthread. @@ -3251,6 +3466,24 @@ enum zebra_dplane_result dplane_local_mac_add(const struct interface *ifp, } /* + * Enqueue local mac del + */ +enum zebra_dplane_result +dplane_local_mac_del(const struct interface *ifp, + const struct interface *bridge_ifp, vlanid_t vid, + const struct ethaddr *mac) +{ + enum zebra_dplane_result result; + struct in_addr vtep_ip; + + vtep_ip.s_addr = 0; + + /* Use common helper api */ + result = mac_update_common(DPLANE_OP_MAC_DELETE, ifp, bridge_ifp, vid, + mac, vtep_ip, false, 0, 0); + return result; +} +/* * Public api to init an empty context - either newly-allocated or * reset/cleared - for a MAC update. */ @@ -3305,15 +3538,9 @@ mac_update_common(enum dplane_op_e op, int ret; struct zebra_dplane_ctx *ctx = NULL; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN]; - - zlog_debug("init mac ctx %s: mac %s, ifp %s, vtep %s", - dplane_op2str(op), - prefix_mac2str(mac, buf1, sizeof(buf1)), - ifp->name, - inet_ntop(AF_INET, &vtep_ip, buf2, sizeof(buf2))); - } + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("init mac ctx %s: mac %pEA, ifp %s, vtep %pI4", + dplane_op2str(op), mac, ifp->name, &vtep_ip); ctx = dplane_ctx_alloc(); ctx->zd_op = op; @@ -3491,14 +3718,9 @@ neigh_update_internal(enum dplane_op_e op, struct zebra_dplane_ctx *ctx = NULL; struct zebra_ns *zns; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { - char buf1[ETHER_ADDR_STRLEN], buf2[PREFIX_STRLEN]; - - zlog_debug("init neigh ctx %s: ifp %s, mac %s, ip %s", - dplane_op2str(op), ifp->name, - prefix_mac2str(mac, buf1, sizeof(buf1)), - ipaddr2str(ip, buf2, sizeof(buf2))); - } + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) + zlog_debug("init neigh ctx %s: ifp %s, mac %pEA, ip %pIA", + dplane_op2str(op), ifp->name, mac, ip); ctx = dplane_ctx_alloc(); @@ -3590,6 +3812,139 @@ enum zebra_dplane_result dplane_pbr_rule_update(struct zebra_pbr_rule *old_rule, { return rule_update_internal(DPLANE_OP_RULE_UPDATE, new_rule, old_rule); } +/* + * Common helper api for iptable updates + */ +static enum zebra_dplane_result +iptable_update_internal(enum dplane_op_e op, struct zebra_pbr_iptable *iptable) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx; + int ret; + + ctx = dplane_ctx_alloc(); + + ret = dplane_ctx_iptable_init(ctx, op, iptable); + if (ret != AOK) + goto done; + + ret = dplane_update_enqueue(ctx); + +done: + atomic_fetch_add_explicit(&zdplane_info.dg_iptable_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_iptable_errors, 1, + memory_order_relaxed); + dplane_ctx_free(&ctx); + } + + return result; +} + +enum zebra_dplane_result +dplane_pbr_iptable_add(struct zebra_pbr_iptable *iptable) +{ + return iptable_update_internal(DPLANE_OP_IPTABLE_ADD, iptable); +} + +enum zebra_dplane_result +dplane_pbr_iptable_delete(struct zebra_pbr_iptable *iptable) +{ + return iptable_update_internal(DPLANE_OP_IPTABLE_DELETE, iptable); +} + +/* + * Common helper api for ipset updates + */ +static enum zebra_dplane_result +ipset_update_internal(enum dplane_op_e op, struct zebra_pbr_ipset *ipset) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx; + int ret; + + ctx = dplane_ctx_alloc(); + + ret = dplane_ctx_ipset_init(ctx, op, ipset); + if (ret != AOK) + goto done; + + ret = dplane_update_enqueue(ctx); + +done: + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_errors, 1, + memory_order_relaxed); + dplane_ctx_free(&ctx); + } + + return result; +} + +enum zebra_dplane_result dplane_pbr_ipset_add(struct zebra_pbr_ipset *ipset) +{ + return ipset_update_internal(DPLANE_OP_IPSET_ADD, ipset); +} + +enum zebra_dplane_result dplane_pbr_ipset_delete(struct zebra_pbr_ipset *ipset) +{ + return ipset_update_internal(DPLANE_OP_IPSET_DELETE, ipset); +} + +/* + * Common helper api for ipset updates + */ +static enum zebra_dplane_result +ipset_entry_update_internal(enum dplane_op_e op, + struct zebra_pbr_ipset_entry *ipset_entry) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx; + int ret; + + ctx = dplane_ctx_alloc(); + + ret = dplane_ctx_ipset_entry_init(ctx, op, ipset_entry); + if (ret != AOK) + goto done; + + ret = dplane_update_enqueue(ctx); + +done: + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_entry_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_entry_errors, + 1, memory_order_relaxed); + dplane_ctx_free(&ctx); + } + + return result; +} + +enum zebra_dplane_result +dplane_pbr_ipset_entry_add(struct zebra_pbr_ipset_entry *ipset) +{ + return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_ADD, ipset); +} + +enum zebra_dplane_result +dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset) +{ + return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_DELETE, ipset); +} /* * Handler for 'show dplane' @@ -3675,6 +4030,24 @@ int dplane_show_helper(struct vty *vty, bool detailed) vty_out(vty, "Bridge port updates: %" PRIu64 "\n", incoming); vty_out(vty, "Bridge port errors: %" PRIu64 "\n", errs); + incoming = atomic_load_explicit(&zdplane_info.dg_iptable_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_iptable_errors, + memory_order_relaxed); + vty_out(vty, "IPtable updates: %" PRIu64 "\n", incoming); + vty_out(vty, "IPtable errors: %" PRIu64 "\n", errs); + incoming = atomic_load_explicit(&zdplane_info.dg_ipset_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_ipset_errors, + memory_order_relaxed); + vty_out(vty, "IPset updates: %" PRIu64 "\n", incoming); + vty_out(vty, "IPset errors: %" PRIu64 "\n", errs); + incoming = atomic_load_explicit(&zdplane_info.dg_ipset_entry_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_ipset_entry_errors, + memory_order_relaxed); + vty_out(vty, "IPset entry updates: %" PRIu64 "\n", incoming); + vty_out(vty, "IPset entry errors: %" PRIu64 "\n", errs); return CMD_SUCCESS; } @@ -4085,6 +4458,33 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NONE: break; + + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: { + struct zebra_pbr_iptable ipt; + + if (dplane_ctx_get_pbr_iptable(ctx, &ipt)) + zlog_debug("Dplane iptable update op %s, unique(%u), ctx %p", + dplane_op2str(dplane_ctx_get_op(ctx)), ipt.unique, ctx); + } break; + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: { + struct zebra_pbr_ipset ipset; + + if (dplane_ctx_get_pbr_ipset(ctx, &ipset)) + zlog_debug("Dplane ipset update op %s, unique(%u), ctx %p", + dplane_op2str(dplane_ctx_get_op(ctx)), + ipset.unique, ctx); + } break; + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: { + struct zebra_pbr_ipset_entry ipent; + + if (dplane_ctx_get_pbr_ipset_entry(ctx, &ipent)) + zlog_debug("Dplane ipset entry update op %s, unique(%u), ctx %p", + dplane_op2str(dplane_ctx_get_op(ctx)), + ipent.unique, ctx); + } break; } } @@ -4181,6 +4581,29 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) 1, memory_order_relaxed); break; + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_iptable_errors, 1, + memory_order_relaxed); + break; + + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit(&zdplane_info.dg_ipset_errors, + 1, memory_order_relaxed); + break; + + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_ipset_entry_errors, 1, + memory_order_relaxed); + break; + /* Ignore 'notifications' - no-op */ case DPLANE_OP_SYS_ROUTE_ADD: case DPLANE_OP_SYS_ROUTE_DELETE: @@ -4197,6 +4620,28 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) } } +static void kernel_dplane_process_iptable(struct zebra_dplane_provider *prov, + struct zebra_dplane_ctx *ctx) +{ + zebra_pbr_process_iptable(ctx); + dplane_provider_enqueue_out_ctx(prov, ctx); +} + +static void kernel_dplane_process_ipset(struct zebra_dplane_provider *prov, + struct zebra_dplane_ctx *ctx) +{ + zebra_pbr_process_ipset(ctx); + dplane_provider_enqueue_out_ctx(prov, ctx); +} + +static void +kernel_dplane_process_ipset_entry(struct zebra_dplane_provider *prov, + struct zebra_dplane_ctx *ctx) +{ + zebra_pbr_process_ipset_entry(ctx); + dplane_provider_enqueue_out_ctx(prov, ctx); +} + /* * Kernel provider callback */ @@ -4218,11 +4663,21 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) ctx = dplane_provider_dequeue_in_ctx(prov); if (ctx == NULL) break; - if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) kernel_dplane_log_detail(ctx); - TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries); + if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD + || dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_DELETE)) + kernel_dplane_process_iptable(prov, ctx); + else if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD + || dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_DELETE)) + kernel_dplane_process_ipset(prov, ctx); + else if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD + || dplane_ctx_get_op(ctx) + == DPLANE_OP_IPSET_ENTRY_DELETE)) + kernel_dplane_process_ipset_entry(prov, ctx); + else + TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries); } kernel_update_multi(&work_list); |
