xref: /f-stack/lib/ff_veth.c (revision f6b123a0)
1 /*
2  * Copyright (c) 2010 Kip Macy. All rights reserved.
3  * Copyright (C) 2017-2021 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 #include <sys/ck.h>
43 
44 #include <net/if.h>
45 #include <net/if_var.h>
46 #include <net/if_types.h>
47 #include <net/ethernet.h>
48 #include <net/if_arp.h>
49 #include <net/if_tap.h>
50 #include <net/if_dl.h>
51 #include <net/route.h>
52 #include <net/route/route_ctl.h>
53 
54 #include <netinet/in.h>
55 #include <netinet/in_var.h>
56 #include <netinet6/nd6.h>
57 
58 #include <machine/atomic.h>
59 
60 #include "ff_veth.h"
61 #include "ff_config.h"
62 #include "ff_dpdk_if.h"
63 
64 struct ff_veth_softc {
65     struct ifnet *ifp;
66     uint8_t mac[ETHER_ADDR_LEN];
67     char host_ifname[IF_NAMESIZE];
68 
69     in_addr_t ip;
70     in_addr_t netmask;
71     in_addr_t broadcast;
72     in_addr_t gateway;
73 
74     uint8_t nb_vip;
75     in_addr_t vip[VIP_MAX_NUM];
76 
77 #ifdef INET6
78     struct in6_addr ip6;
79     struct in6_addr gateway6;
80     uint8_t prefix_length;
81 
82     uint8_t nb_vip6;
83     uint8_t vip_prefix_length;
84     struct in6_addr vip6[VIP_MAX_NUM];
85 #endif /* INET6 */
86 
87     struct ff_dpdk_if_context *host_ctx;
88 };
89 
90 static int
91 ff_veth_config(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
92 {
93     int i, j;
94 
95     memcpy(sc->mac, cfg->mac, ETHER_ADDR_LEN);
96     inet_pton(AF_INET, cfg->addr, &sc->ip);
97     inet_pton(AF_INET, cfg->netmask, &sc->netmask);
98     inet_pton(AF_INET, cfg->broadcast, &sc->broadcast);
99     inet_pton(AF_INET, cfg->gateway, &sc->gateway);
100 
101     if (cfg->nb_vip) {
102         for (i = 0, j = 0; i < cfg->nb_vip; ++i) {
103             if (inet_pton(AF_INET, cfg->vip_addr_array[i], &sc->vip[j])) {
104                 j++;
105             } else {
106                 printf("ff_veth_config inet_pton vip %s failed.\n", cfg->vip_addr_array[i]);
107             }
108         }
109 
110         sc->nb_vip = j;
111     }
112 
113 #ifdef INET6
114     if (cfg->addr6_str) {
115         inet_pton(AF_INET6_LINUX, cfg->addr6_str, &sc->ip6);
116         printf("%s: Addr6: %s\n", sc->host_ifname, cfg->addr6_str);
117 
118         if (cfg->gateway6_str) {
119             inet_pton(AF_INET6_LINUX, cfg->gateway6_str, &sc->gateway6);
120             printf("%s: Gateway6: %s\n", sc->host_ifname, cfg->gateway6_str);
121         } else {
122             printf("%s: No gateway6 config found.\n", sc->host_ifname);
123         }
124 
125         sc->prefix_length = cfg->prefix_len == 0 ? 64 : cfg->prefix_len;
126     } else {
127         printf("%s: No addr6 config found.\n", sc->host_ifname);
128     }
129 
130     if (cfg->nb_vip6) {
131         for (i = 0, j = 0; i < cfg->nb_vip6; ++i) {
132             if (inet_pton(AF_INET6_LINUX, cfg->vip_addr6_array[i], &sc->vip6[j])) {
133                 j++;
134             } else {
135                 printf("ff_veth_config inet_pton vip6 %s failed.\n", cfg->vip_addr6_array[i]);
136             }
137         }
138 
139         sc->nb_vip6 = j;
140         sc->vip_prefix_length = cfg->vip_prefix_len == 0 ? 64 : cfg->vip_prefix_len;
141     }
142 #endif /* INET6 */
143 
144     return 0;
145 }
146 
147 static void
148 ff_veth_init(void *arg)
149 {
150     struct ff_veth_softc *sc = arg;
151     struct ifnet *ifp = sc->ifp;
152 
153     ifp->if_drv_flags |= IFF_DRV_RUNNING;
154     ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
155 }
156 
157 static void
158 ff_veth_start(struct ifnet *ifp)
159 {
160     /* nothing to do */
161 }
162 
163 static void
164 ff_veth_stop(struct ff_veth_softc *sc)
165 {
166     struct ifnet *ifp = sc->ifp;
167 
168     ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
169 }
170 
171 static int
172 ff_veth_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
173 {
174     int error = 0;
175     struct ff_veth_softc *sc = ifp->if_softc;
176 
177     switch (cmd) {
178     case SIOCSIFFLAGS:
179         if (ifp->if_flags & IFF_UP) {
180             ff_veth_init(sc);
181         } else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
182             ff_veth_stop(sc);
183         break;
184     default:
185         error = ether_ioctl(ifp, cmd, data);
186         break;
187     }
188 
189     return (error);
190 }
191 
192 int
193 ff_mbuf_copydata(void *m, void *data, int off, int len)
194 {
195     int ret;
196     struct mbuf *mb = (struct mbuf *)m;
197 
198     if (off + len > mb->m_pkthdr.len) {
199         return -1;
200     }
201 
202     m_copydata(mb, off, len, data);
203 
204     return 0;
205 }
206 
207 void
208 ff_mbuf_tx_offload(void *m, struct ff_tx_offload *offload)
209 {
210     struct mbuf *mb = (struct mbuf *)m;
211     if (mb->m_pkthdr.csum_flags & CSUM_IP) {
212         offload->ip_csum = 1;
213     }
214 
215     if (mb->m_pkthdr.csum_flags & CSUM_TCP) {
216         offload->tcp_csum = 1;
217     }
218 
219     if (mb->m_pkthdr.csum_flags & CSUM_UDP) {
220         offload->udp_csum = 1;
221     }
222 
223     if (mb->m_pkthdr.csum_flags & CSUM_SCTP) {
224         offload->sctp_csum = 1;
225     }
226 
227     if (mb->m_pkthdr.csum_flags & CSUM_TSO) {
228         offload->tso_seg_size = mb->m_pkthdr.tso_segsz;
229     }
230 }
231 
232 void
233 ff_mbuf_free(void *m)
234 {
235     m_freem((struct mbuf *)m);
236 }
237 
238 static void
239 ff_mbuf_ext_free(struct mbuf *m)
240 {
241     ff_dpdk_pktmbuf_free(ff_rte_frm_extcl(m));
242 }
243 
244 int ff_zc_mbuf_get(struct ff_zc_mbuf *m, int len) {
245     struct mbuf *mb;
246 
247     if (m == NULL) {
248         return -1;
249     }
250 
251     mb = m_getm2(NULL, max(len, 1), M_WAITOK, MT_DATA, 0);
252     if (mb == NULL) {
253         return -1;
254     }
255 
256     m->bsd_mbuf = m->bsd_mbuf_off = mb;
257     m->off = 0;
258     m->len = len;
259 
260     return 0;
261 }
262 
263 int
264 ff_zc_mbuf_write(struct ff_zc_mbuf *zm, const char *data, int len)
265 {
266     int ret, length, progress = 0;
267     struct mbuf *m, *mb;
268 
269     if (zm == NULL) {
270         return -1;
271     }
272     m = (struct mbuf *)zm->bsd_mbuf_off;
273 
274     if (zm->off + len > zm->len) {
275         return -1;
276     }
277 
278     for (mb = m; mb != NULL; mb = mb->m_next) {
279         length = min(M_TRAILINGSPACE(mb), len - progress);
280         bcopy(data + progress, mtod(mb, char *) + mb->m_len, length);
281 
282         mb->m_len += length;
283         progress += length;
284         if (len == progress) {
285             break;
286         }
287         //if (flags & M_PKTHDR)
288         //    m->m_pkthdr.len += length;
289     }
290     zm->off += len;
291     zm->bsd_mbuf_off = mb;
292 
293     return len;
294 }
295 
296 int
297 ff_zc_mbuf_read(struct ff_zc_mbuf *m, const char *data, int len)
298 {
299     // DOTO: Support read zero copy
300     return 0;
301 }
302 
303 void *
304 ff_mbuf_gethdr(void *pkt, uint16_t total, void *data,
305     uint16_t len, uint8_t rx_csum)
306 {
307     struct mbuf *m = m_gethdr(M_NOWAIT, MT_DATA);
308     if (m == NULL) {
309         return NULL;
310     }
311 
312     if (m_pkthdr_init(m, M_NOWAIT) != 0) {
313         return NULL;
314     }
315 
316     m_extadd(m, data, len, ff_mbuf_ext_free, pkt, NULL, 0, EXT_DISPOSABLE);
317 
318     m->m_pkthdr.len = total;
319     m->m_len = len;
320     m->m_next = NULL;
321     m->m_nextpkt = NULL;
322 
323     if (rx_csum) {
324         m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
325             CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
326         m->m_pkthdr.csum_data = 0xffff;
327     }
328     return (void *)m;
329 }
330 
331 void *
332 ff_mbuf_get(void *p, void *m, void *data, uint16_t len)
333 {
334     struct mbuf *prev = (struct mbuf *)p;
335     struct mbuf *mb = m_get(M_NOWAIT, MT_DATA);
336 
337     if (mb == NULL) {
338         return NULL;
339     }
340 
341     m_extadd(mb, data, len, ff_mbuf_ext_free, m, NULL, 0, EXT_DISPOSABLE);
342 
343     mb->m_next = NULL;
344     mb->m_nextpkt = NULL;
345     mb->m_len = len;
346 
347     if (prev != NULL) {
348         prev->m_next = mb;
349     }
350 
351     return (void *)mb;
352 }
353 
354 void
355 ff_veth_process_packet(void *arg, void *m)
356 {
357     struct ifnet *ifp = (struct ifnet *)arg;
358     struct mbuf *mb = (struct mbuf *)m;
359 
360     mb->m_pkthdr.rcvif = ifp;
361 
362     ifp->if_input(ifp, mb);
363 }
364 
365 static int
366 ff_veth_transmit(struct ifnet *ifp, struct mbuf *m)
367 {
368     struct ff_veth_softc *sc = (struct ff_veth_softc *)ifp->if_softc;
369     return ff_dpdk_if_send(sc->host_ctx, (void*)m, m->m_pkthdr.len);
370 }
371 
372 static void
373 ff_veth_qflush(struct ifnet *ifp)
374 {
375 
376 }
377 
378 static int
379 ff_veth_setaddr(struct ff_veth_softc *sc)
380 {
381     struct in_aliasreq req;
382     bzero(&req, sizeof req);
383     strcpy(req.ifra_name, sc->ifp->if_dname);
384 
385     struct sockaddr_in sa;
386     bzero(&sa, sizeof(sa));
387     sa.sin_len = sizeof(sa);
388     sa.sin_family = AF_INET;
389     sa.sin_addr.s_addr = sc->ip;
390     bcopy(&sa, &req.ifra_addr, sizeof(sa));
391 
392     sa.sin_addr.s_addr = sc->netmask;
393     bcopy(&sa, &req.ifra_mask, sizeof(sa));
394 
395     sa.sin_addr.s_addr = sc->broadcast;
396     bcopy(&sa, &req.ifra_broadaddr, sizeof(sa));
397 
398     struct socket *so = NULL;
399     socreate(AF_INET, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread);
400     int ret = ifioctl(so, SIOCAIFADDR, (caddr_t)&req, curthread);
401 
402     sofree(so);
403 
404     return ret;
405 }
406 
407 static int
408 ff_veth_set_gateway(struct ff_veth_softc *sc)
409 {
410     struct rt_addrinfo info;
411     struct rib_cmd_info rci;
412 
413     bzero((caddr_t)&info, sizeof(info));
414     info.rti_flags = RTF_GATEWAY;
415 
416     struct sockaddr_in gw;
417     bzero(&gw, sizeof(gw));
418     gw.sin_len = sizeof(gw);
419     gw.sin_family = AF_INET;
420     gw.sin_addr.s_addr = sc->gateway;
421     info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gw;
422 
423     struct sockaddr_in dst;
424     bzero(&dst, sizeof(dst));
425     dst.sin_len = sizeof(dst);
426     dst.sin_family = AF_INET;
427     dst.sin_addr.s_addr = 0;
428     info.rti_info[RTAX_DST] = (struct sockaddr *)&dst;
429 
430     struct sockaddr_in nm;
431     bzero(&nm, sizeof(nm));
432     nm.sin_len = sizeof(nm);
433     nm.sin_family = AF_INET;
434     nm.sin_addr.s_addr = 0;
435     info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&nm;
436 
437     return rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rci);
438 }
439 
440 static int
441 ff_veth_setvaddr(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
442 {
443     struct in_aliasreq req;
444     bzero(&req, sizeof req);
445 
446     if (cfg->vip_ifname) {
447         strlcpy(req.ifra_name, cfg->vip_ifname, IFNAMSIZ);
448     } else {
449         strlcpy(req.ifra_name, sc->ifp->if_dname, IFNAMSIZ);
450     }
451 
452     struct sockaddr_in sa;
453     bzero(&sa, sizeof(sa));
454     sa.sin_len = sizeof(sa);
455     sa.sin_family = AF_INET;
456 
457     int i, ret;
458     struct socket *so = NULL;
459     socreate(AF_INET, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread);
460 
461     for (i = 0; i < sc->nb_vip; ++i) {
462         sa.sin_addr.s_addr = sc->vip[i];
463         bcopy(&sa, &req.ifra_addr, sizeof(sa));
464 
465         // Only support '255.255.255.255' netmask now
466         sa.sin_addr.s_addr = 0xFFFFFFFF;
467         bcopy(&sa, &req.ifra_mask, sizeof(sa));
468 
469         // Only support 'x.x.x.255' broadaddr now
470         sa.sin_addr.s_addr = sc->vip[i] | 0xFF000000;
471         bcopy(&sa, &req.ifra_broadaddr, sizeof(sa));
472 
473         ret = ifioctl(so, SIOCAIFADDR, (caddr_t)&req, curthread);
474         if (ret < 0) {
475             printf("ff_veth_setvaddr ifioctl SIOCAIFADDR error\n");
476             goto done;
477         }
478     }
479 
480 done:
481     sofree(so);
482 
483     return ret;
484 }
485 
486 #ifdef INET6
487 static int
488 ff_veth_setaddr6(struct ff_veth_softc *sc)
489 {
490     struct in6_aliasreq ifr6;
491     bzero(&ifr6, sizeof(ifr6));
492     strcpy(ifr6.ifra_name, sc->ifp->if_dname);
493 
494     ifr6.ifra_addr.sin6_len = sizeof ifr6.ifra_addr;
495     ifr6.ifra_addr.sin6_family = AF_INET6;
496     ifr6.ifra_addr.sin6_addr = sc->ip6;
497 
498     ifr6.ifra_prefixmask.sin6_len = sizeof ifr6.ifra_prefixmask;
499     memset(&ifr6.ifra_prefixmask.sin6_addr, 0xff, sc->prefix_length / 8);
500     uint8_t mask_size_mod = sc->prefix_length % 8;
501     if (mask_size_mod)
502     {
503         ifr6.ifra_prefixmask.sin6_addr.__u6_addr.__u6_addr8[sc->prefix_length / 8] = \
504             ((1 << mask_size_mod) - 1) << (8 - mask_size_mod);
505     }
506 
507     ifr6.ifra_lifetime.ia6t_pltime = ifr6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
508 
509     struct socket *so = NULL;
510     socreate(AF_INET6, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread);
511     int ret = ifioctl(so, SIOCAIFADDR_IN6, (caddr_t)&ifr6, curthread);
512 
513     sofree(so);
514 
515     return ret;
516 }
517 
518 static int
519 ff_veth_set_gateway6(struct ff_veth_softc *sc)
520 {
521     struct sockaddr_in6 gw;
522     struct rt_addrinfo info;
523     struct rib_cmd_info rci;
524 
525     bzero((caddr_t)&info, sizeof(info));
526     info.rti_flags = RTF_GATEWAY;
527 
528     bzero(&gw, sizeof(gw));
529 
530     gw.sin6_len = sizeof(struct sockaddr_in6);
531     gw.sin6_family = AF_INET6;
532 
533     gw.sin6_addr = sc->gateway6;
534 
535     info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gw;
536 
537     return rib_action(RT_DEFAULT_FIB, RTM_ADD, &info, &rci);
538 }
539 
540 static int
541 ff_veth_setvaddr6(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
542 {
543     struct in6_aliasreq ifr6;
544     bzero(&ifr6, sizeof(ifr6));
545 
546     if (cfg->vip_ifname) {
547         strlcpy(ifr6.ifra_name, cfg->vip_ifname, IFNAMSIZ);
548     } else {
549         strlcpy(ifr6.ifra_name, sc->ifp->if_dname, IFNAMSIZ);
550     }
551 
552     ifr6.ifra_addr.sin6_len = sizeof ifr6.ifra_addr;
553     ifr6.ifra_addr.sin6_family = AF_INET6;
554 
555     ifr6.ifra_prefixmask.sin6_len = sizeof ifr6.ifra_prefixmask;
556     memset(&ifr6.ifra_prefixmask.sin6_addr, 0xff, sc->prefix_length / 8);
557     uint8_t mask_size_mod = sc->prefix_length % 8;
558     if (mask_size_mod)
559     {
560         ifr6.ifra_prefixmask.sin6_addr.__u6_addr.__u6_addr8[sc->prefix_length / 8] = \
561             ((1 << mask_size_mod) - 1) << (8 - mask_size_mod);
562     }
563 
564     ifr6.ifra_lifetime.ia6t_pltime = ifr6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
565 
566     struct socket *so = NULL;
567     socreate(AF_INET6, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread);
568 
569     int i, ret;
570     for (i = 0; i < sc->nb_vip6; ++i) {
571         ifr6.ifra_addr.sin6_addr = sc->vip6[i];
572 
573         ret = ifioctl(so, SIOCAIFADDR_IN6, (caddr_t)&ifr6, curthread);
574         if (ret < 0) {
575             printf("ff_veth_setvaddr6 ifioctl SIOCAIFADDR error\n");
576             goto done;
577         }
578     }
579 
580 done:
581     sofree(so);
582 
583     return ret;
584 }
585 #endif /* INET6 */
586 
587 static int
588 ff_veth_setup_interface(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
589 {
590     struct ifnet *ifp;
591 
592     ifp = sc->ifp = if_alloc(IFT_ETHER);
593 
594     ifp->if_init = ff_veth_init;
595     ifp->if_softc = sc;
596 
597     if_initname(ifp, sc->host_ifname, IF_DUNIT_NONE);
598     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
599     ifp->if_ioctl = ff_veth_ioctl;
600     ifp->if_start = ff_veth_start;
601     ifp->if_transmit = ff_veth_transmit;
602     ifp->if_qflush = ff_veth_qflush;
603     ether_ifattach(ifp, sc->mac);
604 
605     if (cfg->hw_features.rx_csum) {
606         ifp->if_capabilities |= IFCAP_RXCSUM;
607     }
608     if (cfg->hw_features.tx_csum_ip) {
609         ifp->if_capabilities |= IFCAP_TXCSUM;
610         ifp->if_hwassist |= CSUM_IP;
611     }
612     if (cfg->hw_features.tx_csum_l4) {
613         ifp->if_hwassist |= CSUM_DELAY_DATA;
614     }
615     if (cfg->hw_features.tx_tso) {
616         ifp->if_capabilities |= IFCAP_TSO;
617         ifp->if_hwassist |= CSUM_TSO;
618     }
619 
620     ifp->if_capenable = ifp->if_capabilities;
621 
622     sc->host_ctx = ff_dpdk_register_if((void *)sc, (void *)sc->ifp, cfg);
623     if (sc->host_ctx == NULL) {
624         printf("%s: Failed to register dpdk interface\n", sc->host_ifname);
625         return -1;
626     }
627 
628     // Set ip
629     int ret = ff_veth_setaddr(sc);
630     if (ret != 0) {
631         printf("ff_veth_setaddr failed\n");
632     }
633     ret = ff_veth_set_gateway(sc);
634     if (ret != 0) {
635         printf("ff_veth_set_gateway failed\n");
636     }
637 
638     if (sc->nb_vip) {
639         ret = ff_veth_setvaddr(sc, cfg);
640     }
641 
642 #ifdef INET6
643     // Set IPv6
644     if (cfg->addr6_str) {
645         ret = ff_veth_setaddr6(sc);
646         if (ret != 0) {
647             printf("ff_veth_setaddr6 failed\n");
648         }
649 
650         if (cfg->gateway6_str) {
651             ret = ff_veth_set_gateway6(sc);
652             if (ret != 0) {
653                 printf("ff_veth_set_gateway6 failed\n");
654             }
655         }
656     }
657 
658     if (sc->nb_vip6) {
659         ret = ff_veth_setvaddr6(sc, cfg);
660     }
661 #endif /* INET6 */
662 
663     return (0);
664 }
665 
666 void *
667 ff_veth_attach(struct ff_port_cfg *cfg)
668 {
669     struct ff_veth_softc *sc = NULL;
670     int error;
671 
672     sc = malloc(sizeof(struct ff_veth_softc), M_DEVBUF, M_WAITOK);
673     if (NULL == sc) {
674         printf("ff_veth_softc allocation failed\n");
675         goto fail;
676     }
677     memset(sc, 0, sizeof(struct ff_veth_softc));
678 
679     if(cfg->ifname){
680         snprintf(sc->host_ifname, sizeof(sc->host_ifname), "%s", cfg->ifname);
681     } else {
682         snprintf(sc->host_ifname, sizeof(sc->host_ifname), ff_IF_NAME, cfg->port_id);
683     }
684 
685     error = ff_veth_config(sc, cfg);
686     if (0 != error) {
687         goto fail;
688     }
689 
690     if (0 != ff_veth_setup_interface(sc, cfg)) {
691         goto fail;
692     }
693 
694     return sc->host_ctx;
695 
696 fail:
697     if (sc) {
698         if (sc->host_ctx)
699             ff_dpdk_deregister_if(sc->host_ctx);
700 
701         free(sc, M_DEVBUF);
702     }
703 
704     return NULL;
705 }
706 
707 int
708 ff_veth_detach(void *arg)
709 {
710     struct ff_veth_softc *sc = (struct ff_veth_softc *)arg;
711     if (sc) {
712         ff_dpdk_deregister_if(sc->host_ctx);
713         free(sc, M_DEVBUF);
714     }
715 
716     return (0);
717 }
718 
719 void *
720 ff_veth_softc_to_hostc(void *softc)
721 {
722     struct ff_veth_softc *sc = (struct ff_veth_softc *)softc;
723     return (void *)sc->host_ctx;
724 }
725 
726 /********************
727 *  get next mbuf's addr, current mbuf's data and datalen.
728 *
729 ********************/
730 int ff_next_mbuf(void **mbuf_bsd, void **data, unsigned *len)
731 {
732     struct mbuf *mb = *(struct mbuf **)mbuf_bsd;
733 
734     *len = mb->m_len;
735     *data = mb->m_data;
736 
737     if (mb->m_next)
738         *mbuf_bsd = mb->m_next;
739     else
740         *mbuf_bsd = NULL;
741     return 0;
742 }
743 
744 void * ff_mbuf_mtod(void* bsd_mbuf)
745 {
746     if ( !bsd_mbuf )
747         return NULL;
748     return (void*)((struct mbuf *)bsd_mbuf)->m_data;
749 }
750 
751 // get source rte_mbuf from ext cluster, which carry rte_mbuf while recving pkt, such as arp.
752 void* ff_rte_frm_extcl(void* mbuf)
753 {
754     struct mbuf *bsd_mbuf = mbuf;
755 
756     if ( (bsd_mbuf->m_flags & M_EXT) &&
757         bsd_mbuf->m_ext.ext_type == EXT_DISPOSABLE && bsd_mbuf->m_ext.ext_free == ff_mbuf_ext_free ) {
758         return bsd_mbuf->m_ext.ext_arg1;
759     }
760     else
761         return NULL;
762 }
763 
764 void
765 ff_mbuf_set_vlan_info(void *hdr, uint16_t vlan_tci) {
766     struct mbuf *m = (struct mbuf *)hdr;
767     m->m_pkthdr.ether_vtag = vlan_tci;
768     m->m_flags |= M_VLANTAG;
769     return;
770 }
771 
772