]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/ntb/if_ntb/if_ntb.c
MFC r368207,368607:
[FreeBSD/stable/10.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/limits.h>
49 #include <sys/module.h>
50 #include <sys/socket.h>
51 #include <sys/sockio.h>
52 #include <sys/sysctl.h>
53 #include <sys/taskqueue.h>
54
55 #include <net/if.h>
56 #include <net/if_media.h>
57 #include <net/if_types.h>
58 #include <net/if_media.h>
59 #include <net/if_var.h>
60 #include <net/bpf.h>
61 #include <net/ethernet.h>
62
63 #include <machine/bus.h>
64
65 #include "../ntb_transport.h"
66
67 #define KTR_NTB KTR_SPARE3
68 #define NTB_MEDIATYPE            (IFM_ETHER | IFM_AUTO | IFM_FDX)
69
70 #define NTB_CSUM_FEATURES       (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP)
71 #define NTB_CSUM_FEATURES6      (CSUM_TCP_IPV6 | CSUM_UDP_IPV6 | CSUM_SCTP_IPV6)
72 #define NTB_CSUM_SET            (CSUM_DATA_VALID | CSUM_DATA_VALID_IPV6 | \
73                                     CSUM_PSEUDO_HDR | \
74                                     CSUM_IP_CHECKED | CSUM_IP_VALID | \
75                                     CSUM_SCTP_VALID)
76
77 static SYSCTL_NODE(_hw, OID_AUTO, if_ntb, CTLFLAG_RW, 0, "if_ntb");
78
79 static unsigned g_if_ntb_num_queues = UINT_MAX;
80 SYSCTL_UINT(_hw_if_ntb, OID_AUTO, num_queues, CTLFLAG_RWTUN,
81     &g_if_ntb_num_queues, 0, "Number of queues per interface");
82
83 struct ntb_net_queue {
84         struct ntb_net_ctx      *sc;
85         struct ifnet            *ifp;
86         struct ntb_transport_qp *qp;
87         struct buf_ring         *br;
88         struct task              tx_task;
89         struct taskqueue        *tx_tq;
90         struct mtx               tx_lock;
91         struct callout           queue_full;
92 };
93
94 struct ntb_net_ctx {
95         struct ifnet            *ifp;
96         struct ifmedia           media;
97         u_char                   eaddr[ETHER_ADDR_LEN];
98         int                      num_queues;
99         struct ntb_net_queue    *queues;
100         int                      mtu;
101 };
102
103 static int ntb_net_probe(device_t dev);
104 static int ntb_net_attach(device_t dev);
105 static int ntb_net_detach(device_t dev);
106 static void ntb_net_init(void *arg);
107 static int ntb_ifmedia_upd(struct ifnet *);
108 static void ntb_ifmedia_sts(struct ifnet *, struct ifmediareq *);
109 static int ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
110 static int ntb_transmit(struct ifnet *ifp, struct mbuf *m);
111 static void ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
112     void *data, int len);
113 static void ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
114     void *data, int len);
115 static void ntb_net_event_handler(void *data, enum ntb_link_event status);
116 static void ntb_handle_tx(void *arg, int pending);
117 static void ntb_qp_full(void *arg);
118 static void ntb_qflush(struct ifnet *ifp);
119 static void create_random_local_eui48(u_char *eaddr);
120
121 static int
122 ntb_net_probe(device_t dev)
123 {
124
125         device_set_desc(dev, "NTB Network Interface");
126         return (0);
127 }
128
129 static int
130 ntb_net_attach(device_t dev)
131 {
132         struct ntb_net_ctx *sc = device_get_softc(dev);
133         struct ntb_net_queue *q;
134         struct ifnet *ifp;
135         struct ntb_queue_handlers handlers = { ntb_net_rx_handler,
136             ntb_net_tx_handler, ntb_net_event_handler };
137         int i;
138
139         ifp = sc->ifp = if_alloc(IFT_ETHER);
140         if (ifp == NULL) {
141                 printf("ntb: Cannot allocate ifnet structure\n");
142                 return (ENOMEM);
143         }
144         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
145
146         sc->num_queues = min(g_if_ntb_num_queues,
147             ntb_transport_queue_count(dev));
148         sc->queues = malloc(sc->num_queues * sizeof(struct ntb_net_queue),
149             M_DEVBUF, M_WAITOK | M_ZERO);
150         sc->mtu = INT_MAX;
151         for (i = 0; i < sc->num_queues; i++) {
152                 q = &sc->queues[i];
153                 q->sc = sc;
154                 q->ifp = ifp;
155                 q->qp = ntb_transport_create_queue(dev, i, &handlers, q);
156                 if (q->qp == NULL)
157                         break;
158                 sc->mtu = imin(sc->mtu, ntb_transport_max_size(q->qp));
159                 mtx_init(&q->tx_lock, "ntb tx", NULL, MTX_DEF);
160                 q->br = buf_ring_alloc(4096, M_DEVBUF, M_WAITOK, &q->tx_lock);
161                 TASK_INIT(&q->tx_task, 0, ntb_handle_tx, q);
162                 q->tx_tq = taskqueue_create_fast("ntb_txq", M_NOWAIT,
163                     taskqueue_thread_enqueue, &q->tx_tq);
164                 taskqueue_start_threads(&q->tx_tq, 1, PI_NET, "%s txq%d",
165                     device_get_nameunit(dev), i);
166                 callout_init(&q->queue_full, 1);
167         }
168         sc->num_queues = i;
169         device_printf(dev, "%d queue(s)\n", sc->num_queues);
170
171         ifp->if_init = ntb_net_init;
172         ifp->if_softc = sc;
173         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
174         ifp->if_ioctl = ntb_ioctl;
175         ifp->if_transmit = ntb_transmit;
176         ifp->if_qflush = ntb_qflush;
177         create_random_local_eui48(sc->eaddr);
178         ether_ifattach(ifp, sc->eaddr);
179         ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 |
180             IFCAP_JUMBO_MTU | IFCAP_LINKSTATE;
181         ifp->if_capenable = IFCAP_JUMBO_MTU | IFCAP_LINKSTATE;
182         ifp->if_mtu = sc->mtu - ETHER_HDR_LEN;
183
184         ifmedia_init(&sc->media, IFM_IMASK, ntb_ifmedia_upd,
185             ntb_ifmedia_sts);
186         ifmedia_add(&sc->media, NTB_MEDIATYPE, 0, NULL);
187         ifmedia_set(&sc->media, NTB_MEDIATYPE);
188
189         for (i = 0; i < sc->num_queues; i++)
190                 ntb_transport_link_up(sc->queues[i].qp);
191         return (0);
192 }
193
194 static int
195 ntb_net_detach(device_t dev)
196 {
197         struct ntb_net_ctx *sc = device_get_softc(dev);
198         struct ntb_net_queue *q;
199         int i;
200
201         for (i = 0; i < sc->num_queues; i++)
202                 ntb_transport_link_down(sc->queues[i].qp);
203         ether_ifdetach(sc->ifp);
204         if_free(sc->ifp);
205         ifmedia_removeall(&sc->media);
206         for (i = 0; i < sc->num_queues; i++) {
207                 q = &sc->queues[i];
208                 ntb_transport_free_queue(q->qp);
209                 buf_ring_free(q->br, M_DEVBUF);
210                 callout_drain(&q->queue_full);
211                 taskqueue_drain_all(q->tx_tq);
212                 mtx_destroy(&q->tx_lock);
213         }
214         free(sc->queues, M_DEVBUF);
215         return (0);
216 }
217
218 /* Network device interface */
219
220 static void
221 ntb_net_init(void *arg)
222 {
223         struct ntb_net_ctx *sc = arg;
224         struct ifnet *ifp = sc->ifp;
225
226         ifp->if_drv_flags |= IFF_DRV_RUNNING;
227         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
228         if_link_state_change(ifp, ntb_transport_link_query(sc->queues[0].qp) ?
229             LINK_STATE_UP : LINK_STATE_DOWN);
230 }
231
232 static int
233 ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
234 {
235         struct ntb_net_ctx *sc = ifp->if_softc;
236         struct ifreq *ifr = (struct ifreq *)data;
237         int error = 0;
238
239         switch (command) {
240         case SIOCSIFFLAGS:
241         case SIOCADDMULTI:
242         case SIOCDELMULTI:
243                 break;
244
245         case SIOCSIFMTU:
246             {
247                 if (ifr->ifr_mtu > sc->mtu - ETHER_HDR_LEN) {
248                         error = EINVAL;
249                         break;
250                 }
251
252                 ifp->if_mtu = ifr->ifr_mtu;
253                 break;
254             }
255
256         case SIOCSIFMEDIA:
257         case SIOCGIFMEDIA:
258                 error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
259                 break;
260
261         case SIOCSIFCAP:
262                 if (ifr->ifr_reqcap & IFCAP_RXCSUM)
263                         ifp->if_capenable |= IFCAP_RXCSUM;
264                 else
265                         ifp->if_capenable &= ~IFCAP_RXCSUM;
266                 if (ifr->ifr_reqcap & IFCAP_TXCSUM) {
267                         ifp->if_capenable |= IFCAP_TXCSUM;
268                         ifp->if_hwassist |= NTB_CSUM_FEATURES;
269                 } else {
270                         ifp->if_capenable &= ~IFCAP_TXCSUM;
271                         ifp->if_hwassist &= ~NTB_CSUM_FEATURES;
272                 }
273                 if (ifr->ifr_reqcap & IFCAP_RXCSUM_IPV6)
274                         ifp->if_capenable |= IFCAP_RXCSUM_IPV6;
275                 else
276                         ifp->if_capenable &= ~IFCAP_RXCSUM_IPV6;
277                 if (ifr->ifr_reqcap & IFCAP_TXCSUM_IPV6) {
278                         ifp->if_capenable |= IFCAP_TXCSUM_IPV6;
279                         ifp->if_hwassist |= NTB_CSUM_FEATURES6;
280                 } else {
281                         ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6;
282                         ifp->if_hwassist &= ~NTB_CSUM_FEATURES6;
283                 }
284                 break;
285
286         default:
287                 error = ether_ioctl(ifp, command, data);
288                 break;
289         }
290
291         return (error);
292 }
293
294 static int
295 ntb_ifmedia_upd(struct ifnet *ifp)
296 {
297         struct ntb_net_ctx *sc = ifp->if_softc;
298         struct ifmedia *ifm = &sc->media;
299
300         if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
301                 return (EINVAL);
302
303         return (0);
304 }
305
306 static void
307 ntb_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
308 {
309         struct ntb_net_ctx *sc = ifp->if_softc;
310
311         ifmr->ifm_status = IFM_AVALID;
312         ifmr->ifm_active = NTB_MEDIATYPE;
313         if (ntb_transport_link_query(sc->queues[0].qp))
314                 ifmr->ifm_status |= IFM_ACTIVE;
315 }
316
317 static void
318 ntb_transmit_locked(struct ntb_net_queue *q)
319 {
320         struct ifnet *ifp = q->ifp;
321         struct mbuf *m;
322         int rc, len;
323         short mflags;
324
325         CTR0(KTR_NTB, "TX: ntb_transmit_locked");
326         while ((m = drbr_peek(ifp, q->br)) != NULL) {
327                 CTR1(KTR_NTB, "TX: start mbuf %p", m);
328                 ETHER_BPF_MTAP(ifp, m);
329                 len = m->m_pkthdr.len;
330                 mflags = m->m_flags;
331                 rc = ntb_transport_tx_enqueue(q->qp, m, m, len);
332                 if (rc != 0) {
333                         CTR2(KTR_NTB, "TX: could not tx mbuf %p: %d", m, rc);
334                         if (rc == EAGAIN) {
335                                 drbr_putback(ifp, q->br, m);
336                                 callout_reset_sbt(&q->queue_full,
337                                     SBT_1MS / 4, SBT_1MS / 4,
338                                     ntb_qp_full, q, 0);
339                         } else {
340                                 m_freem(m);
341                                 drbr_advance(ifp, q->br);
342                                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
343                         }
344                         break;
345                 }
346                 drbr_advance(ifp, q->br);
347                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
348                 if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
349                 if (mflags & M_MCAST)
350                         if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
351         }
352 }
353
354 static int
355 ntb_transmit(struct ifnet *ifp, struct mbuf *m)
356 {
357         struct ntb_net_ctx *sc = ifp->if_softc;
358         struct ntb_net_queue *q;
359         int error, i;
360
361         CTR0(KTR_NTB, "TX: ntb_transmit");
362         if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
363                 i = m->m_pkthdr.flowid % sc->num_queues;
364         else
365                 i = curcpu % sc->num_queues;
366         q = &sc->queues[i];
367
368         error = drbr_enqueue(ifp, q->br, m);
369         if (error)
370                 return (error);
371
372         if (mtx_trylock(&q->tx_lock)) {
373                 ntb_transmit_locked(q);
374                 mtx_unlock(&q->tx_lock);
375         } else
376                 taskqueue_enqueue(q->tx_tq, &q->tx_task);
377         return (0);
378 }
379
380 static void
381 ntb_handle_tx(void *arg, int pending)
382 {
383         struct ntb_net_queue *q = arg;
384
385         mtx_lock(&q->tx_lock);
386         ntb_transmit_locked(q);
387         mtx_unlock(&q->tx_lock);
388 }
389
390 static void
391 ntb_qp_full(void *arg)
392 {
393         struct ntb_net_queue *q = arg;
394
395         CTR0(KTR_NTB, "TX: qp_full callout");
396         if (ntb_transport_tx_free_entry(q->qp) > 0)
397                 taskqueue_enqueue(q->tx_tq, &q->tx_task);
398         else
399                 callout_schedule_sbt(&q->queue_full,
400                     SBT_1MS / 4, SBT_1MS / 4, 0);
401 }
402
403 static void
404 ntb_qflush(struct ifnet *ifp)
405 {
406         struct ntb_net_ctx *sc = ifp->if_softc;
407         struct ntb_net_queue *q;
408         struct mbuf *m;
409         int i;
410
411         for (i = 0; i < sc->num_queues; i++) {
412                 q = &sc->queues[i];
413                 mtx_lock(&q->tx_lock);
414                 while ((m = buf_ring_dequeue_sc(q->br)) != NULL)
415                         m_freem(m);
416                 mtx_unlock(&q->tx_lock);
417         }
418         if_qflush(ifp);
419 }
420
421 /* Network Device Callbacks */
422 static void
423 ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
424     int len)
425 {
426
427         m_freem(data);
428         CTR1(KTR_NTB, "TX: tx_handler freeing mbuf %p", data);
429 }
430
431 static void
432 ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
433     int len)
434 {
435         struct ntb_net_queue *q = qp_data;
436         struct ntb_net_ctx *sc = q->sc;
437         struct mbuf *m = data;
438         struct ifnet *ifp = q->ifp;
439         uint16_t proto;
440
441         CTR1(KTR_NTB, "RX: rx handler (%d)", len);
442         if (len < 0) {
443                 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
444                 return;
445         }
446
447         m->m_pkthdr.rcvif = ifp;
448         if (sc->num_queues > 1) {
449                 m->m_pkthdr.flowid = q - sc->queues;
450                 M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
451         }
452         if (ifp->if_capenable & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
453                 m_copydata(m, 12, 2, (void *)&proto);
454                 switch (ntohs(proto)) {
455                 case ETHERTYPE_IP:
456                         if (ifp->if_capenable & IFCAP_RXCSUM) {
457                                 m->m_pkthdr.csum_data = 0xffff;
458                                 m->m_pkthdr.csum_flags = NTB_CSUM_SET;
459                         }
460                         break;
461                 case ETHERTYPE_IPV6:
462                         if (ifp->if_capenable & IFCAP_RXCSUM_IPV6) {
463                                 m->m_pkthdr.csum_data = 0xffff;
464                                 m->m_pkthdr.csum_flags = NTB_CSUM_SET;
465                         }
466                         break;
467                 }
468         }
469         if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
470         ifp->if_input(ifp, m);
471 }
472
473 static void
474 ntb_net_event_handler(void *data, enum ntb_link_event status)
475 {
476         struct ntb_net_queue *q = data;
477         int new_state;
478
479         switch (status) {
480         case NTB_LINK_DOWN:
481                 new_state = LINK_STATE_DOWN;
482                 break;
483         case NTB_LINK_UP:
484                 new_state = LINK_STATE_UP;
485                 break;
486         default:
487                 new_state = LINK_STATE_UNKNOWN;
488                 break;
489         }
490         if_link_state_change(q->ifp, new_state);
491 }
492
493 /* Helper functions */
494 /* TODO: This too should really be part of the kernel */
495 #define EUI48_MULTICAST                 1 << 0
496 #define EUI48_LOCALLY_ADMINISTERED      1 << 1
497 static void
498 create_random_local_eui48(u_char *eaddr)
499 {
500         static uint8_t counter = 0;
501
502         eaddr[0] = EUI48_LOCALLY_ADMINISTERED;
503         arc4rand(&eaddr[1], 4, 0);
504         eaddr[5] = counter++;
505 }
506
507 static device_method_t ntb_net_methods[] = {
508         /* Device interface */
509         DEVMETHOD(device_probe,     ntb_net_probe),
510         DEVMETHOD(device_attach,    ntb_net_attach),
511         DEVMETHOD(device_detach,    ntb_net_detach),
512         DEVMETHOD_END
513 };
514
515 devclass_t ntb_net_devclass;
516 static DEFINE_CLASS_0(ntb, ntb_net_driver, ntb_net_methods,
517     sizeof(struct ntb_net_ctx));
518 DRIVER_MODULE(if_ntb, ntb_transport, ntb_net_driver, ntb_net_devclass,
519     NULL, NULL);
520 MODULE_DEPEND(if_ntb, ntb_transport, 1, 1, 1);
521 MODULE_VERSION(if_ntb, 1);