xref: /dpdk/drivers/net/nfp/nfp_net_meta.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2023 Corigine, Inc.
3  * All rights reserved.
4  */
5 
6 #include "nfp_net_meta.h"
7 
8 #include "nfp_net_common.h"
9 #include "nfp_ipsec.h"
10 #include "nfp_logs.h"
11 
12 enum nfp_net_meta_ipsec_layer {
13 	NFP_NET_META_IPSEC_SAIDX,       /**< Order of SA index in metadata */
14 	NFP_NET_META_IPSEC_SEQLOW,      /**< Order of Sequence Number (low 32bits) in metadata */
15 	NFP_NET_META_IPSEC_SEQHI,       /**< Order of Sequence Number (high 32bits) in metadata */
16 };
17 
18 /* Parse the chained metadata from packet */
19 static bool
20 nfp_net_meta_parse_chained(uint8_t *meta_base,
21 		rte_be32_t meta_header,
22 		struct nfp_net_meta_parsed *meta)
23 {
24 	uint32_t meta_info;
25 	uint32_t vlan_info;
26 	uint8_t *meta_offset;
27 
28 	meta_info = rte_be_to_cpu_32(meta_header);
29 	meta_offset = meta_base + 4;
30 
31 	for (; meta_info != 0; meta_info >>= NFP_NET_META_FIELD_SIZE, meta_offset += 4) {
32 		switch (meta_info & NFP_NET_META_FIELD_MASK) {
33 		case NFP_NET_META_PORTID:
34 			meta->flags |= (1 << NFP_NET_META_PORTID);
35 			meta->port_id = rte_be_to_cpu_32(*(rte_be32_t *)meta_offset);
36 			break;
37 		case NFP_NET_META_HASH:
38 			meta->flags |= (1 << NFP_NET_META_HASH);
39 			/* Next field type is about the hash type */
40 			meta_info >>= NFP_NET_META_FIELD_SIZE;
41 			/* Hash value is in the data field */
42 			meta->hash = rte_be_to_cpu_32(*(rte_be32_t *)meta_offset);
43 			meta->hash_type = meta_info & NFP_NET_META_FIELD_MASK;
44 			break;
45 		case NFP_NET_META_VLAN:
46 			meta->flags |= (1 << NFP_NET_META_VLAN);
47 			vlan_info = rte_be_to_cpu_32(*(rte_be32_t *)meta_offset);
48 			meta->vlan[meta->vlan_layer].offload =
49 					vlan_info >> NFP_NET_META_VLAN_OFFLOAD;
50 			meta->vlan[meta->vlan_layer].tci =
51 					vlan_info & NFP_NET_META_VLAN_MASK;
52 			meta->vlan[meta->vlan_layer].tpid = NFP_NET_META_TPID(vlan_info);
53 			meta->vlan_layer++;
54 			break;
55 		case NFP_NET_META_IPSEC:
56 			meta->flags |= (1 << NFP_NET_META_IPSEC);
57 			meta->sa_idx = rte_be_to_cpu_32(*(rte_be32_t *)meta_offset);
58 			break;
59 		case NFP_NET_META_MARK:
60 			meta->flags |= (1 << NFP_NET_META_MARK);
61 			meta->mark_id = rte_be_to_cpu_32(*(rte_be32_t *)meta_offset);
62 			break;
63 		default:
64 			/* Unsupported metadata can be a performance issue */
65 			return false;
66 		}
67 	}
68 
69 	return true;
70 }
71 
72 /*
73  * Parse the single metadata
74  *
75  * The RSS hash and hash-type are prepended to the packet data.
76  * Get it from metadata area.
77  */
78 static inline void
79 nfp_net_meta_parse_single(uint8_t *meta_base,
80 		rte_be32_t meta_header,
81 		struct nfp_net_meta_parsed *meta)
82 {
83 	meta->flags = 0;
84 	meta->flags |= (1 << NFP_NET_META_HASH);
85 	meta->hash_type = rte_be_to_cpu_32(meta_header);
86 	meta->hash = rte_be_to_cpu_32(*(rte_be32_t *)(meta_base + 4));
87 }
88 
89 /* Set mbuf hash data based on the metadata info */
90 static void
91 nfp_net_meta_parse_hash(const struct nfp_net_meta_parsed *meta,
92 		struct nfp_net_rxq *rxq,
93 		struct rte_mbuf *mbuf)
94 {
95 	struct nfp_net_hw *hw = rxq->hw;
96 
97 	if ((hw->super.ctrl & NFP_NET_CFG_CTRL_RSS_ANY) == 0)
98 		return;
99 
100 	if (((meta->flags >> NFP_NET_META_HASH) & 0x1) == 0)
101 		return;
102 
103 	mbuf->hash.rss = meta->hash;
104 	mbuf->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
105 }
106 
107 /* Set mbuf vlan_strip data based on metadata info */
108 static void
109 nfp_net_meta_parse_vlan(const struct nfp_net_meta_parsed *meta,
110 		struct nfp_net_rx_desc *rxd,
111 		struct nfp_net_rxq *rxq,
112 		struct rte_mbuf *mb)
113 {
114 	uint32_t ctrl = rxq->hw->super.ctrl;
115 
116 	/* Skip if hardware don't support setting vlan. */
117 	if ((ctrl & (NFP_NET_CFG_CTRL_RXVLAN | NFP_NET_CFG_CTRL_RXVLAN_V2)) == 0)
118 		return;
119 
120 	if (((meta->flags >> NFP_NET_META_VLAN) & 0x1) == 0)
121 		return;
122 
123 	/*
124 	 * The firmware support two ways to send the VLAN info (with priority) :
125 	 * 1. Using the metadata when NFP_NET_CFG_CTRL_RXVLAN_V2 is set,
126 	 * 2. Using the descriptor when NFP_NET_CFG_CTRL_RXVLAN is set.
127 	 */
128 	if ((ctrl & NFP_NET_CFG_CTRL_RXVLAN_V2) != 0) {
129 		if (meta->vlan_layer > 0 && meta->vlan[0].offload != 0) {
130 			mb->vlan_tci = rte_cpu_to_le_32(meta->vlan[0].tci);
131 			mb->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
132 		}
133 	} else if ((ctrl & NFP_NET_CFG_CTRL_RXVLAN) != 0) {
134 		if ((rxd->rxd.flags & PCIE_DESC_RX_VLAN) != 0) {
135 			mb->vlan_tci = rte_cpu_to_le_32(rxd->rxd.offload_info);
136 			mb->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
137 		}
138 	}
139 }
140 
141 /*
142  * Set mbuf qinq_strip data based on metadata info
143  *
144  * The out VLAN tci are prepended to the packet data.
145  * Extract and decode it and set the mbuf fields.
146  *
147  * If both RTE_MBUF_F_RX_VLAN and NFP_NET_CFG_CTRL_RXQINQ are set, the 2 VLANs
148  *   have been stripped by the hardware and their TCIs are saved in
149  *   mbuf->vlan_tci (inner) and mbuf->vlan_tci_outer (outer).
150  * If NFP_NET_CFG_CTRL_RXQINQ is set and RTE_MBUF_F_RX_VLAN is unset, only the
151  *   outer VLAN is removed from packet data, but both tci are saved in
152  *   mbuf->vlan_tci (inner) and mbuf->vlan_tci_outer (outer).
153  *
154  * qinq set & vlan set : meta->vlan_layer>=2, meta->vlan[0].offload=1, meta->vlan[1].offload=1
155  * qinq set & vlan not set: meta->vlan_layer>=2, meta->vlan[1].offload=1,meta->vlan[0].offload=0
156  * qinq not set & vlan set: meta->vlan_layer=1, meta->vlan[0].offload=1
157  * qinq not set & vlan not set: meta->vlan_layer=0
158  */
159 static void
160 nfp_net_meta_parse_qinq(const struct nfp_net_meta_parsed *meta,
161 		struct nfp_net_rxq *rxq,
162 		struct rte_mbuf *mb)
163 {
164 	struct nfp_hw *hw = &rxq->hw->super;
165 
166 	if ((hw->ctrl & NFP_NET_CFG_CTRL_RXQINQ) == 0 ||
167 			(hw->cap & NFP_NET_CFG_CTRL_RXQINQ) == 0)
168 		return;
169 
170 	if (((meta->flags >> NFP_NET_META_VLAN) & 0x1) == 0)
171 		return;
172 
173 	if (meta->vlan_layer < NFP_NET_META_MAX_VLANS)
174 		return;
175 
176 	if (meta->vlan[0].offload == 0)
177 		mb->vlan_tci = rte_cpu_to_le_16(meta->vlan[0].tci);
178 
179 	mb->vlan_tci_outer = rte_cpu_to_le_16(meta->vlan[1].tci);
180 	PMD_RX_LOG(DEBUG, "Received outer vlan TCI is %u inner vlan TCI is %u.",
181 			mb->vlan_tci_outer, mb->vlan_tci);
182 	mb->ol_flags |= RTE_MBUF_F_RX_QINQ | RTE_MBUF_F_RX_QINQ_STRIPPED;
183 }
184 
185 /*
186  * Set mbuf IPsec Offload features based on metadata info.
187  *
188  * The IPsec Offload features is prepended to the mbuf ol_flags.
189  * Extract and decode metadata info and set the mbuf ol_flags.
190  */
191 static void
192 nfp_net_meta_parse_ipsec(struct nfp_net_meta_parsed *meta,
193 		struct nfp_net_rxq *rxq,
194 		struct rte_mbuf *mbuf)
195 {
196 	int offset;
197 	uint32_t sa_idx;
198 	struct nfp_net_hw *hw;
199 	struct nfp_tx_ipsec_desc_msg *desc_md;
200 
201 	if (((meta->flags >> NFP_NET_META_IPSEC) & 0x1) == 0)
202 		return;
203 
204 	hw = rxq->hw;
205 	sa_idx = meta->sa_idx;
206 
207 	if (sa_idx >= NFP_NET_IPSEC_MAX_SA_CNT) {
208 		mbuf->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED;
209 	} else {
210 		mbuf->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD;
211 		offset = hw->ipsec_data->pkt_dynfield_offset;
212 		desc_md = RTE_MBUF_DYNFIELD(mbuf, offset, struct nfp_tx_ipsec_desc_msg *);
213 		desc_md->sa_idx = sa_idx;
214 		desc_md->enc = 0;
215 	}
216 }
217 
218 static void
219 nfp_net_meta_parse_mark(const struct nfp_net_meta_parsed *meta,
220 		struct rte_mbuf *mbuf)
221 {
222 	if (((meta->flags >> NFP_NET_META_MARK) & 0x1) == 0)
223 		return;
224 
225 	mbuf->hash.fdir.hi = meta->mark_id;
226 	mbuf->ol_flags |= RTE_MBUF_F_RX_FDIR | RTE_MBUF_F_RX_FDIR_ID;
227 }
228 
229 /* Parse the metadata from packet */
230 void
231 nfp_net_meta_parse(struct nfp_net_rx_desc *rxds,
232 		struct nfp_net_rxq *rxq,
233 		struct nfp_net_hw *hw,
234 		struct rte_mbuf *mb,
235 		struct nfp_net_meta_parsed *meta)
236 {
237 	uint8_t *meta_base;
238 	rte_be32_t meta_header;
239 
240 	meta->flags = 0;
241 
242 	if (unlikely(NFP_DESC_META_LEN(rxds) == 0))
243 		return;
244 
245 	meta_base = rte_pktmbuf_mtod_offset(mb, uint8_t *, -NFP_DESC_META_LEN(rxds));
246 	meta_header = *(rte_be32_t *)meta_base;
247 
248 	switch (hw->meta_format) {
249 	case NFP_NET_METAFORMAT_CHAINED:
250 		if (nfp_net_meta_parse_chained(meta_base, meta_header, meta)) {
251 			nfp_net_meta_parse_hash(meta, rxq, mb);
252 			nfp_net_meta_parse_vlan(meta, rxds, rxq, mb);
253 			nfp_net_meta_parse_qinq(meta, rxq, mb);
254 			nfp_net_meta_parse_ipsec(meta, rxq, mb);
255 			nfp_net_meta_parse_mark(meta, mb);
256 		} else {
257 			PMD_RX_LOG(DEBUG, "RX chained metadata format is wrong!");
258 		}
259 		break;
260 	case NFP_NET_METAFORMAT_SINGLE:
261 		if ((rxds->rxd.flags & PCIE_DESC_RX_RSS) != 0) {
262 			nfp_net_meta_parse_single(meta_base, meta_header, meta);
263 			nfp_net_meta_parse_hash(meta, rxq, mb);
264 		}
265 		break;
266 	default:
267 		PMD_RX_LOG(DEBUG, "RX metadata do not exist.");
268 	}
269 }
270 
271 void
272 nfp_net_meta_init_format(struct nfp_net_hw *hw,
273 		struct nfp_pf_dev *pf_dev)
274 {
275 	/*
276 	 * ABI 4.x and ctrl vNIC always use chained metadata, in other cases we allow use of
277 	 * single metadata if only RSS(v1) is supported by hw capability, and RSS(v2)
278 	 * also indicate that we are using chained metadata.
279 	 */
280 	if (pf_dev->ver.major == 4) {
281 		hw->meta_format = NFP_NET_METAFORMAT_CHAINED;
282 	} else if ((hw->super.cap & NFP_NET_CFG_CTRL_CHAIN_META) != 0) {
283 		hw->meta_format = NFP_NET_METAFORMAT_CHAINED;
284 		/*
285 		 * RSS is incompatible with chained metadata. hw->super.cap just represents
286 		 * firmware's ability rather than the firmware's configuration. We decide
287 		 * to reduce the confusion to allow us can use hw->super.cap to identify RSS later.
288 		 */
289 		hw->super.cap &= ~NFP_NET_CFG_CTRL_RSS;
290 	} else {
291 		hw->meta_format = NFP_NET_METAFORMAT_SINGLE;
292 	}
293 }
294 
295 void
296 nfp_net_meta_set_vlan(struct nfp_net_meta_raw *meta_data,
297 		struct rte_mbuf *pkt,
298 		uint8_t layer)
299 {
300 	uint16_t tpid;
301 	uint16_t vlan_tci;
302 
303 	tpid = RTE_ETHER_TYPE_VLAN;
304 	vlan_tci = pkt->vlan_tci;
305 
306 	meta_data->data[layer] = tpid << 16 | vlan_tci;
307 }
308 
309 void
310 nfp_net_meta_set_ipsec(struct nfp_net_meta_raw *meta_data,
311 		struct nfp_net_txq *txq,
312 		struct rte_mbuf *pkt,
313 		uint8_t layer,
314 		uint8_t ipsec_layer)
315 {
316 	int offset;
317 	struct nfp_net_hw *hw;
318 	struct nfp_tx_ipsec_desc_msg *desc_md;
319 
320 	hw = txq->hw;
321 	offset = hw->ipsec_data->pkt_dynfield_offset;
322 	desc_md = RTE_MBUF_DYNFIELD(pkt, offset, struct nfp_tx_ipsec_desc_msg *);
323 
324 	switch (ipsec_layer) {
325 	case NFP_NET_META_IPSEC_SAIDX:
326 		meta_data->data[layer] = desc_md->sa_idx;
327 		break;
328 	case NFP_NET_META_IPSEC_SEQLOW:
329 		meta_data->data[layer] = desc_md->esn.low;
330 		break;
331 	case NFP_NET_META_IPSEC_SEQHI:
332 		meta_data->data[layer] = desc_md->esn.hi;
333 		break;
334 	default:
335 		break;
336 	}
337 }
338