if_ntb.c revision 304380
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: stable/10/sys/dev/ntb/if_ntb/if_ntb.c 304380 2016-08-18 10:39:00Z mav $");
42
43#include <sys/param.h>
44#include <sys/kernel.h>
45#include <sys/systm.h>
46#include <sys/bus.h>
47#include <sys/limits.h>
48#include <sys/module.h>
49#include <sys/socket.h>
50#include <sys/sockio.h>
51
52#include <net/if.h>
53#include <net/if_media.h>
54#include <net/if_types.h>
55#include <net/if_var.h>
56#include <net/bpf.h>
57#include <net/ethernet.h>
58
59#include <machine/bus.h>
60
61#include "../ntb_transport.h"
62
63#define KTR_NTB KTR_SPARE3
64
65struct ntb_net_ctx {
66	device_t		*dev;
67	struct ifnet		*ifp;
68	struct ntb_transport_qp *qp;
69	u_char			eaddr[ETHER_ADDR_LEN];
70	struct mtx		tx_lock;
71	struct callout		queue_full;
72};
73
74static int ntb_net_probe(device_t dev);
75static int ntb_net_attach(device_t dev);
76static int ntb_net_detach(device_t dev);
77static void ntb_net_init(void *arg);
78static int ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
79static void ntb_start(struct ifnet *ifp);
80static void ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
81    void *data, int len);
82static void ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
83    void *data, int len);
84static void ntb_net_event_handler(void *data, enum ntb_link_event status);
85static void ntb_qp_full(void *arg);
86static void create_random_local_eui48(u_char *eaddr);
87
88static int
89ntb_net_probe(device_t dev)
90{
91
92	device_set_desc(dev, "NTB Network Interface");
93	return (0);
94}
95
96static int
97ntb_net_attach(device_t dev)
98{
99	struct ntb_net_ctx *sc = device_get_softc(dev);
100	struct ifnet *ifp;
101	struct ntb_queue_handlers handlers = { ntb_net_rx_handler,
102	    ntb_net_tx_handler, ntb_net_event_handler };
103
104	ifp = sc->ifp = if_alloc(IFT_ETHER);
105	if (ifp == NULL) {
106		printf("ntb: Cannot allocate ifnet structure\n");
107		return (ENOMEM);
108	}
109	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
110
111	mtx_init(&sc->tx_lock, "ntb tx", NULL, MTX_DEF);
112	callout_init(&sc->queue_full, 1);
113
114	sc->qp = ntb_transport_create_queue(ifp, device_get_parent(dev),
115	    &handlers);
116	ifp->if_init = ntb_net_init;
117	ifp->if_softc = sc;
118	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
119	ifp->if_ioctl = ntb_ioctl;
120	ifp->if_start = ntb_start;
121	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
122	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
123	IFQ_SET_READY(&ifp->if_snd);
124	create_random_local_eui48(sc->eaddr);
125	ether_ifattach(ifp, sc->eaddr);
126	ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_JUMBO_MTU;
127	ifp->if_capenable = ifp->if_capabilities;
128	ifp->if_mtu = ntb_transport_max_size(sc->qp) - ETHER_HDR_LEN -
129	    ETHER_CRC_LEN;
130
131	ntb_transport_link_up(sc->qp);
132	return (0);
133}
134
135static int
136ntb_net_detach(device_t dev)
137{
138	struct ntb_net_ctx *sc = device_get_softc(dev);
139
140	if (sc->qp != NULL) {
141		ntb_transport_link_down(sc->qp);
142		ntb_transport_free_queue(sc->qp);
143	}
144
145	if (sc->ifp != NULL) {
146		ether_ifdetach(sc->ifp);
147		if_free(sc->ifp);
148		sc->ifp = NULL;
149	}
150	mtx_destroy(&sc->tx_lock);
151
152	return (0);
153}
154
155/* Network device interface */
156
157static void
158ntb_net_init(void *arg)
159{
160	struct ntb_net_ctx *sc = arg;
161	struct ifnet *ifp = sc->ifp;
162
163	ifp->if_drv_flags |= IFF_DRV_RUNNING;
164	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
165	ifp->if_flags |= IFF_UP;
166	if_link_state_change(ifp, LINK_STATE_UP);
167}
168
169static int
170ntb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
171{
172	struct ntb_net_ctx *sc = ifp->if_softc;
173	struct ifreq *ifr = (struct ifreq *)data;
174	int error = 0;
175
176	switch (command) {
177	case SIOCSIFMTU:
178	    {
179		if (ifr->ifr_mtu > ntb_transport_max_size(sc->qp) -
180		    ETHER_HDR_LEN - ETHER_CRC_LEN) {
181			error = EINVAL;
182			break;
183		}
184
185		ifp->if_mtu = ifr->ifr_mtu;
186		break;
187	    }
188	default:
189		error = ether_ioctl(ifp, command, data);
190		break;
191	}
192
193	return (error);
194}
195
196
197static void
198ntb_start(struct ifnet *ifp)
199{
200	struct mbuf *m_head;
201	struct ntb_net_ctx *sc = ifp->if_softc;
202	int rc;
203
204	mtx_lock(&sc->tx_lock);
205	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
206	CTR0(KTR_NTB, "TX: ntb_start");
207	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
208		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
209		CTR1(KTR_NTB, "TX: start mbuf %p", m_head);
210		rc = ntb_transport_tx_enqueue(sc->qp, m_head, m_head,
211			     m_length(m_head, NULL));
212		if (rc != 0) {
213			CTR1(KTR_NTB,
214			    "TX: could not tx mbuf %p. Returning to snd q",
215			    m_head);
216			if (rc == EAGAIN) {
217				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
218				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
219				callout_reset(&sc->queue_full, hz / 1000,
220				    ntb_qp_full, ifp);
221			}
222			break;
223		}
224	}
225	mtx_unlock(&sc->tx_lock);
226}
227
228/* Network Device Callbacks */
229static void
230ntb_net_tx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
231    int len)
232{
233
234	m_freem(data);
235	CTR1(KTR_NTB, "TX: tx_handler freeing mbuf %p", data);
236}
237
238static void
239ntb_net_rx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data,
240    int len)
241{
242	struct mbuf *m = data;
243	struct ifnet *ifp = qp_data;
244
245	CTR0(KTR_NTB, "RX: rx handler");
246	m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID;
247	(*ifp->if_input)(ifp, m);
248}
249
250static void
251ntb_net_event_handler(void *data, enum ntb_link_event status)
252{
253	struct ifnet *ifp;
254
255	ifp = data;
256	(void)ifp;
257
258	/* XXX The Linux driver munges with the carrier status here. */
259
260	switch (status) {
261	case NTB_LINK_DOWN:
262		break;
263	case NTB_LINK_UP:
264		break;
265	default:
266		panic("Bogus ntb_link_event %u\n", status);
267	}
268}
269
270static void
271ntb_qp_full(void *arg)
272{
273
274	CTR0(KTR_NTB, "TX: qp_full callout");
275	ntb_start(arg);
276}
277
278/* Helper functions */
279/* TODO: This too should really be part of the kernel */
280#define EUI48_MULTICAST			1 << 0
281#define EUI48_LOCALLY_ADMINISTERED	1 << 1
282static void
283create_random_local_eui48(u_char *eaddr)
284{
285	static uint8_t counter = 0;
286	uint32_t seed = ticks;
287
288	eaddr[0] = EUI48_LOCALLY_ADMINISTERED;
289	memcpy(&eaddr[1], &seed, sizeof(uint32_t));
290	eaddr[5] = counter++;
291}
292
293static device_method_t ntb_net_methods[] = {
294	/* Device interface */
295	DEVMETHOD(device_probe,     ntb_net_probe),
296	DEVMETHOD(device_attach,    ntb_net_attach),
297	DEVMETHOD(device_detach,    ntb_net_detach),
298	DEVMETHOD_END
299};
300
301devclass_t ntb_net_devclass;
302static DEFINE_CLASS_0(ntb, ntb_net_driver, ntb_net_methods,
303    sizeof(struct ntb_net_ctx));
304DRIVER_MODULE(if_ntb, ntb_transport, ntb_net_driver, ntb_net_devclass,
305    NULL, NULL);
306MODULE_DEPEND(if_ntb, ntb_transport, 1, 1, 1);
307MODULE_VERSION(if_ntb, 1);
308