From e18747a9676baf559b244434c0119ada19c4021e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 26 Feb 2021 10:04:25 +0100 Subject: [PATCH] zebra: move neighbor table configuration to dplane contexts Instead of directly configuring the neighbor table after read from zapi interface, a zebra dplane context is prepared to host the interface and the family where the neighbor table is updated. Also, some other fields are hosted: app_probes, ucast_probes, and mcast_probes. More information on those fields can be found on ip-ntable configuration. Signed-off-by: Philippe Guibert --- zebra/kernel_netlink.c | 1 + zebra/rt.h | 4 +- zebra/rt_netlink.c | 102 ++++++++++++++++----------------- zebra/rt_socket.c | 3 +- zebra/zapi_msg.c | 6 +- zebra/zebra_dplane.c | 127 +++++++++++++++++++++++++++++++++++++++++ zebra/zebra_dplane.h | 20 +++++++ zebra/zebra_nhg.c | 1 + zebra/zebra_rib.c | 1 + 9 files changed, 207 insertions(+), 58 deletions(-) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 8086021621..adb61023c1 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1337,6 +1337,7 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_NEIGH_IP_INSTALL: case DPLANE_OP_NEIGH_IP_DELETE: + case DPLANE_OP_NEIGH_TABLE_UPDATE: return netlink_put_neigh_update_msg(bth, ctx); case DPLANE_OP_RULE_ADD: diff --git a/zebra/rt.h b/zebra/rt.h index 01d3246164..daaa926a7d 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -81,7 +81,9 @@ extern int mpls_kernel_init(void); extern uint32_t kernel_get_speed(struct interface *ifp, int *error); extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); -extern int kernel_configure_arp(struct interface *ifp, int family, ns_id_t ns_id); +extern int kernel_configure_if_link(struct interface *ifp, + struct interface *link_ifp, ns_id_t ns_id); + /* * Southbound Initialization routines to get initial starting * state. diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 97122668dc..b641d07000 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1542,52 +1542,6 @@ static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) routedesc, nl_msg_type_to_str(cmd), label); } -static int netlink_configure_arp(struct interface *ifp, int family, ns_id_t ns_id) -{ - struct { - struct nlmsghdr n; - struct ndtmsg ndtm; - char buf[256]; - } req; - struct zebra_ns *zns = zebra_ns_lookup(ns_id); - struct rtattr *nest; - uint32_t val; - - memset(&req, 0, sizeof(req)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE; - req.n.nlmsg_type = RTM_SETNEIGHTBL; - req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; - - req.ndtm.ndtm_family = family; - - nl_attr_put(&req.n, sizeof(req), NDTA_NAME, family == AF_INET ? "arp_cache" : - "ndisc_cache", 10); - - nest = nl_attr_nest(&req.n, sizeof(req), NDTA_PARMS); - if (nest == NULL) - return; - if (!nl_attr_put(&req.n, sizeof(req), NDTPA_IFINDEX, &ifp->ifindex, - sizeof(ifp->ifindex))) - return 0; - val = 1; - if (!nl_attr_put(&req.n, sizeof(req), NDTPA_APP_PROBES, &val, - sizeof(val))) - return 0; - val = 0; - if (!nl_attr_put(&req.n, sizeof(req), NDTPA_MCAST_PROBES, &val, - sizeof(val))) - return 0; - if (!nl_attr_put(&req.n, sizeof(req), NDTPA_UCAST_PROBES, &val, - sizeof(val))) - return 0; - nl_attr_nest_end(&req.n, nest); - - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - 0); -} - static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla, int llalen, ns_id_t ns_id, uint8_t family, bool permanent, uint8_t protocol) @@ -3817,6 +3771,53 @@ static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, ext_flags, buf, buflen, zebra2proto(dplane_ctx_get_type(ctx))); } +static int netlink_neigh_table_update_ctx(const struct zebra_dplane_ctx *ctx, + void *data, size_t datalen) +{ + struct { + struct nlmsghdr n; + struct ndtmsg ndtm; + char buf[]; + } *req = data; + struct rtattr *nest; + uint8_t family; + ifindex_t idx; + uint32_t val; + + if (datalen < sizeof(*req)) + return 0; + memset(req, 0, sizeof(*req)); + family = dplane_ctx_neightable_get_family(ctx); + idx = dplane_ctx_get_ifindex(ctx); + + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)); + req->n.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE; + req->n.nlmsg_type = RTM_SETNEIGHTBL; + req->ndtm.ndtm_family = family; + + nl_attr_put(&req->n, datalen, NDTA_NAME, + family == AF_INET ? "arp_cache" : "ndisc_cache", 10); + nest = nl_attr_nest(&req->n, datalen, NDTA_PARMS); + if (nest == NULL) + return 0; + if (!nl_attr_put(&req->n, datalen, NDTPA_IFINDEX, &idx, sizeof(idx))) + return 0; + val = dplane_ctx_neightable_get_app_probes(ctx); + if (!nl_attr_put(&req->n, datalen, NDTPA_APP_PROBES, &val, sizeof(val))) + return 0; + val = dplane_ctx_neightable_get_mcast_probes(ctx); + if (!nl_attr_put(&req->n, datalen, NDTPA_MCAST_PROBES, &val, + sizeof(val))) + return 0; + val = dplane_ctx_neightable_get_ucast_probes(ctx); + if (!nl_attr_put(&req->n, datalen, NDTPA_UCAST_PROBES, &val, + sizeof(val))) + return 0; + nl_attr_nest_end(&req->n, nest); + + return NLMSG_ALIGN(req->n.nlmsg_len); +} + static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, size_t buflen) { @@ -3841,6 +3842,9 @@ static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx, ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf, buflen); break; + case DPLANE_OP_NEIGH_TABLE_UPDATE: + ret = netlink_neigh_table_update_ctx(ctx, buf, buflen); + break; default: ret = -1; } @@ -3866,12 +3870,6 @@ netlink_put_neigh_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) false); } -int kernel_configure_arp(struct interface *ifp, int family, - ns_id_t ns_id) -{ - return netlink_configure_arp(ifp, family, ns_id); -} - /* * MPLS label forwarding table change via netlink interface, using dataplane * context information. diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index cbbc9b28fb..ada828d016 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -394,7 +394,8 @@ enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx) return ZEBRA_DPLANE_REQUEST_SUCCESS; } -int kernel_configure_arp(struct interface *ifp, int family, ns_id_t ns_id) +int kernel_configure_if_link(struct interface *ifp, struct interface *link_ifp, + ns_id_t ns_id) { return 0; } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 8898235a33..46e4766e97 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -3282,10 +3282,9 @@ stream_failure: static inline void zebra_configure_arp(ZAPI_HANDLER_ARGS) { struct stream *s; - int fam; + uint8_t fam; ifindex_t idx; struct interface *ifp; - ns_id_t ns_id; s = msg; STREAM_GETC(s, fam); @@ -3295,8 +3294,7 @@ static inline void zebra_configure_arp(ZAPI_HANDLER_ARGS) ifp = if_lookup_by_index_per_ns(zvrf->zns, idx); if (!ifp) return; - ns_id = zvrf->zns->ns_id; - kernel_configure_arp(ifp, fam, ns_id); + dplane_neigh_table_update(ifp, fam, 1, 0, 0); stream_failure: return; } diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 44330b785c..8186ab98a5 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -229,6 +229,16 @@ struct dplane_neigh_info { uint32_t update_flags; }; +/* + * Neighbor Table + */ +struct dplane_neigh_table { + uint8_t family; + uint32_t app_probes; + uint32_t ucast_probes; + uint32_t mcast_probes; +}; + /* * Policy based routing rule info for the dataplane */ @@ -316,6 +326,7 @@ struct zebra_dplane_ctx { struct zebra_pbr_ipset_entry entry; struct zebra_pbr_ipset_info info; } ipset_entry; + struct dplane_neigh_table neightable; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -455,6 +466,9 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_ipset_entry_in; _Atomic uint32_t dg_ipset_entry_errors; + _Atomic uint32_t dg_neightable_in; + _Atomic uint32_t dg_neightable_errors; + /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -681,6 +695,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_IPSET_ENTRY_ADD: case DPLANE_OP_IPSET_ENTRY_DELETE: break; + case DPLANE_OP_NEIGH_TABLE_UPDATE: + break; case DPLANE_OP_IPTABLE_ADD: case DPLANE_OP_IPTABLE_DELETE: if (ctx->u.iptable.interface_name_list) { @@ -960,6 +976,9 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_NEIGH_IP_DELETE: ret = "NEIGH_IP_DELETE"; break; + case DPLANE_OP_NEIGH_TABLE_UPDATE: + ret = "NEIGH_TABLE_UPDATE"; + break; } return ret; @@ -1995,6 +2014,37 @@ uint32_t dplane_intf_extra_get_status(const struct dplane_intf_extra *ptr) return ptr->status; } +uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.neightable.family; +} + +uint32_t +dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.neightable.app_probes; +} + +uint32_t +dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.neightable.ucast_probes; +} + +uint32_t +dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.neightable.mcast_probes; +} + /* * End of interface extra info accessors */ @@ -3759,6 +3809,62 @@ enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp, return result; } +enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp, + const uint8_t family, + const uint32_t app_probes, + const uint32_t ucast_probes, + const uint32_t mcast_probes) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + int ret; + struct zebra_dplane_ctx *ctx = NULL; + struct zebra_ns *zns; + enum dplane_op_e op = DPLANE_OP_NEIGH_TABLE_UPDATE; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("set neigh ctx %s: ifp %s, family %s", + dplane_op2str(op), ifp->name, family2str(family)); + } + + ctx = dplane_ctx_alloc(); + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + ctx->zd_vrf_id = ifp->vrf_id; + + zns = zebra_ns_lookup(ifp->vrf_id); + dplane_ctx_ns_init(ctx, zns, false); + + strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname)); + ctx->zd_ifindex = ifp->ifindex; + + /* Init the neighbor-specific data area */ + memset(&ctx->u.neightable, 0, sizeof(ctx->u.neightable)); + + ctx->u.neightable.family = family; + ctx->u.neightable.app_probes = app_probes; + ctx->u.neightable.ucast_probes = ucast_probes; + ctx->u.neightable.mcast_probes = mcast_probes; + + /* Enqueue for processing on the dplane pthread */ + ret = dplane_update_enqueue(ctx); + + /* Increment counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_neightable_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + /* Error counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_neightable_errors, 1, + memory_order_relaxed); + dplane_ctx_free(&ctx); + } + + return result; +} + /* * Common helper api for neighbor updates */ @@ -4124,6 +4230,13 @@ int dplane_show_helper(struct vty *vty, bool detailed) memory_order_relaxed); vty_out(vty, "IPset entry updates: %" PRIu64 "\n", incoming); vty_out(vty, "IPset entry errors: %" PRIu64 "\n", errs); + + incoming = atomic_load_explicit(&zdplane_info.dg_neightable_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_neightable_errors, + memory_order_relaxed); + vty_out(vty, "Neighbor Table updates: %"PRIu64"\n", incoming); + vty_out(vty, "Neighbor Table errors: %"PRIu64"\n", errs); return CMD_SUCCESS; } @@ -4563,6 +4676,13 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_op2str(dplane_ctx_get_op(ctx)), ipent.unique, ctx); } break; + + case DPLANE_OP_NEIGH_TABLE_UPDATE: + zlog_debug("Dplane neigh table op %s, ifp %s, family %s", + dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_ifname(ctx), + family2str(dplane_ctx_neightable_get_family(ctx))); + break; } } @@ -4684,6 +4804,13 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) memory_order_relaxed); break; + case DPLANE_OP_NEIGH_TABLE_UPDATE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_neightable_errors, 1, + memory_order_relaxed); + break; + /* Ignore 'notifications' - no-op */ case DPLANE_OP_SYS_ROUTE_ADD: case DPLANE_OP_SYS_ROUTE_DELETE: diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index fb5d4225e8..c678706354 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -169,6 +169,8 @@ enum dplane_op_e { /* LINK LAYER IP address update */ DPLANE_OP_NEIGH_IP_INSTALL, DPLANE_OP_NEIGH_IP_DELETE, + + DPLANE_OP_NEIGH_TABLE_UPDATE, }; /* @@ -516,6 +518,15 @@ dplane_ctx_get_br_port_sph_filters(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx); +/* Accessors for neighbor table information */ +uint8_t dplane_ctx_neightable_get_family(const struct zebra_dplane_ctx *ctx); +uint32_t +dplane_ctx_neightable_get_app_probes(const struct zebra_dplane_ctx *ctx); +uint32_t +dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx); +uint32_t +dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx); + /* Namespace info - esp. for netlink communication */ const struct zebra_dplane_info *dplane_ctx_get_ns( const struct zebra_dplane_ctx *ctx); @@ -674,6 +685,15 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp, enum zebra_dplane_result dplane_neigh_discover(const struct interface *ifp, const struct ipaddr *ip); +/* + * Enqueue a neighbor table parameter set + */ +enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp, + const uint8_t family, + const uint32_t app_probes, + const uint32_t ucast_probes, + const uint32_t mcast_probes); + /* Forward ref of zebra_pbr_rule */ struct zebra_pbr_rule; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 4ed4bc9ba7..7edf022892 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2914,6 +2914,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_IPSET_DELETE: case DPLANE_OP_IPSET_ENTRY_ADD: case DPLANE_OP_IPSET_ENTRY_DELETE: + case DPLANE_OP_NEIGH_TABLE_UPDATE: break; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 807c9f0e81..11bc0a2c90 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -3931,6 +3931,7 @@ static int rib_process_dplane_results(struct thread *thread) case DPLANE_OP_VTEP_DELETE: case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_BR_PORT_UPDATE: + case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_NONE: /* Don't expect this: just return the struct? */ dplane_ctx_fini(&ctx); -- 2.39.5