]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ntb/if_ntb/if_ntb.c
Extract eventfilter declarations to sys/_eventfilter.h
[FreeBSD/FreeBSD.git] / sys / dev / ntb / if_ntb / if_ntb.c
1 /*-
2  * Copyright (c) 2016 Alexander Motin <mav@FreeBSD.org>
3  * Copyright (C) 2013 Intel Corporation
4  * Copyright (C) 2015 EMC Corporation
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  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*
30  * The Non-Transparent Bridge (NTB) is a device that allows you to connect
31  * two or more systems using a PCI-e links, providing remote memory access.
32  *
33  * This module contains a driver for simulated Ethernet device, using
34  * underlying NTB Transport device.
35  *
36  * NOTE: Much of the code in this module is shared with Linux. Any patches may
37  * be picked up and redistributed in Linux with a dual GPL/BSD license.
38  */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include <sys/param.h>
44 #include <sys/kernel.h>
45 #include <sys/systm.h>
46 #include <sys/buf_ring.h>
47 #include <sys/bus.h>
48 #include <sys/ktr.h>
49 #include <sys/limits.h>
50 #include <sys/module.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/sysctl.h>
54 #include <sys/taskqueue.h>
55
56 #include <net/if.h>
57 #include <net/if_media.h>
58 #include <net/if_types.h>
59 #include <net/if_media.h>
60 #include <net/if_var.h>
61 #include <net/bpf.h>
62 #include <net/ethernet.h>
63
64 #include <machine/bus.h>
65
66 #include "../ntb_transport.h"
67
68 #define KTR_NTB KTR_SPARE3
69 #define NTB_MEDIATYPE            (IFM_ETHER | IFM_AUTO | IFM_FDX)
70
71 #define NTB_CSUM_FEATURES       (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP)
72 #define NTB_CSUM_FEATURES6      (CSUM_TCP_IPV6 | CSUM_UDP_IPV6 | CSUM_SCTP_IPV6)
73 #define NTB_CSUM_SET            (CSUM_DATA_VALID | CSUM_DATA_VALID_IPV6 | \
74                                     CSUM_PSEUDO_HDR | \
75                                     CSUM_IP_CHECKED | CSUM_IP_VALID | \
76                                     CSUM_SCTP_VALID)
77
78 static SYSCTL_NODE(_hw, OID_AUTO, if_ntb, CTLFLAG_RW, 0, "if_ntb");
79
80 static unsigned g_if_ntb_num_queues = UINT_MAX;
81 SYSCTL_UINT(_hw_if_ntb, OID_AUTO, num_queues, CTLFLAG_RWTUN,
82     &g_if_ntb_num_queues, 0, "Number of queues per interface");
83
84 struct ntb_net_queue {
85         struct ntb_net_ctx      *sc;
86         if_t                     ifp;
87         struct ntb_transport_qp *qp;
88         struct buf_ring         *br;
89         struct task              tx_task;
90         struct taskqueue        *tx_tq;
91         struct mtx               tx_lock;
92         struct callout           queue_full;
93 };
94
95 struct ntb_net_ctx {
96         if_t                     ifp;
97         struct ifmedia           media;
98         u_char                   eaddr[ETHER_ADDR_LEN];
99         int                      num_queues;
100         struct ntb_net_queue    *queues;
101         int                      mtu;
102 };
103
104 static int ntb_net_probe(device_t dev);
105 static int ntb_net_attach(device_t dev);
106 static int ntb_net_detach(device_t dev);
107 static void ntb_net_init(void *arg);
108 static int ntb_ifmedia_upd(struct ifnet *);
109 static void ntb_ifmedia_sts(struct ifnet *, struct ifmediareq *);
110 static int ntb_ioctl(if_t ifp, u_long command, caddr_t data);
111 static int ntb_transmit(if_t ifp, struct mbuf *m);
112 static void ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
113     void *data, int len);
114 static void ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
115     void *data, int len);
116 static void ntb_net_event_handler(void *data, enum ntb_link_event status);
117 static void ntb_handle_tx(void *arg, int pending);
118 static void ntb_qp_full(void *arg);
119 static void ntb_qflush(if_t ifp);
120 static void create_random_local_eui48(u_char *eaddr);
121
122 static int
123 ntb_net_probe(device_t dev)
124 {
125
126         device_set_desc(dev, "NTB Network Interface");
127         return (0);
128 }
129
130 static int
131 ntb_net_attach(device_t dev)
132 {
133         struct ntb_net_ctx *sc = device_get_softc(dev);
134         struct ntb_net_queue *q;
135         if_t ifp;
136         struct ntb_queue_handlers handlers = { ntb_net_rx_handler,
137             ntb_net_tx_handler, ntb_net_event_handler };
138         int i;
139
140         ifp = sc->ifp = if_gethandle(IFT_ETHER);
141         if (ifp == NULL) {
142                 printf("ntb: Cannot allocate ifnet structure\n");
143                 return (ENOMEM);
144         }
145         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
146         if_setdev(ifp, dev);
147
148         sc->num_queues = min(g_if_ntb_num_queues,
149             ntb_transport_queue_count(dev));
150         sc->queues = malloc(sc->num_queues * sizeof(struct ntb_net_queue),
151             M_DEVBUF, M_WAITOK | M_ZERO);
152         sc->mtu = INT_MAX;
153         for (i = 0; i < sc->num_queues; i++) {
154                 q = &sc->queues[i];
155                 q->sc = sc;
156                 q->ifp = ifp;
157                 q->qp = ntb_transport_create_queue(dev, i, &handlers, q);
158                 if (q->qp == NULL)
159                         break;
160                 sc->mtu = imin(sc->mtu, ntb_transport_max_size(q->qp));
161                 mtx_init(&q->tx_lock, "ntb tx", NULL, MTX_DEF);
162                 q->br = buf_ring_alloc(4096, M_DEVBUF, M_WAITOK, &q->tx_lock);
163                 TASK_INIT(&q->tx_task, 0, ntb_handle_tx, q);
164                 q->tx_tq = taskqueue_create_fast("ntb_txq", M_NOWAIT,
165                     taskqueue_thread_enqueue, &q->tx_tq);
166                 taskqueue_start_threads(&q->tx_tq, 1, PI_NET, "%s txq%d",
167                     device_get_nameunit(dev), i);
168                 callout_init(&q->queue_full, 1);
169         }
170         sc->num_queues = i;
171         device_printf(dev, "%d queue(s)\n", sc->num_queues);
172
173         if_setinitfn(ifp, ntb_net_init);
174         if_setsoftc(ifp, sc);
175         if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
176         if_setioctlfn(ifp, ntb_ioctl);
177         if_settransmitfn(ifp, ntb_transmit);
178         if_setqflushfn(ifp, ntb_qflush);
179         create_random_local_eui48(sc->eaddr);
180         ether_ifattach(ifp, sc->eaddr);
181         if_setcapabilities(ifp, IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 |
182             IFCAP_JUMBO_MTU | IFCAP_LINKSTATE);
183         if_setcapenable(ifp, IFCAP_JUMBO_MTU | IFCAP_LINKSTATE);
184         if_setmtu(ifp, sc->mtu - ETHER_HDR_LEN);
185
186         ifmedia_init(&sc->media, IFM_IMASK, ntb_ifmedia_upd,
187             ntb_ifmedia_sts);
188         ifmedia_add(&sc->media, NTB_MEDIATYPE, 0, NULL);
189         ifmedia_set(&sc->media, NTB_MEDIATYPE);
190
191         for (i = 0; i < sc->num_queues; i++)
192                 ntb_transport_link_up(sc->queues[i].qp);
193         return (0);
194 }
195
196 static int
197 ntb_net_detach(device_t dev)
198 {
199         struct ntb_net_ctx *sc = device_get_softc(dev);
200         struct ntb_net_queue *q;
201         int i;
202
203         for (i = 0; i < sc->num_queues; i++)
204                 ntb_transport_link_down(sc->queues[i].qp);
205         ether_ifdetach(sc->ifp);
206         if_free(sc->ifp);
207         ifmedia_removeall(&sc->media);
208         for (i = 0; i < sc->num_queues; i++) {
209                 q = &sc->queues[i];
210                 ntb_transport_free_queue(q->qp);
211                 buf_ring_free(q->br, M_DEVBUF);
212                 callout_drain(&q->queue_full);
213                 taskqueue_drain_all(q->tx_tq);
214                 mtx_destroy(&q->tx_lock);
215         }
216         free(sc->queues, M_DEVBUF);
217         return (0);
218 }
219
220 /* Network device interface */
221
222 static void
223 ntb_net_init(void *arg)
224 {
225         struct ntb_net_ctx *sc = arg;
226         if_t ifp = sc->ifp;
227
228         if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
229         if_setbaudrate(ifp, ntb_transport_link_speed(sc->queues[0].qp));
230         if_link_state_change(ifp, ntb_transport_link_query(sc->queues[0].qp) ?
231             LINK_STATE_UP : LINK_STATE_DOWN);
232 }
233
234 static int
235 ntb_ioctl(if_t ifp, u_long command, caddr_t data)
236 {
237         struct ntb_net_ctx *sc = if_getsoftc(ifp);
238         struct ifreq *ifr = (struct ifreq *)data;
239         int error = 0;
240
241         switch (command) {
242         case SIOCSIFFLAGS:
243         case SIOCADDMULTI:
244         case SIOCDELMULTI:
245                 break;
246
247         case SIOCSIFMTU:
248             {
249                 if (ifr->ifr_mtu > sc->mtu - ETHER_HDR_LEN) {
250                         error = EINVAL;
251                         break;
252                 }
253
254                 if_setmtu(ifp, ifr->ifr_mtu);
255                 break;
256             }
257
258         case SIOCSIFMEDIA:
259         case SIOCGIFMEDIA:
260                 error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
261                 break;
262
263         case SIOCSIFCAP:
264                 if (ifr->ifr_reqcap & IFCAP_RXCSUM)
265                         if_setcapenablebit(ifp, IFCAP_RXCSUM, 0);
266                 else
267                         if_setcapenablebit(ifp, 0, IFCAP_RXCSUM);
268                 if (ifr->ifr_reqcap & IFCAP_TXCSUM) {
269                         if_setcapenablebit(ifp, IFCAP_TXCSUM, 0);
270                         if_sethwassistbits(ifp, NTB_CSUM_FEATURES, 0);
271                 } else {
272                         if_setcapenablebit(ifp, 0, IFCAP_TXCSUM);
273                         if_sethwassistbits(ifp, 0, NTB_CSUM_FEATURES);
274                 }
275                 if (ifr->ifr_reqcap & IFCAP_RXCSUM_IPV6)
276                         if_setcapenablebit(ifp, IFCAP_RXCSUM_IPV6, 0);
277                 else
278                         if_setcapenablebit(ifp, 0, IFCAP_RXCSUM_IPV6);
279                 if (ifr->ifr_reqcap & IFCAP_TXCSUM_IPV6) {
280                         if_setcapenablebit(ifp, IFCAP_TXCSUM_IPV6, 0);
281                         if_sethwassistbits(ifp, NTB_CSUM_FEATURES6, 0);
282                 } else {
283                         if_setcapenablebit(ifp, 0, IFCAP_TXCSUM_IPV6);
284                         if_sethwassistbits(ifp, 0, NTB_CSUM_FEATURES6);
285                 }
286                 break;
287
288         default:
289                 error = ether_ioctl(ifp, command, data);
290                 break;
291         }
292
293         return (error);
294 }
295
296 static int
297 ntb_ifmedia_upd(struct ifnet *ifp)
298 {
299         struct ntb_net_ctx *sc = if_getsoftc(ifp);
300         struct ifmedia *ifm = &sc->media;
301
302         if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
303                 return (EINVAL);
304
305         return (0);
306 }
307
308 static void
309 ntb_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
310 {
311         struct ntb_net_ctx *sc = if_getsoftc(ifp);
312
313         ifmr->ifm_status = IFM_AVALID;
314         ifmr->ifm_active = NTB_MEDIATYPE;
315         if (ntb_transport_link_query(sc->queues[0].qp))
316                 ifmr->ifm_status |= IFM_ACTIVE;
317 }
318
319 static void
320 ntb_transmit_locked(struct ntb_net_queue *q)
321 {
322         if_t ifp = q->ifp;
323         struct mbuf *m;
324         int rc, len;
325         short mflags;
326
327         CTR0(KTR_NTB, "TX: ntb_transmit_locked");
328         while ((m = drbr_peek(ifp, q->br)) != NULL) {
329                 CTR1(KTR_NTB, "TX: start mbuf %p", m);
330                 if_etherbpfmtap(ifp, m);
331                 len = m->m_pkthdr.len;
332                 mflags = m->m_flags;
333                 rc = ntb_transport_tx_enqueue(q->qp, m, m, len);
334                 if (rc != 0) {
335                         CTR2(KTR_NTB, "TX: could not tx mbuf %p: %d", m, rc);
336                         if (rc == EAGAIN) {
337                                 drbr_putback(ifp, q->br, m);
338                                 callout_reset_sbt(&q->queue_full,
339                                     SBT_1MS / 4, SBT_1MS / 4,
340                                     ntb_qp_full, q, 0);
341                         } else {
342                                 m_freem(m);
343                                 drbr_advance(ifp, q->br);
344                                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
345                         }
346                         break;
347                 }
348                 drbr_advance(ifp, q->br);
349                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
350                 if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
351                 if (mflags & M_MCAST)
352                         if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
353         }
354 }
355
356 static int
357 ntb_transmit(if_t ifp, struct mbuf *m)
358 {
359         struct ntb_net_ctx *sc = if_getsoftc(ifp);
360         struct ntb_net_queue *q;
361         int error, i;
362
363         CTR0(KTR_NTB, "TX: ntb_transmit");
364         if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
365                 i = m->m_pkthdr.flowid % sc->num_queues;
366         else
367                 i = curcpu % sc->num_queues;
368         q = &sc->queues[i];
369
370         error = drbr_enqueue(ifp, q->br, m);
371         if (error)
372                 return (error);
373
374         if (mtx_trylock(&q->tx_lock)) {
375                 ntb_transmit_locked(q);
376                 mtx_unlock(&q->tx_lock);
377         } else
378                 taskqueue_enqueue(q->tx_tq, &q->tx_task);
379         return (0);
380 }
381
382 static void
383 ntb_handle_tx(void *arg, int pending)
384 {
385         struct ntb_net_queue *q = arg;
386
387         mtx_lock(&q->tx_lock);
388         ntb_transmit_locked(q);
389         mtx_unlock(&q->tx_lock);
390 }
391
392 static void
393 ntb_qp_full(void *arg)
394 {
395         struct ntb_net_queue *q = arg;
396
397         CTR0(KTR_NTB, "TX: qp_full callout");
398         if (ntb_transport_tx_free_entry(q->qp) > 0)
399                 taskqueue_enqueue(q->tx_tq, &q->tx_task);
400         else
401                 callout_schedule_sbt(&q->queue_full,
402                     SBT_1MS / 4, SBT_1MS / 4, 0);
403 }
404
405 static void
406 ntb_qflush(if_t ifp)
407 {
408         struct ntb_net_ctx *sc = if_getsoftc(ifp);
409         struct ntb_net_queue *q;
410         struct mbuf *m;
411         int i;
412
413         for (i = 0; i < sc->num_queues; i++) {
414                 q = &sc->queues[i];
415                 mtx_lock(&q->tx_lock);
416                 while ((m = buf_ring_dequeue_sc(q->br)) != NULL)
417                         m_freem(m);
418                 mtx_unlock(&q->tx_lock);
419         }
420         if_qflush(ifp);
421 }
422
423 /* Network Device Callbacks */
424 static void
425 ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
426     int len)
427 {
428
429         m_freem(data);
430         CTR1(KTR_NTB, "TX: tx_handler freeing mbuf %p", data);
431 }
432
433 static void
434 ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
435     int len)
436 {
437         struct ntb_net_queue *q = qp_data;
438         struct ntb_net_ctx *sc = q->sc;
439         struct mbuf *m = data;
440         if_t ifp = q->ifp;
441         uint16_t proto;
442
443         CTR1(KTR_NTB, "RX: rx handler (%d)", len);
444         if (len < 0) {
445                 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
446                 return;
447         }
448
449         m->m_pkthdr.rcvif = ifp;
450         if (sc->num_queues > 1) {
451                 m->m_pkthdr.flowid = q - sc->queues;
452                 M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
453         }
454         if (if_getcapenable(ifp) & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
455                 m_copydata(m, 12, 2, (void *)&proto);
456                 switch (ntohs(proto)) {
457                 case ETHERTYPE_IP:
458                         if (if_getcapenable(ifp) & IFCAP_RXCSUM) {
459                                 m->m_pkthdr.csum_data = 0xffff;
460                                 m->m_pkthdr.csum_flags = NTB_CSUM_SET;
461                         }
462                         break;
463                 case ETHERTYPE_IPV6:
464                         if (if_getcapenable(ifp) & IFCAP_RXCSUM_IPV6) {
465                                 m->m_pkthdr.csum_data = 0xffff;
466                                 m->m_pkthdr.csum_flags = NTB_CSUM_SET;
467                         }
468                         break;
469                 }
470         }
471         if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
472         if_input(ifp, m);
473 }
474
475 static void
476 ntb_net_event_handler(void *data, enum ntb_link_event status)
477 {
478         struct ntb_net_queue *q = data;
479
480         if_setbaudrate(q->ifp, ntb_transport_link_speed(q->qp));
481         if_link_state_change(q->ifp, (status == NTB_LINK_UP) ? LINK_STATE_UP :
482             LINK_STATE_DOWN);
483 }
484
485 /* Helper functions */
486 /* TODO: This too should really be part of the kernel */
487 #define EUI48_MULTICAST                 1 << 0
488 #define EUI48_LOCALLY_ADMINISTERED      1 << 1
489 static void
490 create_random_local_eui48(u_char *eaddr)
491 {
492         static uint8_t counter = 0;
493
494         eaddr[0] = EUI48_LOCALLY_ADMINISTERED;
495         arc4rand(&eaddr[1], 4, 0);
496         eaddr[5] = counter++;
497 }
498
499 static device_method_t ntb_net_methods[] = {
500         /* Device interface */
501         DEVMETHOD(device_probe,     ntb_net_probe),
502         DEVMETHOD(device_attach,    ntb_net_attach),
503         DEVMETHOD(device_detach,    ntb_net_detach),
504         DEVMETHOD_END
505 };
506
507 devclass_t ntb_net_devclass;
508 static DEFINE_CLASS_0(ntb, ntb_net_driver, ntb_net_methods,
509     sizeof(struct ntb_net_ctx));
510 DRIVER_MODULE(if_ntb, ntb_transport, ntb_net_driver, ntb_net_devclass,
511     NULL, NULL);
512 MODULE_DEPEND(if_ntb, ntb_transport, 1, 1, 1);
513 MODULE_VERSION(if_ntb, 1);