From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ioana Ciocoi Radulescu Subject: [PATCH v2 net-next 1/8] dpaa2-eth: Add basic XDP support Date: Mon, 26 Nov 2018 16:27:29 +0000 Message-ID: <1543249591-14563-2-git-send-email-ruxandra.radulescu@nxp.com> References: <1543249591-14563-1-git-send-email-ruxandra.radulescu@nxp.com> Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Cc: Ioana Ciornei , "dsahern@gmail.com" , Camelia Alexandra Groza To: "netdev@vger.kernel.org" , "davem@davemloft.net" Return-path: Received: from mail-eopbgr80084.outbound.protection.outlook.com ([40.107.8.84]:2992 "EHLO EUR04-VI1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726459AbeK0DWM (ORCPT ); Mon, 26 Nov 2018 22:22:12 -0500 In-Reply-To: <1543249591-14563-1-git-send-email-ruxandra.radulescu@nxp.com> Content-Language: en-US Sender: netdev-owner@vger.kernel.org List-ID: We keep one XDP program reference per channel. The only actions supported for now are XDP_DROP and XDP_PASS. Until now we didn't enforce a maximum size for Rx frames based on MTU value. Change that, since for XDP mode we must ensure no scatter-gather frames can be received. Signed-off-by: Ioana Radulescu --- v2: - xdp packets count towards the rx packets and bytes counters - add warning message with the maximum supported MTU value for XDP drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 189 +++++++++++++++++++= +++- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 6 + 2 files changed, 194 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net= /ethernet/freescale/dpaa2/dpaa2-eth.c index 640967a..d3cfed4 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -13,7 +13,8 @@ #include #include #include - +#include +#include #include =20 #include "dpaa2-eth.h" @@ -199,6 +200,45 @@ static struct sk_buff *build_frag_skb(struct dpaa2_eth= _priv *priv, return skb; } =20 +static u32 run_xdp(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + struct dpaa2_fd *fd, void *vaddr) +{ + struct bpf_prog *xdp_prog; + struct xdp_buff xdp; + u32 xdp_act =3D XDP_PASS; + + rcu_read_lock(); + + xdp_prog =3D READ_ONCE(ch->xdp.prog); + if (!xdp_prog) + goto out; + + xdp.data =3D vaddr + dpaa2_fd_get_offset(fd); + xdp.data_end =3D xdp.data + dpaa2_fd_get_len(fd); + xdp.data_hard_start =3D xdp.data; + xdp_set_data_meta_invalid(&xdp); + + xdp_act =3D bpf_prog_run_xdp(xdp_prog, &xdp); + + switch (xdp_act) { + case XDP_PASS: + break; + default: + bpf_warn_invalid_xdp_action(xdp_act); + case XDP_ABORTED: + trace_xdp_exception(priv->net_dev, xdp_prog, xdp_act); + case XDP_DROP: + ch->buf_count--; + free_rx_fd(priv, fd, vaddr); + break; + } + +out: + rcu_read_unlock(); + return xdp_act; +} + /* Main Rx frame processing routine */ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, struct dpaa2_eth_channel *ch, @@ -215,6 +255,7 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, struct dpaa2_fas *fas; void *buf_data; u32 status =3D 0; + u32 xdp_act; =20 /* Tracing point */ trace_dpaa2_rx_fd(priv->net_dev, fd); @@ -231,8 +272,17 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, percpu_extras =3D this_cpu_ptr(priv->percpu_extras); =20 if (fd_format =3D=3D dpaa2_fd_single) { + xdp_act =3D run_xdp(priv, ch, (struct dpaa2_fd *)fd, vaddr); + if (xdp_act !=3D XDP_PASS) { + percpu_stats->rx_packets++; + percpu_stats->rx_bytes +=3D dpaa2_fd_get_len(fd); + return; + } + skb =3D build_linear_skb(ch, fd, vaddr); } else if (fd_format =3D=3D dpaa2_fd_sg) { + WARN_ON(priv->xdp_prog); + skb =3D build_frag_skb(priv, ch, buf_data); skb_free_frag(vaddr); percpu_extras->rx_sg_frames++; @@ -1427,6 +1477,141 @@ static int dpaa2_eth_ioctl(struct net_device *dev, = struct ifreq *rq, int cmd) return -EINVAL; } =20 +static bool xdp_mtu_valid(struct dpaa2_eth_priv *priv, int mtu) +{ + int mfl, linear_mfl; + + mfl =3D DPAA2_ETH_L2_MAX_FRM(mtu); + linear_mfl =3D DPAA2_ETH_RX_BUF_SIZE - DPAA2_ETH_RX_HWA_SIZE - + dpaa2_eth_rx_head_room(priv); + + if (mfl > linear_mfl) { + netdev_warn(priv->net_dev, "Maximum MTU for XDP is %d\n", + linear_mfl - VLAN_ETH_HLEN); + return false; + } + + return true; +} + +static int set_rx_mfl(struct dpaa2_eth_priv *priv, int mtu, bool has_xdp) +{ + int mfl, err; + + /* We enforce a maximum Rx frame length based on MTU only if we have + * an XDP program attached (in order to avoid Rx S/G frames). + * Otherwise, we accept all incoming frames as long as they are not + * larger than maximum size supported in hardware + */ + if (has_xdp) + mfl =3D DPAA2_ETH_L2_MAX_FRM(mtu); + else + mfl =3D DPAA2_ETH_MFL; + + err =3D dpni_set_max_frame_length(priv->mc_io, 0, priv->mc_token, mfl); + if (err) { + netdev_err(priv->net_dev, "dpni_set_max_frame_length failed\n"); + return err; + } + + return 0; +} + +static int dpaa2_eth_change_mtu(struct net_device *dev, int new_mtu) +{ + struct dpaa2_eth_priv *priv =3D netdev_priv(dev); + int err; + + if (!priv->xdp_prog) + goto out; + + if (!xdp_mtu_valid(priv, new_mtu)) + return -EINVAL; + + err =3D set_rx_mfl(priv, new_mtu, true); + if (err) + return err; + +out: + dev->mtu =3D new_mtu; + return 0; +} + +static int setup_xdp(struct net_device *dev, struct bpf_prog *prog) +{ + struct dpaa2_eth_priv *priv =3D netdev_priv(dev); + struct dpaa2_eth_channel *ch; + struct bpf_prog *old; + bool up, need_update; + int i, err; + + if (prog && !xdp_mtu_valid(priv, dev->mtu)) + return -EINVAL; + + if (prog) { + prog =3D bpf_prog_add(prog, priv->num_channels); + if (IS_ERR(prog)) + return PTR_ERR(prog); + } + + up =3D netif_running(dev); + need_update =3D (!!priv->xdp_prog !=3D !!prog); + + if (up) + dpaa2_eth_stop(dev); + + /* While in xdp mode, enforce a maximum Rx frame size based on MTU */ + if (need_update) { + err =3D set_rx_mfl(priv, dev->mtu, !!prog); + if (err) + goto out_err; + } + + old =3D xchg(&priv->xdp_prog, prog); + if (old) + bpf_prog_put(old); + + for (i =3D 0; i < priv->num_channels; i++) { + ch =3D priv->channel[i]; + old =3D xchg(&ch->xdp.prog, prog); + if (old) + bpf_prog_put(old); + } + + if (up) { + err =3D dpaa2_eth_open(dev); + if (err) + return err; + } + + return 0; + +out_err: + if (prog) + bpf_prog_sub(prog, priv->num_channels); + if (up) + dpaa2_eth_open(dev); + + return err; +} + +static int dpaa2_eth_xdp(struct net_device *dev, struct netdev_bpf *xdp) +{ + struct dpaa2_eth_priv *priv =3D netdev_priv(dev); + + switch (xdp->command) { + case XDP_SETUP_PROG: + return setup_xdp(dev, xdp->prog); + case XDP_QUERY_PROG: + xdp->prog_id =3D priv->xdp_prog ? priv->xdp_prog->aux->id : 0; + break; + default: + return -EINVAL; + } + + return 0; +} + static const struct net_device_ops dpaa2_eth_ops =3D { .ndo_open =3D dpaa2_eth_open, .ndo_start_xmit =3D dpaa2_eth_tx, @@ -1436,6 +1621,8 @@ static const struct net_device_ops dpaa2_eth_ops =3D = { .ndo_set_rx_mode =3D dpaa2_eth_set_rx_mode, .ndo_set_features =3D dpaa2_eth_set_features, .ndo_do_ioctl =3D dpaa2_eth_ioctl, + .ndo_change_mtu =3D dpaa2_eth_change_mtu, + .ndo_bpf =3D dpaa2_eth_xdp, }; =20 static void cdan_cb(struct dpaa2_io_notification_ctx *ctx) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net= /ethernet/freescale/dpaa2/dpaa2-eth.h index 16545e9..2873a15 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -283,6 +283,10 @@ struct dpaa2_eth_fq { struct dpaa2_eth_fq_stats stats; }; =20 +struct dpaa2_eth_ch_xdp { + struct bpf_prog *prog; +}; + struct dpaa2_eth_channel { struct dpaa2_io_notification_ctx nctx; struct fsl_mc_device *dpcon; @@ -294,6 +298,7 @@ struct dpaa2_eth_channel { struct dpaa2_eth_priv *priv; int buf_count; struct dpaa2_eth_ch_stats stats; + struct dpaa2_eth_ch_xdp xdp; }; =20 struct dpaa2_eth_dist_fields { @@ -353,6 +358,7 @@ struct dpaa2_eth_priv { u64 rx_hash_fields; struct dpaa2_eth_cls_rule *cls_rules; u8 rx_cls_enabled; + struct bpf_prog *xdp_prog; }; =20 #define DPAA2_RXH_SUPPORTED (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \ --=20 2.7.4