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 c77a357e9f..aa19b18089 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1350,6 +1350,14 @@ 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: + 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: return FRR_NETLINK_ERROR; } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 46171df848..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; } @@ -886,27 +892,32 @@ 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); + 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,27 +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(struct zebra_pbr_iptable *iptable, - enum zapi_iptable_notify_owner 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_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 %u", __func__, iptable->unique); + 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 (iptable->sock == client->sock) + if (ipent.sock == client->sock) break; } @@ -944,9 +964,10 @@ 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, 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 c03278669a..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(struct zebra_pbr_iptable *iptable, - enum zapi_iptable_notify_owner note); + +extern void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, + 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 b9b6b4af71..82546ce188 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_NETFILTER, "Zebra Netfilter Internal Object") #ifndef AOK # define AOK 0 @@ -307,6 +308,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 +445,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 +671,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 +932,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 +1899,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 +2494,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. @@ -3608,6 +3824,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' @@ -3693,6 +4042,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; } @@ -4103,6 +4470,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; } } @@ -4199,6 +4593,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: @@ -4215,6 +4632,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 */ @@ -4236,11 +4675,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); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index f3ab1058a5..4913ca251f 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -155,6 +155,16 @@ enum dplane_op_e { /* bridge port update */ DPLANE_OP_BR_PORT_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, }; /* @@ -475,7 +485,19 @@ 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); +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 @@ -648,6 +670,23 @@ 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); + +/* 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, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 2864b96c83..3f567d9a70 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2715,6 +2715,12 @@ 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: + 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 87ab900092..92a7a0ba3a 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -542,6 +542,69 @@ 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); +} + +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; @@ -632,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) @@ -646,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); @@ -711,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) @@ -726,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); @@ -761,13 +814,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 +823,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 +860,36 @@ 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 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, @@ -822,85 +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 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..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 * @@ -177,6 +187,9 @@ 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. @@ -198,9 +211,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..128edd9fd3 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3887,6 +3887,12 @@ 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: + 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;