some enhancements on TLDK
[tldk.git] / lib / libtle_glue / rxcb.c
1 /*
2  * Copyright (c) 2018 Ant Financial Services Group.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <rte_ethdev.h>
17 #include <rte_arp.h>
18 #include <rte_ip.h>
19 #include <rte_tcp.h>
20 #include <rte_udp.h>
21
22 #include <netinet/in.h>
23 #include <netinet/ip6.h>
24
25 #include "log.h"
26 #include "ctx.h"
27 #include "internal.h"
28
29 struct ptype2cb {
30         uint32_t mask;
31         const char *name;
32         rte_rx_callback_fn fn;
33 };
34
35 enum {
36         ETHER_ARP_PTYPE = 0x1,
37         IPV4_PTYPE = 0x2,
38         IPV4_EXT_PTYPE = 0x4,
39         IPV6_PTYPE = 0x8,
40         IPV6_EXT_PTYPE = 0x10,
41         TCP_PTYPE = 0x20,
42         UDP_PTYPE = 0x40,
43         ICMP_PTYPE = 0x80,
44 };
45
46 static inline uint64_t
47 _mbuf_tx_offload(uint64_t il2, uint64_t il3, uint64_t il4, uint64_t tso,
48         uint64_t ol3, uint64_t ol2)
49 {
50         return il2 | il3 << 7 | il4 << 16 | tso << 24 | ol3 << 40 | ol2 << 49;
51 }
52
53 static inline int32_t
54 fill_pkt_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t l3, uint32_t l4)
55 {
56         if (l2 + l3 + l4 > m->pkt_len)
57                 return -1;
58         m->tx_offload = _mbuf_tx_offload(l2, l3, l4, 0, 0, 0);
59         return 0;
60 }
61
62 static inline int
63 is_ipv4_frag(const struct ipv4_hdr *iph)
64 {
65         const uint16_t mask = rte_cpu_to_be_16(~IPV4_HDR_DF_FLAG);
66
67         return ((mask & iph->fragment_offset) != 0);
68 }
69
70 static inline uint32_t
71 get_tcp_header_size(struct rte_mbuf *m, uint32_t l2_len, uint32_t l3_len)
72 {
73         const struct tcp_hdr *tcp;
74
75         tcp = rte_pktmbuf_mtod_offset(m, struct tcp_hdr *, l2_len + l3_len);
76         return (tcp->data_off >> 4) * 4;
77 }
78
79 static inline int32_t
80 adjust_ipv4_pktlen(struct rte_mbuf *m, uint32_t l2_len)
81 {
82         uint32_t plen, trim;
83         const struct ipv4_hdr *iph;
84
85         iph = rte_pktmbuf_mtod_offset(m, const struct ipv4_hdr *, l2_len);
86         plen = rte_be_to_cpu_16(iph->total_length) + l2_len;
87         if (plen < m->pkt_len) {
88                 trim = m->pkt_len - plen;
89                 rte_pktmbuf_trim(m, trim);
90         } else if (plen > m->pkt_len) {
91                 return -1;
92         }
93         return 0;
94 }
95
96 static inline int32_t
97 adjust_ipv6_pktlen(struct rte_mbuf *m, uint32_t l2_len)
98 {
99         uint32_t plen, trim;
100         const struct ipv6_hdr *iph;
101
102         iph = rte_pktmbuf_mtod_offset(m, const struct ipv6_hdr *, l2_len);
103         plen = rte_be_to_cpu_16(iph->payload_len) + sizeof(*iph) + l2_len;
104         if (plen < m->pkt_len) {
105                 trim = m->pkt_len - plen;
106                 rte_pktmbuf_trim(m, trim);
107         } else if (plen > m->pkt_len) {
108                 return -1;
109         }
110         return 0;
111 }
112
113 static inline uint32_t
114 get_ipv4_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t proto, uint32_t frag)
115 {
116         const struct ipv4_hdr *iph;
117         int32_t dlen, len;
118
119         dlen = rte_pktmbuf_data_len(m);
120         dlen -= l2;
121
122         iph = rte_pktmbuf_mtod_offset(m, const struct ipv4_hdr *, l2);
123         len = (iph->version_ihl & IPV4_HDR_IHL_MASK) * IPV4_IHL_MULTIPLIER;
124
125         if (frag != 0 && is_ipv4_frag(iph)) {
126                 m->packet_type &= ~RTE_PTYPE_L4_MASK;
127                 m->packet_type |= RTE_PTYPE_L4_FRAG;
128         }
129
130         if (len > dlen || (proto <= IPPROTO_MAX && iph->next_proto_id != proto))
131                 m->packet_type = RTE_PTYPE_UNKNOWN;
132
133         return len;
134 }
135
136 static inline uint32_t
137 get_ipv6x_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t *fproto)
138 {
139         const struct ipv6_hdr *ip6h;
140         const struct ip6_ext *ipx;
141         uint32_t nproto;
142         int32_t dlen, len, ofs;
143
144         ip6h = rte_pktmbuf_mtod_offset(m, struct ipv6_hdr*, l2);
145         nproto = ip6h->proto;
146         len = sizeof(struct ipv6_hdr);
147
148         dlen = rte_pktmbuf_data_len(m);
149         dlen -= l2;
150
151         ofs = l2 + len;
152         ipx = rte_pktmbuf_mtod_offset(m, const struct ip6_ext *, ofs);
153
154         while (ofs > 0 && len < dlen) {
155
156                 switch (nproto) {
157                 case IPPROTO_HOPOPTS:
158                 case IPPROTO_ROUTING:
159                 case IPPROTO_DSTOPTS:
160                         ofs = (ipx->ip6e_len + 1) << 3;
161                         break;
162                 case IPPROTO_AH:
163                         ofs = (ipx->ip6e_len + 2) << 2;
164                         break;
165                 case IPPROTO_FRAGMENT:
166                         /*
167                          * tso_segsz is not used by RX, so use it as temporary
168                          * buffer to store the fragment offset.
169                          */
170                         m->tso_segsz = l2 + len;
171                         ofs = sizeof(struct ip6_frag);
172                         m->packet_type &= ~RTE_PTYPE_L4_MASK;
173                         m->packet_type |= RTE_PTYPE_L4_FRAG;
174                         break;
175                 case IPPROTO_TCP:
176                 case IPPROTO_UDP:
177                 case IPPROTO_ICMPV6:
178                         ofs = 0;
179                         if (*fproto == 0)
180                                 *fproto = nproto;
181                         break;
182                 default:
183                         ofs = 0;
184                 }
185
186                 if (ofs > 0) {
187                         nproto = ipx->ip6e_nxt;
188                         len += ofs;
189                         ipx += ofs / sizeof(*ipx);
190                 }
191         }
192
193         /* unrecognized or invalid packet. */
194         if (*fproto == 0 || len > dlen)
195                 m->packet_type = RTE_PTYPE_UNKNOWN;
196
197         return len;
198 }
199
200 static inline uint32_t
201 get_ipv6_hdr_len(struct rte_mbuf *m, uint32_t l2, uint32_t fproto)
202 {
203         const struct ipv6_hdr *iph;
204
205         iph = rte_pktmbuf_mtod_offset(m, const struct ipv6_hdr *,
206                 sizeof(struct ether_hdr));
207
208         if (iph->proto == fproto)
209                 return sizeof(struct ipv6_hdr);
210         else
211                 return get_ipv6x_hdr_len(m, l2, &fproto);
212 }
213
214 static inline struct rte_mbuf*
215 process_ipv4_frag(struct rte_mbuf *m, struct glue_ctx *ctx, uint32_t l2_len, uint32_t l3_len)
216 {
217         struct ipv4_hdr* iph;
218
219         m->l2_len = l2_len;
220         m->l3_len = l3_len;
221         /* fixme: ip checksum should be checked here.
222          * After reassemble, the ip checksum would be invalid.
223          */
224         m = rte_ipv4_frag_reassemble_packet(ctx->frag_tbl,
225                         &ctx->frag_dr, m, rte_rdtsc(),
226                         rte_pktmbuf_mtod_offset(m, struct ipv4_hdr*, m->l2_len));
227         rte_ip_frag_free_death_row(&ctx->frag_dr, 3);
228         if (m == NULL)
229                 return NULL;
230         iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr*, m->l2_len);
231         switch (iph->next_proto_id) {
232         case IPPROTO_TCP:
233                 m->packet_type &= ~RTE_PTYPE_L4_MASK;
234                 m->packet_type |= RTE_PTYPE_L4_TCP;
235                 break;
236         case IPPROTO_UDP:
237                 m->packet_type &= ~RTE_PTYPE_L4_MASK;
238                 m->packet_type |= RTE_PTYPE_L4_UDP;
239                 break;
240         }
241         return m;
242 }
243
244 static inline struct rte_mbuf*
245 process_ipv6_frag(struct rte_mbuf *m, struct glue_ctx *ctx, uint32_t l2_len, uint32_t l3_len)
246 {
247         struct ipv6_hdr* ip6h;
248
249         m->l2_len = l2_len;
250         m->l3_len = l3_len;
251         m = rte_ipv6_frag_reassemble_packet(ctx->frag_tbl,
252                         &ctx->frag_dr, m, rte_rdtsc(),
253                         rte_pktmbuf_mtod_offset(m, struct ipv6_hdr*, l2_len),
254                         rte_pktmbuf_mtod_offset(m, struct ipv6_extension_fragment*, m->tso_segsz));
255         rte_ip_frag_free_death_row(&ctx->frag_dr, 3);
256         if (m == NULL)
257                 return NULL;
258         ip6h = rte_pktmbuf_mtod_offset(m, struct ipv6_hdr*, m->l2_len);
259         switch (ip6h->proto) {
260         case IPPROTO_TCP:
261                 m->packet_type &= ~RTE_PTYPE_L4_MASK;
262                 m->packet_type |= RTE_PTYPE_L4_TCP;
263                 break;
264         case IPPROTO_UDP:
265                 m->packet_type &= ~RTE_PTYPE_L4_MASK;
266                 m->packet_type |= RTE_PTYPE_L4_UDP;
267                 break;
268         }
269         return m;
270 }
271
272 static inline struct rte_mbuf *
273 fill_ptypes_and_hdr_len(struct glue_ctx *ctx, struct rte_mbuf *m)
274 {
275         uint32_t dlen, l2_len, l3_len, l4_len, proto;
276         const struct ether_hdr *eth;
277         uint32_t ptypes;
278         uint16_t etp;
279         int32_t error = 0;
280
281         dlen = rte_pktmbuf_data_len(m);
282
283         /* L2 */
284         l2_len = sizeof(*eth);
285
286         eth = rte_pktmbuf_mtod(m, const struct ether_hdr *);
287         etp = eth->ether_type;
288         while (etp == rte_be_to_cpu_16(ETHER_TYPE_VLAN)) {
289                 etp = rte_pktmbuf_mtod_offset(m, struct vlan_hdr*, l2_len)->eth_proto;
290                 l2_len += sizeof(struct vlan_hdr);
291         }
292
293         if (etp == rte_be_to_cpu_16(ETHER_TYPE_ARP))
294                 return arp_recv(ctx, m, l2_len);
295
296         if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv4)) {
297                 const struct ipv4_hdr *hdr;
298
299                 /* L3 */
300                 hdr = rte_pktmbuf_mtod_offset(m, const struct ipv4_hdr *, l2_len);
301                 error = adjust_ipv4_pktlen(m, l2_len);
302                 if (error) {
303                         rte_pktmbuf_free(m);
304                         return NULL;
305                 }
306                 l3_len = get_ipv4_hdr_len(m, l2_len, IPPROTO_MAX + 1, 1);
307
308                 if ((m->packet_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_FRAG) {
309                         m = process_ipv4_frag(m, ctx, l2_len, l3_len);
310                         if (m == NULL)
311                                 return NULL;
312                         hdr = rte_pktmbuf_mtod_offset(m, const struct ipv4_hdr*, m->l2_len);
313                         l3_len = get_ipv4_hdr_len(m, m->l2_len, IPPROTO_MAX + 1, 0);
314                 }
315
316                 /* L4 */
317                 switch (hdr->next_proto_id) {
318                 case IPPROTO_ICMP:
319                         return icmp_recv(ctx, m, l2_len, l3_len);
320                 case IPPROTO_TCP:
321                         ptypes = RTE_PTYPE_L4_TCP |
322                                   RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
323                                   RTE_PTYPE_L2_ETHER;
324                         l4_len = get_tcp_header_size(m, l2_len, l3_len);
325                         break;
326                 case IPPROTO_UDP:
327                         ptypes = RTE_PTYPE_L4_UDP |
328                                  RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
329                                  RTE_PTYPE_L2_ETHER;
330                         l4_len = sizeof(struct udp_hdr);
331                         break;
332                 default:
333                         GLUE_LOG(ERR, "drop ipv4 pkt of unknow L4: (%d)",
334                                  hdr->next_proto_id);
335                         rte_pktmbuf_free(m);
336                         return NULL;
337                 }
338
339         } else if (etp == rte_be_to_cpu_16(ETHER_TYPE_IPv6) &&
340                    dlen >= l2_len + sizeof(struct ipv6_hdr) + sizeof(struct udp_hdr)) {
341                 /* L3 */
342                 error = adjust_ipv6_pktlen(m, l2_len);
343                 if (error) {
344                         rte_pktmbuf_free(m);
345                         return NULL;
346                 }
347                 proto = 0;
348                 l3_len = get_ipv6x_hdr_len(m, l2_len, &proto);
349
350                 if ((m->packet_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_FRAG) {
351                         m = process_ipv6_frag(m, ctx, l2_len, l3_len);
352                         if (m == NULL)
353                                 return NULL;
354                         l3_len = get_ipv6x_hdr_len(m, m->l2_len, &proto);
355                 }
356
357                 /* L4 */
358                 switch (proto) {
359                 case IPPROTO_TCP:
360                         ptypes = RTE_PTYPE_L4_TCP |
361                                  RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
362                                  RTE_PTYPE_L2_ETHER;
363                         l4_len = get_tcp_header_size(m, l2_len, l3_len);
364                         break;
365                 case IPPROTO_UDP:
366                         ptypes = RTE_PTYPE_L4_UDP |
367                                  RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
368                                  RTE_PTYPE_L2_ETHER;
369                         l4_len = sizeof(struct udp_hdr);
370                         break;
371                 case IPPROTO_ICMPV6:
372                         return icmp6_recv(ctx, m, l2_len, l3_len);
373                 default:
374                         GLUE_DEBUG("drop ipv6 pkt of unknown L4: (%x)", proto);
375                         rte_pktmbuf_free(m);
376                         return NULL;
377                 }
378         } else {
379                 GLUE_DEBUG("Drop unknown L3 packet: %x", etp);
380                 rte_pktmbuf_free(m);
381                 return NULL;
382         }
383
384         m->packet_type = ptypes;
385         error = fill_pkt_hdr_len(m, l2_len, l3_len, l4_len);
386         if (error) {
387                 rte_pktmbuf_free(m);
388                 return NULL;
389         }
390
391         return m;
392 }
393
394 /* exclude NULLs from the final list of packets. */
395 static inline uint32_t
396 compress_pkt_list(struct rte_mbuf *pkt[], uint32_t nb_pkt, uint32_t nb_zero)
397 {
398         uint32_t i, j, k, l;
399
400         for (j = nb_pkt; nb_zero != 0 && j-- != 0; ) {
401
402                 /* found a hole. */
403                 if (pkt[j] == NULL) {
404
405                         /* find how big is it. */
406                         for (i = j; i-- != 0 && pkt[i] == NULL; )
407                                 ;
408                         /* fill the hole. */
409                         for (k = j + 1, l = i + 1; k != nb_pkt; k++, l++)
410                                 pkt[l] = pkt[k];
411
412                         nb_pkt -= j - i;
413                         nb_zero -= j - i;
414                         j = i + 1;
415                 }
416         }
417
418         return nb_pkt;
419 }
420
421 static inline struct rte_mbuf *
422 common_fill_hdr_len(struct rte_mbuf *m, uint32_t tp, struct glue_ctx *ctx)
423 {
424         uint32_t l4_len, l3_len, l2_len = sizeof(struct ether_hdr);
425         int32_t error = 0;
426
427         switch (tp) {
428         /* possibly fragmented packets. */
429         case (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L2_ETHER):
430         case (RTE_PTYPE_L3_IPV4_EXT | RTE_PTYPE_L2_ETHER):
431                 l3_len = get_ipv4_hdr_len(m, l2_len, IPPROTO_MAX + 1, 1);
432                 if ((m->packet_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_FRAG) {
433                         m = process_ipv4_frag(m, ctx, l2_len, l3_len);
434                         if (m == NULL)
435                                 return NULL;
436                         tp = m->packet_type & (RTE_PTYPE_L2_MASK | RTE_PTYPE_L3_MASK |
437                                         RTE_PTYPE_L4_MASK);
438                 }
439                 break;
440         case (RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L2_ETHER):
441         case (RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L2_ETHER):
442                 l3_len = get_ipv6_hdr_len(m, l2_len, IPPROTO_MAX + 1);
443                 if ((m->packet_type & RTE_PTYPE_L4_MASK) == RTE_PTYPE_L4_FRAG) {
444                         m = process_ipv6_frag(m, ctx, l2_len, l3_len);
445                         if (m == NULL)
446                                 return NULL;
447                         tp = m->packet_type & (RTE_PTYPE_L2_MASK | RTE_PTYPE_L3_MASK |
448                                         RTE_PTYPE_L4_MASK);
449                 }
450                 break;
451         }
452
453         switch (tp) {
454         /* non fragmented tcp packets. */
455         case (RTE_PTYPE_L4_TCP | RTE_PTYPE_L3_IPV4 |
456                         RTE_PTYPE_L2_ETHER):
457                 l3_len = sizeof(struct ipv4_hdr);
458                 l4_len = get_tcp_header_size(m, l2_len, l3_len);
459                 error = adjust_ipv4_pktlen(m, l2_len);
460                 break;
461         case (RTE_PTYPE_L4_TCP | RTE_PTYPE_L3_IPV6 |
462                         RTE_PTYPE_L2_ETHER):
463                 l3_len = sizeof(struct ipv6_hdr);
464                 l4_len = get_tcp_header_size(m, l2_len, l3_len);
465                 error = adjust_ipv6_pktlen(m, l2_len);
466                 break;
467         case (RTE_PTYPE_L4_TCP | RTE_PTYPE_L3_IPV4_EXT |
468                         RTE_PTYPE_L2_ETHER):
469                 l3_len = get_ipv4_hdr_len(m, l2_len,
470                                           IPPROTO_TCP, 0);
471                 l4_len = get_tcp_header_size(m, l2_len, l3_len);
472                 error = adjust_ipv4_pktlen(m, l2_len);
473                 break;
474         case (RTE_PTYPE_L4_TCP | RTE_PTYPE_L3_IPV6_EXT |
475                         RTE_PTYPE_L2_ETHER):
476                 l3_len = get_ipv6_hdr_len(m, l2_len, IPPROTO_TCP);
477                 l4_len = get_tcp_header_size(m, l2_len, l3_len);
478                 error = adjust_ipv6_pktlen(m, l2_len);
479                 break;
480
481         /* non fragmented udp packets. */
482         case (RTE_PTYPE_L4_UDP | RTE_PTYPE_L3_IPV4 |
483                         RTE_PTYPE_L2_ETHER):
484                 l3_len = sizeof(struct ipv4_hdr);
485                 l4_len = sizeof(struct udp_hdr);
486                 error = adjust_ipv4_pktlen(m, l2_len);
487                 break;
488         case (RTE_PTYPE_L4_UDP | RTE_PTYPE_L3_IPV6 |
489                         RTE_PTYPE_L2_ETHER):
490                 l3_len = sizeof(struct ipv6_hdr);
491                 l4_len = sizeof(struct udp_hdr);
492                 error = adjust_ipv6_pktlen(m, l2_len);
493                 break;
494         case (RTE_PTYPE_L4_UDP | RTE_PTYPE_L3_IPV4_EXT |
495                         RTE_PTYPE_L2_ETHER):
496                 l3_len = get_ipv4_hdr_len(m, l2_len,
497                                           IPPROTO_UDP, 0);
498                 l4_len = sizeof(struct udp_hdr);
499                 error = adjust_ipv4_pktlen(m, l2_len);
500                 break;
501         case (RTE_PTYPE_L4_UDP | RTE_PTYPE_L3_IPV6_EXT |
502                         RTE_PTYPE_L2_ETHER):
503                 l3_len = get_ipv6_hdr_len(m, l2_len, IPPROTO_UDP);
504                 l4_len = sizeof(struct udp_hdr);
505                 error = adjust_ipv6_pktlen(m, l2_len);
506                 break;
507         default:
508                 GLUE_LOG(ERR, "drop unknown pkt");
509                 rte_pktmbuf_free(m);
510                 return NULL;
511         }
512
513         if (error) {
514                 rte_pktmbuf_free(m);
515                 return NULL;
516         }
517         error = fill_pkt_hdr_len(m, l2_len, l3_len, l4_len);
518         if (error) {
519                 rte_pktmbuf_free(m);
520                 return NULL;
521         }
522         return m;
523 }
524
525
526 /*
527  * HW can recognize L2-arp/L3 with/without extensions/L4 (i40e)
528  */
529 static uint16_t
530 type0_rx_callback(uint16_t port,
531                   uint16_t queue,
532                   struct rte_mbuf *pkt[],
533                   uint16_t nb_pkts,
534                   uint16_t max_pkts,
535                   void *user_param)
536 {
537         uint32_t j, tp, l2_len, l3_len;
538         struct glue_ctx *ctx;
539         uint16_t nb_zero = 0;
540
541         RTE_SET_USED(port);
542         RTE_SET_USED(queue);
543         RTE_SET_USED(max_pkts);
544
545         ctx = user_param;
546
547         for (j = 0; j != nb_pkts; j++) {
548                 tp = pkt[j]->packet_type & (RTE_PTYPE_L4_MASK |
549                      RTE_PTYPE_L3_MASK | RTE_PTYPE_L2_MASK);
550
551                 switch (tp) {
552                 case (RTE_PTYPE_L2_ETHER_ARP):
553                         arp_recv(ctx, pkt[j], sizeof(struct ether_hdr));
554                         pkt[j] = NULL;
555                         nb_zero++;
556                         break;
557                 case (RTE_PTYPE_L4_ICMP | RTE_PTYPE_L3_IPV4 |
558                       RTE_PTYPE_L2_ETHER):
559                 case (RTE_PTYPE_L4_ICMP | RTE_PTYPE_L3_IPV4_EXT |
560                       RTE_PTYPE_L2_ETHER):
561                         l2_len = sizeof(struct ether_hdr);
562                         l3_len = get_ipv4_hdr_len(pkt[j], l2_len, IPPROTO_ICMP, 0);
563                         icmp_recv(ctx, pkt[j], l2_len, l3_len);
564                         pkt[j] = NULL;
565                         nb_zero++;
566                         break;
567                 case (RTE_PTYPE_L4_ICMP | RTE_PTYPE_L3_IPV6 |
568                       RTE_PTYPE_L2_ETHER):
569                 case (RTE_PTYPE_L4_ICMP | RTE_PTYPE_L3_IPV6_EXT |
570                       RTE_PTYPE_L2_ETHER):
571                         l2_len = sizeof(struct ether_hdr);
572                         l3_len = get_ipv6_hdr_len(pkt[j], l2_len, IPPROTO_ICMPV6);
573                         icmp6_recv(ctx, pkt[j], l2_len, l3_len);
574                         pkt[j] = NULL;
575                         nb_zero++;
576                         break;
577                 default:
578                         if (common_fill_hdr_len(pkt[j], tp, ctx) == NULL) {
579                                 pkt[j] = NULL;
580                                 nb_zero++;
581                         }
582                         break;
583                 }
584         }
585
586         if (nb_zero == 0)
587                 return nb_pkts;
588
589         return compress_pkt_list(pkt, nb_pkts, nb_zero);
590 }
591
592 /*
593  * HW can recognize L2/L3/L4 and fragments; but cannot recognize ARP
594  * nor ICMP (ixgbe).
595  */
596 static uint16_t
597 type1_rx_callback(uint16_t port,
598                   uint16_t queue,
599                   struct rte_mbuf *pkt[],
600                   uint16_t nb_pkts,
601                   uint16_t max_pkts,
602                   void *user_param)
603 {
604         uint32_t j, tp, l2_len, l3_len;
605         struct glue_ctx *ctx;
606         uint16_t nb_zero = 0;
607         const struct ether_hdr *eth;
608         const struct ipv4_hdr *ip4;
609         const struct ipv6_hdr *ip6;
610         uint16_t etp;
611
612         RTE_SET_USED(port);
613         RTE_SET_USED(queue);
614         RTE_SET_USED(max_pkts);
615
616         ctx = user_param;
617
618         for (j = 0; j != nb_pkts; j++) {
619                 tp = pkt[j]->packet_type & (RTE_PTYPE_L4_MASK |
620                         RTE_PTYPE_L3_MASK | RTE_PTYPE_L2_MASK);
621
622                 switch (tp) {
623                 case RTE_PTYPE_L2_ETHER:
624                         eth = rte_pktmbuf_mtod(pkt[j], const struct ether_hdr *);
625                         etp = eth->ether_type;
626                         if (etp == rte_be_to_cpu_16(ETHER_TYPE_ARP))
627                                 arp_recv(ctx, pkt[j], sizeof(*eth));
628                         pkt[j] = NULL;
629                         nb_zero++;
630                         break;
631                 case (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L2_ETHER):
632                 case (RTE_PTYPE_L3_IPV4_EXT | RTE_PTYPE_L2_ETHER):
633                         ip4 = rte_pktmbuf_mtod_offset(pkt[j],
634                                                       const struct ipv4_hdr *,
635                                                       sizeof(*eth));
636                         if (ip4->next_proto_id == IPPROTO_ICMP) {
637                                 l2_len = sizeof(struct ether_hdr);
638                                 l3_len = get_ipv4_hdr_len(pkt[j], l2_len, IPPROTO_ICMP, 0);
639                                 icmp_recv(ctx, pkt[j], l2_len, l3_len);
640                         } else {
641                                 rte_pktmbuf_free(pkt[j]);
642                         }
643                         pkt[j] = NULL;
644                         nb_zero++;
645                         break;
646                 case (RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L2_ETHER):
647                 case (RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L2_ETHER):
648                         ip6 = rte_pktmbuf_mtod_offset(pkt[j],
649                                                       const struct ipv6_hdr *,
650                                                       sizeof(*eth));
651                         if (ip6->proto == IPPROTO_ICMPV6) {
652                                 l2_len = sizeof(struct ether_hdr);
653                                 l3_len = get_ipv6_hdr_len(pkt[j], l2_len, IPPROTO_ICMPV6);
654                                 icmp6_recv(ctx, pkt[j], l2_len, l3_len);
655                         } else {
656                                 rte_pktmbuf_free(pkt[j]);
657                         }
658                         pkt[j] = NULL;
659                         nb_zero++;
660                         break;
661                 default:
662                         if (common_fill_hdr_len(pkt[j], tp, ctx) == NULL) {
663                                 pkt[j] = NULL;
664                                 nb_zero++;
665                         }
666                         break;
667                 }
668         }
669
670         if (nb_zero == 0)
671                 return nb_pkts;
672
673         return compress_pkt_list(pkt, nb_pkts, nb_zero);
674 }
675
676 /*
677  * generic, assumes HW doesn't recognize any packet type.
678  */
679 uint16_t
680 typen_rx_callback(uint16_t port,
681                   uint16_t queue,
682                   struct rte_mbuf *pkt[],
683                   uint16_t nb_pkts,
684                   uint16_t max_pkts,
685                   void *user_param)
686 {
687         uint32_t j;
688         uint16_t nb_zero;
689         struct glue_ctx *ctx;
690
691         RTE_SET_USED(port);
692         RTE_SET_USED(queue);
693         RTE_SET_USED(max_pkts);
694
695         ctx = user_param;
696
697         nb_zero = 0;
698         for (j = 0; j != nb_pkts; j++) {
699                 /* fix me: now we avoid checking ip checksum */
700                 pkt[j]->ol_flags &= (~PKT_RX_IP_CKSUM_BAD);
701                 pkt[j]->packet_type = 0;
702                 pkt[j] = fill_ptypes_and_hdr_len(ctx, pkt[j]);
703                 nb_zero += (pkt[j] == NULL);
704         }
705
706         if (nb_zero == 0)
707                 return nb_pkts;
708
709         return compress_pkt_list(pkt, nb_pkts, nb_zero);
710 }
711
712 static uint32_t
713 get_ptypes(uint16_t port_id)
714 {
715         uint32_t smask;
716         int32_t i, rc;
717         const uint32_t pmask =
718                 RTE_PTYPE_L2_MASK | RTE_PTYPE_L3_MASK | RTE_PTYPE_L4_MASK;
719
720         smask = 0;
721         rc = rte_eth_dev_get_supported_ptypes(port_id, pmask, NULL, 0);
722         if (rc < 0) {
723                 RTE_LOG(ERR, USER1,
724                         "%s(port=%u) failed to get supported ptypes;\n",
725                         __func__, port_id);
726                 return smask;
727         }
728
729         uint32_t ptype[rc];
730         rc = rte_eth_dev_get_supported_ptypes(port_id, pmask, ptype, rc);
731
732         for (i = 0; i != rc; i++) {
733                 switch (ptype[i]) {
734                 case RTE_PTYPE_L2_ETHER_ARP:
735                         smask |= ETHER_ARP_PTYPE;
736                         break;
737                 case RTE_PTYPE_L3_IPV4:
738                 case RTE_PTYPE_L3_IPV4_EXT_UNKNOWN:
739                         smask |= IPV4_PTYPE;
740                         break;
741                 case RTE_PTYPE_L3_IPV4_EXT:
742                         smask |= IPV4_EXT_PTYPE;
743                         break;
744                 case RTE_PTYPE_L3_IPV6:
745                 case RTE_PTYPE_L3_IPV6_EXT_UNKNOWN:
746                         smask |= IPV6_PTYPE;
747                         break;
748                 case RTE_PTYPE_L3_IPV6_EXT:
749                         smask |= IPV6_EXT_PTYPE;
750                         break;
751                 case RTE_PTYPE_L4_TCP:
752                         smask |= TCP_PTYPE;
753                         break;
754                 case RTE_PTYPE_L4_UDP:
755                         smask |= UDP_PTYPE;
756                         break;
757                 case RTE_PTYPE_L4_ICMP:
758                         smask |= ICMP_PTYPE;
759                         break;
760                 }
761         }
762
763         return smask;
764 }
765
766 /* In rx callbacks, we need to check and make sure below things are done,
767  * either by hw or by sw:
768  * 1. filter out arp packets, and handle arp packets properly
769  *    - for arp request packet, reply arp if it's requesting myself.
770  * 2. fill l2, l3, l4 header length
771  *
772  * 3. GSO/GRO setup (TODO)
773  *
774  */
775 int
776 setup_rx_cb(uint16_t port_id, uint16_t qid)
777 {
778         int32_t rc;
779         uint32_t i, n, smask;
780         const void *cb;
781         struct glue_ctx *ctx;
782         const struct ptype2cb *ptype2cb;
783
784         static const struct ptype2cb tcp_arp_ptype2cb[] = {
785                 { /* i40e */
786                         .mask = ETHER_ARP_PTYPE |
787                                 ICMP_PTYPE |
788                                 IPV4_PTYPE | IPV4_EXT_PTYPE |
789                                 IPV6_PTYPE | IPV6_EXT_PTYPE |
790                                 TCP_PTYPE | UDP_PTYPE,
791                         .name = "HW l2-arp/l3x/l4-tcp ptype",
792                         .fn = type0_rx_callback,
793                 },
794                 { /* ixgbe does not support ARP ptype */
795                         .mask = IPV4_PTYPE | IPV4_EXT_PTYPE |
796                                 IPV6_PTYPE | IPV6_EXT_PTYPE |
797                                 TCP_PTYPE | UDP_PTYPE,
798                         .name = "HW l3x/l4-tcp ptype",
799                         .fn = type1_rx_callback,
800                 },
801                 { /* virtio */
802                         .mask = 0,
803                         .name = "HW does not support any ptype",
804                         .fn = typen_rx_callback,
805                 },
806         };
807
808         ctx = glue_ctx_lookup(port_id, qid);
809         if (ctx == NULL) {
810                 GLUE_LOG(ERR, "no ctx fount by port(%d) and queue (%d)",
811                          port_id, qid);
812                 return -EINVAL;
813         }
814
815         smask = get_ptypes(port_id);
816
817         ptype2cb = tcp_arp_ptype2cb;
818         n = RTE_DIM(tcp_arp_ptype2cb);
819
820         for (i = 0; i != n; i++) {
821                 if ((smask & ptype2cb[i].mask) == ptype2cb[i].mask) {
822                         cb = rte_eth_add_rx_callback(port_id, qid,
823                                                      ptype2cb[i].fn, ctx);
824                         rc = -rte_errno;
825                         GLUE_LOG(ERR, "%s(port=%u), setup RX callback \"%s\";",
826                                  __func__, port_id,  ptype2cb[i].name);
827                         return ((cb == NULL) ? rc : 0);
828                 }
829         }
830
831         GLUE_LOG(ERR, "%s(port=%u) failed to find an appropriate callback",
832                  __func__, port_id);
833         return -ENOENT;
834 }