]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: new dplane action to set gre link interface
authorPhilippe Guibert <philippe.guibert@6wind.com>
Thu, 11 Mar 2021 14:33:41 +0000 (15:33 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 30 Apr 2021 08:33:18 +0000 (10:33 +0200)
This action is initiated by nhrp and has been stubbed when
moving to zebra. Now, a netlink request is forged to set
the link interface of a gre interface if that gre interface
does not have already a link interface.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
12 files changed:
zebra/if_netlink.c
zebra/if_netlink.h
zebra/kernel_netlink.c
zebra/rt.h
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/zapi_msg.c
zebra/zebra_dplane.c
zebra/zebra_dplane.h
zebra/zebra_errors.h
zebra/zebra_nhg.c
zebra/zebra_rib.c

index bc74babd19bf1fd4a64d287e3995b2184ae469c1..44ee8d94692ec9922029d814a45154489a861967 100644 (file)
@@ -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)
 {
index 0bbba81ca6f96845c41ece361e95995d5ede3fdc..4f09b10b755f285f51269c16084ded384ef95fd5 100644 (file)
@@ -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);
index adb61023c1f11b0b564baeee4f0dabe42c71b0f9..cd22e95737b1e0da1e16c8ff446a980b270ce800 100644 (file)
@@ -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;
        }
index daaa926a7dc2834617fcacb4be45d1584c35477d..f79ddbe95837f969b48a6c299aceb24357b9c883 100644 (file)
@@ -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.
index d8405f277e83ff7889b9c57fd68c274d0b2936b0..d2ec7da57cc13df091bfa51523eca862f256147f 100644 (file)
@@ -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.
index ada828d01688879aa0c2bb8b4adb6639cc81996d..006513ac9efbc34bfbfab3f2a2f53b324db3c398 100644 (file)
@@ -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)
 {
index d36c6becd783371c506c712d1040e7944dcf01f1..22a6bf496b1d6fb271d3af1ce1ebce7131a6d4c0 100644 (file)
@@ -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;
index c8ee8f9051223ddce792441f1291209229c2d8f1..565ab821dfa46e20d017e1c22f31a78d837207c8 100644 (file)
@@ -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:
index 8d51d93cd4bfcd8ac4ad0e1b6aee61ecf47f5eba..5df58e6e993716bb47b66a4dbb6a3accfd5f351a 100644 (file)
@@ -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;
 
index fc0382a6cdaedbf72f2ecf4897f131267522336c..200a977a69f99a4dd9cc95a60e1ccd94dec4ff34 100644 (file)
@@ -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);
index 47651318a413698b498b49bd0c0da5374fe30770..6b40eae5b7d4cfb2ff836741cf413420fc25cda0 100644 (file)
@@ -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;
        }
 
index bdacd411bd9ac7ff35077d4b9abfd1303d87fe1c..dbc5c77fd99b68a21a2d99f6c5a730fcf5a2e24a 100644 (file)
@@ -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);