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