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