1 /*- 2 * BSD LICENSE 3 * 4 * Copyright 2016 6WIND S.A. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of 6WIND S.A. nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stdint.h> 35 36 #include <rte_mbuf.h> 37 #include <rte_mbuf_ptype.h> 38 #include <rte_byteorder.h> 39 #include <rte_ether.h> 40 #include <rte_ip.h> 41 #include <rte_tcp.h> 42 #include <rte_udp.h> 43 #include <rte_sctp.h> 44 #include <rte_gre.h> 45 #include <rte_net.h> 46 47 /* get l3 packet type from ip6 next protocol */ 48 static uint32_t 49 ptype_l3_ip6(uint8_t ip6_proto) 50 { 51 static const uint32_t ip6_ext_proto_map[256] = { 52 [IPPROTO_HOPOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6, 53 [IPPROTO_ROUTING] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6, 54 [IPPROTO_FRAGMENT] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6, 55 [IPPROTO_ESP] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6, 56 [IPPROTO_AH] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6, 57 [IPPROTO_DSTOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6, 58 }; 59 60 return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto]; 61 } 62 63 /* get l3 packet type from ip version and header length */ 64 static uint32_t 65 ptype_l3_ip(uint8_t ipv_ihl) 66 { 67 static const uint32_t ptype_l3_ip_proto_map[256] = { 68 [0x45] = RTE_PTYPE_L3_IPV4, 69 [0x46] = RTE_PTYPE_L3_IPV4_EXT, 70 [0x47] = RTE_PTYPE_L3_IPV4_EXT, 71 [0x48] = RTE_PTYPE_L3_IPV4_EXT, 72 [0x49] = RTE_PTYPE_L3_IPV4_EXT, 73 [0x4A] = RTE_PTYPE_L3_IPV4_EXT, 74 [0x4B] = RTE_PTYPE_L3_IPV4_EXT, 75 [0x4C] = RTE_PTYPE_L3_IPV4_EXT, 76 [0x4D] = RTE_PTYPE_L3_IPV4_EXT, 77 [0x4E] = RTE_PTYPE_L3_IPV4_EXT, 78 [0x4F] = RTE_PTYPE_L3_IPV4_EXT, 79 }; 80 81 return ptype_l3_ip_proto_map[ipv_ihl]; 82 } 83 84 /* get l4 packet type from proto */ 85 static uint32_t 86 ptype_l4(uint8_t proto) 87 { 88 static const uint32_t ptype_l4_proto[256] = { 89 [IPPROTO_UDP] = RTE_PTYPE_L4_UDP, 90 [IPPROTO_TCP] = RTE_PTYPE_L4_TCP, 91 [IPPROTO_SCTP] = RTE_PTYPE_L4_SCTP, 92 }; 93 94 return ptype_l4_proto[proto]; 95 } 96 97 /* get inner l3 packet type from ip6 next protocol */ 98 static uint32_t 99 ptype_inner_l3_ip6(uint8_t ip6_proto) 100 { 101 static const uint32_t ptype_inner_ip6_ext_proto_map[256] = { 102 [IPPROTO_HOPOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT - 103 RTE_PTYPE_INNER_L3_IPV6, 104 [IPPROTO_ROUTING] = RTE_PTYPE_INNER_L3_IPV6_EXT - 105 RTE_PTYPE_INNER_L3_IPV6, 106 [IPPROTO_FRAGMENT] = RTE_PTYPE_INNER_L3_IPV6_EXT - 107 RTE_PTYPE_INNER_L3_IPV6, 108 [IPPROTO_ESP] = RTE_PTYPE_INNER_L3_IPV6_EXT - 109 RTE_PTYPE_INNER_L3_IPV6, 110 [IPPROTO_AH] = RTE_PTYPE_INNER_L3_IPV6_EXT - 111 RTE_PTYPE_INNER_L3_IPV6, 112 [IPPROTO_DSTOPTS] = RTE_PTYPE_INNER_L3_IPV6_EXT - 113 RTE_PTYPE_INNER_L3_IPV6, 114 }; 115 116 return RTE_PTYPE_INNER_L3_IPV6 + 117 ptype_inner_ip6_ext_proto_map[ip6_proto]; 118 } 119 120 /* get inner l3 packet type from ip version and header length */ 121 static uint32_t 122 ptype_inner_l3_ip(uint8_t ipv_ihl) 123 { 124 static const uint32_t ptype_inner_l3_ip_proto_map[256] = { 125 [0x45] = RTE_PTYPE_INNER_L3_IPV4, 126 [0x46] = RTE_PTYPE_INNER_L3_IPV4_EXT, 127 [0x47] = RTE_PTYPE_INNER_L3_IPV4_EXT, 128 [0x48] = RTE_PTYPE_INNER_L3_IPV4_EXT, 129 [0x49] = RTE_PTYPE_INNER_L3_IPV4_EXT, 130 [0x4A] = RTE_PTYPE_INNER_L3_IPV4_EXT, 131 [0x4B] = RTE_PTYPE_INNER_L3_IPV4_EXT, 132 [0x4C] = RTE_PTYPE_INNER_L3_IPV4_EXT, 133 [0x4D] = RTE_PTYPE_INNER_L3_IPV4_EXT, 134 [0x4E] = RTE_PTYPE_INNER_L3_IPV4_EXT, 135 [0x4F] = RTE_PTYPE_INNER_L3_IPV4_EXT, 136 }; 137 138 return ptype_inner_l3_ip_proto_map[ipv_ihl]; 139 } 140 141 /* get inner l4 packet type from proto */ 142 static uint32_t 143 ptype_inner_l4(uint8_t proto) 144 { 145 static const uint32_t ptype_inner_l4_proto[256] = { 146 [IPPROTO_UDP] = RTE_PTYPE_INNER_L4_UDP, 147 [IPPROTO_TCP] = RTE_PTYPE_INNER_L4_TCP, 148 [IPPROTO_SCTP] = RTE_PTYPE_INNER_L4_SCTP, 149 }; 150 151 return ptype_inner_l4_proto[proto]; 152 } 153 154 /* get the tunnel packet type if any, update proto and off. */ 155 static uint32_t 156 ptype_tunnel(uint16_t *proto, const struct rte_mbuf *m, 157 uint32_t *off) 158 { 159 switch (*proto) { 160 case IPPROTO_GRE: { 161 static const uint8_t opt_len[16] = { 162 [0x0] = 4, 163 [0x1] = 8, 164 [0x2] = 8, 165 [0x8] = 8, 166 [0x3] = 12, 167 [0x9] = 12, 168 [0xa] = 12, 169 [0xb] = 16, 170 }; 171 const struct gre_hdr *gh; 172 struct gre_hdr gh_copy; 173 uint16_t flags; 174 175 gh = rte_pktmbuf_read(m, *off, sizeof(*gh), &gh_copy); 176 if (unlikely(gh == NULL)) 177 return 0; 178 179 flags = rte_be_to_cpu_16(*(const uint16_t *)gh); 180 flags >>= 12; 181 if (opt_len[flags] == 0) 182 return 0; 183 184 *off += opt_len[flags]; 185 *proto = gh->proto; 186 if (*proto == rte_cpu_to_be_16(ETHER_TYPE_TEB)) 187 return RTE_PTYPE_TUNNEL_NVGRE; 188 else 189 return RTE_PTYPE_TUNNEL_GRE; 190 } 191 case IPPROTO_IPIP: 192 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv4); 193 return RTE_PTYPE_TUNNEL_IP; 194 case IPPROTO_IPV6: 195 *proto = rte_cpu_to_be_16(ETHER_TYPE_IPv6); 196 return RTE_PTYPE_TUNNEL_IP; /* IP is also valid for IPv6 */ 197 default: 198 return 0; 199 } 200 } 201 202 /* get the ipv4 header length */ 203 static uint8_t 204 ip4_hlen(const struct ipv4_hdr *hdr) 205 { 206 return (hdr->version_ihl & 0xf) * 4; 207 } 208 209 /* parse ipv6 extended headers, update offset and return next proto */ 210 static uint16_t 211 skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off, 212 int *frag) 213 { 214 struct ext_hdr { 215 uint8_t next_hdr; 216 uint8_t len; 217 }; 218 const struct ext_hdr *xh; 219 struct ext_hdr xh_copy; 220 unsigned int i; 221 222 *frag = 0; 223 224 #define MAX_EXT_HDRS 5 225 for (i = 0; i < MAX_EXT_HDRS; i++) { 226 switch (proto) { 227 case IPPROTO_HOPOPTS: 228 case IPPROTO_ROUTING: 229 case IPPROTO_DSTOPTS: 230 xh = rte_pktmbuf_read(m, *off, sizeof(*xh), 231 &xh_copy); 232 if (xh == NULL) 233 return 0; 234 *off += (xh->len + 1) * 8; 235 proto = xh->next_hdr; 236 break; 237 case IPPROTO_FRAGMENT: 238 xh = rte_pktmbuf_read(m, *off, sizeof(*xh), 239 &xh_copy); 240 if (xh == NULL) 241 return 0; 242 *off += 8; 243 proto = xh->next_hdr; 244 *frag = 1; 245 return proto; /* this is always the last ext hdr */ 246 case IPPROTO_NONE: 247 return 0; 248 default: 249 return proto; 250 } 251 } 252 return 0; 253 } 254 255 /* parse mbuf data to get packet type */ 256 uint32_t rte_net_get_ptype(const struct rte_mbuf *m, 257 struct rte_net_hdr_lens *hdr_lens, uint32_t layers) 258 { 259 struct rte_net_hdr_lens local_hdr_lens; 260 const struct ether_hdr *eh; 261 struct ether_hdr eh_copy; 262 uint32_t pkt_type = RTE_PTYPE_L2_ETHER; 263 uint32_t off = 0; 264 uint16_t proto; 265 266 if (hdr_lens == NULL) 267 hdr_lens = &local_hdr_lens; 268 269 eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy); 270 if (unlikely(eh == NULL)) 271 return 0; 272 proto = eh->ether_type; 273 off = sizeof(*eh); 274 hdr_lens->l2_len = off; 275 276 if ((layers & RTE_PTYPE_L2_MASK) == 0) 277 return 0; 278 279 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) 280 goto l3; /* fast path if packet is IPv4 */ 281 282 if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) { 283 const struct vlan_hdr *vh; 284 struct vlan_hdr vh_copy; 285 286 pkt_type = RTE_PTYPE_L2_ETHER_VLAN; 287 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy); 288 if (unlikely(vh == NULL)) 289 return pkt_type; 290 off += sizeof(*vh); 291 hdr_lens->l2_len += sizeof(*vh); 292 proto = vh->eth_proto; 293 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) { 294 const struct vlan_hdr *vh; 295 struct vlan_hdr vh_copy; 296 297 pkt_type = RTE_PTYPE_L2_ETHER_QINQ; 298 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh), 299 &vh_copy); 300 if (unlikely(vh == NULL)) 301 return pkt_type; 302 off += 2 * sizeof(*vh); 303 hdr_lens->l2_len += 2 * sizeof(*vh); 304 proto = vh->eth_proto; 305 } 306 307 l3: 308 if ((layers & RTE_PTYPE_L3_MASK) == 0) 309 return pkt_type; 310 311 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) { 312 const struct ipv4_hdr *ip4h; 313 struct ipv4_hdr ip4h_copy; 314 315 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy); 316 if (unlikely(ip4h == NULL)) 317 return pkt_type; 318 319 pkt_type |= ptype_l3_ip(ip4h->version_ihl); 320 hdr_lens->l3_len = ip4_hlen(ip4h); 321 off += hdr_lens->l3_len; 322 323 if ((layers & RTE_PTYPE_L4_MASK) == 0) 324 return pkt_type; 325 326 if (ip4h->fragment_offset & rte_cpu_to_be_16( 327 IPV4_HDR_OFFSET_MASK | IPV4_HDR_MF_FLAG)) { 328 pkt_type |= RTE_PTYPE_L4_FRAG; 329 hdr_lens->l4_len = 0; 330 return pkt_type; 331 } 332 proto = ip4h->next_proto_id; 333 pkt_type |= ptype_l4(proto); 334 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) { 335 const struct ipv6_hdr *ip6h; 336 struct ipv6_hdr ip6h_copy; 337 int frag = 0; 338 339 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy); 340 if (unlikely(ip6h == NULL)) 341 return pkt_type; 342 343 proto = ip6h->proto; 344 hdr_lens->l3_len = sizeof(*ip6h); 345 off += hdr_lens->l3_len; 346 pkt_type |= ptype_l3_ip6(proto); 347 if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) { 348 proto = skip_ip6_ext(proto, m, &off, &frag); 349 hdr_lens->l3_len = off - hdr_lens->l2_len; 350 } 351 if (proto == 0) 352 return pkt_type; 353 354 if ((layers & RTE_PTYPE_L4_MASK) == 0) 355 return pkt_type; 356 357 if (frag) { 358 pkt_type |= RTE_PTYPE_L4_FRAG; 359 hdr_lens->l4_len = 0; 360 return pkt_type; 361 } 362 pkt_type |= ptype_l4(proto); 363 } 364 365 if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) { 366 hdr_lens->l4_len = sizeof(struct udp_hdr); 367 return pkt_type; 368 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) { 369 const struct tcp_hdr *th; 370 struct tcp_hdr th_copy; 371 372 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy); 373 if (unlikely(th == NULL)) 374 return pkt_type & (RTE_PTYPE_L2_MASK | 375 RTE_PTYPE_L3_MASK); 376 hdr_lens->l4_len = (th->data_off & 0xf0) >> 2; 377 return pkt_type; 378 } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) { 379 hdr_lens->l4_len = sizeof(struct sctp_hdr); 380 return pkt_type; 381 } else { 382 uint32_t prev_off = off; 383 384 hdr_lens->l4_len = 0; 385 386 if ((layers & RTE_PTYPE_TUNNEL_MASK) == 0) 387 return pkt_type; 388 389 pkt_type |= ptype_tunnel(&proto, m, &off); 390 hdr_lens->tunnel_len = off - prev_off; 391 } 392 393 /* same job for inner header: we need to duplicate the code 394 * because the packet types do not have the same value. 395 */ 396 if ((layers & RTE_PTYPE_INNER_L2_MASK) == 0) 397 return pkt_type; 398 399 hdr_lens->inner_l2_len = 0; 400 if (proto == rte_cpu_to_be_16(ETHER_TYPE_TEB)) { 401 eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy); 402 if (unlikely(eh == NULL)) 403 return pkt_type; 404 pkt_type |= RTE_PTYPE_INNER_L2_ETHER; 405 proto = eh->ether_type; 406 off += sizeof(*eh); 407 hdr_lens->inner_l2_len = sizeof(*eh); 408 } 409 410 if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) { 411 const struct vlan_hdr *vh; 412 struct vlan_hdr vh_copy; 413 414 pkt_type &= ~RTE_PTYPE_INNER_L2_MASK; 415 pkt_type |= RTE_PTYPE_INNER_L2_ETHER_VLAN; 416 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy); 417 if (unlikely(vh == NULL)) 418 return pkt_type; 419 off += sizeof(*vh); 420 hdr_lens->inner_l2_len += sizeof(*vh); 421 proto = vh->eth_proto; 422 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_QINQ)) { 423 const struct vlan_hdr *vh; 424 struct vlan_hdr vh_copy; 425 426 pkt_type &= ~RTE_PTYPE_INNER_L2_MASK; 427 pkt_type |= RTE_PTYPE_INNER_L2_ETHER_QINQ; 428 vh = rte_pktmbuf_read(m, off + sizeof(*vh), sizeof(*vh), 429 &vh_copy); 430 if (unlikely(vh == NULL)) 431 return pkt_type; 432 off += 2 * sizeof(*vh); 433 hdr_lens->inner_l2_len += 2 * sizeof(*vh); 434 proto = vh->eth_proto; 435 } 436 437 if ((layers & RTE_PTYPE_INNER_L3_MASK) == 0) 438 return pkt_type; 439 440 if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) { 441 const struct ipv4_hdr *ip4h; 442 struct ipv4_hdr ip4h_copy; 443 444 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy); 445 if (unlikely(ip4h == NULL)) 446 return pkt_type; 447 448 pkt_type |= ptype_inner_l3_ip(ip4h->version_ihl); 449 hdr_lens->inner_l3_len = ip4_hlen(ip4h); 450 off += hdr_lens->inner_l3_len; 451 452 if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0) 453 return pkt_type; 454 if (ip4h->fragment_offset & 455 rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK | 456 IPV4_HDR_MF_FLAG)) { 457 pkt_type |= RTE_PTYPE_INNER_L4_FRAG; 458 hdr_lens->inner_l4_len = 0; 459 return pkt_type; 460 } 461 proto = ip4h->next_proto_id; 462 pkt_type |= ptype_inner_l4(proto); 463 } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) { 464 const struct ipv6_hdr *ip6h; 465 struct ipv6_hdr ip6h_copy; 466 int frag = 0; 467 468 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy); 469 if (unlikely(ip6h == NULL)) 470 return pkt_type; 471 472 proto = ip6h->proto; 473 hdr_lens->inner_l3_len = sizeof(*ip6h); 474 off += hdr_lens->inner_l3_len; 475 pkt_type |= ptype_inner_l3_ip6(proto); 476 if ((pkt_type & RTE_PTYPE_INNER_L3_MASK) == 477 RTE_PTYPE_INNER_L3_IPV6_EXT) { 478 uint32_t prev_off; 479 480 prev_off = off; 481 proto = skip_ip6_ext(proto, m, &off, &frag); 482 hdr_lens->inner_l3_len += off - prev_off; 483 } 484 if (proto == 0) 485 return pkt_type; 486 487 if ((layers & RTE_PTYPE_INNER_L4_MASK) == 0) 488 return pkt_type; 489 490 if (frag) { 491 pkt_type |= RTE_PTYPE_INNER_L4_FRAG; 492 hdr_lens->inner_l4_len = 0; 493 return pkt_type; 494 } 495 pkt_type |= ptype_inner_l4(proto); 496 } 497 498 if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == RTE_PTYPE_INNER_L4_UDP) { 499 hdr_lens->inner_l4_len = sizeof(struct udp_hdr); 500 } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == 501 RTE_PTYPE_INNER_L4_TCP) { 502 const struct tcp_hdr *th; 503 struct tcp_hdr th_copy; 504 505 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy); 506 if (unlikely(th == NULL)) 507 return pkt_type & (RTE_PTYPE_INNER_L2_MASK | 508 RTE_PTYPE_INNER_L3_MASK); 509 hdr_lens->inner_l4_len = (th->data_off & 0xf0) >> 2; 510 } else if ((pkt_type & RTE_PTYPE_INNER_L4_MASK) == 511 RTE_PTYPE_INNER_L4_SCTP) { 512 hdr_lens->inner_l4_len = sizeof(struct sctp_hdr); 513 } else { 514 hdr_lens->inner_l4_len = 0; 515 } 516 517 return pkt_type; 518 } 519