net: add function to get packet type from data
[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_IPv4)) {
171                 const struct ipv4_hdr *ip4h;
172                 struct ipv4_hdr ip4h_copy;
173
174                 ip4h = rte_pktmbuf_read(m, off, sizeof(*ip4h), &ip4h_copy);
175                 if (unlikely(ip4h == NULL))
176                         return pkt_type;
177
178                 pkt_type |= ptype_l3_ip(ip4h->version_ihl);
179                 hdr_lens->l3_len = ip4_hlen(ip4h);
180                 off += hdr_lens->l3_len;
181                 if (ip4h->fragment_offset &
182                                 rte_cpu_to_be_16(IPV4_HDR_OFFSET_MASK |
183                                         IPV4_HDR_MF_FLAG)) {
184                         pkt_type |= RTE_PTYPE_L4_FRAG;
185                         hdr_lens->l4_len = 0;
186                         return pkt_type;
187                 }
188                 proto = ip4h->next_proto_id;
189                 pkt_type |= ptype_l4(proto);
190         } else if (proto == rte_cpu_to_be_16(ETHER_TYPE_IPv6)) {
191                 const struct ipv6_hdr *ip6h;
192                 struct ipv6_hdr ip6h_copy;
193                 int frag = 0;
194
195                 ip6h = rte_pktmbuf_read(m, off, sizeof(*ip6h), &ip6h_copy);
196                 if (unlikely(ip6h == NULL))
197                         return pkt_type;
198
199                 proto = ip6h->proto;
200                 hdr_lens->l3_len = sizeof(*ip6h);
201                 off += hdr_lens->l3_len;
202                 pkt_type |= ptype_l3_ip6(proto);
203                 if ((pkt_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV6_EXT) {
204                         proto = skip_ip6_ext(proto, m, &off, &frag);
205                         hdr_lens->l3_len = off - hdr_lens->l2_len;
206                 }
207                 if (proto == 0)
208                         return pkt_type;
209                 if (frag) {
210                         pkt_type |= RTE_PTYPE_L4_FRAG;
211                         hdr_lens->l4_len = 0;
212                         return pkt_type;
213                 }
214                 pkt_type |= ptype_l4(proto);
215         }
216
217         if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_UDP) {
218                 hdr_lens->l4_len = sizeof(struct udp_hdr);
219         } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_TCP) {
220                 const struct tcp_hdr *th;
221                 struct tcp_hdr th_copy;
222
223                 th = rte_pktmbuf_read(m, off, sizeof(*th), &th_copy);
224                 if (unlikely(th == NULL))
225                         return pkt_type & (RTE_PTYPE_L2_MASK |
226                                 RTE_PTYPE_L3_MASK);
227                 hdr_lens->l4_len = (th->data_off & 0xf0) >> 2;
228         } else if ((pkt_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_SCTP) {
229                 hdr_lens->l4_len = sizeof(struct sctp_hdr);
230         } else {
231                 hdr_lens->l4_len = 0;
232         }
233
234         return pkt_type;
235 }