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 2009 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 xnbu_m_getcapab 74 }; 75 76 static void 77 xnbu_to_host(xnb_t *xnbp, mblk_t *mp) 78 { 79 xnbu_t *xnbup = xnbp->xnb_flavour_data; 80 boolean_t sched = B_FALSE; 81 82 ASSERT(mp != NULL); 83 84 mac_rx(xnbup->u_mh, NULL, mp); 85 86 mutex_enter(&xnbp->xnb_rx_lock); 87 88 /* 89 * If a transmit attempt failed because we ran out of ring 90 * space and there is now some space, re-enable the transmit 91 * path. 92 */ 93 if (xnbup->u_need_sched && 94 RING_HAS_UNCONSUMED_REQUESTS(&xnbp->xnb_rx_ring)) { 95 sched = B_TRUE; 96 xnbup->u_need_sched = B_FALSE; 97 } 98 99 mutex_exit(&xnbp->xnb_rx_lock); 100 101 if (sched) 102 mac_tx_update(xnbup->u_mh); 103 } 104 105 static mblk_t * 106 xnbu_cksum_from_peer(xnb_t *xnbp, mblk_t *mp, uint16_t flags) 107 { 108 /* 109 * Take a conservative approach - if the checksum is blank 110 * then we fill it in. 111 * 112 * If the consumer of the packet is IP then we might actually 113 * only need fill it in if the data is not validated, but how 114 * do we know who might end up with the packet? 115 */ 116 117 if ((flags & NETTXF_csum_blank) != 0) { 118 /* 119 * The checksum is blank. We must fill it in here. 120 */ 121 mp = xnb_process_cksum_flags(xnbp, mp, 0); 122 123 /* 124 * Because we calculated the checksum ourselves we 125 * know that it must be good, so we assert this. 126 */ 127 flags |= NETTXF_data_validated; 128 } 129 130 if ((flags & NETTXF_data_validated) != 0) { 131 /* 132 * The checksum is asserted valid. 133 * 134 * The hardware checksum offload specification says 135 * that we must provide the actual checksum as well as 136 * an assertion that it is valid, but the protocol 137 * stack doesn't actually use it so we don't bother. 138 * If it was necessary we could grovel in the packet 139 * to find it. 140 */ 141 (void) hcksum_assoc(mp, NULL, NULL, 0, 0, 0, 0, 142 HCK_FULLCKSUM | HCK_FULLCKSUM_OK, KM_NOSLEEP); 143 } 144 145 return (mp); 146 } 147 148 static uint16_t 149 xnbu_cksum_to_peer(xnb_t *xnbp, mblk_t *mp) 150 { 151 _NOTE(ARGUNUSED(xnbp)); 152 uint16_t r = 0; 153 uint32_t pflags; 154 155 hcksum_retrieve(mp, NULL, NULL, NULL, NULL, 156 NULL, NULL, &pflags); 157 158 /* 159 * If the protocol stack has requested checksum 160 * offload, inform the peer that we have not 161 * calculated the checksum. 162 */ 163 if ((pflags & HCK_FULLCKSUM) != 0) 164 r |= NETRXF_csum_blank; 165 166 return (r); 167 } 168 169 static boolean_t 170 xnbu_start_connect(xnb_t *xnbp) 171 { 172 xnbu_t *xnbup = xnbp->xnb_flavour_data; 173 174 mac_link_update(xnbup->u_mh, LINK_STATE_UP); 175 /* 176 * We are able to send packets now - bring them on. 177 */ 178 mac_tx_update(xnbup->u_mh); 179 180 return (B_TRUE); 181 } 182 183 static boolean_t 184 xnbu_peer_connected(xnb_t *xnbp) 185 { 186 _NOTE(ARGUNUSED(xnbp)); 187 188 return (B_TRUE); 189 } 190 191 static void 192 xnbu_peer_disconnected(xnb_t *xnbp) 193 { 194 xnbu_t *xnbup = xnbp->xnb_flavour_data; 195 196 mac_link_update(xnbup->u_mh, LINK_STATE_DOWN); 197 } 198 199 /*ARGSUSED*/ 200 static boolean_t 201 xnbu_hotplug_connected(xnb_t *xnbp) 202 { 203 return (B_TRUE); 204 } 205 206 static mblk_t * 207 xnbu_m_send(void *arg, mblk_t *mp) 208 { 209 xnb_t *xnbp = arg; 210 xnbu_t *xnbup = xnbp->xnb_flavour_data; 211 boolean_t sched = B_FALSE; 212 213 mp = xnb_copy_to_peer(arg, mp); 214 215 mutex_enter(&xnbp->xnb_rx_lock); 216 /* 217 * If we consumed all of the mblk_t's offered, perhaps we need 218 * to indicate that we can accept more. Otherwise we are full 219 * and need to wait for space. 220 */ 221 if (mp == NULL) { 222 sched = xnbup->u_need_sched; 223 xnbup->u_need_sched = B_FALSE; 224 } else { 225 xnbup->u_need_sched = B_TRUE; 226 } 227 mutex_exit(&xnbp->xnb_rx_lock); 228 229 /* 230 * If a previous transmit attempt failed because the ring 231 * was full, try again now. 232 */ 233 if (sched) 234 mac_tx_update(xnbup->u_mh); 235 236 return (mp); 237 } 238 239 /* 240 * xnbu_m_set_mac_addr() -- set the physical network address on the board 241 */ 242 /* ARGSUSED */ 243 static int 244 xnbu_m_set_mac_addr(void *arg, const uint8_t *macaddr) 245 { 246 xnb_t *xnbp = arg; 247 xnbu_t *xnbup = xnbp->xnb_flavour_data; 248 249 bcopy(macaddr, xnbp->xnb_mac_addr, ETHERADDRL); 250 mac_unicst_update(xnbup->u_mh, xnbp->xnb_mac_addr); 251 252 return (0); 253 } 254 255 /* 256 * xnbu_m_set_multicast() -- set (enable) or disable a multicast address 257 */ 258 /*ARGSUSED*/ 259 static int 260 xnbu_m_set_multicast(void *arg, boolean_t add, const uint8_t *mca) 261 { 262 /* 263 * We always accept all packets from the peer, so nothing to 264 * do for enable or disable. 265 */ 266 return (0); 267 } 268 269 270 /* 271 * xnbu_m_set_promiscuous() -- set or reset promiscuous mode on the board 272 */ 273 /* ARGSUSED */ 274 static int 275 xnbu_m_set_promiscuous(void *arg, boolean_t on) 276 { 277 /* 278 * We always accept all packets from the peer, so nothing to 279 * do for enable or disable. 280 */ 281 return (0); 282 } 283 284 /* 285 * xnbu_m_start() -- start the board receiving and enable interrupts. 286 */ 287 /*ARGSUSED*/ 288 static int 289 xnbu_m_start(void *arg) 290 { 291 return (0); 292 } 293 294 /* 295 * xnbu_m_stop() - disable hardware 296 */ 297 /*ARGSUSED*/ 298 static void 299 xnbu_m_stop(void *arg) 300 { 301 } 302 303 static int 304 xnbu_m_stat(void *arg, uint_t stat, uint64_t *val) 305 { 306 xnb_t *xnbp = arg; 307 308 mutex_enter(&xnbp->xnb_tx_lock); 309 mutex_enter(&xnbp->xnb_rx_lock); 310 311 #define map_stat(q, r) \ 312 case (MAC_STAT_##q): \ 313 *val = xnbp->xnb_stat_##r; \ 314 break 315 316 switch (stat) { 317 318 map_stat(IPACKETS, opackets); 319 map_stat(OPACKETS, ipackets); 320 map_stat(RBYTES, obytes); 321 map_stat(OBYTES, rbytes); 322 323 default: 324 mutex_exit(&xnbp->xnb_rx_lock); 325 mutex_exit(&xnbp->xnb_tx_lock); 326 327 return (ENOTSUP); 328 } 329 330 #undef map_stat 331 332 mutex_exit(&xnbp->xnb_rx_lock); 333 mutex_exit(&xnbp->xnb_tx_lock); 334 335 return (0); 336 } 337 338 static boolean_t 339 xnbu_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 340 { 341 _NOTE(ARGUNUSED(arg)); 342 343 switch (cap) { 344 case MAC_CAPAB_HCKSUM: { 345 uint32_t *capab = cap_data; 346 347 *capab = HCKSUM_INET_PARTIAL; 348 break; 349 } 350 default: 351 return (B_FALSE); 352 } 353 354 return (B_TRUE); 355 } 356 357 /* 358 * All packets are passed to the peer, so adding and removing 359 * multicast addresses is meaningless. 360 */ 361 static boolean_t 362 xnbu_mcast_add(xnb_t *xnbp, ether_addr_t *addr) 363 { 364 _NOTE(ARGUNUSED(xnbp, addr)); 365 366 return (B_TRUE); 367 } 368 369 static boolean_t 370 xnbu_mcast_del(xnb_t *xnbp, ether_addr_t *addr) 371 { 372 _NOTE(ARGUNUSED(xnbp, addr)); 373 374 return (B_TRUE); 375 } 376 377 static int 378 xnbu_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 379 { 380 static xnb_flavour_t flavour = { 381 xnbu_to_host, xnbu_peer_connected, xnbu_peer_disconnected, 382 xnbu_hotplug_connected, xnbu_start_connect, 383 xnbu_cksum_from_peer, xnbu_cksum_to_peer, 384 xnbu_mcast_add, xnbu_mcast_del, 385 }; 386 xnbu_t *xnbup; 387 xnb_t *xnbp; 388 mac_register_t *mr; 389 int err; 390 391 switch (cmd) { 392 case DDI_ATTACH: 393 break; 394 case DDI_RESUME: 395 return (DDI_SUCCESS); 396 default: 397 return (DDI_FAILURE); 398 } 399 400 xnbup = kmem_zalloc(sizeof (*xnbup), KM_SLEEP); 401 402 if ((mr = mac_alloc(MAC_VERSION)) == NULL) { 403 kmem_free(xnbup, sizeof (*xnbup)); 404 return (DDI_FAILURE); 405 } 406 407 if (xnb_attach(dip, &flavour, xnbup) != DDI_SUCCESS) { 408 mac_free(mr); 409 kmem_free(xnbup, sizeof (*xnbup)); 410 return (DDI_FAILURE); 411 } 412 413 xnbp = ddi_get_driver_private(dip); 414 ASSERT(xnbp != NULL); 415 416 mr->m_dip = dip; 417 mr->m_driver = xnbp; 418 419 /* 420 * Initialize pointers to device specific functions which will be 421 * used by the generic layer. 422 */ 423 mr->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 424 mr->m_src_addr = xnbp->xnb_mac_addr; 425 mr->m_callbacks = &xnbu_callbacks; 426 mr->m_min_sdu = 0; 427 mr->m_max_sdu = XNBMAXPKT; 428 /* 429 * xnbu is a virtual device, and it is not associated with any 430 * physical device. Its margin size is determined by the maximum 431 * packet size it can handle, which is PAGESIZE. 432 */ 433 mr->m_margin = PAGESIZE - XNBMAXPKT - sizeof (struct ether_header); 434 435 (void) memset(xnbp->xnb_mac_addr, 0xff, ETHERADDRL); 436 xnbp->xnb_mac_addr[0] &= 0xfe; 437 xnbup->u_need_sched = B_FALSE; 438 439 /* 440 * Register ourselves with the GLDv3 interface. 441 */ 442 err = mac_register(mr, &xnbup->u_mh); 443 mac_free(mr); 444 if (err != 0) { 445 xnb_detach(dip); 446 kmem_free(xnbup, sizeof (*xnbup)); 447 return (DDI_FAILURE); 448 } 449 450 mac_link_update(xnbup->u_mh, LINK_STATE_DOWN); 451 452 return (DDI_SUCCESS); 453 } 454 455 /*ARGSUSED*/ 456 int 457 xnbu_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 458 { 459 xnb_t *xnbp = ddi_get_driver_private(dip); 460 xnbu_t *xnbup = xnbp->xnb_flavour_data; 461 462 switch (cmd) { 463 case DDI_DETACH: 464 break; 465 case DDI_SUSPEND: 466 return (DDI_SUCCESS); 467 default: 468 return (DDI_FAILURE); 469 } 470 471 ASSERT(xnbp != NULL); 472 ASSERT(xnbup != NULL); 473 474 mutex_enter(&xnbp->xnb_tx_lock); 475 mutex_enter(&xnbp->xnb_rx_lock); 476 477 if (!xnbp->xnb_detachable || xnbp->xnb_connected || 478 (xnbp->xnb_tx_buf_count > 0)) { 479 mutex_exit(&xnbp->xnb_rx_lock); 480 mutex_exit(&xnbp->xnb_tx_lock); 481 482 return (DDI_FAILURE); 483 } 484 485 mutex_exit(&xnbp->xnb_rx_lock); 486 mutex_exit(&xnbp->xnb_tx_lock); 487 488 /* 489 * Attempt to unregister the mac. 490 */ 491 if ((xnbup->u_mh != NULL) && (mac_unregister(xnbup->u_mh) != 0)) 492 return (DDI_FAILURE); 493 kmem_free(xnbup, sizeof (*xnbup)); 494 495 xnb_detach(dip); 496 497 return (DDI_SUCCESS); 498 } 499 500 DDI_DEFINE_STREAM_OPS(ops, nulldev, nulldev, xnbu_attach, xnbu_detach, 501 nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported); 502 503 static struct modldrv modldrv = { 504 &mod_driverops, "xnbu driver", &ops 505 }; 506 507 static struct modlinkage modlinkage = { 508 MODREV_1, &modldrv, NULL 509 }; 510 511 int 512 _init(void) 513 { 514 int i; 515 516 mac_init_ops(&ops, "xnbu"); 517 518 i = mod_install(&modlinkage); 519 if (i != DDI_SUCCESS) 520 mac_fini_ops(&ops); 521 522 return (i); 523 } 524 525 int 526 _fini(void) 527 { 528 int i; 529 530 i = mod_remove(&modlinkage); 531 if (i == DDI_SUCCESS) 532 mac_fini_ops(&ops); 533 534 return (i); 535 } 536 537 int 538 _info(struct modinfo *modinfop) 539 { 540 return (mod_info(&modlinkage, modinfop)); 541 } 542