From patchwork Tue Aug 23 15:45:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eyal Birger X-Patchwork-Id: 12952429 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BE454C32789 for ; Tue, 23 Aug 2022 17:49:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232418AbiHWRtY (ORCPT ); Tue, 23 Aug 2022 13:49:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51514 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232550AbiHWRsi (ORCPT ); Tue, 23 Aug 2022 13:48:38 -0400 Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D9995B08A0; Tue, 23 Aug 2022 08:46:15 -0700 (PDT) Received: by mail-wm1-x332.google.com with SMTP id n23-20020a7bc5d7000000b003a62f19b453so6753443wmk.3; Tue, 23 Aug 2022 08:46:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=tQE4ydUcPxwbxO0avKpHsCIS7vpKuEprui+Ow5s46Bk=; b=pQtzpA+URTbCbEVwWRkaXnaIaFQEMCqVzb77ZpaHZ5y0OBYh7sbB/H9twQEoCdO9f5 mcNSHak+jPjUTin+aJYAl5p6UGwMprC6QWZd7wGKtBq2UBEXQXU0Q/d6Cu5GSx8KBfXq qos/bXKSj3rxu0/2V/5dQqVg3/jGCM+FEkVSEca439Vuhs57S0pk/h/NvfmVWR57ntwL BuhMNUbYhvpgwsD4H2lY59HAo9JRU3ytD4hQVLGr8dsdV9RPfohYlxX3ux+7bGrYvc+n rVEb7/rhV+JK8EFwn8RuZ1G38PgGEoduXK7yQ0U+T+Z76g4kBv8oSuc2SplROalWWuar oLkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=tQE4ydUcPxwbxO0avKpHsCIS7vpKuEprui+Ow5s46Bk=; b=H1AvWixeH30LcMtOa7vVHqLORqVKYO6i+y7BqAyIiDPYfb05HLpWOkGegju5XXYLl/ ZmcEb/dkksajpx6kFgv0paWEl+y8xkNxKacqOkegWPHurlIGy5fg7p1UifQ4NS5XVhZg aIuM7d77ZG23uXJ5LfK5Bc+9957IELYki5DWtyna38ehw6CuJ2LYZvyYWMi1jeMbhIEl BmD541+dgKOV7618NMZE47JHhB4YXAQ0pNuXL43Y6g0SnaoGqM3iu3CFqDMT37qTdaMo y5MyWcbojMqnMSEQLoEMqGpYTA6fvMaB9T6CcifKyJFJyjb2bhDTWGcEeCGrbYClE4yZ bZKg== X-Gm-Message-State: ACgBeo3035zcMnSE1CoyCwjnMUjo5FC6MTE72ZUOIbjzpfTSpQ29INSL t2eyqHJQXQVww8n8HQAlmcKJvjOkn+46AA== X-Google-Smtp-Source: AA6agR6dYJzdWDrLD9RAi5VIyK1sGEMhDxiY3xdoWlun3UxW3xK6lKzCzabGa/k4mtlngmdd9X1R8w== X-Received: by 2002:a05:600c:490:b0:3a5:a6aa:bf2f with SMTP id d16-20020a05600c049000b003a5a6aabf2fmr2618427wme.17.1661269574152; Tue, 23 Aug 2022 08:46:14 -0700 (PDT) Received: from jimi.localdomain ([213.57.189.88]) by smtp.gmail.com with ESMTPSA id i26-20020a1c541a000000b003a64f684704sm11341211wmb.40.2022.08.23.08.46.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Aug 2022 08:46:13 -0700 (PDT) From: Eyal Birger To: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, steffen.klassert@secunet.com, herbert@gondor.apana.org.au, pablo@netfilter.org, contact@proelbtn.com, dsahern@kernel.org Cc: netdev@vger.kernel.org, bpf@vger.kernel.org, devel@linux-ipsec.org, Eyal Birger Subject: [PATCH ipsec-next 1/3] net: allow storing xfrm interface metadata in metadata_dst Date: Tue, 23 Aug 2022 18:45:55 +0300 Message-Id: <20220823154557.1400380-2-eyal.birger@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220823154557.1400380-1-eyal.birger@gmail.com> References: <20220823154557.1400380-1-eyal.birger@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org XFRM interfaces provide the association of various XFRM transformations to a netdevice using an 'if_id' identifier common to both the XFRM data structures (polcies, states) and the interface. The if_id is configured by the controlling entity (usually the IKE daemon) and can be used by the administrator to define logical relations between different connections. For example, different connections can share the if_id identifier so that they pass through the same interface, . However, currently it is not possible for connections using a different if_id to use the same interface while retaining the logical separation between them, without using additional criteria such as skb marks or different traffic selectors. When having a large number of connections, it is useful to have a the logical separation offered by the if_id identifier but use a single network interface. Similar to the way collect_md mode is used in IP tunnels. This patch attempts to enable different configuration mechanisms - such as ebpf programs, LWT encapsulations, and TC - to attach metadata to skbs which would carry the if_id. This way a single xfrm interface in collect_md mode can demux traffic based on this configuration on tx and provide this metadata on rx. The XFRM metadata is somewhat similar to ip tunnel metadata in that it has an "id", and shares similar configuration entities (bpf, tc, ...), however, it does not use other ip tunnel information, and may have additional xfrm related criteria added to it in the future, and it also does not necessarily represent a tunnel as XFRM interfaces support other modes of operation. Therefore, a new metadata type is introduced, to be used in subsequent patches in the xfrm interface and configuration entities. Signed-off-by: Eyal Birger --- include/net/dst_metadata.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index adab27ba1ecb..7e13210b868f 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -9,6 +9,7 @@ enum metadata_type { METADATA_IP_TUNNEL, METADATA_HW_PORT_MUX, + METADATA_XFRM, }; struct hw_port_info { @@ -16,12 +17,17 @@ struct hw_port_info { u32 port_id; }; +struct xfrm_md_info { + u32 if_id; +}; + struct metadata_dst { struct dst_entry dst; enum metadata_type type; union { struct ip_tunnel_info tun_info; struct hw_port_info port_info; + struct xfrm_md_info xfrm_info; } u; }; @@ -53,6 +59,16 @@ skb_tunnel_info(const struct sk_buff *skb) return NULL; } +static inline struct xfrm_md_info *skb_xfrm_md_info(const struct sk_buff *skb) +{ + struct metadata_dst *md_dst = skb_metadata_dst(skb); + + if (md_dst && md_dst->type == METADATA_XFRM) + return &md_dst->u.xfrm_info; + + return NULL; +} + static inline bool skb_valid_dst(const struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); @@ -82,6 +98,9 @@ static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a, return memcmp(&a->u.tun_info, &b->u.tun_info, sizeof(a->u.tun_info) + a->u.tun_info.options_len); + case METADATA_XFRM: + return memcmp(&a->u.xfrm_info, &b->u.xfrm_info, + sizeof(a->u.xfrm_info)); default: return 1; } From patchwork Tue Aug 23 15:45:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eyal Birger X-Patchwork-Id: 12952431 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 70295C32774 for ; Tue, 23 Aug 2022 17:49:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232464AbiHWRt0 (ORCPT ); Tue, 23 Aug 2022 13:49:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51572 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232587AbiHWRsj (ORCPT ); Tue, 23 Aug 2022 13:48:39 -0400 Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D3A5696DB; Tue, 23 Aug 2022 08:46:22 -0700 (PDT) Received: by mail-wm1-x32e.google.com with SMTP id ay39-20020a05600c1e2700b003a5503a80cfso7967203wmb.2; Tue, 23 Aug 2022 08:46:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=tPKbavRdFK/u4df00oalSVINqAUAigsKU5d+68m+1Sk=; b=SQmbkDxJ7HyLRW/K86ANeowpoVGKXj+lYHQ96bxkrFdAYzVV3Brsoby7pMQ3PAMuOh eetuUM76lHKqFiRASTZZ6tHDFNxuAzoikNnDdM2PCTL8k/oXJXCI1qyhh6IHJg0nS+xH qggm8xKjUslpvWh8/2qZMxvI1WlCv1PVOsGzKol11UVyTIf+ojabeTdHTN3dSbKiJWLM 5JX34SdcaF8veH7/0/5vtrQYoIsL++PKMyYptAziXHGfyO9qfBSif2Wvz35MMd4e5gMz MR+YhZPIhOsQEXm9ta6a2DXo+SDLj2/2IQXlEt12JemD0OWNJEwkRXhX0j5kxea+CSKm Ed4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=tPKbavRdFK/u4df00oalSVINqAUAigsKU5d+68m+1Sk=; b=Av4TlMGG+kawUp5GiwCuN5J+fbLDhN56SDvao7SDl5fjw8arym1MFtzyQBvDrUOP8l xwkl/51RPl2fXMQuuqwW5W/Zzdhz8OED6pfE1RfuzHqSJKIpYTK3itKZF8IXN05TUn5N Omk645PhkNRhRwYkRCOT4V/it4KmAv7YiTYi6scbyepgo2sIR1jufG/OqVkshCKGzOnC uM3ezZhafwTT2NQeZgpvYj9Jgm6qnpjg3NsWiBxQnLFyCMy9inb0wJtIfSd0+w/sbzou Eb27UgjUPegbwLP+ckQ+x+CEPgT+50dmYlSS8/dKzzXerXZWJXEyzIVix05A1684C9Sr Et/A== X-Gm-Message-State: ACgBeo3anWf4raVN4B4KYy2TYI3lzQ2Uhi5h24sRS00eM08Imjyv/9mB Res8/R8+HevKIQyQXIMRgwY= X-Google-Smtp-Source: AA6agR7AoUhIYOHrG9C6C9Iym/ur+IFgYP3LfyfwXzwdnBRLT1lnejivk7pJ0+sigmr7RlOQQM9rMg== X-Received: by 2002:a05:600c:350:b0:3a5:3473:1c23 with SMTP id u16-20020a05600c035000b003a534731c23mr2699350wmd.9.1661269580554; Tue, 23 Aug 2022 08:46:20 -0700 (PDT) Received: from jimi.localdomain ([213.57.189.88]) by smtp.gmail.com with ESMTPSA id i26-20020a1c541a000000b003a64f684704sm11341211wmb.40.2022.08.23.08.46.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Aug 2022 08:46:20 -0700 (PDT) From: Eyal Birger To: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, steffen.klassert@secunet.com, herbert@gondor.apana.org.au, pablo@netfilter.org, contact@proelbtn.com, dsahern@kernel.org Cc: netdev@vger.kernel.org, bpf@vger.kernel.org, devel@linux-ipsec.org, Eyal Birger Subject: [PATCH ipsec-next 2/3] xfrm: interface: support collect metadata mode Date: Tue, 23 Aug 2022 18:45:56 +0300 Message-Id: <20220823154557.1400380-3-eyal.birger@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220823154557.1400380-1-eyal.birger@gmail.com> References: <20220823154557.1400380-1-eyal.birger@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org This commit adds support for 'collect_md' mode on xfrm interfaces. Each net can have one collect_md device, created by providing the IFLA_XFRM_COLLECT_METADATA flag at creation. This device cannot be altered and has no if_id or link device attributes. On transmit to this device, the if_id is fetched from the attached dst metadata on the skb. The dst metadata type used is METADATA_XFRM which holds the if_id property. On the receive side, xfrmi_rcv_cb() populates a dst metadata for each packet received and attaches it to the skb. The if_id used in this case is fetched from the xfrm state. This can later be used by upper layers such as tc, ebpf, and ip rules. Because the skb is scrubed in xfrmi_rcv_cb(), the attachment of the dst metadata is postponed until after scrubing. Similarly, xfrm_input() is adapted to avoid dropping metadata dsts by only dropping 'valid' (skb_valid_dst(skb) == true) dsts. Policy matching on packets arriving from collect_md xfrmi devices is done by using the xfrm state existing in the skb's sec_path. The xfrm_if_cb.decode_cb() interface implemented by xfrmi_decode_session() is changed to keep the details of the if_id extraction tucked away in xfrm_interface.c. Signed-off-by: Eyal Birger --- include/net/xfrm.h | 11 +++- include/uapi/linux/if_link.h | 1 + net/xfrm/xfrm_input.c | 7 ++- net/xfrm/xfrm_interface.c | 115 +++++++++++++++++++++++++++++------ net/xfrm/xfrm_policy.c | 10 +-- 5 files changed, 116 insertions(+), 28 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 6e8fa98f786f..756b1bbc27f5 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -312,9 +312,15 @@ struct km_event { struct net *net; }; +struct xfrm_if_decode_session_params { + struct net *net; + u32 if_id; +}; + struct xfrm_if_cb { - struct xfrm_if *(*decode_session)(struct sk_buff *skb, - unsigned short family); + bool (*decode_session)(struct sk_buff *skb, + unsigned short family, + struct xfrm_if_decode_session_params *params); }; void xfrm_if_register_cb(const struct xfrm_if_cb *ifcb); @@ -985,6 +991,7 @@ void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); struct xfrm_if_parms { int link; /* ifindex of underlying L2 interface */ u32 if_id; /* interface identifyer */ + bool collect_md; }; struct xfrm_if { diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index e36d9d2c65a7..d96f13a42589 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -694,6 +694,7 @@ enum { IFLA_XFRM_UNSPEC, IFLA_XFRM_LINK, IFLA_XFRM_IF_ID, + IFLA_XFRM_COLLECT_METADATA, __IFLA_XFRM_MAX }; diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 144238a50f3d..25e822fb5771 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "xfrm_inout.h" @@ -720,7 +721,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) sp = skb_sec_path(skb); if (sp) sp->olen = 0; - skb_dst_drop(skb); + if (skb_valid_dst(skb)) + skb_dst_drop(skb); gro_cells_receive(&gro_cells, skb); return 0; } else { @@ -738,7 +740,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) sp = skb_sec_path(skb); if (sp) sp->olen = 0; - skb_dst_drop(skb); + if (skb_valid_dst(skb)) + skb_dst_drop(skb); gro_cells_receive(&gro_cells, skb); return err; } diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index 5113fa0fbcee..efb8263e1c22 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,7 @@ static const struct net_device_ops xfrmi_netdev_ops; struct xfrmi_net { /* lists for storing interfaces in use */ struct xfrm_if __rcu *xfrmi[XFRMI_HASH_SIZE]; + struct xfrm_if __rcu *collect_md_xfrmi; }; #define for_each_xfrmi_rcu(start, xi) \ @@ -77,17 +79,23 @@ static struct xfrm_if *xfrmi_lookup(struct net *net, struct xfrm_state *x) return xi; } + xi = rcu_dereference(xfrmn->collect_md_xfrmi); + if (xi && xi->dev->flags & IFF_UP) + return xi; + return NULL; } -static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb, - unsigned short family) +static bool xfrmi_decode_session(struct sk_buff *skb, + unsigned short family, + struct xfrm_if_decode_session_params *params) { struct net_device *dev; + struct xfrm_if *xi; int ifindex = 0; if (!secpath_exists(skb) || !skb->dev) - return NULL; + return false; switch (family) { case AF_INET6: @@ -107,11 +115,18 @@ static struct xfrm_if *xfrmi_decode_session(struct sk_buff *skb, } if (!dev || !(dev->flags & IFF_UP)) - return NULL; + return false; if (dev->netdev_ops != &xfrmi_netdev_ops) - return NULL; + return false; - return netdev_priv(dev); + xi = netdev_priv(dev); + params->net = xi->net; + + if (xi->p.collect_md) + params->if_id = xfrm_input_state(skb)->if_id; + else + params->if_id = xi->p.if_id; + return true; } static void xfrmi_link(struct xfrmi_net *xfrmn, struct xfrm_if *xi) @@ -157,7 +172,10 @@ static int xfrmi_create(struct net_device *dev) if (err < 0) goto out; - xfrmi_link(xfrmn, xi); + if (xi->p.collect_md) + rcu_assign_pointer(xfrmn->collect_md_xfrmi, xi); + else + xfrmi_link(xfrmn, xi); return 0; @@ -185,7 +203,10 @@ static void xfrmi_dev_uninit(struct net_device *dev) struct xfrm_if *xi = netdev_priv(dev); struct xfrmi_net *xfrmn = net_generic(xi->net, xfrmi_net_id); - xfrmi_unlink(xfrmn, xi); + if (xi->p.collect_md) + rcu_assign_pointer(xfrmn->collect_md_xfrmi, NULL); + else + xfrmi_unlink(xfrmn, xi); } static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet) @@ -254,6 +275,16 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err) } xfrmi_scrub_packet(skb, xnet); + if (xi->p.collect_md) { + struct metadata_dst *md_dst; + + md_dst = metadata_dst_alloc(0, METADATA_XFRM, GFP_ATOMIC); + if (!md_dst) + return -ENOMEM; + + md_dst->u.xfrm_info.if_id = x->if_id; + skb_dst_set(skb, (struct dst_entry *)md_dst); + } dev_sw_netstats_rx_add(dev, skb->len); return 0; @@ -269,10 +300,22 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) struct net_device *tdev; struct xfrm_state *x; int err = -1; + u32 if_id; int mtu; + if (xi->p.collect_md) { + struct xfrm_md_info *md_info = skb_xfrm_md_info(skb); + + if (unlikely(!md_info)) + return -EINVAL; + + if_id = md_info->if_id; + } else { + if_id = xi->p.if_id; + } + dst_hold(dst); - dst = xfrm_lookup_with_ifid(xi->net, dst, fl, NULL, 0, xi->p.if_id); + dst = xfrm_lookup_with_ifid(xi->net, dst, fl, NULL, 0, if_id); if (IS_ERR(dst)) { err = PTR_ERR(dst); dst = NULL; @@ -283,7 +326,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) if (!x) goto tx_err_link_failure; - if (x->if_id != xi->p.if_id) + if (x->if_id != if_id) goto tx_err_link_failure; tdev = dst->dev; @@ -633,6 +676,9 @@ static void xfrmi_netlink_parms(struct nlattr *data[], if (data[IFLA_XFRM_IF_ID]) parms->if_id = nla_get_u32(data[IFLA_XFRM_IF_ID]); + + if (data[IFLA_XFRM_COLLECT_METADATA]) + parms->collect_md = true; } static int xfrmi_newlink(struct net *src_net, struct net_device *dev, @@ -645,14 +691,27 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev, int err; xfrmi_netlink_parms(data, &p); - if (!p.if_id) { - NL_SET_ERR_MSG(extack, "if_id must be non zero"); - return -EINVAL; - } + if (p.collect_md) { + struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id); - xi = xfrmi_locate(net, &p); - if (xi) - return -EEXIST; + if (p.link || p.if_id) { + NL_SET_ERR_MSG(extack, "link and if_id must be zero"); + return -EINVAL; + } + + if (rtnl_dereference(xfrmn->collect_md_xfrmi)) + return -EEXIST; + + } else { + if (!p.if_id) { + NL_SET_ERR_MSG(extack, "if_id must be non zero"); + return -EINVAL; + } + + xi = xfrmi_locate(net, &p); + if (xi) + return -EEXIST; + } xi = netdev_priv(dev); xi->p = p; @@ -682,12 +741,19 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[], return -EINVAL; } + if (p.collect_md) { + NL_SET_ERR_MSG(extack, "collect_md can't be changed"); + return -EINVAL; + } + xi = xfrmi_locate(net, &p); if (!xi) { xi = netdev_priv(dev); } else { if (xi->dev != dev) return -EEXIST; + if (xi->p.collect_md) + return -EINVAL; } return xfrmi_update(xi, &p); @@ -700,6 +766,8 @@ static size_t xfrmi_get_size(const struct net_device *dev) nla_total_size(4) + /* IFLA_XFRM_IF_ID */ nla_total_size(4) + + /* IFLA_XFRM_COLLECT_METADATA */ + nla_total_size(0) + 0; } @@ -711,6 +779,10 @@ static int xfrmi_fill_info(struct sk_buff *skb, const struct net_device *dev) if (nla_put_u32(skb, IFLA_XFRM_LINK, parm->link) || nla_put_u32(skb, IFLA_XFRM_IF_ID, parm->if_id)) goto nla_put_failure; + if (xi->p.collect_md) { + if (nla_put_flag(skb, IFLA_XFRM_COLLECT_METADATA)) + goto nla_put_failure; + } return 0; nla_put_failure: @@ -725,8 +797,10 @@ static struct net *xfrmi_get_link_net(const struct net_device *dev) } static const struct nla_policy xfrmi_policy[IFLA_XFRM_MAX + 1] = { - [IFLA_XFRM_LINK] = { .type = NLA_U32 }, - [IFLA_XFRM_IF_ID] = { .type = NLA_U32 }, + [IFLA_XFRM_UNSPEC] = { .strict_start_type = IFLA_XFRM_COLLECT_METADATA }, + [IFLA_XFRM_LINK] = { .type = NLA_U32 }, + [IFLA_XFRM_IF_ID] = { .type = NLA_U32 }, + [IFLA_XFRM_COLLECT_METADATA] = { .type = NLA_FLAG }, }; static struct rtnl_link_ops xfrmi_link_ops __read_mostly = { @@ -762,6 +836,9 @@ static void __net_exit xfrmi_exit_batch_net(struct list_head *net_exit_list) xip = &xi->next) unregister_netdevice_queue(xi->dev, &list); } + xi = rcu_dereference(xfrmn->collect_md_xfrmi); + if (xi) + unregister_netdevice_queue(xi->dev, &list); } unregister_netdevice_many(&list); rtnl_unlock(); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index f1a0bab920a5..76894adcc82f 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -3516,17 +3516,17 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, int xerr_idx = -1; const struct xfrm_if_cb *ifcb; struct sec_path *sp; - struct xfrm_if *xi; u32 if_id = 0; rcu_read_lock(); ifcb = xfrm_if_get_cb(); if (ifcb) { - xi = ifcb->decode_session(skb, family); - if (xi) { - if_id = xi->p.if_id; - net = xi->net; + struct xfrm_if_decode_session_params p; + + if (ifcb->decode_session(skb, family, &p)) { + if_id = p.if_id; + net = p.net; } } rcu_read_unlock(); From patchwork Tue Aug 23 15:45:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eyal Birger X-Patchwork-Id: 12952432 X-Patchwork-Delegate: kuba@kernel.org Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69029C32772 for ; Tue, 23 Aug 2022 17:49:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232509AbiHWRta (ORCPT ); Tue, 23 Aug 2022 13:49:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51586 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232594AbiHWRsk (ORCPT ); Tue, 23 Aug 2022 13:48:40 -0400 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AD205558A; Tue, 23 Aug 2022 08:46:24 -0700 (PDT) Received: by mail-wm1-x32d.google.com with SMTP id d5so7408661wms.5; Tue, 23 Aug 2022 08:46:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=aGpZ22pjo1td/ZEvELwJO1izwL3afks4DDd4sKgSdh0=; b=pQjPk4V1UFc7H9inSC+nUAbnANveDxjDK/p7rfSf5FqdnW/amrV26MdIrQG6ykLVWd w7qXMSlLwjl2yF+yz9JNTnAuOWNT84z6Tx/wvDNDWIo51g8iw80zxtl0EjMp0ODFCWSx Pws4wPeua8zMBFkZpGjXXWZlMxQKTVCn4bXWBy7nF10emqPtd3rwAqROyBEScpAYzCsf E0hgMVPvZ+kl2ZCh6ofck2y2P9SkK119MN7O/cFqgd2gL1brZ0s9C4WqVgxjHM3ntgok 02tbQIWSens/zR4GF21vOlgynU6MKXrBnjCSYAPSZlmggdqQ2++wwOPQhlmS0B1Y3v6C jqHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=aGpZ22pjo1td/ZEvELwJO1izwL3afks4DDd4sKgSdh0=; b=AMjKvHayzQhGJno842I4JYko7tm8IItKmHmzLCdDrb3mHBmSq6HDrgaTbpoVcH8U50 cVQTJJylcgkPy5rkP+GRFVVGevoidw2QuRQnlF2TPZDPiddl2eM2MnvIUL6NszpGF0k8 OaRy0St32ehcncDJh5rqoPaaaAj00xd1v2xGd4as0QooT+ti8BU5/44l7d4lqUwhECDh dLnvpohLWuRUzp6ee12Fe4ffxlqvmMBwyERN536vl/LoowBa5wfqGt2C0flYBdNQaLub b/C4LvbI9CiaR8j0kKVDjdlvnUBwnPHqCEqxAGaA0JZS+4a31XEfQHVlzOssuSTfqylj 0iJA== X-Gm-Message-State: ACgBeo3V9Tjk5V+Sl3x5vWOxfzewaBej+EANeZiilKY8PX7y9H8046yS TuDqWSI8QbetKHhggHcmZeQ= X-Google-Smtp-Source: AA6agR7/zEQCAiTvNgtM65VBilQ613il1fHwesCaJaUx24CR/3VFse6mvsXWNsGbGCVT/IXO3h65Mw== X-Received: by 2002:a05:600c:4f05:b0:3a5:ffec:b6b with SMTP id l5-20020a05600c4f0500b003a5ffec0b6bmr2571865wmq.199.1661269583108; Tue, 23 Aug 2022 08:46:23 -0700 (PDT) Received: from jimi.localdomain ([213.57.189.88]) by smtp.gmail.com with ESMTPSA id i26-20020a1c541a000000b003a64f684704sm11341211wmb.40.2022.08.23.08.46.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 23 Aug 2022 08:46:22 -0700 (PDT) From: Eyal Birger To: davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, steffen.klassert@secunet.com, herbert@gondor.apana.org.au, pablo@netfilter.org, contact@proelbtn.com, dsahern@kernel.org Cc: netdev@vger.kernel.org, bpf@vger.kernel.org, devel@linux-ipsec.org, Eyal Birger Subject: [PATCH ipsec-next 3/3] xfrm: lwtunnel: add lwtunnel support for xfrm interfaces in collect_md mode Date: Tue, 23 Aug 2022 18:45:57 +0300 Message-Id: <20220823154557.1400380-4-eyal.birger@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220823154557.1400380-1-eyal.birger@gmail.com> References: <20220823154557.1400380-1-eyal.birger@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Allow specifying the xfrm interface if_id as part of a route metadata using the lwtunnel infrastructure. This allows for example using a single xfrm interface in collect_md mode as the target of multiple routes each specifying a different if_id. With the appropriate changes to iproute2, considering an xfrm device ipsec1 in collect_md mode one can for example add a route specifying an if_id like so: ip route add dev ipsec1 encap xfrm if_id 1 In which case traffic routed to the device via this route would use if_id in the xfrm interface policy lookup. Signed-off-by: Eyal Birger --- include/net/dst_metadata.h | 6 +++ include/uapi/linux/lwtunnel.h | 9 ++++ net/core/lwtunnel.c | 1 + net/xfrm/xfrm_interface.c | 88 +++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 7e13210b868f..122066595966 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -62,10 +62,16 @@ skb_tunnel_info(const struct sk_buff *skb) static inline struct xfrm_md_info *skb_xfrm_md_info(const struct sk_buff *skb) { struct metadata_dst *md_dst = skb_metadata_dst(skb); + struct dst_entry *dst; if (md_dst && md_dst->type == METADATA_XFRM) return &md_dst->u.xfrm_info; + dst = skb_dst(skb); + if (dst && dst->lwtstate && + dst->lwtstate->type == LWTUNNEL_ENCAP_XFRM) + return (struct xfrm_md_info *)dst->lwtstate->data; + return NULL; } diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h index 2e206919125c..d26bace86332 100644 --- a/include/uapi/linux/lwtunnel.h +++ b/include/uapi/linux/lwtunnel.h @@ -15,6 +15,7 @@ enum lwtunnel_encap_types { LWTUNNEL_ENCAP_SEG6_LOCAL, LWTUNNEL_ENCAP_RPL, LWTUNNEL_ENCAP_IOAM6, + LWTUNNEL_ENCAP_XFRM, __LWTUNNEL_ENCAP_MAX, }; @@ -111,4 +112,12 @@ enum { #define LWT_BPF_MAX_HEADROOM 256 +enum { + LWT_XFRM_UNSPEC, + LWT_XFRM_IF_ID, + __LWT_XFRM_MAX, +}; + +#define LWT_XFRM_MAX (__LWT_XFRM_MAX - 1) + #endif /* _UAPI_LWTUNNEL_H_ */ diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c index 9ccd64e8a666..6fac2f0ef074 100644 --- a/net/core/lwtunnel.c +++ b/net/core/lwtunnel.c @@ -50,6 +50,7 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type) return "IOAM6"; case LWTUNNEL_ENCAP_IP6: case LWTUNNEL_ENCAP_IP: + case LWTUNNEL_ENCAP_XFRM: case LWTUNNEL_ENCAP_NONE: case __LWTUNNEL_ENCAP_MAX: /* should not have got here */ diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index efb8263e1c22..9f0a5cc2895d 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c @@ -60,6 +60,91 @@ struct xfrmi_net { struct xfrm_if __rcu *collect_md_xfrmi; }; +static inline struct xfrm_md_info *xfrm_lwt(struct lwtunnel_state *lwt) +{ + return (struct xfrm_md_info *)lwt->data; +} + +static const struct nla_policy xfrm_lwt_policy[LWT_XFRM_MAX + 1] = { + [LWT_XFRM_UNSPEC] = { .type = NLA_REJECT }, + [LWT_XFRM_IF_ID] = { .type = NLA_U32 }, +}; + +static void xfrmi_destroy_state(struct lwtunnel_state *lwt) +{ +} + +static int xfrmi_build_state(struct net *net, struct nlattr *nla, + unsigned int family, const void *cfg, + struct lwtunnel_state **ts, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[LWT_XFRM_MAX + 1]; + struct lwtunnel_state *new_state; + struct xfrm_md_info *info; + int ret; + + ret = nla_parse_nested(tb, LWT_XFRM_MAX, nla, xfrm_lwt_policy, extack); + if (ret < 0) + return ret; + + if (!tb[LWT_XFRM_IF_ID]) + return -EINVAL; + + new_state = lwtunnel_state_alloc(sizeof(*info)); + if (!new_state) + return -ENOMEM; + + new_state->type = LWTUNNEL_ENCAP_XFRM; + + info = xfrm_lwt(new_state); + info->if_id = nla_get_u32(tb[LWT_XFRM_IF_ID]); + if (!info->if_id) { + ret = -EINVAL; + goto errout; + } + *ts = new_state; + return 0; + +errout: + xfrmi_destroy_state(new_state); + kfree(new_state); + return ret; +} + +static int xfrmi_fill_encap_info(struct sk_buff *skb, + struct lwtunnel_state *lwt) +{ + struct xfrm_md_info *info = xfrm_lwt(lwt); + + if (nla_put_u32(skb, LWT_XFRM_IF_ID, info->if_id)) + return -EMSGSIZE; + + return 0; +} + +static int xfrmi_encap_nlsize(struct lwtunnel_state *lwtstate) +{ + return nla_total_size(4); /* LWT_XFRM_IF_ID */ +} + +static int xfrmi_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b) +{ + struct xfrm_md_info *a_info = xfrm_lwt(a); + struct xfrm_md_info *b_info = xfrm_lwt(b); + + return memcmp(a_info, b_info, sizeof(*a_info)); +} + +static const struct lwtunnel_encap_ops xfrmi_encap_ops = { + .build_state = xfrmi_build_state, + .destroy_state = xfrmi_destroy_state, + .fill_encap = xfrmi_fill_encap_info, + .get_encap_size = xfrmi_encap_nlsize, + .cmp_encap = xfrmi_encap_cmp, + .owner = THIS_MODULE, +}; + #define for_each_xfrmi_rcu(start, xi) \ for (xi = rcu_dereference(start); xi; xi = rcu_dereference(xi->next)) @@ -1076,6 +1161,8 @@ static int __init xfrmi_init(void) if (err < 0) goto rtnl_link_failed; + lwtunnel_encap_add_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM); + xfrm_if_register_cb(&xfrm_if_cb); return err; @@ -1094,6 +1181,7 @@ static int __init xfrmi_init(void) static void __exit xfrmi_fini(void) { xfrm_if_unregister_cb(); + lwtunnel_encap_del_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM); rtnl_link_unregister(&xfrmi_link_ops); xfrmi4_fini(); xfrmi6_fini();