Commit fd4b96c4 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'nfp-vlan-strip-and-insert'



Simon Horman says:

====================
nfp: support VLAN strip and insert

this series adds support to the NFP driver for HW offload of both:

* RX VLAN ctag/stag strip
* TX VLAN ctag insert
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5ee4bba2 d80702ff
Loading
Loading
Loading
Loading
+46 −17
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

#include <linux/bpf_trace.h>
#include <linux/netdevice.h>
#include <linux/bitfield.h>

#include "../nfp_app.h"
#include "../nfp_net.h"
@@ -166,30 +167,35 @@ nfp_nfd3_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
	u64_stats_update_end(&r_vec->tx_sync);
}

static int nfp_nfd3_prep_tx_meta(struct sk_buff *skb, u64 tls_handle)
static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb, u64 tls_handle)
{
	struct metadata_dst *md_dst = skb_metadata_dst(skb);
	unsigned char *data;
	bool vlan_insert;
	u32 meta_id = 0;
	int md_bytes;

	if (likely(!md_dst && !tls_handle))
		return 0;
	if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX)) {
		if (!tls_handle)
			return 0;
	if (unlikely(md_dst || tls_handle)) {
		if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX))
			md_dst = NULL;
	}

	md_bytes = 4 + !!md_dst * 4 + !!tls_handle * 8;
	vlan_insert = skb_vlan_tag_present(skb) && (dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2);

	if (!(md_dst || tls_handle || vlan_insert))
		return 0;

	md_bytes = sizeof(meta_id) +
		   !!md_dst * NFP_NET_META_PORTID_SIZE +
		   !!tls_handle * NFP_NET_META_CONN_HANDLE_SIZE +
		   vlan_insert * NFP_NET_META_VLAN_SIZE;

	if (unlikely(skb_cow_head(skb, md_bytes)))
		return -ENOMEM;

	meta_id = 0;
	data = skb_push(skb, md_bytes) + md_bytes;
	if (md_dst) {
		data -= 4;
		data -= NFP_NET_META_PORTID_SIZE;
		put_unaligned_be32(md_dst->u.port_info.port_id, data);
		meta_id = NFP_NET_META_PORTID;
	}
@@ -197,13 +203,23 @@ static int nfp_nfd3_prep_tx_meta(struct sk_buff *skb, u64 tls_handle)
		/* conn handle is opaque, we just use u64 to be able to quickly
		 * compare it to zero
		 */
		data -= 8;
		data -= NFP_NET_META_CONN_HANDLE_SIZE;
		memcpy(data, &tls_handle, sizeof(tls_handle));
		meta_id <<= NFP_NET_META_FIELD_SIZE;
		meta_id |= NFP_NET_META_CONN_HANDLE;
	}
	if (vlan_insert) {
		data -= NFP_NET_META_VLAN_SIZE;
		/* data type of skb->vlan_proto is __be16
		 * so it fills metadata without calling put_unaligned_be16
		 */
		memcpy(data, &skb->vlan_proto, sizeof(skb->vlan_proto));
		put_unaligned_be16(skb_vlan_tag_get(skb), data + sizeof(skb->vlan_proto));
		meta_id <<= NFP_NET_META_FIELD_SIZE;
		meta_id |= NFP_NET_META_VLAN;
	}

	data -= 4;
	data -= sizeof(meta_id);
	put_unaligned_be32(meta_id, data);

	return md_bytes;
@@ -257,7 +273,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev)
		return NETDEV_TX_OK;
	}

	md_bytes = nfp_nfd3_prep_tx_meta(skb, tls_handle);
	md_bytes = nfp_nfd3_prep_tx_meta(dp, skb, tls_handle);
	if (unlikely(md_bytes < 0))
		goto err_flush;

@@ -703,7 +719,7 @@ bool
nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
		    void *data, void *pkt, unsigned int pkt_len, int meta_len)
{
	u32 meta_info;
	u32 meta_info, vlan_info;

	meta_info = get_unaligned_be32(data);
	data += 4;
@@ -721,6 +737,17 @@ nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
			meta->mark = get_unaligned_be32(data);
			data += 4;
			break;
		case NFP_NET_META_VLAN:
			vlan_info = get_unaligned_be32(data);
			if (FIELD_GET(NFP_NET_META_VLAN_STRIP, vlan_info)) {
				meta->vlan.stripped = true;
				meta->vlan.tpid = FIELD_GET(NFP_NET_META_VLAN_TPID_MASK,
							    vlan_info);
				meta->vlan.tci = FIELD_GET(NFP_NET_META_VLAN_TCI_MASK,
							   vlan_info);
			}
			data += 4;
			break;
		case NFP_NET_META_PORTID:
			meta->portid = get_unaligned_be32(data);
			data += 4;
@@ -1049,9 +1076,11 @@ static int nfp_nfd3_rx(struct nfp_net_rx_ring *rx_ring, int budget)
		}
