1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Xen inter-domain backend - GLDv3 driver edition. 29 * 30 * A traditional GLDv3 driver used to communicate with a guest 31 * domain. This driver is typically plumbed underneath the IP stack 32 * or a software ethernet bridge. 33 */ 34 35 #include "xnb.h" 36 37 #include <sys/sunddi.h> 38 #include <sys/conf.h> 39 #include <sys/modctl.h> 40 #include <sys/strsubr.h> 41 #include <sys/dlpi.h> 42 #include <sys/pattr.h> 43 #include <sys/mac_provider.h> 44 #include <sys/mac_ether.h> 45 #include <xen/sys/xendev.h> 46 #include <sys/note.h> 47 48 /* Required driver entry points for GLDv3 */ 49 static int xnbu_m_start(void *); 50 static void xnbu_m_stop(void *); 51 static int xnbu_m_set_mac_addr(void *, const uint8_t *); 52 static int xnbu_m_set_multicast(void *, boolean_t, const uint8_t *); 53 static int xnbu_m_set_promiscuous(void *, boolean_t); 54 static int xnbu_m_stat(void *, uint_t, uint64_t *); 55 static boolean_t xnbu_m_getcapab(void *, mac_capab_t, void *); 56 static mblk_t *xnbu_m_send(void *, mblk_t *); 57 58 typedef struct xnbu { 59 mac_handle_t u_mh; 60 boolean_t u_need_sched; 61 } xnbu_t; 62 63 static mac_callbacks_t xnbu_callbacks = { 64 MC_GETCAPAB, 65 xnbu_m_stat, 66 xnbu_m_start, 67 xnbu_m_stop, 68 xnbu_m_set_promiscuous, 69 xnbu_m_set_multicast, 70 xnbu_m_set_mac_addr, 71 xnbu_m_send, 72 NULL, 73 NULL, 74 xnbu_m_getcapab 75 }; 76 77 static void 78 xnbu_to_host(xnb_t *xnbp, mblk_t *mp) 79 { 80 xnbu_t *xnbup = xnbp->xnb_flavour_data; 81 boolean_t sched = B_FALSE; 82 83 ASSERT(mp != NULL); 84 85 mac_rx(xnbup->u_mh, NULL, mp); 86 87 mutex_enter(&xnbp->xnb_rx_lock); 88 89 /* 90 * If a transmit attempt failed because we ran out of ring 91 * space and there is now some space, re-enable the transmit 92 * path. 93 */ 94 if (xnbup->u_need_sched && 95 RING_HAS_UNCONSUMED_REQUESTS(&xnbp->xnb_rx_ring)) { 96 sched = B_TRUE; 97 xnbup->u_need_sched = B_FALSE; 98 } 99 100 mutex_exit(&xnbp->xnb_rx_lock); 101 102 if (sched) 103 mac_tx_update(xnbup->u_mh); 104 } 105 106 static mblk_t * 107 xnbu_cksum_from_peer(xnb_t *xnbp, mblk_t *mp, uint16_t flags) 108 { 109 /* 110 * Take a conservative approach - if the checksum is blank 111 * then we fill it in. 112 * 113 * If the consumer of the packet is IP then we might actually 114 * only need fill it in if the data is not validated, but how 115 * do we know who might end up with the packet? 116 */ 117 118 if ((flags & NETTXF_csum_blank) != 0) { 119 /* 120 * The checksum is blank. We must fill it in here. 121 */ 122 mp = xnb_process_cksum_flags(xnbp, mp, 0); 123 124 /* 125 * Because we calculated the checksum ourselves we 126 * know that it must be good, so we assert this. 127 */ 128 flags |= NETTXF_data_validated; 129 } 130 131 if ((flags & NETTXF_data_validated) != 0) { 132 /* 133 * The checksum is asserted valid. 134 */ 135 mac_hcksum_set(mp, 0, 0, 0, 0, HCK_FULLCKSUM_OK); 136 } 137 138 return (mp); 139 } 140 141 static uint16_t 142 xnbu_cksum_to_peer(xnb_t *xnbp, mblk_t *mp) 143 { 144 _NOTE(ARGUNUSED(xnbp)); 145 uint16_t r = 0; 146 uint32_t pflags; 147 148 mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &pflags); 149 150 /* 151 * If the protocol stack has requested checksum 152 * offload, inform the peer that we have not 153 * calculated the checksum. 154 */ 155 if ((pflags & HCK_FULLCKSUM) != 0) 156 r |= NETRXF_csum_blank; 157 158 return (r); 159 } 160 161 static boolean_t 162 xnbu_start_connect(xnb_t *xnbp) 163 { 164 xnbu_t *xnbup = xnbp->xnb_flavour_data; 165 166 mac_link_update(xnbup->u_mh, LINK_STATE_UP); 167 /* 168 * We are able to send packets now - bring them on. 169 */ 170 mac_tx_update(xnbup->u_mh); 171 172 return (B_TRUE); 173 } 174 175 static boolean_t 176 xnbu_peer_connected(xnb_t *xnbp) 177 { 178 _NOTE(ARGUNUSED(xnbp)); 179 180 return (B_TRUE); 181 } 182 183 static void 184 xnbu_peer_disconnected(xnb_t *xnbp) 185 { 186 xnbu_t *xnbup = xnbp->xnb_flavour_data; 187 188 mac_link_update(xnbup->u_mh, LINK_STATE_DOWN); 189 } 190 191 /*ARGSUSED*/ 192 static boolean_t 193 xnbu_hotplug_connected(xnb_t *xnbp) 194 { 195 return (B_TRUE); 196 } 197 198 static mblk_t * 199 xnbu_m_send(void *arg, mblk_t *mp) 200 { 201 xnb_t *xnbp = arg; 202 xnbu_t *xnbup = xnbp->xnb_flavour_data; 203 boolean_t sched = B_FALSE; 204 205 mp = xnb_copy_to_peer(arg, mp); 206 207 mutex_enter(&xnbp->xnb_rx_lock); 208 /* 209 * If we consumed all of the mblk_t's offered, perhaps we need 210 * to indicate that we can accept more. Otherwise we are full 211 * and need to wait for space. 212 */ 213 if (mp == NULL) { 214 sched = xnbup->u_need_sched; 215 xnbup->u_need_sched = B_FALSE; 216 } else { 217 xnbup->u_need_sched = B_TRUE; 218 } 219 mutex_exit(&xnbp->xnb_rx_lock); 220 221 /* 222 * If a previous transmit attempt failed because the ring 223 * was full, try again now. 224 */ 225 if (sched) 226 mac_tx_update(xnbup->u_mh); 227 228 return (mp); 229 } 230 231 /* 232 * xnbu_m_set_mac_addr() -- set the physical network address on the board 233 */ 234 /* ARGSUSED */ 235 static int 236 xnbu_m_set_mac_addr(void *arg, const uint8_t *macaddr) 237 { 238 xnb_t *xnbp = arg; 239 xnbu_t *xnbup = xnbp->xnb_flavour_data; 240 241 bcopy(macaddr, xnbp->xnb_mac_addr, ETHERADDRL); 242 mac_unicst_update(xnbup->u_mh, xnbp->xnb_mac_addr); 243 244 return (0); 245 } 246 247 /* 248 * xnbu_m_set_multicast() -- set (enable) or disable a multicast address 249 */ 250 /*ARGSUSED*/ 251 static int 252 xnbu_m_set_multicast(void *arg, boolean_t add, const uint8_t *mca) 253 { 254 /* 255 * We always accept all packets from the peer, so nothing to 256 * do for enable or disable. 257 */ 258 return (0); 259 } 260 261 262 /* 263 * xnbu_m_set_promiscuous() -- set or reset promiscuous mode on the board 264 */ 265 /* ARGSUSED */ 266 static int 267 xnbu_m_set_promiscuous(void *arg, boolean_t on) 268 { 269 /* 270 * We always accept all packets from the peer, so nothing to 271 * do for enable or disable. 272 */ 273 return (0); 274 } 275 276 /* 277 * xnbu_m_start() -- start the board receiving and enable interrupts. 278 */ 279 /*ARGSUSED*/ 280 static int 281 xnbu_m_start(void *arg) 282 { 283 return (0); 284 } 285 286 /* 287 * xnbu_m_stop() - disable hardware 288 */ 289 /*ARGSUSED*/ 290 static void 291 xnbu_m_stop(void *arg) 292 { 293 } 294 295 static int 296 xnbu_m_stat(void *arg, uint_t stat, uint64_t *val) 297 { 298 xnb_t *xnbp = arg; 299 300 mutex_enter(&xnbp->xnb_tx_lock); 301 mutex_enter(&xnbp->xnb_rx_lock); 302 303 #define map_stat(q, r) \ 304 case (MAC_STAT_##q): \ 305 *val = xnbp->xnb_stat_##r; \ 306 break 307 308 switch (stat) { 309 310 map_stat(IPACKETS, opackets); 311 map_stat(OPACKETS, ipackets); 312 map_stat(RBYTES, obytes); 313 map_stat(OBYTES, rbytes); 314 315 default: 316 mutex_exit(&xnbp->xnb_rx_lock); 317 mutex_exit(&xnbp->xnb_tx_lock); 318 319 return (ENOTSUP); 320 } 321 322 #undef map_stat 323 324 mutex_exit(&xnbp->xnb_rx_lock); 325 mutex_exit(&xnbp->xnb_tx_lock); 326 327 return (0); 328 } 329 330 static boolean_t 331 xnbu_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 332 { 333 _NOTE(ARGUNUSED(arg)); 334 335 switch (cap) { 336 case MAC_CAPAB_HCKSUM: { 337 uint32_t *capab = cap_data; 338 339 *capab = HCKSUM_INET_PARTIAL; 340 break; 341 } 342 default: 343 return (B_FALSE); 344 } 345 346 return (B_TRUE); 347 } 348 349 /* 350 * All packets are passed to the peer, so adding and removing 351 * multicast addresses is meaningless. 352 */ 353 static boolean_t 354 xnbu_mcast_add(xnb_t *xnbp, ether_addr_t *addr) 355 { 356 _NOTE(ARGUNUSED(xnbp, addr)); 357 358 return (B_TRUE); 359 } 360 361 static boolean_t 362 xnbu_mcast_del(xnb_t *xnbp, ether_addr_t *addr) 363 { 364 _NOTE(ARGUNUSED(xnbp, addr)); 365 366 return (B_TRUE); 367 } 368 369 static int 370 xnbu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 371 { 372 static xnb_flavour_t flavour = { 373 xnbu_to_host, xnbu_peer_connected, xnbu_peer_disconnected, 374 xnbu_hotplug_connected, xnbu_start_connect, 375 xnbu_cksum_from_peer, xnbu_cksum_to_peer, 376 xnbu_mcast_add, xnbu_mcast_del, 377 }; 378 xnbu_t *xnbup; 379 xnb_t *xnbp; 380 mac_register_t *mr; 381 int err; 382 383 switch (cmd) { 384 case DDI_ATTACH: 385 break; 386 case DDI_RESUME: 387 return (DDI_SUCCESS); 388 default: 389 return (DDI_FAILURE); 390 } 391 392 xnbup = kmem_zalloc(sizeof (*xnbup), KM_SLEEP); 393 394 if ((mr = mac_alloc(MAC_VERSION)) == NULL) { 395 kmem_free(xnbup, sizeof (*xnbup)); 396 return (DDI_FAILURE); 397 } 398 399 if (xnb_attach(dip, &flavour, xnbup) != DDI_SUCCESS) { 400 mac_free(mr); 401 kmem_free(xnbup, sizeof (*xnbup)); 402 return (DDI_FAILURE); 403 } 404 405 xnbp = ddi_get_driver_private(dip); 406 ASSERT(xnbp != NULL); 407 408 mr->m_dip = dip; 409 mr->m_driver = xnbp; 410 411 /* 412 * Initialize pointers to device specific functions which will be 413 * used by the generic layer. 414 */ 415 mr->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 416 mr->m_src_addr = xnbp->xnb_mac_addr; 417 mr->m_callbacks = &xnbu_callbacks; 418 mr->m_min_sdu = 0; 419 mr->m_max_sdu = XNBMAXPKT; 420 /* 421 * xnbu is a virtual device, and it is not associated with any 422 * physical device. Its margin size is determined by the maximum 423 * packet size it can handle, which is PAGESIZE. 424 */ 425 mr->m_margin = PAGESIZE - XNBMAXPKT - sizeof (struct ether_header); 426 427 (void) memset(xnbp->xnb_mac_addr, 0xff, ETHERADDRL); 428 xnbp->xnb_mac_addr[0] &= 0xfe; 429 xnbup->u_need_sched = B_FALSE; 430 431 /* 432 * Register ourselves with the GLDv3 interface. 433 */ 434 err = mac_register(mr, &xnbup->u_mh); 435 mac_free(mr); 436 if (err != 0) { 437 xnb_detach(dip); 438 kmem_free(xnbup, sizeof (*xnbup)); 439 return (DDI_FAILURE); 440 } 441 442 mac_link_update(xnbup->u_mh, LINK_STATE_DOWN); 443 444 return (DDI_SUCCESS); 445 } 446 447 /*ARGSUSED*/ 448 int 449 xnbu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 450 { 451 xnb_t *xnbp = ddi_get_driver_private(dip); 452 xnbu_t *xnbup = xnbp->xnb_flavour_data; 453 454 switch (cmd) { 455 case DDI_DETACH: 456 break; 457 case DDI_SUSPEND: 458 return (DDI_SUCCESS); 459 default: 460 return (DDI_FAILURE); 461 } 462 463 ASSERT(xnbp != NULL); 464 ASSERT(xnbup != NULL); 465 466 mutex_enter(&xnbp->xnb_tx_lock); 467 mutex_enter(&xnbp->xnb_rx_lock); 468 469 if (!xnbp->xnb_detachable || xnbp->xnb_connected || 470 (xnbp->xnb_tx_buf_count > 0)) { 471 mutex_exit(&xnbp->xnb_rx_lock); 472 mutex_exit(&xnbp->xnb_tx_lock); 473 474 return (DDI_FAILURE); 475 } 476 477 mutex_exit(&xnbp->xnb_rx_lock); 478 mutex_exit(&xnbp->xnb_tx_lock); 479 480 /* 481 * Attempt to unregister the mac. 482 */ 483 if ((xnbup->u_mh != NULL) && (mac_unregister(xnbup->u_mh) != 0)) 484 return (DDI_FAILURE); 485 kmem_free(xnbup, sizeof (*xnbup)); 486 487 xnb_detach(dip); 488 489 return (DDI_SUCCESS); 490 } 491 492 DDI_DEFINE_STREAM_OPS(ops, nulldev, nulldev, xnbu_attach, xnbu_detach, 493 nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported); 494 495 static struct modldrv modldrv = { 496 &mod_driverops, "xnbu driver", &ops 497 }; 498 499 static struct modlinkage modlinkage = { 500 MODREV_1, &modldrv, NULL 501 }; 502 503 int 504 _init(void) 505 { 506 int i; 507 508 mac_init_ops(&ops, "xnbu"); 509 510 i = mod_install(&modlinkage); 511 if (i != DDI_SUCCESS) 512 mac_fini_ops(&ops); 513 514 return (i); 515 } 516 517 int 518 _fini(void) 519 { 520 int i; 521 522 i = mod_remove(&modlinkage); 523 if (i == DDI_SUCCESS) 524 mac_fini_ops(&ops); 525 526 return (i); 527 } 528 529 int 530 _info(struct modinfo *modinfop) 531 { 532 return (mod_info(&modlinkage, modinfop)); 533 }