diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index bc74babd19..44ee8d9469 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -463,6 +463,46 @@ uint32_t kernel_get_speed(struct interface *ifp, int *error) return get_iflink_speed(ifp, error); } +static ssize_t +netlink_gre_set_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, + size_t buflen) +{ + struct { + struct nlmsghdr n; + struct ifinfomsg ifi; + char buf[]; + } *req = buf; + uint32_t link_idx; + struct rtattr *rta_info, *rta_data; + + if (buflen < sizeof(*req)) + return 0; + memset(req, 0, sizeof(*req)); + + req->n.nlmsg_type = RTM_NEWLINK; + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req->n.nlmsg_flags = NLM_F_REQUEST; + + req->ifi.ifi_index = dplane_ctx_get_ifindex(ctx); + req->ifi.ifi_change = 0xFFFFFFFF; + link_idx = dplane_ctx_gre_get_link_ifindex(ctx); + + rta_info = nl_attr_nest(&req->n, buflen, IFLA_LINKINFO); + if (!rta_info) + return 0; + if (!nl_attr_put(&req->n, buflen, IFLA_INFO_KIND, "gre", 3)) + return 0; + rta_data = nl_attr_nest(&req->n, buflen, IFLA_INFO_DATA); + if (!rta_info) + return 0; + if (!nl_attr_put32(&req->n, buflen, IFLA_GRE_LINK, link_idx)) + return 0; + nl_attr_nest_end(&req->n, rta_data); + nl_attr_nest_end(&req->n, rta_info); + + return NLMSG_ALIGN(req->n.nlmsg_len); +} + static int netlink_extract_bridge_info(struct rtattr *link_data, struct zebra_l2info_bridge *bridge_info) { @@ -524,9 +564,13 @@ static int netlink_extract_gre_info(struct rtattr *link_data, if (!attr[IFLA_GRE_LINK]) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("IFLA_GRE_LINK missing from GRE IF message"); - } else + } else { gre_info->ifindex_link = *(ifindex_t *)RTA_DATA(attr[IFLA_GRE_LINK]); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("IFLA_GRE_LINK obtained is %u", + gre_info->ifindex_link); + } if (attr[IFLA_GRE_IKEY]) gre_info->ikey = *(uint32_t *)RTA_DATA(attr[IFLA_GRE_IKEY]); if (attr[IFLA_GRE_OKEY]) @@ -986,6 +1030,20 @@ static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family, return netlink_request(netlink_cmd, &req); } +enum netlink_msg_status +netlink_put_gre_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) +{ + enum dplane_op_e op; + enum netlink_msg_status ret; + + op = dplane_ctx_get_op(ctx); + assert(op == DPLANE_OP_GRE_SET); + + ret = netlink_batch_add_msg(bth, ctx, netlink_gre_set_msg_encoder, false); + + return ret; +} + /* Interface lookup by netlink socket. */ int interface_lookup_netlink(struct zebra_ns *zns) { diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h index 0bbba81ca6..4f09b10b75 100644 --- a/zebra/if_netlink.h +++ b/zebra/if_netlink.h @@ -32,6 +32,9 @@ extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int interface_lookup_netlink(struct zebra_ns *zns); +extern enum netlink_msg_status +netlink_put_gre_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); + extern enum netlink_msg_status netlink_put_address_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index adb61023c1..cd22e95737 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1360,6 +1360,9 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_IPSET_ENTRY_DELETE: return FRR_NETLINK_ERROR; + case DPLANE_OP_GRE_SET: + return netlink_put_gre_set_msg(bth, ctx); + case DPLANE_OP_NONE: return FRR_NETLINK_ERROR; } diff --git a/zebra/rt.h b/zebra/rt.h index daaa926a7d..f79ddbe958 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -81,9 +81,6 @@ 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_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 d8405f277e..d2ec7da57c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -3890,14 +3890,6 @@ netlink_put_neigh_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) false); } -int kernel_configure_if_link(struct interface *ifp, - struct interface *link_ifp, - ns_id_t ns_id) -{ - /* TODO */ - return 0; -} - /* * 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 ada828d016..006513ac9e 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -394,12 +394,6 @@ enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx) return ZEBRA_DPLANE_REQUEST_SUCCESS; } -int kernel_configure_if_link(struct interface *ifp, struct interface *link_ifp, - ns_id_t ns_id) -{ - return 0; -} - extern int kernel_interface_set_master(struct interface *master, struct interface *slave) { diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index d36c6becd7..22a6bf496b 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -3435,22 +3435,40 @@ static inline void zebra_gre_source_set(ZAPI_HANDLER_ARGS) vrf_id_t link_vrf_id; struct interface *ifp; struct interface *ifp_link; - ns_id_t ns_id; vrf_id_t vrf_id = zvrf->vrf->vrf_id; + struct zebra_if *zif, *gre_zif; + struct zebra_l2info_gre *gre_info; s = msg; STREAM_GETL(s, idx); ifp = if_lookup_by_index(idx, vrf_id); STREAM_GETL(s, link_idx); STREAM_GETL(s, link_vrf_id); + ifp_link = if_lookup_by_index(link_idx, link_vrf_id); if (!ifp_link || !ifp) { zlog_warn("GRE (index %u, VRF %u) or GRE link interface (index %u, VRF %u) not found, when setting GRE params", idx, vrf_id, link_idx, link_vrf_id); return; } - ns_id = zvrf->zns->ns_id; - kernel_configure_if_link(ifp, ifp_link, ns_id); + + if (!IS_ZEBRA_IF_GRE(ifp)) + return; + + gre_zif = (struct zebra_if *)ifp->info; + zif = (struct zebra_if *)ifp_link->info; + if (!zif || !gre_zif) + return; + + gre_info = &zif->l2info.gre; + if (!gre_info) + return; + + /* if gre link already set */ + if (gre_zif->link && gre_zif->link == ifp_link) + return; + + dplane_gre_set(ifp, ifp_link); stream_failure: return; diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index c8ee8f9051..565ab821df 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -271,6 +271,9 @@ struct dplane_rule_info { struct dplane_ctx_rule old; }; +struct dplane_gre_ctx { + uint32_t link_ifindex; +}; /* * The context block used to exchange info about route updates across * the boundary between the zebra main context (and pthread) and the @@ -327,6 +330,7 @@ struct zebra_dplane_ctx { struct zebra_pbr_ipset_info info; } ipset_entry; struct dplane_neigh_table neightable; + struct dplane_gre_ctx gre; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -469,6 +473,9 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_neightable_in; _Atomic uint32_t dg_neightable_errors; + _Atomic uint32_t dg_gre_set_in; + _Atomic uint32_t dg_gre_set_errors; + /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -713,6 +720,9 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) } list_delete(&ctx->u.iptable.interface_name_list); } + break; + case DPLANE_OP_GRE_SET: + break; } } @@ -979,6 +989,10 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_NEIGH_TABLE_UPDATE: ret = "NEIGH_TABLE_UPDATE"; break; + + case DPLANE_OP_GRE_SET: + ret = "GRE_SET"; + break; } return ret; @@ -1772,6 +1786,15 @@ uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx) return ctx->u.neigh.update_flags; } +/* Accessor for GRE set */ +uint32_t +dplane_ctx_gre_get_link_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.gre.link_ifindex; +} + /* Accessors for PBR rule information */ int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx) { @@ -4125,6 +4148,67 @@ dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset) return ipset_entry_update_internal(DPLANE_OP_IPSET_ENTRY_DELETE, ipset); } +/* + * Common helper api for GRE set + */ +enum zebra_dplane_result +dplane_gre_set(struct interface *ifp, struct interface *ifp_link) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx; + enum dplane_op_e op = DPLANE_OP_GRE_SET; + int ret; + struct zebra_ns *zns; + + ctx = dplane_ctx_alloc(); + + if (!ifp) + return result; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("init dplane ctx %s: if %s link %s%s", + dplane_op2str(op), ifp->name, + ifp_link ? "set" : "unset", ifp_link ? + ifp_link->name : ""); + } + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + zns = zebra_ns_lookup(ifp->vrf_id); + if (!zns) + return result; + dplane_ctx_ns_init(ctx, zns, false); + + dplane_ctx_set_ifname(ctx, ifp->name); + ctx->zd_vrf_id = ifp->vrf_id; + ctx->zd_ifindex = ifp->ifindex; + if (ifp_link) + ctx->u.gre.link_ifindex = ifp_link->ifindex; + else + ctx->u.gre.link_ifindex = 0; + + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + /* Enqueue context for processing */ + ret = dplane_update_enqueue(ctx); + + /* Update counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_gre_set_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit( + &zdplane_info.dg_gre_set_errors, 1, + memory_order_relaxed); + if (ctx) + dplane_ctx_free(&ctx); + result = ZEBRA_DPLANE_REQUEST_FAILURE; + } + return result; +} + /* * Handler for 'show dplane' */ @@ -4234,6 +4318,13 @@ int dplane_show_helper(struct vty *vty, bool detailed) memory_order_relaxed); vty_out(vty, "Neighbor Table updates: %"PRIu64"\n", incoming); vty_out(vty, "Neighbor Table errors: %"PRIu64"\n", errs); + + incoming = atomic_load_explicit(&zdplane_info.dg_gre_set_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_gre_set_errors, + memory_order_relaxed); + vty_out(vty, "GRE set updates: %"PRIu64"\n", incoming); + vty_out(vty, "GRE set errors: %"PRIu64"\n", errs); return CMD_SUCCESS; } @@ -4680,6 +4771,12 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_ctx_get_ifname(ctx), family2str(dplane_ctx_neightable_get_family(ctx))); break; + case DPLANE_OP_GRE_SET: + zlog_debug("Dplane gre set op %s, ifp %s, link %u", + dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_ifname(ctx), + ctx->u.gre.link_ifindex); + break; } } @@ -4808,6 +4905,12 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) memory_order_relaxed); break; + case DPLANE_OP_GRE_SET: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_gre_set_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 8d51d93cd4..5df58e6e99 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -171,6 +171,7 @@ enum dplane_op_e { DPLANE_OP_NEIGH_IP_DELETE, DPLANE_OP_NEIGH_TABLE_UPDATE, + DPLANE_OP_GRE_SET, }; /* @@ -527,6 +528,10 @@ 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); +/* Accessor for GRE set */ +uint32_t +dplane_ctx_gre_get_link_ifindex(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); @@ -695,6 +700,12 @@ enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp, const uint32_t ucast_probes, const uint32_t mcast_probes); +/* + * Enqueue a GRE set + */ +enum zebra_dplane_result +dplane_gre_set(struct interface *ifp, struct interface *ifp_link); + /* Forward ref of zebra_pbr_rule */ struct zebra_pbr_rule; diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index fc0382a6cd..200a977a69 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -134,6 +134,7 @@ enum zebra_log_refs { EC_ZEBRA_DUPLICATE_NHG_MESSAGE, EC_ZEBRA_VRF_MISCONFIGURED, EC_ZEBRA_ES_CREATE, + EC_ZEBRA_GRE_SET_UPDATE, }; void zebra_error_init(void); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 47651318a4..6b40eae5b7 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2965,6 +2965,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_IPSET_ENTRY_ADD: case DPLANE_OP_IPSET_ENTRY_DELETE: case DPLANE_OP_NEIGH_TABLE_UPDATE: + case DPLANE_OP_GRE_SET: break; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index bdacd411bd..dbc5c77fd9 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -4062,6 +4062,7 @@ static int rib_process_dplane_results(struct thread *thread) case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NEIGH_TABLE_UPDATE: + case DPLANE_OP_GRE_SET: case DPLANE_OP_NONE: /* Don't expect this: just return the struct? */ dplane_ctx_fini(&ctx);