net: support VLAN in software packet type parser
[dpdk.git] / lib / librte_net / rte_net.c
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_net.h>
45
46 /* get l3 packet type from ip6 next protocol */
47 static uint32_t
48 ptype_l3_ip6(uint8_t ip6_proto)
49 {
50         static const uint32_t ip6_ext_proto_map[256] = {
51                 [IPPROTO_HOPOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
52                 [IPPROTO_ROUTING] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
53                 [IPPROTO_FRAGMENT] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
54                 [IPPROTO_ESP] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
55                 [IPPROTO_AH] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
56                 [IPPROTO_DSTOPTS] = RTE_PTYPE_L3_IPV6_EXT - RTE_PTYPE_L3_IPV6,
57         };
58
59         return RTE_PTYPE_L3_IPV6 + ip6_ext_proto_map[ip6_proto];
60 }
61
62 /* get l3 packet type from ip version and header length */
63 static uint32_t
64 ptype_l3_ip(uint8_t ipv_ihl)
65 {
66         static const uint32_t ptype_l3_ip_proto_map[256] = {
67                 [0x45] = RTE_PTYPE_L3_IPV4,
68                 [0x46] = RTE_PTYPE_L3_IPV4_EXT,
69                 [0x47] = RTE_PTYPE_L3_IPV4_EXT,
70                 [0x48] = RTE_PTYPE_L3_IPV4_EXT,
71                 [0x49] = RTE_PTYPE_L3_IPV4_EXT,
72                 [0x4A] = RTE_PTYPE_L3_IPV4_EXT,
73                 [0x4B] = RTE_PTYPE_L3_IPV4_EXT,
74                 [0x4C] = RTE_PTYPE_L3_IPV4_EXT,
75                 [0x4D] = RTE_PTYPE_L3_IPV4_EXT,
76                 [0x4E] = RTE_PTYPE_L3_IPV4_EXT,
77                 [0x4F] = RTE_PTYPE_L3_IPV4_EXT,
78         };
79
80         return ptype_l3_ip_proto_map[ipv_ihl];
81 }
82
83 /* get l4 packet type from proto */
84 static uint32_t
85 ptype_l4(uint8_t proto)
86 {
87         static const uint32_t ptype_l4_proto[256] = {
88                 [IPPROTO_UDP] = RTE_PTYPE_L4_UDP,
89                 [IPPROTO_TCP] = RTE_PTYPE_L4_TCP,
90                 [IPPROTO_SCTP] = RTE_PTYPE_L4_SCTP,
91         };
92
93         return ptype_l4_proto[proto];
94 }
95
96 /* get the ipv4 header length */
97 static uint8_t
98 ip4_hlen(const struct ipv4_hdr *hdr)
99 {
100         return (hdr->version_ihl & 0xf) * 4;
101 }
102
103 /* parse ipv6 extended headers, update offset and return next proto */
104 static uint16_t
105 skip_ip6_ext(uint16_t proto, const struct rte_mbuf *m, uint32_t *off,
106         int *frag)
107 {
108         struct ext_hdr {
109                 uint8_t next_hdr;
110                 uint8_t len;
111         };
112         const struct ext_hdr *xh;
113         struct ext_hdr xh_copy;
114         unsigned int i;
115
116         *frag = 0;
117
118 #define MAX_EXT_HDRS 5
119         for (i = 0; i < MAX_EXT_HDRS; i++) {
120                 switch (proto) {
121                 case IPPROTO_HOPOPTS:
122                 case IPPROTO_ROUTING:
123                 case IPPROTO_DSTOPTS:
124                         xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
125                                 &xh_copy);
126                         if (xh == NULL)
127                                 return 0;
128                         *off += (xh->len + 1) * 8;
129                         proto = xh->next_hdr;
130                         break;
131                 case IPPROTO_FRAGMENT:
132                         xh = rte_pktmbuf_read(m, *off, sizeof(*xh),
133                                 &xh_copy);
134                         if (xh == NULL)
135                                 return 0;
136                         *off += 8;
137                         proto = xh->next_hdr;
138                         *frag = 1;
139                         return proto; /* this is always the last ext hdr */
140                 case IPPROTO_NONE:
141                         return 0;
142                 default:
143                         return proto;
144                 }
145         }
146         return 0;
147 }
148
149 /* parse mbuf data to get packet type */
150 uint32_t rte_net_get_ptype(const struct rte_mbuf *m,
151         struct rte_net_hdr_lens *hdr_lens)
152 {
153         struct rte_net_hdr_lens local_hdr_lens;
154         const struct ether_hdr *eh;
155         struct ether_hdr eh_copy;
156         uint32_t pkt_type = RTE_PTYPE_L2_ETHER;
157         uint32_t off = 0;
158         uint16_t proto;
159
160         if (hdr_lens == NULL)
161                 hdr_lens = &local_hdr_lens;
162
163         eh = rte_pktmbuf_read(m, off, sizeof(*eh), &eh_copy);
164         if (unlikely(eh == NULL))
165                 return 0;
166         proto = eh->ether_type;
167         off = sizeof(*eh);
168         hdr_lens->l2_len = off;
169
170         if (proto == rte_cpu_to_be_16(ETHER_TYPE_VLAN)) {
171                 const struct vlan_hdr *vh;
172                 struct vlan_hdr vh_copy;
173
174                 pkt_type = RTE_PTYPE_L2_ETHER_VLAN;
175                 vh = rte_pktmbuf_read(m, off, sizeof(*vh), &vh_copy);
176                 if (unlikely(vh == NULL))
177                         return pkt_type;
178                 off += sizeof(*vh);
179                 hdr_lens->l2_len += sizeof(*vh);
180                 proto = vh->eth_proto;
181         }
182
183         if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
184                 const struct ipv4_hdr *ip4h;
185                 struct ipv4_hdr ip4h_copy;
186
187                 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
188                 if (unlikely(ip4h == NULL))
189                         return pkt_type;
190
191                 pkt_type |= ptype_l3_ip(ip4h->version_ihl);
192                 hdr_lens->l3_len = ip4_hlen(ip4h);
193                 off += hdr_lens->l3_len;
194                 if (ip4h->fragment_offset &
195                                 rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
196                                         IPV4_HDR_MF_FLAG)) {
197                         pkt_type |= RTE_PTYPE_L4_FRAG;
198                         hdr_lens->l4_len = 0;
199                         return pkt_type;
200                 }
201                 proto = ip4h->next_proto_id;
202                 pkt_type |= ptype_l4(proto);
203         } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
204                 const struct ipv6_hdr *ip6h;
205                 struct ipv6_hdr ip6h_copy;
206                 int frag = 0;
207
208                 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
209                 if (unlikely(ip6h == NULL))
210                         return pkt_type;
211
212                 proto = ip6h->proto;
213                 hdr_lens->l3_len = sizeof(*ip6h);
214                 off += hdr_lens->l3_len;
215                 pkt_type |= ptype_l3_ip6(proto);
216                 if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
217                         proto = skip_ip6_ext(proto, m, &off, &frag);
218                         hdr_lens->l3_len = off - hdr_lens->l2_len;
219                 }
220                 if (proto == 0)
221                         return pkt_type;
222                 if (frag) {
223                         pkt_type |= RTE_PTYPE_L4_FRAG;
224                         hdr_lens->l4_len = 0;
225                         return pkt_type;
226                 }
227                 pkt_type |= ptype_l4(proto);
228         }
229
230         if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
231                 hdr_lens->l4_len = sizeof(struct udp_hdr);
232         } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
233                 const struct tcp_hdr *th;
234                 struct tcp_hdr th_copy;
235
236                 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
237                 if (unlikely(th == NULL))
238                         return pkt_type & (RTE_PTYPE_L2_MASK |
239                                 RTE_PTYPE_L3_MASK);
240                 hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
241         } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
242                 hdr_lens->l4_len = sizeof(struct sctp_hdr);
243         } else {
244                 hdr_lens->l4_len = 0;
245         }
246
247         return pkt_type;
248 }