xref: /f-stack/lib/ff_veth.c (revision 98895edd)
1 /*
2  * Copyright (c) 2010 Kip Macy. All rights reserved.
3  * Copyright (C) 2017 THL A29 Limited, a Tencent company.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  *   list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * Derived in part from libplebnet's pn_veth.c.
27  *
28  */
29 
30 #include <sys/ctype.h>
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/socket.h>
35 #include <sys/socketvar.h>
36 #include <sys/module.h>
37 #include <sys/kernel.h>
38 #include <sys/proc.h>
39 #include <sys/kthread.h>
40 #include <sys/sched.h>
41 #include <sys/sockio.h>
42 
43 #include <net/if.h>
44 #include <net/if_var.h>
45 #include <net/if_types.h>
46 #include <net/ethernet.h>
47 #include <net/if_arp.h>
48 #include <net/if_tap.h>
49 #include <net/if_dl.h>
50 #include <net/route.h>
51 
52 #include <netinet/in.h>
53 #include <netinet/in_var.h>
54 #include <netinet6/nd6.h>
55 
56 #include <machine/atomic.h>
57 
58 #include "ff_veth.h"
59 #include "ff_config.h"
60 #include "ff_dpdk_if.h"
61 
62 struct ff_veth_softc {
63     struct ifnet *ifp;
64     uint8_t mac[ETHER_ADDR_LEN];
65     char host_ifname[IF_NAMESIZE];
66 
67     in_addr_t ip;
68     in_addr_t netmask;
69     in_addr_t broadcast;
70     in_addr_t gateway;
71 
72     uint8_t nb_vip;
73     in_addr_t vip[VIP_MAX_NUM];
74 
75 #ifdef INET6
76     struct in6_addr ip6;
77     struct in6_addr gateway6;
78     uint8_t prefix_length;
79 
80     uint8_t nb_vip6;
81     uint8_t vip_prefix_length;
82     struct in6_addr vip6[VIP_MAX_NUM];
83 #endif /* INET6 */
84 
85     struct ff_dpdk_if_context *host_ctx;
86 };
87 
88 static int
89 ff_veth_config(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
90 {
91     int i, j;
92 
93     memcpy(sc->mac, cfg->mac, ETHER_ADDR_LEN);
94     inet_pton(AF_INET, cfg->addr, &sc->ip);
95     inet_pton(AF_INET, cfg->netmask, &sc->netmask);
96     inet_pton(AF_INET, cfg->broadcast, &sc->broadcast);
97     inet_pton(AF_INET, cfg->gateway, &sc->gateway);
98 
99     if (cfg->nb_vip) {
100         for (i = 0, j = 0; i < cfg->nb_vip; ++i) {
101             if (inet_pton(AF_INET, cfg->vip_addr_array[i], &sc->vip[j])) {
102                 j++;
103             } else {
104                 printf("ff_veth_config inet_pton vip %s failed.\n", cfg->vip_addr_array[i]);
105             }
106         }
107 
108         sc->nb_vip = j;
109     }
110 
111 #ifdef INET6
112     if (cfg->addr6_str) {
113         inet_pton(AF_INET6_LINUX, cfg->addr6_str, &sc->ip6);
114         printf("%s: Addr6: %s\n", sc->host_ifname, cfg->addr6_str);
115 
116         if (cfg->gateway6_str) {
117             inet_pton(AF_INET6_LINUX, cfg->gateway6_str, &sc->gateway6);
118             printf("%s: Gateway6: %s\n", sc->host_ifname, cfg->gateway6_str);
119         } else {
120             printf("%s: No gateway6 config found.\n", sc->host_ifname);
121         }
122 
123         sc->prefix_length = cfg->prefix_len == 0 ? 64 : cfg->prefix_len;
124     } else {
125         printf("%s: No addr6 config found.\n", sc->host_ifname);
126     }
127 
128     if (cfg->nb_vip6) {
129         for (i = 0, j = 0; i < cfg->nb_vip6; ++i) {
130             if (inet_pton(AF_INET6_LINUX, cfg->vip_addr6_array[i], &sc->vip6[j])) {
131                 j++;
132             } else {
133                 printf("ff_veth_config inet_pton vip6 %s failed.\n", cfg->vip_addr6_array[i]);
134             }
135         }
136 
137         sc->nb_vip6 = j;
138         sc->vip_prefix_length = cfg->vip_prefix_len == 0 ? 64 : cfg->vip_prefix_len;
139     }
140 #endif /* INET6 */
141 
142     return 0;
143 }
144 
145 static void
146 ff_veth_init(void *arg)
147 {
148     struct ff_veth_softc *sc = arg;
149     struct ifnet *ifp = sc->ifp;
150 
151     ifp->if_drv_flags |= IFF_DRV_RUNNING;
152     ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
153 }
154 
155 static void
156 ff_veth_start(struct ifnet *ifp)
157 {
158     /* nothing to do */
159 }
160 
161 static void
162 ff_veth_stop(struct ff_veth_softc *sc)
163 {
164     struct ifnet *ifp = sc->ifp;
165 
166     ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
167 }
168 
169 static int
170 ff_veth_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
171 {
172     int error = 0;
173     struct ff_veth_softc *sc = ifp->if_softc;
174 
175     switch (cmd) {
176     case SIOCSIFFLAGS:
177         if (ifp->if_flags & IFF_UP) {
178             ff_veth_init(sc);
179         } else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
180             ff_veth_stop(sc);
181         break;
182     default:
183         error = ether_ioctl(ifp, cmd, data);
184         break;
185     }
186 
187     return (error);
188 }
189 
190 int
191 ff_mbuf_copydata(void *m, void *data, int off, int len)
192 {
193     int ret;
194     struct mbuf *mb = (struct mbuf *)m;
195 
196     if (off + len > mb->m_pkthdr.len) {
197         return -1;
198     }
199 
200     m_copydata(mb, off, len, data);
201 
202     return 0;
203 }
204 
205 void
206 ff_mbuf_tx_offload(void *m, struct ff_tx_offload *offload)
207 {
208     struct mbuf *mb = (struct mbuf *)m;
209     if (mb->m_pkthdr.csum_flags & CSUM_IP) {
210         offload->ip_csum = 1;
211     }
212 
213     if (mb->m_pkthdr.csum_flags & CSUM_TCP) {
214         offload->tcp_csum = 1;
215     }
216 
217     if (mb->m_pkthdr.csum_flags & CSUM_UDP) {
218         offload->udp_csum = 1;
219     }
220 
221     if (mb->m_pkthdr.csum_flags & CSUM_SCTP) {
222         offload->sctp_csum = 1;
223     }
224 
225     if (mb->m_pkthdr.csum_flags & CSUM_TSO) {
226         offload->tso_seg_size = mb->m_pkthdr.tso_segsz;
227     }
228 }
229 
230 void
231 ff_mbuf_free(void *m)
232 {
233     m_freem((struct mbuf *)m);
234 }
235 
236 static void
237 ff_mbuf_ext_free(struct mbuf *m, void *arg1, void *arg2)
238 {
239     ff_dpdk_pktmbuf_free(arg1);
240 }
241 
242 void *
243 ff_mbuf_gethdr(void *pkt, uint16_t total, void *data,
244     uint16_t len, uint8_t rx_csum)
245 {
246     struct mbuf *m = m_gethdr(M_NOWAIT, MT_DATA);
247     if (m == NULL) {
248         return NULL;
249     }
250 
251     if (m_pkthdr_init(m, M_NOWAIT) != 0) {
252         return NULL;
253     }
254 
255     m_extadd(m, data, len, ff_mbuf_ext_free, pkt, NULL, 0, EXT_DISPOSABLE);
256 
257     m->m_pkthdr.len = total;
258     m->m_len = len;
259     m->m_next = NULL;
260     m->m_nextpkt = NULL;
261 
262     if (rx_csum) {
263         m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
264             CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
265         m->m_pkthdr.csum_data = 0xffff;
266     }
267     return (void *)m;
268 }
269 
270 void *
271 ff_mbuf_get(void *p, void *m, void *data, uint16_t len)
272 {
273     struct mbuf *prev = (struct mbuf *)p;
274     struct mbuf *mb = m_get(M_NOWAIT, MT_DATA);
275 
276     if (mb == NULL) {
277         return NULL;
278     }
279 
280     m_extadd(mb, data, len, ff_mbuf_ext_free, m, NULL, 0, EXT_DISPOSABLE);
281 
282     mb->m_next = NULL;
283     mb->m_nextpkt = NULL;
284     mb->m_len = len;
285 
286     if (prev != NULL) {
287         prev->m_next = mb;
288     }
289 
290     return (void *)mb;
291 }
292 
293 void
294 ff_veth_process_packet(void *arg, void *m)
295 {
296     struct ifnet *ifp = (struct ifnet *)arg;
297     struct mbuf *mb = (struct mbuf *)m;
298 
299     mb->m_pkthdr.rcvif = ifp;
300 
301     ifp->if_input(ifp, mb);
302 }
303 
304 static int
305 ff_veth_transmit(struct ifnet *ifp, struct mbuf *m)
306 {
307     struct ff_veth_softc *sc = (struct ff_veth_softc *)ifp->if_softc;
308     return ff_dpdk_if_send(sc->host_ctx, (void*)m, m->m_pkthdr.len);
309 }
310 
311 static void
312 ff_veth_qflush(struct ifnet *ifp)
313 {
314 
315 }
316 
317 static int
318 ff_veth_setaddr(struct ff_veth_softc *sc)
319 {
320     struct in_aliasreq req;
321     bzero(&req, sizeof req);
322     strcpy(req.ifra_name, sc->ifp->if_dname);
323 
324     struct sockaddr_in sa;
325     bzero(&sa, sizeof(sa));
326     sa.sin_len = sizeof(sa);
327     sa.sin_family = AF_INET;
328     sa.sin_addr.s_addr = sc->ip;
329     bcopy(&sa, &req.ifra_addr, sizeof(sa));
330 
331     sa.sin_addr.s_addr = sc->netmask;
332     bcopy(&sa, &req.ifra_mask, sizeof(sa));
333 
334     sa.sin_addr.s_addr = sc->broadcast;
335     bcopy(&sa, &req.ifra_broadaddr, sizeof(sa));
336 
337     struct socket *so = NULL;
338     socreate(AF_INET, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread);
339     int ret = ifioctl(so, SIOCAIFADDR, (caddr_t)&req, curthread);
340 
341     sofree(so);
342 
343     return ret;
344 }
345 
346 static int
347 ff_veth_set_gateway(struct ff_veth_softc *sc)
348 {
349     struct sockaddr_in gw;
350     bzero(&gw, sizeof(gw));
351     gw.sin_len = sizeof(gw);
352     gw.sin_family = AF_INET;
353     gw.sin_addr.s_addr = sc->gateway;
354 
355     struct sockaddr_in dst;
356     bzero(&dst, sizeof(dst));
357     dst.sin_len = sizeof(dst);
358     dst.sin_family = AF_INET;
359     dst.sin_addr.s_addr = 0;
360 
361     struct sockaddr_in nm;
362     bzero(&nm, sizeof(nm));
363     nm.sin_len = sizeof(nm);
364     nm.sin_family = AF_INET;
365     nm.sin_addr.s_addr = 0;
366 
367     return rtrequest_fib(RTM_ADD, (struct sockaddr *)&dst, (struct sockaddr *)&gw,
368         (struct sockaddr *)&nm, RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
369 }
370 
371 static int
372 ff_veth_setvaddr(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
373 {
374     struct in_aliasreq req;
375     bzero(&req, sizeof req);
376 
377     if (cfg->vip_ifname) {
378         strlcpy(req.ifra_name, cfg->vip_ifname, IFNAMSIZ);
379     } else {
380         strlcpy(req.ifra_name, sc->ifp->if_dname, IFNAMSIZ);
381     }
382 
383     struct sockaddr_in sa;
384     bzero(&sa, sizeof(sa));
385     sa.sin_len = sizeof(sa);
386     sa.sin_family = AF_INET;
387 
388     int i, ret;
389     struct socket *so = NULL;
390     socreate(AF_INET, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread);
391 
392     for (i = 0; i < sc->nb_vip; ++i) {
393         sa.sin_addr.s_addr = sc->vip[i];
394         bcopy(&sa, &req.ifra_addr, sizeof(sa));
395 
396         // Only support '255.255.255.255' netmask now
397         sa.sin_addr.s_addr = 0xFFFFFFFF;
398         bcopy(&sa, &req.ifra_mask, sizeof(sa));
399 
400         // Only support 'x.x.x.255' broadaddr now
401         sa.sin_addr.s_addr = sc->vip[i] | 0xFF000000;
402         bcopy(&sa, &req.ifra_broadaddr, sizeof(sa));
403 
404         ret = ifioctl(so, SIOCAIFADDR, (caddr_t)&req, curthread);
405         if (ret < 0) {
406             printf("ff_veth_setvaddr ifioctl SIOCAIFADDR error\n");
407             goto done;
408         }
409     }
410 
411 done:
412     sofree(so);
413 
414     return ret;
415 }
416 
417 #ifdef INET6
418 static int
419 ff_veth_setaddr6(struct ff_veth_softc *sc)
420 {
421     struct in6_aliasreq ifr6;
422     bzero(&ifr6, sizeof(ifr6));
423     strcpy(ifr6.ifra_name, sc->ifp->if_dname);
424 
425     ifr6.ifra_addr.sin6_len = sizeof ifr6.ifra_addr;
426     ifr6.ifra_addr.sin6_family = AF_INET6;
427     ifr6.ifra_addr.sin6_addr = sc->ip6;
428 
429     ifr6.ifra_prefixmask.sin6_len = sizeof ifr6.ifra_prefixmask;
430     memset(&ifr6.ifra_prefixmask.sin6_addr, 0xff, sc->prefix_length / 8);
431     uint8_t mask_size_mod = sc->prefix_length % 8;
432     if (mask_size_mod)
433     {
434         ifr6.ifra_prefixmask.sin6_addr.__u6_addr.__u6_addr8[sc->prefix_length / 8] = \
435             ((1 << mask_size_mod) - 1) << (8 - mask_size_mod);
436     }
437 
438     ifr6.ifra_lifetime.ia6t_pltime = ifr6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
439 
440     struct socket *so = NULL;
441     socreate(AF_INET6, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread);
442     int ret = ifioctl(so, SIOCAIFADDR_IN6, (caddr_t)&ifr6, curthread);
443 
444     sofree(so);
445 
446     return ret;
447 }
448 
449 static int
450 ff_veth_set_gateway6(struct ff_veth_softc *sc)
451 {
452     struct sockaddr_in6 gw, dst, nm;
453 
454     bzero(&gw, sizeof(gw));
455     bzero(&dst, sizeof(dst));
456     bzero(&nm, sizeof(nm));
457 
458     gw.sin6_len = dst.sin6_len = nm.sin6_len = sizeof(struct sockaddr_in6);
459     gw.sin6_family = dst.sin6_family = AF_INET6;
460 
461     gw.sin6_addr = sc->gateway6;
462     //dst.sin6_addr = nm.sin6_addr = 0;
463 
464     return rtrequest_fib(RTM_ADD, (struct sockaddr *)&dst, (struct sockaddr *)&gw,
465         (struct sockaddr *)&nm, RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
466 }
467 
468 static int
469 ff_veth_setvaddr6(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
470 {
471     struct in6_aliasreq ifr6;
472     bzero(&ifr6, sizeof(ifr6));
473 
474     if (cfg->vip_ifname) {
475         strlcpy(ifr6.ifra_name, cfg->vip_ifname, IFNAMSIZ);
476     } else {
477         strlcpy(ifr6.ifra_name, sc->ifp->if_dname, IFNAMSIZ);
478     }
479 
480     ifr6.ifra_addr.sin6_len = sizeof ifr6.ifra_addr;
481     ifr6.ifra_addr.sin6_family = AF_INET6;
482 
483     ifr6.ifra_prefixmask.sin6_len = sizeof ifr6.ifra_prefixmask;
484     memset(&ifr6.ifra_prefixmask.sin6_addr, 0xff, sc->prefix_length / 8);
485     uint8_t mask_size_mod = sc->prefix_length % 8;
486     if (mask_size_mod)
487     {
488         ifr6.ifra_prefixmask.sin6_addr.__u6_addr.__u6_addr8[sc->prefix_length / 8] = \
489             ((1 << mask_size_mod) - 1) << (8 - mask_size_mod);
490     }
491 
492     ifr6.ifra_lifetime.ia6t_pltime = ifr6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
493 
494     struct socket *so = NULL;
495     socreate(AF_INET6, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread);
496 
497     int i, ret;
498     for (i = 0; i < sc->nb_vip6; ++i) {
499         ifr6.ifra_addr.sin6_addr = sc->vip6[i];
500 
501         ret = ifioctl(so, SIOCAIFADDR_IN6, (caddr_t)&ifr6, curthread);
502         if (ret < 0) {
503             printf("ff_veth_setvaddr6 ifioctl SIOCAIFADDR error\n");
504             goto done;
505         }
506     }
507 
508 done:
509     sofree(so);
510 
511     return ret;
512 }
513 #endif /* INET6 */
514 
515 static int
516 ff_veth_setup_interface(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
517 {
518     struct ifnet *ifp;
519 
520     ifp = sc->ifp = if_alloc(IFT_ETHER);
521 
522     ifp->if_init = ff_veth_init;
523     ifp->if_softc = sc;
524 
525     if_initname(ifp, sc->host_ifname, IF_DUNIT_NONE);
526     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
527     ifp->if_ioctl = ff_veth_ioctl;
528     ifp->if_start = ff_veth_start;
529     ifp->if_transmit = ff_veth_transmit;
530     ifp->if_qflush = ff_veth_qflush;
531     ether_ifattach(ifp, sc->mac);
532 
533     if (cfg->hw_features.rx_csum) {
534         ifp->if_capabilities |= IFCAP_RXCSUM;
535     }
536     if (cfg->hw_features.tx_csum_ip) {
537         ifp->if_capabilities |= IFCAP_TXCSUM;
538         ifp->if_hwassist |= CSUM_IP;
539     }
540     if (cfg->hw_features.tx_csum_l4) {
541         ifp->if_hwassist |= CSUM_DELAY_DATA;
542     }
543     if (cfg->hw_features.tx_tso) {
544         ifp->if_capabilities |= IFCAP_TSO;
545         ifp->if_hwassist |= CSUM_TSO;
546     }
547 
548     ifp->if_capenable = ifp->if_capabilities;
549 
550     sc->host_ctx = ff_dpdk_register_if((void *)sc, (void *)sc->ifp, cfg);
551     if (sc->host_ctx == NULL) {
552         printf("%s: Failed to register dpdk interface\n", sc->host_ifname);
553         return -1;
554     }
555 
556     // Set ip
557     int ret = ff_veth_setaddr(sc);
558     if (ret != 0) {
559         printf("ff_veth_setaddr failed\n");
560     }
561     ret = ff_veth_set_gateway(sc);
562     if (ret != 0) {
563         printf("ff_veth_set_gateway failed\n");
564     }
565 
566     if (sc->nb_vip) {
567         ret = ff_veth_setvaddr(sc, cfg);
568     }
569 
570 #ifdef INET6
571     // Set IPv6
572     if (cfg->addr6_str) {
573         ret = ff_veth_setaddr6(sc);
574         if (ret != 0) {
575             printf("ff_veth_setaddr6 failed\n");
576         }
577 
578         if (cfg->gateway6_str) {
579             ret = ff_veth_set_gateway6(sc);
580             if (ret != 0) {
581                 printf("ff_veth_set_gateway6 failed\n");
582             }
583         }
584     }
585 
586     if (sc->nb_vip6) {
587         ret = ff_veth_setvaddr6(sc, cfg);
588     }
589 #endif /* INET6 */
590 
591     return (0);
592 }
593 
594 void *
595 ff_veth_attach(struct ff_port_cfg *cfg)
596 {
597     struct ff_veth_softc *sc = NULL;
598     int error;
599 
600     sc = malloc(sizeof(struct ff_veth_softc), M_DEVBUF, M_WAITOK);
601     if (NULL == sc) {
602         printf("ff_veth_softc allocation failed\n");
603         goto fail;
604     }
605     memset(sc, 0, sizeof(struct ff_veth_softc));
606 
607     snprintf(sc->host_ifname, sizeof(sc->host_ifname), ff_IF_NAME, cfg->port_id);
608 
609     error = ff_veth_config(sc, cfg);
610     if (0 != error) {
611         goto fail;
612     }
613 
614     if (0 != ff_veth_setup_interface(sc, cfg)) {
615         goto fail;
616     }
617 
618     return sc->host_ctx;
619 
620 fail:
621     if (sc) {
622         if (sc->host_ctx)
623             ff_dpdk_deregister_if(sc->host_ctx);
624 
625         free(sc, M_DEVBUF);
626     }
627 
628     return NULL;
629 }
630 
631 int
632 ff_veth_detach(void *arg)
633 {
634     struct ff_veth_softc *sc = (struct ff_veth_softc *)arg;
635     if (sc) {
636         ff_dpdk_deregister_if(sc->host_ctx);
637         free(sc, M_DEVBUF);
638     }
639 
640     return (0);
641 }
642 
643 void *
644 ff_veth_softc_to_hostc(void *softc)
645 {
646     struct ff_veth_softc *sc = (struct ff_veth_softc *)softc;
647     return (void *)sc->host_ctx;
648 }
649 
650 /********************
651 *  get next mbuf's addr, current mbuf's data and datalen.
652 *
653 ********************/
654 int ff_next_mbuf(void **mbuf_bsd, void **data, unsigned *len)
655 {
656     struct mbuf *mb = *(struct mbuf **)mbuf_bsd;
657 
658     *len = mb->m_len;
659     *data = mb->m_data;
660 
661     if (mb->m_next)
662         *mbuf_bsd = mb->m_next;
663     else
664         *mbuf_bsd = NULL;
665     return 0;
666 }
667 
668 void * ff_mbuf_mtod(void* bsd_mbuf)
669 {
670     if ( !bsd_mbuf )
671         return NULL;
672     return (void*)((struct mbuf *)bsd_mbuf)->m_data;
673 }
674 
675 // get source rte_mbuf from ext cluster, which carry rte_mbuf while recving pkt, such as arp.
676 void* ff_rte_frm_extcl(void* mbuf)
677 {
678     struct mbuf *bsd_mbuf = mbuf;
679 
680     if ( (bsd_mbuf->m_flags & M_EXT) &&
681         bsd_mbuf->m_ext.ext_type == EXT_DISPOSABLE && bsd_mbuf->m_ext.ext_free == ff_mbuf_ext_free ) {
682         return bsd_mbuf->m_ext.ext_arg1;
683     }
684     else
685         return NULL;
686 }
687 
688 void
689 ff_mbuf_set_vlan_info(void *hdr, uint16_t vlan_tci) {
690     struct mbuf *m = (struct mbuf *)hdr;
691     m->m_pkthdr.ether_vtag = vlan_tci;
692     m->m_flags |= M_VLANTAG;
693     return;
694 }
695 
696