#endif

		if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
					       le16_to_cpu(rxd->rxd.vlan));
		if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) {
			nfp_nfd3_rx_drop(dp, r_vec, rx_ring, NULL, skb);
			continue;
		}

		if (meta_len_xdp)
			skb_metadata_set(skb, meta_len_xdp);

+2 −0
Original line number Diff line number Diff line
@@ -247,6 +247,8 @@ nfp_nfd3_print_tx_descs(struct seq_file *file,
	 NFP_NET_CFG_CTRL_L2BC | NFP_NET_CFG_CTRL_L2MC |		\
	 NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM |		\
	 NFP_NET_CFG_CTRL_RXVLAN | NFP_NET_CFG_CTRL_TXVLAN |		\
	 NFP_NET_CFG_CTRL_RXVLAN_V2 | NFP_NET_CFG_CTRL_RXQINQ |		\
	 NFP_NET_CFG_CTRL_TXVLAN_V2 |					\
	 NFP_NET_CFG_CTRL_GATHER | NFP_NET_CFG_CTRL_LSO |		\
	 NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA |	\
	 NFP_NET_CFG_CTRL_RINGCFG | NFP_NET_CFG_CTRL_RSS |		\
+6 −3
Original line number Diff line number Diff line
@@ -94,9 +94,12 @@ static void nfp_nfd3_xsk_rx_skb(struct nfp_net_rx_ring *rx_ring,

	nfp_nfd3_rx_csum(dp, r_vec, rxd, meta, skb);

	if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
				       le16_to_cpu(rxd->rxd.vlan));
	if (unlikely(!nfp_net_vlan_strip(skb, rxd, meta))) {
		dev_kfree_skb_any(skb);
		nfp_net_xsk_rx_drop(r_vec, xrxbuf);
		return;
	}

	if (meta_xdp)
		skb_metadata_set(skb,
				 xrxbuf->xdp->data - xrxbuf->xdp->data_meta);
+17 −4
Original line number Diff line number Diff line
@@ -716,7 +716,7 @@ static bool
nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
		    void *data, void *pkt, unsigned int pkt_len, int meta_len)
{
	u32 meta_info;
	u32 meta_info, vlan_info;

	meta_info = get_unaligned_be32(data);
	data += 4;
@@ -734,6 +734,17 @@ nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
			meta->mark = get_unaligned_be32(data);
			data += 4;
			break;
		case NFP_NET_META_VLAN:
			vlan_info = get_unaligned_be32(data);
			if (FIELD_GET(NFP_NET_META_VLAN_STRIP, vlan_info)) {
				meta->vlan.stripped = true;
				meta->vlan.tpid = FIELD_GET(NFP_NET_META_VLAN_TPID_MASK,
							    vlan_info);
				meta->vlan.tci = FIELD_GET(NFP_NET_META_VLAN_TCI_MASK,
							   vlan_info);
			}
			data += 4;
			break;
		case NFP_NET_META_PORTID:
			meta->portid = get_unaligned_be32(data);
			data += 4;
@@ -1169,9 +1180,11 @@ static int nfp_nfdk_rx(struct nfp_net_rx_ring *rx_ring, int budget)

		nfp_nfdk_rx_csum(dp, r_vec, rxd, &meta, skb);

		if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
					       le16_to_cpu(rxd->rxd.vlan));
		if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) {
			nfp_nfdk_rx_drop(dp, r_vec, rx_ring, NULL, skb);
			continue;
		}

		if (meta_len_xdp)
			skb_metadata_set(skb, meta_len_xdp);

+1 −0
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ nfp_nfdk_print_tx_descs(struct seq_file *file,
	 NFP_NET_CFG_CTRL_L2BC | NFP_NET_CFG_CTRL_L2MC |		\
	 NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM |		\
	 NFP_NET_CFG_CTRL_RXVLAN |					\
	 NFP_NET_CFG_CTRL_RXVLAN_V2 | NFP_NET_CFG_CTRL_RXQINQ |		\
	 NFP_NET_CFG_CTRL_GATHER | NFP_NET_CFG_CTRL_LSO |		\
	 NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA |	\
	 NFP_NET_CFG_CTRL_RINGCFG | NFP_NET_CFG_CTRL_IRQMOD |		\
Loading