From ef524230a6baa5dd5dd337d723d47fe984d3e304 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 17 Feb 2021 11:43:52 +0100 Subject: [PATCH] zebra: move ipset and ipset_entry to zebra dplane contexts like it has been done for iptable contexts, a zebra dplane context is created for each ipset/ipset entry event. The zebra_dplane_ctx job is then enqueued and processed by separate thread. Like it has been done for zebra_pbr_iptable context, the ipset and ipset entry contexts are encapsulated into an union of structures in zebra_dplane_ctx. There is a specificity in that when storing ipset_entry structure, there was a backpointer pointer to the ipset structure that is necessary to get some complementary information before calling the hook. The proposal is to use an ipset_entry_info structure next to the ipset_entry, in the zebra_dplane context. That information is used for ipset_entry processing. The ipset name and the ipset type are the only fields necessary. Signed-off-by: Philippe Guibert --- lib/zclient.c | 13 +- lib/zclient.h | 6 +- zebra/kernel_netlink.c | 4 + zebra/zapi_msg.c | 57 +++++--- zebra/zapi_msg.h | 12 +- zebra/zebra_dplane.c | 297 ++++++++++++++++++++++++++++++++++++++++- zebra/zebra_dplane.h | 28 +++- zebra/zebra_nhg.c | 4 + zebra/zebra_pbr.c | 137 +++++++++---------- zebra/zebra_pbr.h | 12 ++ zebra/zebra_rib.c | 4 + 11 files changed, 466 insertions(+), 108 deletions(-) diff --git a/lib/zclient.c b/lib/zclient.c index 20c285cf7f..6ce2113b91 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1551,15 +1551,16 @@ bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_notify_owner *note) { uint32_t uni; + uint16_t notew; - STREAM_GET(note, s, sizeof(*note)); + STREAM_GETW(s, notew); STREAM_GETL(s, uni); if (zclient_debug) zlog_debug("%s: %u", __func__, uni); *unique = uni; - + *note = (enum zapi_ipset_notify_owner)notew; return true; stream_failure: @@ -1571,8 +1572,9 @@ bool zapi_ipset_entry_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_entry_notify_owner *note) { uint32_t uni; + uint16_t notew; - STREAM_GET(note, s, sizeof(*note)); + STREAM_GETW(s, notew); STREAM_GETL(s, uni); @@ -1581,6 +1583,7 @@ bool zapi_ipset_entry_notify_decode(struct stream *s, uint32_t *unique, if (zclient_debug) zlog_debug("%s: %u", __func__, uni); *unique = uni; + *note = (enum zapi_ipset_entry_notify_owner)notew; return true; @@ -1593,14 +1596,16 @@ bool zapi_iptable_notify_decode(struct stream *s, enum zapi_iptable_notify_owner *note) { uint32_t uni; + uint16_t notew; - STREAM_GET(note, s, sizeof(*note)); + STREAM_GETW(s, notew); STREAM_GETL(s, uni); if (zclient_debug) zlog_debug("%s: %u", __func__, uni); *unique = uni; + *note = (enum zapi_iptable_notify_owner)notew; return true; diff --git a/lib/zclient.h b/lib/zclient.h index cf52ea91a0..43197534a8 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -713,21 +713,21 @@ enum ipset_type { }; enum zapi_ipset_notify_owner { - ZAPI_IPSET_FAIL_INSTALL, + ZAPI_IPSET_FAIL_INSTALL = 0, ZAPI_IPSET_INSTALLED, ZAPI_IPSET_REMOVED, ZAPI_IPSET_FAIL_REMOVE, }; enum zapi_ipset_entry_notify_owner { - ZAPI_IPSET_ENTRY_FAIL_INSTALL, + ZAPI_IPSET_ENTRY_FAIL_INSTALL = 0, ZAPI_IPSET_ENTRY_INSTALLED, ZAPI_IPSET_ENTRY_REMOVED, ZAPI_IPSET_ENTRY_FAIL_REMOVE, }; enum zapi_iptable_notify_owner { - ZAPI_IPTABLE_FAIL_INSTALL, + ZAPI_IPTABLE_FAIL_INSTALL = 0, ZAPI_IPTABLE_INSTALLED, ZAPI_IPTABLE_REMOVED, ZAPI_IPTABLE_FAIL_REMOVE, diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 8dd0c14d5d..aa19b18089 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1352,6 +1352,10 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_IPTABLE_ADD: case DPLANE_OP_IPTABLE_DELETE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: return FRR_NETLINK_ERROR; case DPLANE_OP_NONE: diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 92a11cc4bf..9f5adfa409 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -866,18 +866,24 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, zserv_send_message(client, s); } -void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, - enum zapi_ipset_notify_owner note) +void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, + uint16_t note) { struct listnode *node; struct zserv *client; struct stream *s; + struct zebra_pbr_iptable ipt; + uint16_t cmd = ZEBRA_IPTABLE_NOTIFY_OWNER; + + if (!dplane_ctx_get_pbr_iptable(ctx, &ipt)) + return; if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s: Notifying %u", __func__, ipset->unique); + zlog_debug("%s: Notifying %s id %u note %u", __func__, + zserv_command_string(cmd), ipt.unique, note); for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { - if (ipset->sock == client->sock) + if (ipt.sock == client->sock) break; } @@ -888,25 +894,30 @@ void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, zclient_create_header(s, cmd, VRF_DEFAULT); stream_put(s, ¬e, sizeof(note)); - stream_putl(s, ipset->unique); - stream_put(s, ipset->ipset_name, ZEBRA_IPSET_NAME_SIZE); + stream_putl(s, ipt.unique); + stream_put(s, ipt.ipset_name, ZEBRA_IPSET_NAME_SIZE); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } -void zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset, - enum zapi_ipset_entry_notify_owner note) +void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, uint16_t note) { struct listnode *node; struct zserv *client; struct stream *s; + struct zebra_pbr_ipset ipset; + uint16_t cmd = ZEBRA_IPSET_NOTIFY_OWNER; + + if (!dplane_ctx_get_pbr_ipset(ctx, &ipset)) + return; if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s: Notifying %u", __func__, ipset->unique); + zlog_debug("%s: Notifying %s id %u note %u", __func__, + zserv_command_string(cmd), ipset.unique, note); for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { - if (ipset->sock == client->sock) + if (ipset.sock == client->sock) break; } @@ -915,33 +926,36 @@ void zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset, s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_IPSET_ENTRY_NOTIFY_OWNER, VRF_DEFAULT); + zclient_create_header(s, cmd, VRF_DEFAULT); stream_put(s, ¬e, sizeof(note)); - stream_putl(s, ipset->unique); - stream_put(s, ipset->backpointer->ipset_name, ZEBRA_IPSET_NAME_SIZE); + stream_putl(s, ipset.unique); + stream_put(s, ipset.ipset_name, ZEBRA_IPSET_NAME_SIZE); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } -void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, - uint16_t note) +void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, + uint16_t note) { struct listnode *node; struct zserv *client; struct stream *s; - struct zebra_pbr_iptable ipt; - uint16_t cmd = ZEBRA_IPTABLE_NOTIFY_OWNER; + struct zebra_pbr_ipset_entry ipent; + struct zebra_pbr_ipset ipset; + uint16_t cmd = ZEBRA_IPSET_ENTRY_NOTIFY_OWNER; - if (!dplane_ctx_get_pbr_iptable(ctx, &ipt)) + if (!dplane_ctx_get_pbr_ipset_entry(ctx, &ipent)) + return; + if (!dplane_ctx_get_pbr_ipset(ctx, &ipset)) return; if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: Notifying %s id %u note %u", __func__, - zserv_command_string(cmd), ipt.unique, note); + zserv_command_string(cmd), ipent.unique, note); for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { - if (ipt.sock == client->sock) + if (ipent.sock == client->sock) break; } @@ -952,7 +966,8 @@ void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, zclient_create_header(s, cmd, VRF_DEFAULT); stream_put(s, ¬e, sizeof(note)); - stream_putl(s, ipt.unique); + stream_putl(s, ipent.unique); + stream_put(s, ipset.ipset_name, ZEBRA_IPSET_NAME_SIZE); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 2401db4d18..023b9f74a8 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -84,13 +84,13 @@ extern int zsend_route_notify_owner_ctx(const struct zebra_dplane_ctx *ctx, extern void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx, enum zapi_rule_notify_owner note); -extern void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, - enum zapi_ipset_notify_owner note); -extern void -zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset, - enum zapi_ipset_entry_notify_owner note); + extern void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, - enum zapi_iptable_notify_owner note); + uint16_t note); +extern void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, + uint16_t note); +extern void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, + uint16_t note); extern bool zserv_nexthop_num_warn(const char *caller, const struct prefix *p, const unsigned int nexthop_num); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index b9e6df2a7a..82546ce188 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -42,7 +42,7 @@ 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_IFACE, "Zebra DPlane IFACE") +DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object") #ifndef AOK # define AOK 0 @@ -309,6 +309,11 @@ struct zebra_dplane_ctx { 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 */ @@ -442,6 +447,12 @@ static struct zebra_dplane_globals { _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; @@ -660,8 +671,13 @@ 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) { @@ -674,7 +690,7 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) LISTNODE_DETACH( ctx->u.iptable.interface_name_list, node); - XFREE(MTYPE_DP_IFACE, ifname); + XFREE(MTYPE_DP_NETFILTER, ifname); } list_delete(&ctx->u.iptable.interface_name_list); } @@ -923,6 +939,18 @@ const char *dplane_op2str(enum dplane_op_e op) 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; @@ -1882,6 +1910,35 @@ dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, 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 */ @@ -2477,12 +2534,86 @@ static int dplane_ctx_iptable_init(struct zebra_dplane_ctx *ctx, for (ALL_LIST_ELEMENTS_RO(iptable->interface_name_list, node, ifname)) { listnode_add(ctx->u.iptable.interface_name_list, - XSTRDUP(MTYPE_DP_IFACE, ifname)); + 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. @@ -3738,6 +3869,95 @@ 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' */ @@ -3828,6 +4048,18 @@ int dplane_show_helper(struct vty *vty, bool detailed) 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; } @@ -4247,6 +4479,24 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) 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; } } @@ -4351,6 +4601,21 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) 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: @@ -4374,6 +4639,21 @@ static void kernel_dplane_process_iptable(struct zebra_dplane_provider *prov, 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 */ @@ -4398,9 +4678,16 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov) if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) kernel_dplane_log_detail(ctx); - if ((dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD || - dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_DELETE)) + 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); } diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 3416c62b84..4913ca251f 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -156,9 +156,15 @@ enum dplane_op_e { /* bridge port update */ DPLANE_OP_BR_PORT_UPDATE, - /* Policy based routing rule update */ + /* Policy based routing iptable update */ DPLANE_OP_IPTABLE_ADD, DPLANE_OP_IPTABLE_DELETE, + + /* Policy based routing ipset update */ + DPLANE_OP_IPSET_ADD, + DPLANE_OP_IPSET_DELETE, + DPLANE_OP_IPSET_ENTRY_ADD, + DPLANE_OP_IPSET_ENTRY_DELETE, }; /* @@ -484,6 +490,14 @@ struct zebra_pbr_iptable; bool dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, struct zebra_pbr_iptable *table); +struct zebra_pbr_ipset; +bool +dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset *ipset); +struct zebra_pbr_ipset_entry; +bool +dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset_entry *entry); /* Accessors for bridge port information */ uint32_t dplane_ctx_get_br_port_flags(const struct zebra_dplane_ctx *ctx); uint32_t @@ -662,6 +676,18 @@ dplane_pbr_iptable_add(struct zebra_pbr_iptable *iptable); enum zebra_dplane_result dplane_pbr_iptable_delete(struct zebra_pbr_iptable *iptable); +/* ipset */ +struct zebra_pbr_ipset; +enum zebra_dplane_result dplane_pbr_ipset_add(struct zebra_pbr_ipset *ipset); +enum zebra_dplane_result dplane_pbr_ipset_delete(struct zebra_pbr_ipset *ipset); + +/* ipset entry */ +struct zebra_pbr_ipset_entry; +enum zebra_dplane_result +dplane_pbr_ipset_entry_add(struct zebra_pbr_ipset_entry *ipset); +enum zebra_dplane_result +dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset); + /* Encode route information into data plane context. */ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, struct route_node *rn, struct route_entry *re); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 3fafa19a70..3f567d9a70 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2717,6 +2717,10 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NONE: case DPLANE_OP_IPTABLE_ADD: case DPLANE_OP_IPTABLE_DELETE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: break; } diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 51c3bd9fdd..92a7a0ba3a 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -555,12 +555,56 @@ void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx) if (dplane_ctx_get_pbr_iptable(ctx, &ipt)) { ret = hook_call(zebra_pbr_iptable_update, mode, &ipt); if (ret) - dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); + dplane_ctx_set_status(ctx, + ZEBRA_DPLANE_REQUEST_SUCCESS); } if (!ret) dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); } +void zebra_pbr_process_ipset(struct zebra_dplane_ctx *ctx) +{ + int mode, ret = 0; + struct zebra_pbr_ipset ipset; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD) + mode = 1; + else + mode = 0; + if (dplane_ctx_get_pbr_ipset(ctx, &ipset)) { + ret = hook_call(zebra_pbr_ipset_update, mode, &ipset); + if (ret) + dplane_ctx_set_status(ctx, + ZEBRA_DPLANE_REQUEST_SUCCESS); + } + if (!ret) + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); +} + +void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx *ctx) +{ + int mode, ret = 0; + struct zebra_pbr_ipset_entry ipset_entry; + struct zebra_pbr_ipset ipset; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD) + mode = 1; + else + mode = 0; + + if (!dplane_ctx_get_pbr_ipset_entry(ctx, &ipset_entry)) + return; + if (!dplane_ctx_get_pbr_ipset(ctx, &ipset)) + return; + ipset_entry.backpointer = &ipset; + + ret = hook_call(zebra_pbr_ipset_entry_update, mode, &ipset_entry); + if (ret) + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); + else + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); +} + static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data) { struct zebra_pbr_rule *rule = b->data; @@ -651,13 +695,8 @@ static void *pbr_ipset_alloc_intern(void *arg) void zebra_pbr_create_ipset(struct zebra_pbr_ipset *ipset) { - int ret; - (void)hash_get(zrouter.ipset_hash, ipset, pbr_ipset_alloc_intern); - ret = hook_call(zebra_pbr_ipset_update, 1, ipset); - kernel_pbr_ipset_add_del_status(ipset, - ret ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); + (void)dplane_pbr_ipset_add(ipset); } void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset) @@ -665,7 +704,7 @@ void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset) struct zebra_pbr_ipset *lookup; lookup = hash_lookup(zrouter.ipset_hash, ipset); - hook_call(zebra_pbr_ipset_update, 0, ipset); + (void)dplane_pbr_ipset_delete(ipset); if (lookup) { hash_release(zrouter.ipset_hash, lookup); XFREE(MTYPE_TMP, lookup); @@ -730,14 +769,9 @@ static void *pbr_ipset_entry_alloc_intern(void *arg) void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry *ipset) { - int ret; - (void)hash_get(zrouter.ipset_entry_hash, ipset, pbr_ipset_entry_alloc_intern); - ret = hook_call(zebra_pbr_ipset_entry_update, 1, ipset); - kernel_pbr_ipset_entry_add_del_status(ipset, - ret ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); + (void)dplane_pbr_ipset_entry_add(ipset); } void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset) @@ -745,7 +779,7 @@ void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset) struct zebra_pbr_ipset_entry *lookup; lookup = hash_lookup(zrouter.ipset_entry_hash, ipset); - hook_call(zebra_pbr_ipset_entry_update, 0, ipset); + (void)dplane_pbr_ipset_entry_delete(ipset); if (lookup) { hash_release(zrouter.ipset_entry_hash, lookup); XFREE(MTYPE_TMP, lookup); @@ -836,6 +870,26 @@ void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx) res == ZEBRA_DPLANE_REQUEST_SUCCESS ? ZAPI_IPTABLE_REMOVED : ZAPI_IPTABLE_FAIL_REMOVE); + else if (op == DPLANE_OP_IPSET_ADD) + zsend_ipset_notify_owner(ctx, + res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPSET_INSTALLED + : ZAPI_IPSET_FAIL_INSTALL); + else if (op == DPLANE_OP_IPSET_DELETE) + zsend_ipset_notify_owner(ctx, + res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPSET_REMOVED + : ZAPI_IPSET_FAIL_REMOVE); + else if (op == DPLANE_OP_IPSET_ENTRY_ADD) + zsend_ipset_entry_notify_owner( + ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPSET_ENTRY_INSTALLED + : ZAPI_IPSET_ENTRY_FAIL_INSTALL); + else if (op == DPLANE_OP_IPSET_ENTRY_DELETE) + zsend_ipset_entry_notify_owner( + ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPSET_ENTRY_REMOVED + : ZAPI_IPSET_ENTRY_FAIL_REMOVE); else flog_err( EC_ZEBRA_PBR_RULE_UPDATE, @@ -846,59 +900,6 @@ void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx) dplane_ctx_fini(&ctx); } -/* - * Handle success or failure of ipset (un)install in the kernel. - */ -void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset, - enum zebra_dplane_status res) -{ - switch (res) { - case ZEBRA_DPLANE_INSTALL_SUCCESS: - zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED); - break; - case ZEBRA_DPLANE_INSTALL_FAILURE: - zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL); - break; - case ZEBRA_DPLANE_DELETE_SUCCESS: - zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED); - break; - case ZEBRA_DPLANE_DELETE_FAILURE: - zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE); - break; - case ZEBRA_DPLANE_STATUS_NONE: - break; - } -} - -/* - * Handle success or failure of ipset (un)install in the kernel. - */ -void kernel_pbr_ipset_entry_add_del_status( - struct zebra_pbr_ipset_entry *ipset, - enum zebra_dplane_status res) -{ - switch (res) { - case ZEBRA_DPLANE_INSTALL_SUCCESS: - zsend_ipset_entry_notify_owner(ipset, - ZAPI_IPSET_ENTRY_INSTALLED); - break; - case ZEBRA_DPLANE_INSTALL_FAILURE: - zsend_ipset_entry_notify_owner(ipset, - ZAPI_IPSET_ENTRY_FAIL_INSTALL); - break; - case ZEBRA_DPLANE_DELETE_SUCCESS: - zsend_ipset_entry_notify_owner(ipset, - ZAPI_IPSET_ENTRY_REMOVED); - break; - case ZEBRA_DPLANE_DELETE_FAILURE: - zsend_ipset_entry_notify_owner(ipset, - ZAPI_IPSET_ENTRY_FAIL_REMOVE); - break; - case ZEBRA_DPLANE_STATUS_NONE: - break; - } -} - /* * Handle rule delete notification from kernel. */ diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 1e025bab64..ef93033661 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -64,6 +64,15 @@ struct zebra_pbr_rule { * * This is a filter mapped on ipset entries */ +struct zebra_pbr_ipset_info { + /* type is encoded as uint32_t + * but value is an enum ipset_type + */ + uint32_t type; + + char ipset_name[ZEBRA_IPSET_NAME_SIZE]; +}; + struct zebra_pbr_ipset { /* * Originating zclient sock fd, so we can know who to send @@ -85,6 +94,7 @@ struct zebra_pbr_ipset { char ipset_name[ZEBRA_IPSET_NAME_SIZE]; }; + /* * An IPSet Entry Filter * @@ -178,6 +188,8 @@ void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset); void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable); void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable); void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx); +void zebra_pbr_process_ipset(struct zebra_dplane_ctx *ctx); +void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx *ctx); /* * Get to know existing PBR rules in the kernel - typically called at startup. diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index b6303485fa..128edd9fd3 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3889,6 +3889,10 @@ static int rib_process_dplane_results(struct thread *thread) case DPLANE_OP_RULE_UPDATE: case DPLANE_OP_IPTABLE_ADD: case DPLANE_OP_IPTABLE_DELETE: + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: zebra_pbr_dplane_result(ctx); break; -- 2.39.5