From 5162e00045e1fe5ee4acd34d9e507e54f668e1e0 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 16 Feb 2021 15:29:29 +0100 Subject: [PATCH 1/2] zebra: move iptable handling in zebra_dplane The iptable processing was not handled in remote dataplane, and was directly processed by the thread in charge of zapi calls. Now that call can be handled in the zebra_dplane separate thread. once a zebra_dplane_ctx is allocated for iptable handling, the hook call is performed later. Subsequently, a return code may be triggered to zclient interface if any problem occurs when calling the hook call. Signed-off-by: Philippe Guibert --- zebra/kernel_netlink.c | 4 + zebra/zapi_msg.c | 20 +++-- zebra/zapi_msg.h | 2 +- zebra/zebra_dplane.c | 166 ++++++++++++++++++++++++++++++++++++++++- zebra/zebra_dplane.h | 15 +++- zebra/zebra_nhg.c | 2 + zebra/zebra_pbr.c | 64 ++++++++-------- zebra/zebra_pbr.h | 4 +- zebra/zebra_rib.c | 2 + 9 files changed, 232 insertions(+), 47 deletions(-) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index c77a357e9f..8dd0c14d5d 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1350,6 +1350,10 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_BR_PORT_UPDATE: return FRR_NETLINK_SUCCESS; + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: + return FRR_NETLINK_ERROR; + case DPLANE_OP_NONE: return FRR_NETLINK_ERROR; } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 46171df848..92a11cc4bf 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -886,7 +886,7 @@ void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_IPSET_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->ipset_name, ZEBRA_IPSET_NAME_SIZE); @@ -924,18 +924,24 @@ void zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset, zserv_send_message(client, s); } -void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable, - enum zapi_iptable_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__, iptable->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 (iptable->sock == client->sock) + if (ipt.sock == client->sock) break; } @@ -944,9 +950,9 @@ void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable, s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_IPTABLE_NOTIFY_OWNER, VRF_DEFAULT); + zclient_create_header(s, cmd, VRF_DEFAULT); stream_put(s, ¬e, sizeof(note)); - stream_putl(s, iptable->unique); + stream_putl(s, ipt.unique); 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 c03278669a..2401db4d18 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -89,7 +89,7 @@ extern void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset, 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(struct zebra_pbr_iptable *iptable, +extern void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, enum zapi_iptable_notify_owner 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 b9b6b4af71..b9e6df2a7a 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -42,6 +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") #ifndef AOK # define AOK 0 @@ -307,6 +308,7 @@ struct zebra_dplane_ctx { struct dplane_mac_info macinfo; struct dplane_neigh_info neigh; struct dplane_rule_info rule; + struct zebra_pbr_iptable iptable; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -438,6 +440,8 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_update_yields; + _Atomic uint32_t dg_iptable_in; + _Atomic uint32_t dg_iptable_errors; /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -657,6 +661,23 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NONE: 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_IFACE, ifname); + } + list_delete(&ctx->u.iptable.interface_name_list); + } } } @@ -895,6 +916,13 @@ 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; } return ret; @@ -1843,6 +1871,17 @@ 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; +} + /* * End of dplane context accessors */ @@ -2398,6 +2437,52 @@ 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_IFACE, ifname)); + } + } + return AOK; +} + /* * Enqueue a new update, * and ensure an event is active for the dataplane pthread. @@ -3608,6 +3693,50 @@ 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); +} /* * Handler for 'show dplane' @@ -3693,6 +3822,12 @@ 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); return CMD_SUCCESS; } @@ -4103,6 +4238,15 @@ 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; } } @@ -4199,6 +4343,14 @@ 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; + /* Ignore 'notifications' - no-op */ case DPLANE_OP_SYS_ROUTE_ADD: case DPLANE_OP_SYS_ROUTE_DELETE: @@ -4215,6 +4367,13 @@ 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); +} + /* * Kernel provider callback */ @@ -4236,11 +4395,14 @@ 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 + TAILQ_INSERT_TAIL(&work_list, ctx, zd_q_entries); } kernel_update_multi(&work_list); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index f3ab1058a5..3416c62b84 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -155,6 +155,10 @@ enum dplane_op_e { /* bridge port update */ DPLANE_OP_BR_PORT_UPDATE, + + /* Policy based routing rule update */ + DPLANE_OP_IPTABLE_ADD, + DPLANE_OP_IPTABLE_DELETE, }; /* @@ -475,7 +479,11 @@ const struct prefix * dplane_ctx_rule_get_dst_ip(const struct zebra_dplane_ctx *ctx); const struct prefix * dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx); - +/* Accessors for policy based routing iptable information */ +struct zebra_pbr_iptable; +bool +dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_iptable *table); /* Accessors for bridge port information */ uint32_t dplane_ctx_get_br_port_flags(const struct zebra_dplane_ctx *ctx); uint32_t @@ -648,6 +656,11 @@ enum zebra_dplane_result dplane_pbr_rule_delete(struct zebra_pbr_rule *rule); enum zebra_dplane_result dplane_pbr_rule_update(struct zebra_pbr_rule *old_rule, struct zebra_pbr_rule *new_rule); +/* iptable */ +enum zebra_dplane_result +dplane_pbr_iptable_add(struct zebra_pbr_iptable *iptable); +enum zebra_dplane_result +dplane_pbr_iptable_delete(struct zebra_pbr_iptable *iptable); /* Encode route information into data plane context. */ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 2864b96c83..3fafa19a70 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2715,6 +2715,8 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NONE: + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: break; } diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 87ab900092..51c3bd9fdd 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -542,6 +542,25 @@ void zebra_pbr_del_rule(struct zebra_pbr_rule *rule) __func__); } +void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx) +{ + int mode, ret = 0; + struct zebra_pbr_iptable ipt; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD) + mode = 1; + else + mode = 0; + + 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); + } + if (!ret) + 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; @@ -761,13 +780,8 @@ static void *pbr_iptable_alloc_intern(void *arg) void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable) { - int ret; - (void)hash_get(zrouter.iptable_hash, iptable, pbr_iptable_alloc_intern); - ret = hook_call(zebra_pbr_iptable_update, 1, iptable); - kernel_pbr_iptable_add_del_status(iptable, - ret ? ZEBRA_DPLANE_INSTALL_SUCCESS - : ZEBRA_DPLANE_INSTALL_FAILURE); + (void)dplane_pbr_iptable_add(iptable); } void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable) @@ -775,7 +789,7 @@ void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable) struct zebra_pbr_iptable *lookup; lookup = hash_lookup(zrouter.iptable_hash, iptable); - hook_call(zebra_pbr_iptable_update, 0, iptable); + (void)dplane_pbr_iptable_delete(iptable); if (lookup) { struct listnode *node, *nnode; char *name; @@ -812,6 +826,16 @@ void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx) zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS ? ZAPI_RULE_REMOVED : ZAPI_RULE_FAIL_REMOVE); + else if (op == DPLANE_OP_IPTABLE_ADD) + zsend_iptable_notify_owner(ctx, + res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPTABLE_INSTALLED + : ZAPI_IPTABLE_FAIL_INSTALL); + else if (op == DPLANE_OP_IPTABLE_DELETE) + zsend_iptable_notify_owner(ctx, + res == ZEBRA_DPLANE_REQUEST_SUCCESS + ? ZAPI_IPTABLE_REMOVED + : ZAPI_IPTABLE_FAIL_REMOVE); else flog_err( EC_ZEBRA_PBR_RULE_UPDATE, @@ -875,32 +899,6 @@ void kernel_pbr_ipset_entry_add_del_status( } } -/* - * Handle success or failure of ipset (un)install in the kernel. - */ -void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable, - enum zebra_dplane_status res) -{ - switch (res) { - case ZEBRA_DPLANE_INSTALL_SUCCESS: - zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED); - break; - case ZEBRA_DPLANE_INSTALL_FAILURE: - zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL); - break; - case ZEBRA_DPLANE_DELETE_SUCCESS: - zsend_iptable_notify_owner(iptable, - ZAPI_IPTABLE_REMOVED); - break; - case ZEBRA_DPLANE_DELETE_FAILURE: - zsend_iptable_notify_owner(iptable, - ZAPI_IPTABLE_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 e7504a3547..1e025bab64 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -177,6 +177,7 @@ 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); /* * Get to know existing PBR rules in the kernel - typically called at startup. @@ -198,9 +199,6 @@ extern void kernel_pbr_ipset_entry_add_del_status( struct zebra_pbr_ipset_entry *ipset, enum zebra_dplane_status res); -extern void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable, - enum zebra_dplane_status res); - /* * Handle rule delete notification from kernel. */ diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c5d977017e..b6303485fa 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3887,6 +3887,8 @@ static int rib_process_dplane_results(struct thread *thread) case DPLANE_OP_RULE_ADD: case DPLANE_OP_RULE_DELETE: case DPLANE_OP_RULE_UPDATE: + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: zebra_pbr_dplane_result(ctx); break; From ef524230a6baa5dd5dd337d723d47fe984d3e304 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 17 Feb 2021 11:43:52 +0100 Subject: [PATCH 2/2] 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 | 131 ++++++++++-------- 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, 503 insertions(+), 145 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,64 +866,6 @@ 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) -{ - struct listnode *node; - struct zserv *client; - struct stream *s; - - if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s: Notifying %u", __func__, ipset->unique); - - for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { - if (ipset->sock == client->sock) - break; - } - - if (!client) - return; - - s = stream_new(ZEBRA_MAX_PACKET_SIZ); - - 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_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) -{ - struct listnode *node; - struct zserv *client; - struct stream *s; - - if (IS_ZEBRA_DEBUG_PACKET) - zlog_debug("%s: Notifying %u", __func__, ipset->unique); - - for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { - if (ipset->sock == client->sock) - break; - } - - if (!client) - return; - - s = stream_new(ZEBRA_MAX_PACKET_SIZ); - - zclient_create_header(s, ZEBRA_IPSET_ENTRY_NOTIFY_OWNER, 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_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) { @@ -953,6 +895,79 @@ 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_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_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 %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) + break; + } + + if (!client) + return; + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + 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_putw_at(s, 0, stream_get_endp(s)); + + zserv_send_message(client, s); +} + +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_ipset_entry ipent; + struct zebra_pbr_ipset ipset; + uint16_t cmd = ZEBRA_IPSET_ENTRY_NOTIFY_OWNER; + + 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), ipent.unique, note); + + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) { + if (ipent.sock == client->sock) + break; + } + + if (!client) + return; + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, cmd, VRF_DEFAULT); + stream_put(s, ¬e, sizeof(note)); + 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;