xref: /f-stack/lib/ff_veth.c (revision 73e135b8)
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 
55 #include <machine/atomic.h>
56 
57 #include "ff_veth.h"
58 #include "ff_config.h"
59 #include "ff_dpdk_if.h"
60 
61 struct ff_veth_softc {
62     struct ifnet *ifp;
63     uint8_t mac[ETHER_ADDR_LEN];
64     char host_ifname[IF_NAMESIZE];
65 
66     in_addr_t ip;
67     in_addr_t netmask;
68     in_addr_t broadcast;
69     in_addr_t gateway;
70 
71     struct ff_dpdk_if_context *host_ctx;
72 };
73 
74 static int
75 ff_veth_config(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
76 {
77     memcpy(sc->mac, cfg->mac, ETHER_ADDR_LEN);
78     inet_pton(AF_INET, cfg->addr, &sc->ip);
79     inet_pton(AF_INET, cfg->netmask, &sc->netmask);
80     inet_pton(AF_INET, cfg->broadcast, &sc->broadcast);
81     inet_pton(AF_INET, cfg->gateway, &sc->gateway);
82 
83     return 0;
84 }
85 
86 static void
87 ff_veth_init(void *arg)
88 {
89     struct ff_veth_softc *sc = arg;
90     struct ifnet *ifp = sc->ifp;
91 
92     ifp->if_drv_flags |= IFF_DRV_RUNNING;
93     ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
94 }
95 
96 static void
97 ff_veth_start(struct ifnet *ifp)
98 {
99     /* nothing to do */
100 }
101 
102 static void
103 ff_veth_stop(struct ff_veth_softc *sc)
104 {
105     struct ifnet *ifp = sc->ifp;
106 
107     ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
108 }
109 
110 static int
111 ff_veth_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
112 {
113     int error = 0;
114     struct ff_veth_softc *sc = ifp->if_softc;
115 
116     switch (cmd) {
117     case SIOCSIFFLAGS:
118         if (ifp->if_flags & IFF_UP) {
119             ff_veth_init(sc);
120         } else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
121             ff_veth_stop(sc);
122         break;
123     default:
124         error = ether_ioctl(ifp, cmd, data);
125         break;
126     }
127 
128     return (error);
129 }
130 
131 int
132 ff_mbuf_copydata(void *m, void *data, int off, int len)
133 {
134     int ret;
135     struct mbuf *mb = (struct mbuf *)m;
136 
137     if (off + len > mb->m_pkthdr.len) {
138         return -1;
139     }
140 
141     m_copydata(mb, off, len, data);
142 
143     return 0;
144 }
145 
146 void
147 ff_mbuf_tx_offload(void *m, struct ff_tx_offload *offload)
148 {
149     struct mbuf *mb = (struct mbuf *)m;
150     if (mb->m_pkthdr.csum_flags & CSUM_IP) {
151         offload->ip_csum = 1;
152     }
153 
154     if (mb->m_pkthdr.csum_flags & CSUM_TCP) {
155         offload->tcp_csum = 1;
156     }
157 
158     if (mb->m_pkthdr.csum_flags & CSUM_UDP) {
159         offload->udp_csum = 1;
160     }
161 
162     if (mb->m_pkthdr.csum_flags & CSUM_SCTP) {
163         offload->sctp_csum = 1;
164     }
165 
166     if (mb->m_pkthdr.csum_flags & CSUM_TSO) {
167         offload->tso_seg_size = mb->m_pkthdr.tso_segsz;
168     }
169 }
170 
171 void
172 ff_mbuf_free(void *m)
173 {
174     m_freem((struct mbuf *)m);
175 }
176 
177 static void
178 ff_mbuf_ext_free(struct mbuf *m, void *arg1, void *arg2)
179 {
180     ff_dpdk_pktmbuf_free(arg1);
181 }
182 
183 void *
184 ff_mbuf_gethdr(void *pkt, uint16_t total, void *data,
185     uint16_t len, uint8_t rx_csum)
186 {
187     struct mbuf *m = m_gethdr(M_NOWAIT, MT_DATA);
188     if (m == NULL) {
189         return NULL;
190     }
191 
192     if (m_pkthdr_init(m, M_NOWAIT) != 0) {
193         return NULL;
194     }
195 
196     m_extadd(m, data, len, ff_mbuf_ext_free, pkt, NULL, 0, EXT_DISPOSABLE);
197 
198     m->m_pkthdr.len = total;
199     m->m_len = len;
200     m->m_next = NULL;
201     m->m_nextpkt = NULL;
202 
203     if (rx_csum) {
204         m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID |
205             CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
206         m->m_pkthdr.csum_data = 0xffff;
207     }
208     return (void *)m;
209 }
210 
211 void *
212 ff_mbuf_get(void *m, void *data, uint16_t len)
213 {
214     struct mbuf *prev = (struct mbuf *)m;
215     struct mbuf *mb = m_get(M_NOWAIT, MT_DATA);
216 
217     if (mb == NULL) {
218         return NULL;
219     }
220 
221     m_extadd(mb, data, len, NULL, NULL, NULL, 0, 0);
222 
223     mb->m_next = NULL;
224     mb->m_nextpkt = NULL;
225     mb->m_len = len;
226 
227     if (prev != NULL) {
228         prev->m_next = mb;
229     }
230 
231     return (void *)mb;
232 }
233 
234 void
235 ff_veth_process_packet(void *arg, void *m)
236 {
237     struct ifnet *ifp = (struct ifnet *)arg;
238     struct mbuf *mb = (struct mbuf *)m;
239 
240     mb->m_pkthdr.rcvif = ifp;
241 
242     ifp->if_input(ifp, mb);
243 }
244 
245 static int
246 ff_veth_transmit(struct ifnet *ifp, struct mbuf *m)
247 {
248     struct ff_veth_softc *sc = (struct ff_veth_softc *)ifp->if_softc;
249     return ff_dpdk_if_send(sc->host_ctx, (void*)m, m->m_pkthdr.len);
250 }
251 
252 static void
253 ff_veth_qflush(struct ifnet *ifp)
254 {
255 
256 }
257 
258 static int
259 ff_veth_setaddr(struct ff_veth_softc *sc)
260 {
261     struct in_aliasreq req;
262     bzero(&req, sizeof req);
263     strcpy(req.ifra_name, sc->ifp->if_dname);
264 
265     struct sockaddr_in sa;
266     bzero(&sa, sizeof(sa));
267     sa.sin_len = sizeof(sa);
268     sa.sin_family = AF_INET;
269     sa.sin_addr.s_addr = sc->ip;
270     bcopy(&sa, &req.ifra_addr, sizeof(sa));
271 
272     sa.sin_addr.s_addr = sc->netmask;
273     bcopy(&sa, &req.ifra_mask, sizeof(sa));
274 
275     sa.sin_addr.s_addr = sc->broadcast;
276     bcopy(&sa, &req.ifra_broadaddr, sizeof(sa));
277 
278     struct socket *so = NULL;
279     socreate(AF_INET, &so, SOCK_DGRAM, 0, curthread->td_ucred, curthread);
280     int ret = ifioctl(so, SIOCAIFADDR, (caddr_t)&req, curthread);
281 
282     sofree(so);
283 
284     return ret;
285 }
286 
287 static int
288 ff_veth_set_gateway(struct ff_veth_softc *sc)
289 {
290     struct sockaddr_in gw;
291     bzero(&gw, sizeof(gw));
292     gw.sin_len = sizeof(gw);
293     gw.sin_family = AF_INET;
294     gw.sin_addr.s_addr = sc->gateway;
295 
296     struct sockaddr_in dst;
297     bzero(&dst, sizeof(dst));
298     dst.sin_len = sizeof(dst);
299     dst.sin_family = AF_INET;
300     dst.sin_addr.s_addr = 0;
301 
302     struct sockaddr_in nm;
303     bzero(&nm, sizeof(nm));
304     nm.sin_len = sizeof(nm);
305     nm.sin_family = AF_INET;
306     nm.sin_addr.s_addr = 0;
307 
308     return rtrequest_fib(RTM_ADD, (struct sockaddr *)&dst, (struct sockaddr *)&gw,
309         (struct sockaddr *)&nm, RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
310 }
311 
312 static int
313 ff_veth_setup_interface(struct ff_veth_softc *sc, struct ff_port_cfg *cfg)
314 {
315     struct ifnet *ifp;
316 
317     ifp = sc->ifp = if_alloc(IFT_ETHER);
318 
319     ifp->if_init = ff_veth_init;
320     ifp->if_softc = sc;
321 
322     if_initname(ifp, sc->host_ifname, IF_DUNIT_NONE);
323     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
324     ifp->if_ioctl = ff_veth_ioctl;
325     ifp->if_start = ff_veth_start;
326     ifp->if_transmit = ff_veth_transmit;
327     ifp->if_qflush = ff_veth_qflush;
328     ether_ifattach(ifp, sc->mac);
329 
330     if (cfg->hw_features.rx_csum) {
331         ifp->if_capabilities |= IFCAP_RXCSUM;
332     }
333     if (cfg->hw_features.tx_csum_ip) {
334         ifp->if_capabilities |= IFCAP_TXCSUM;
335         ifp->if_hwassist |= CSUM_IP;
336     }
337     if (cfg->hw_features.tx_csum_l4) {
338         ifp->if_hwassist |= CSUM_DELAY_DATA;
339     }
340     if (cfg->hw_features.tx_tso) {
341         ifp->if_capabilities |= IFCAP_TSO;
342         ifp->if_hwassist |= CSUM_TSO;
343     }
344 
345     ifp->if_capenable = ifp->if_capabilities;
346 
347     sc->host_ctx = ff_dpdk_register_if((void *)sc, (void *)sc->ifp, cfg);
348     if (sc->host_ctx == NULL) {
349         printf("%s: Failed to register dpdk interface\n", sc->host_ifname);
350         return -1;
351     }
352 
353     //set ip
354     int ret = ff_veth_setaddr(sc);
355     if (ret != 0) {
356         printf("ff_veth_setaddr failed\n");
357     }
358     ret = ff_veth_set_gateway(sc);
359     if (ret != 0) {
360         printf("ff_veth_set_gateway failed\n");
361     }
362 
363     return (0);
364 }
365 
366 void *
367 ff_veth_attach(struct ff_port_cfg *cfg)
368 {
369     struct ff_veth_softc *sc = NULL;
370     int error;
371 
372     sc = malloc(sizeof(struct ff_veth_softc), M_DEVBUF, M_WAITOK);
373     if (NULL == sc) {
374         printf("ff_veth_softc allocation failed\n");
375         goto fail;
376     }
377     memset(sc, 0, sizeof(struct ff_veth_softc));
378 
379     snprintf(sc->host_ifname, sizeof(sc->host_ifname), ff_IF_NAME, cfg->port_id);
380 
381     error = ff_veth_config(sc, cfg);
382     if (0 != error) {
383         goto fail;
384     }
385 
386     if (0 != ff_veth_setup_interface(sc, cfg)) {
387         goto fail;
388     }
389 
390     return sc->host_ctx;
391 
392 fail:
393     if (sc) {
394         if (sc->host_ctx)
395             ff_dpdk_deregister_if(sc->host_ctx);
396 
397         free(sc, M_DEVBUF);
398     }
399 
400     return NULL;
401 }
402 
403 int
404 ff_veth_detach(void *arg)
405 {
406     struct ff_veth_softc *sc = (struct ff_veth_softc *)arg;
407     if (sc) {
408         ff_dpdk_deregister_if(sc->host_ctx);
409         free(sc, M_DEVBUF);
410     }
411 
412     return (0);
413 }
414 
415 void *
416 ff_veth_softc_to_hostc(void *softc)
417 {
418     struct ff_veth_softc *sc = (struct ff_veth_softc *)softc;
419     return (void *)sc->host_ctx;
420 }
421 
422 /********************
423 *  get next mbuf's addr, current mbuf's data and datalen.
424 *
425 ********************/
426 int ff_next_mbuf(void **mbuf_bsd, void **data, unsigned *len)
427 {
428     struct mbuf *mb = *(struct mbuf **)mbuf_bsd;
429 
430     *len = mb->m_len;
431     *data = mb->m_data;
432 
433     if (mb->m_next)
434         *mbuf_bsd = mb->m_next;
435     else
436         *mbuf_bsd = NULL;
437     return 0;
438 }
439 
440 void * ff_mbuf_mtod(void* bsd_mbuf)
441 {
442     if ( !bsd_mbuf )
443         return NULL;
444     return (void*)((struct mbuf *)bsd_mbuf)->m_data;
445 }
446 
447 // get source rte_mbuf from ext cluster, which carry rte_mbuf while recving pkt, such as arp.
448 void* ff_rte_frm_extcl(void* mbuf)
449 {
450     struct mbuf *bsd_mbuf = mbuf;
451 
452     if ( bsd_mbuf->m_ext.ext_type==EXT_DISPOSABLE && bsd_mbuf->m_ext.ext_free==ff_mbuf_ext_free ){
453         return bsd_mbuf->m_ext.ext_arg1;
454     }
455     else
456         return NULL;
457 }
458 
459 void
460 ff_mbuf_set_vlan_info(void *hdr, uint16_t vlan_tci) {
461     struct mbuf *m = (struct mbuf *)hdr;
462     m->m_pkthdr.ether_vtag = vlan_tci;
463     m->m_flags |= M_VLANTAG;
464     return;
465 }
466 
467