1*1ae08745Sheppo /* 2*1ae08745Sheppo * CDDL HEADER START 3*1ae08745Sheppo * 4*1ae08745Sheppo * The contents of this file are subject to the terms of the 5*1ae08745Sheppo * Common Development and Distribution License (the "License"). 6*1ae08745Sheppo * You may not use this file except in compliance with the License. 7*1ae08745Sheppo * 8*1ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 10*1ae08745Sheppo * See the License for the specific language governing permissions 11*1ae08745Sheppo * and limitations under the License. 12*1ae08745Sheppo * 13*1ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 14*1ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 16*1ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 17*1ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 18*1ae08745Sheppo * 19*1ae08745Sheppo * CDDL HEADER END 20*1ae08745Sheppo */ 21*1ae08745Sheppo 22*1ae08745Sheppo /* 23*1ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1ae08745Sheppo * Use is subject to license terms. 25*1ae08745Sheppo */ 26*1ae08745Sheppo 27*1ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 28*1ae08745Sheppo 29*1ae08745Sheppo #include <sys/types.h> 30*1ae08745Sheppo #include <sys/errno.h> 31*1ae08745Sheppo #include <sys/param.h> 32*1ae08745Sheppo #include <sys/stream.h> 33*1ae08745Sheppo #include <sys/kmem.h> 34*1ae08745Sheppo #include <sys/conf.h> 35*1ae08745Sheppo #include <sys/devops.h> 36*1ae08745Sheppo #include <sys/ksynch.h> 37*1ae08745Sheppo #include <sys/stat.h> 38*1ae08745Sheppo #include <sys/modctl.h> 39*1ae08745Sheppo #include <sys/debug.h> 40*1ae08745Sheppo #include <sys/ethernet.h> 41*1ae08745Sheppo #include <sys/dlpi.h> 42*1ae08745Sheppo #include <net/if.h> 43*1ae08745Sheppo #include <sys/mac.h> 44*1ae08745Sheppo #include <sys/ddi.h> 45*1ae08745Sheppo #include <sys/sunddi.h> 46*1ae08745Sheppo #include <sys/strsun.h> 47*1ae08745Sheppo #include <sys/note.h> 48*1ae08745Sheppo #include <sys/vnet.h> 49*1ae08745Sheppo 50*1ae08745Sheppo /* 51*1ae08745Sheppo * Function prototypes. 52*1ae08745Sheppo */ 53*1ae08745Sheppo 54*1ae08745Sheppo /* DDI entrypoints */ 55*1ae08745Sheppo static int vnetdevinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 56*1ae08745Sheppo static int vnetattach(dev_info_t *, ddi_attach_cmd_t); 57*1ae08745Sheppo static int vnetdetach(dev_info_t *, ddi_detach_cmd_t); 58*1ae08745Sheppo 59*1ae08745Sheppo /* MAC entrypoints */ 60*1ae08745Sheppo static uint64_t vnet_m_stat(void *arg, enum mac_stat stat); 61*1ae08745Sheppo static int vnet_m_start(void *); 62*1ae08745Sheppo static void vnet_m_stop(void *); 63*1ae08745Sheppo static int vnet_m_promisc(void *, boolean_t); 64*1ae08745Sheppo static int vnet_m_multicst(void *, boolean_t, const uint8_t *); 65*1ae08745Sheppo static int vnet_m_unicst(void *, const uint8_t *); 66*1ae08745Sheppo static void vnet_m_resources(void *); 67*1ae08745Sheppo static void vnet_m_ioctl(void *, queue_t *, mblk_t *); 68*1ae08745Sheppo mblk_t *vnet_m_tx(void *, mblk_t *); 69*1ae08745Sheppo 70*1ae08745Sheppo /* vnet internal functions */ 71*1ae08745Sheppo static int vnet_mac_register(vnet_t *); 72*1ae08745Sheppo static int vnet_read_mac_address(vnet_t *vnetp); 73*1ae08745Sheppo static void vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 74*1ae08745Sheppo static void vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp); 75*1ae08745Sheppo static vp_tl_t *vnet_get_vptl(vnet_t *vnetp, const char *devname); 76*1ae08745Sheppo static fdb_t *vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr); 77*1ae08745Sheppo 78*1ae08745Sheppo /* exported functions */ 79*1ae08745Sheppo void vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 80*1ae08745Sheppo void vnet_del_fdb(void *arg, uint8_t *macaddr); 81*1ae08745Sheppo void vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg); 82*1ae08745Sheppo void vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg); 83*1ae08745Sheppo void vnet_del_def_rte(void *arg); 84*1ae08745Sheppo 85*1ae08745Sheppo /* externs */ 86*1ae08745Sheppo extern int vgen_init(void *vnetp, dev_info_t *vnetdip, void *vnetmacp, 87*1ae08745Sheppo const uint8_t *macaddr, mac_t **vgenmacp); 88*1ae08745Sheppo extern void vgen_uninit(void *arg); 89*1ae08745Sheppo 90*1ae08745Sheppo /* 91*1ae08745Sheppo * Linked list of "vnet_t" structures - one per instance. 92*1ae08745Sheppo */ 93*1ae08745Sheppo static vnet_t *vnet_headp = NULL; 94*1ae08745Sheppo static krwlock_t vnet_rw; 95*1ae08745Sheppo 96*1ae08745Sheppo /* Tunables */ 97*1ae08745Sheppo uint32_t vnet_ntxds = VNET_NTXDS; /* power of 2 transmit descriptors */ 98*1ae08745Sheppo uint32_t vnet_reclaim_lowat = VNET_RECLAIM_LOWAT; /* tx recl low watermark */ 99*1ae08745Sheppo uint32_t vnet_reclaim_hiwat = VNET_RECLAIM_HIWAT; /* tx recl high watermark */ 100*1ae08745Sheppo uint32_t vnet_ldcwd_interval = VNET_LDCWD_INTERVAL; /* watchdog freq in msec */ 101*1ae08745Sheppo uint32_t vnet_ldcwd_txtimeout = VNET_LDCWD_TXTIMEOUT; /* tx timeout in msec */ 102*1ae08745Sheppo uint32_t vnet_ldc_qlen = VNET_LDC_QLEN; /* ldc qlen */ 103*1ae08745Sheppo uint32_t vnet_nfdb_hash = VNET_NFDB_HASH; /* size of fdb hash table */ 104*1ae08745Sheppo 105*1ae08745Sheppo /* 106*1ae08745Sheppo * Property names 107*1ae08745Sheppo */ 108*1ae08745Sheppo static char macaddr_propname[] = "local-mac-address"; 109*1ae08745Sheppo 110*1ae08745Sheppo static struct ether_addr etherbroadcastaddr = { 111*1ae08745Sheppo 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 112*1ae08745Sheppo }; 113*1ae08745Sheppo 114*1ae08745Sheppo /* 115*1ae08745Sheppo * MIB II broadcast/multicast packets 116*1ae08745Sheppo */ 117*1ae08745Sheppo #define IS_BROADCAST(ehp) \ 118*1ae08745Sheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) 119*1ae08745Sheppo #define IS_MULTICAST(ehp) \ 120*1ae08745Sheppo ((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1) 121*1ae08745Sheppo 122*1ae08745Sheppo /* 123*1ae08745Sheppo * This is the string displayed by modinfo(1m). 124*1ae08745Sheppo */ 125*1ae08745Sheppo static char vnet_ident[] = "vnet driver v1.0"; 126*1ae08745Sheppo extern struct mod_ops mod_driverops; 127*1ae08745Sheppo static struct cb_ops cb_vnetops = { 128*1ae08745Sheppo nulldev, /* cb_open */ 129*1ae08745Sheppo nulldev, /* cb_close */ 130*1ae08745Sheppo nodev, /* cb_strategy */ 131*1ae08745Sheppo nodev, /* cb_print */ 132*1ae08745Sheppo nodev, /* cb_dump */ 133*1ae08745Sheppo nodev, /* cb_read */ 134*1ae08745Sheppo nodev, /* cb_write */ 135*1ae08745Sheppo nodev, /* cb_ioctl */ 136*1ae08745Sheppo nodev, /* cb_devmap */ 137*1ae08745Sheppo nodev, /* cb_mmap */ 138*1ae08745Sheppo nodev, /* cb_segmap */ 139*1ae08745Sheppo nochpoll, /* cb_chpoll */ 140*1ae08745Sheppo ddi_prop_op, /* cb_prop_op */ 141*1ae08745Sheppo NULL, /* cb_stream */ 142*1ae08745Sheppo (int)(D_MP) /* cb_flag */ 143*1ae08745Sheppo }; 144*1ae08745Sheppo 145*1ae08745Sheppo static struct dev_ops vnetops = { 146*1ae08745Sheppo DEVO_REV, /* devo_rev */ 147*1ae08745Sheppo 0, /* devo_refcnt */ 148*1ae08745Sheppo NULL, /* devo_getinfo */ 149*1ae08745Sheppo nulldev, /* devo_identify */ 150*1ae08745Sheppo nulldev, /* devo_probe */ 151*1ae08745Sheppo vnetattach, /* devo_attach */ 152*1ae08745Sheppo vnetdetach, /* devo_detach */ 153*1ae08745Sheppo nodev, /* devo_reset */ 154*1ae08745Sheppo &cb_vnetops, /* devo_cb_ops */ 155*1ae08745Sheppo (struct bus_ops *)NULL /* devo_bus_ops */ 156*1ae08745Sheppo }; 157*1ae08745Sheppo 158*1ae08745Sheppo static struct modldrv modldrv = { 159*1ae08745Sheppo &mod_driverops, /* Type of module. This one is a driver */ 160*1ae08745Sheppo vnet_ident, /* ID string */ 161*1ae08745Sheppo &vnetops /* driver specific ops */ 162*1ae08745Sheppo }; 163*1ae08745Sheppo 164*1ae08745Sheppo static struct modlinkage modlinkage = { 165*1ae08745Sheppo MODREV_1, (void *)&modldrv, NULL 166*1ae08745Sheppo }; 167*1ae08745Sheppo 168*1ae08745Sheppo 169*1ae08745Sheppo /* 170*1ae08745Sheppo * Print debug messages - set to 0xf to enable all msgs 171*1ae08745Sheppo */ 172*1ae08745Sheppo int _vnet_dbglevel = 0x8; 173*1ae08745Sheppo 174*1ae08745Sheppo void 175*1ae08745Sheppo _vnetdebug_printf(void *arg, const char *fmt, ...) 176*1ae08745Sheppo { 177*1ae08745Sheppo char buf[512]; 178*1ae08745Sheppo va_list ap; 179*1ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 180*1ae08745Sheppo 181*1ae08745Sheppo va_start(ap, fmt); 182*1ae08745Sheppo (void) vsprintf(buf, fmt, ap); 183*1ae08745Sheppo va_end(ap); 184*1ae08745Sheppo 185*1ae08745Sheppo if (vnetp == NULL) 186*1ae08745Sheppo cmn_err(CE_CONT, "%s\n", buf); 187*1ae08745Sheppo else 188*1ae08745Sheppo cmn_err(CE_CONT, "vnet%d: %s\n", vnetp->instance, buf); 189*1ae08745Sheppo } 190*1ae08745Sheppo 191*1ae08745Sheppo #ifdef DEBUG 192*1ae08745Sheppo 193*1ae08745Sheppo /* 194*1ae08745Sheppo * XXX: any changes to the definitions below need corresponding changes in 195*1ae08745Sheppo * vnet_gen.c 196*1ae08745Sheppo */ 197*1ae08745Sheppo 198*1ae08745Sheppo /* 199*1ae08745Sheppo * debug levels: 200*1ae08745Sheppo * DBG_LEVEL1: Function entry/exit tracing 201*1ae08745Sheppo * DBG_LEVEL2: Info messages 202*1ae08745Sheppo * DBG_LEVEL3: Warning messages 203*1ae08745Sheppo * DBG_LEVEL4: Error messages 204*1ae08745Sheppo */ 205*1ae08745Sheppo 206*1ae08745Sheppo enum { DBG_LEVEL1 = 0x01, DBG_LEVEL2 = 0x02, DBG_LEVEL3 = 0x04, 207*1ae08745Sheppo DBG_LEVEL4 = 0x08 }; 208*1ae08745Sheppo 209*1ae08745Sheppo #define DBG1(_s) do { \ 210*1ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL1) != 0) { \ 211*1ae08745Sheppo _vnetdebug_printf _s; \ 212*1ae08745Sheppo } \ 213*1ae08745Sheppo _NOTE(CONSTCOND) } while (0) 214*1ae08745Sheppo 215*1ae08745Sheppo #define DBG2(_s) do { \ 216*1ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL2) != 0) { \ 217*1ae08745Sheppo _vnetdebug_printf _s; \ 218*1ae08745Sheppo } \ 219*1ae08745Sheppo _NOTE(CONSTCOND) } while (0) 220*1ae08745Sheppo 221*1ae08745Sheppo #define DWARN(_s) do { \ 222*1ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL3) != 0) { \ 223*1ae08745Sheppo _vnetdebug_printf _s; \ 224*1ae08745Sheppo } \ 225*1ae08745Sheppo _NOTE(CONSTCOND) } while (0) 226*1ae08745Sheppo 227*1ae08745Sheppo #define DERR(_s) do { \ 228*1ae08745Sheppo if ((_vnet_dbglevel & DBG_LEVEL4) != 0) { \ 229*1ae08745Sheppo _vnetdebug_printf _s; \ 230*1ae08745Sheppo } \ 231*1ae08745Sheppo _NOTE(CONSTCOND) } while (0) 232*1ae08745Sheppo 233*1ae08745Sheppo #else 234*1ae08745Sheppo 235*1ae08745Sheppo #define DBG1(_s) if (0) _vnetdebug_printf _s 236*1ae08745Sheppo #define DBG2(_s) if (0) _vnetdebug_printf _s 237*1ae08745Sheppo #define DWARN(_s) if (0) _vnetdebug_printf _s 238*1ae08745Sheppo #define DERR(_s) if (0) _vnetdebug_printf _s 239*1ae08745Sheppo 240*1ae08745Sheppo #endif 241*1ae08745Sheppo 242*1ae08745Sheppo /* _init(9E): initialize the loadable module */ 243*1ae08745Sheppo int 244*1ae08745Sheppo _init(void) 245*1ae08745Sheppo { 246*1ae08745Sheppo int status; 247*1ae08745Sheppo 248*1ae08745Sheppo DBG1((NULL, "_init: enter\n")); 249*1ae08745Sheppo 250*1ae08745Sheppo mac_init_ops(&vnetops, "vnet"); 251*1ae08745Sheppo status = mod_install(&modlinkage); 252*1ae08745Sheppo if (status != 0) { 253*1ae08745Sheppo mac_fini_ops(&vnetops); 254*1ae08745Sheppo } 255*1ae08745Sheppo 256*1ae08745Sheppo DBG1((NULL, "_init: exit\n")); 257*1ae08745Sheppo return (status); 258*1ae08745Sheppo } 259*1ae08745Sheppo 260*1ae08745Sheppo /* _fini(9E): prepare the module for unloading. */ 261*1ae08745Sheppo int 262*1ae08745Sheppo _fini(void) 263*1ae08745Sheppo { 264*1ae08745Sheppo int status; 265*1ae08745Sheppo 266*1ae08745Sheppo DBG1((NULL, "_fini: enter\n")); 267*1ae08745Sheppo 268*1ae08745Sheppo status = mod_remove(&modlinkage); 269*1ae08745Sheppo if (status != 0) 270*1ae08745Sheppo return (status); 271*1ae08745Sheppo mac_fini_ops(&vnetops); 272*1ae08745Sheppo 273*1ae08745Sheppo DBG1((NULL, "_fini: exit\n")); 274*1ae08745Sheppo return (status); 275*1ae08745Sheppo } 276*1ae08745Sheppo 277*1ae08745Sheppo /* _info(9E): return information about the loadable module */ 278*1ae08745Sheppo int 279*1ae08745Sheppo _info(struct modinfo *modinfop) 280*1ae08745Sheppo { 281*1ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 282*1ae08745Sheppo } 283*1ae08745Sheppo 284*1ae08745Sheppo /* 285*1ae08745Sheppo * attach(9E): attach a device to the system. 286*1ae08745Sheppo * called once for each instance of the device on the system. 287*1ae08745Sheppo */ 288*1ae08745Sheppo static int 289*1ae08745Sheppo vnetattach(dev_info_t *dip, ddi_attach_cmd_t cmd) 290*1ae08745Sheppo { 291*1ae08745Sheppo mac_t *macp; 292*1ae08745Sheppo vnet_t *vnetp; 293*1ae08745Sheppo vp_tl_t *vp_tlp; 294*1ae08745Sheppo int instance; 295*1ae08745Sheppo int status; 296*1ae08745Sheppo enum { AST_init = 0x0, AST_vnet_alloc = 0x1, 297*1ae08745Sheppo AST_mac_alloc = 0x2, AST_read_macaddr = 0x4, 298*1ae08745Sheppo AST_vgen_init = 0x8, AST_vptl_alloc = 0x10, 299*1ae08745Sheppo AST_fdbh_alloc = 0x20 } 300*1ae08745Sheppo attach_state; 301*1ae08745Sheppo mac_t *vgenmacp = NULL; 302*1ae08745Sheppo uint32_t nfdbh = 0; 303*1ae08745Sheppo 304*1ae08745Sheppo attach_state = AST_init; 305*1ae08745Sheppo 306*1ae08745Sheppo switch (cmd) { 307*1ae08745Sheppo case DDI_ATTACH: 308*1ae08745Sheppo break; 309*1ae08745Sheppo case DDI_RESUME: 310*1ae08745Sheppo case DDI_PM_RESUME: 311*1ae08745Sheppo default: 312*1ae08745Sheppo goto vnet_attach_fail; 313*1ae08745Sheppo } 314*1ae08745Sheppo 315*1ae08745Sheppo instance = ddi_get_instance(dip); 316*1ae08745Sheppo DBG1((NULL, "vnetattach: instance(%d) enter\n", instance)); 317*1ae08745Sheppo 318*1ae08745Sheppo /* allocate vnet_t and mac_t structures */ 319*1ae08745Sheppo vnetp = kmem_zalloc(sizeof (vnet_t), KM_SLEEP); 320*1ae08745Sheppo attach_state |= AST_vnet_alloc; 321*1ae08745Sheppo 322*1ae08745Sheppo macp = kmem_zalloc(sizeof (mac_t), KM_SLEEP); 323*1ae08745Sheppo attach_state |= AST_mac_alloc; 324*1ae08745Sheppo 325*1ae08745Sheppo /* setup links to vnet_t from both devinfo and mac_t */ 326*1ae08745Sheppo ddi_set_driver_private(dip, (caddr_t)vnetp); 327*1ae08745Sheppo macp->m_driver = vnetp; 328*1ae08745Sheppo vnetp->dip = dip; 329*1ae08745Sheppo vnetp->macp = macp; 330*1ae08745Sheppo vnetp->instance = instance; 331*1ae08745Sheppo 332*1ae08745Sheppo /* read the mac address */ 333*1ae08745Sheppo status = vnet_read_mac_address(vnetp); 334*1ae08745Sheppo if (status != DDI_SUCCESS) { 335*1ae08745Sheppo goto vnet_attach_fail; 336*1ae08745Sheppo } 337*1ae08745Sheppo attach_state |= AST_read_macaddr; 338*1ae08745Sheppo 339*1ae08745Sheppo /* 340*1ae08745Sheppo * Initialize the generic vnet proxy transport. This is the first 341*1ae08745Sheppo * and default transport used by vnet. The generic transport 342*1ae08745Sheppo * is provided by using sun4v LDC (logical domain channel). On success, 343*1ae08745Sheppo * vgen_init() provides a pointer to mac_t of generic transport. 344*1ae08745Sheppo * Currently, this generic layer provides network connectivity to other 345*1ae08745Sheppo * vnets within ldoms and also to remote hosts oustide ldoms through 346*1ae08745Sheppo * the virtual switch (vsw) device on domain0. In the future, when 347*1ae08745Sheppo * physical adapters that are able to share their resources (such as 348*1ae08745Sheppo * dma channels) with guest domains become available, the vnet device 349*1ae08745Sheppo * will use hardware specific driver to communicate directly over the 350*1ae08745Sheppo * physical device to reach remote hosts without going through vswitch. 351*1ae08745Sheppo */ 352*1ae08745Sheppo status = vgen_init(vnetp, vnetp->dip, vnetp->macp, 353*1ae08745Sheppo (uint8_t *)vnetp->curr_macaddr, &vgenmacp); 354*1ae08745Sheppo if (status != DDI_SUCCESS) { 355*1ae08745Sheppo DERR((vnetp, "vgen_init() failed\n")); 356*1ae08745Sheppo goto vnet_attach_fail; 357*1ae08745Sheppo } 358*1ae08745Sheppo attach_state |= AST_vgen_init; 359*1ae08745Sheppo 360*1ae08745Sheppo vp_tlp = kmem_zalloc(sizeof (vp_tl_t), KM_SLEEP); 361*1ae08745Sheppo vp_tlp->macp = vgenmacp; 362*1ae08745Sheppo (void) snprintf(vp_tlp->name, MAXNAMELEN, "%s%u", "vgen", instance); 363*1ae08745Sheppo (void) strcpy(vnetp->vgen_name, vp_tlp->name); 364*1ae08745Sheppo 365*1ae08745Sheppo /* add generic transport to the list of vnet proxy transports */ 366*1ae08745Sheppo vnet_add_vptl(vnetp, vp_tlp); 367*1ae08745Sheppo attach_state |= AST_vptl_alloc; 368*1ae08745Sheppo 369*1ae08745Sheppo nfdbh = vnet_nfdb_hash; 370*1ae08745Sheppo if ((nfdbh < VNET_NFDB_HASH) || (nfdbh > VNET_NFDB_HASH_MAX)) { 371*1ae08745Sheppo vnetp->nfdb_hash = VNET_NFDB_HASH; 372*1ae08745Sheppo } 373*1ae08745Sheppo else 374*1ae08745Sheppo vnetp->nfdb_hash = nfdbh; 375*1ae08745Sheppo 376*1ae08745Sheppo /* allocate fdb hash table, with an extra slot for default route */ 377*1ae08745Sheppo vnetp->fdbhp = kmem_zalloc(sizeof (fdb_fanout_t) * 378*1ae08745Sheppo (vnetp->nfdb_hash + 1), KM_SLEEP); 379*1ae08745Sheppo attach_state |= AST_fdbh_alloc; 380*1ae08745Sheppo 381*1ae08745Sheppo /* register with MAC layer */ 382*1ae08745Sheppo status = vnet_mac_register(vnetp); 383*1ae08745Sheppo if (status != DDI_SUCCESS) { 384*1ae08745Sheppo goto vnet_attach_fail; 385*1ae08745Sheppo } 386*1ae08745Sheppo 387*1ae08745Sheppo /* add to the list of vnet devices */ 388*1ae08745Sheppo WRITE_ENTER(&vnet_rw); 389*1ae08745Sheppo vnetp->nextp = vnet_headp; 390*1ae08745Sheppo vnet_headp = vnetp; 391*1ae08745Sheppo RW_EXIT(&vnet_rw); 392*1ae08745Sheppo 393*1ae08745Sheppo DBG1((NULL, "vnetattach: instance(%d) exit\n", instance)); 394*1ae08745Sheppo return (DDI_SUCCESS); 395*1ae08745Sheppo 396*1ae08745Sheppo vnet_attach_fail: 397*1ae08745Sheppo if (attach_state & AST_fdbh_alloc) { 398*1ae08745Sheppo kmem_free(vnetp->fdbhp, 399*1ae08745Sheppo sizeof (fdb_fanout_t) * (vnetp->nfdb_hash + 1)); 400*1ae08745Sheppo } 401*1ae08745Sheppo if (attach_state & AST_vptl_alloc) { 402*1ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 403*1ae08745Sheppo vnet_del_vptl(vnetp, vp_tlp); 404*1ae08745Sheppo RW_EXIT(&vnetp->trwlock); 405*1ae08745Sheppo } 406*1ae08745Sheppo if (attach_state & AST_vgen_init) { 407*1ae08745Sheppo vgen_uninit(vgenmacp->m_driver); 408*1ae08745Sheppo } 409*1ae08745Sheppo if (attach_state & AST_mac_alloc) { 410*1ae08745Sheppo KMEM_FREE(macp); 411*1ae08745Sheppo } 412*1ae08745Sheppo if (attach_state & AST_vnet_alloc) { 413*1ae08745Sheppo KMEM_FREE(vnetp); 414*1ae08745Sheppo } 415*1ae08745Sheppo return (DDI_FAILURE); 416*1ae08745Sheppo } 417*1ae08745Sheppo 418*1ae08745Sheppo /* 419*1ae08745Sheppo * detach(9E): detach a device from the system. 420*1ae08745Sheppo */ 421*1ae08745Sheppo static int 422*1ae08745Sheppo vnetdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) 423*1ae08745Sheppo { 424*1ae08745Sheppo vnet_t *vnetp; 425*1ae08745Sheppo vnet_t **vnetpp; 426*1ae08745Sheppo vp_tl_t *vp_tlp; 427*1ae08745Sheppo int instance; 428*1ae08745Sheppo 429*1ae08745Sheppo instance = ddi_get_instance(dip); 430*1ae08745Sheppo DBG1((NULL, "vnetdetach: instance(%d) enter\n", instance)); 431*1ae08745Sheppo 432*1ae08745Sheppo vnetp = ddi_get_driver_private(dip); 433*1ae08745Sheppo if (vnetp == NULL) { 434*1ae08745Sheppo goto vnet_detach_fail; 435*1ae08745Sheppo } 436*1ae08745Sheppo 437*1ae08745Sheppo switch (cmd) { 438*1ae08745Sheppo case DDI_DETACH: 439*1ae08745Sheppo break; 440*1ae08745Sheppo case DDI_SUSPEND: 441*1ae08745Sheppo case DDI_PM_SUSPEND: 442*1ae08745Sheppo default: 443*1ae08745Sheppo goto vnet_detach_fail; 444*1ae08745Sheppo } 445*1ae08745Sheppo 446*1ae08745Sheppo /* 447*1ae08745Sheppo * Unregister from the MAC subsystem. This can fail, in 448*1ae08745Sheppo * particular if there are DLPI style-2 streams still open - 449*1ae08745Sheppo * in which case we just return failure. 450*1ae08745Sheppo */ 451*1ae08745Sheppo if (mac_unregister(vnetp->macp) != 0) 452*1ae08745Sheppo goto vnet_detach_fail; 453*1ae08745Sheppo 454*1ae08745Sheppo /* unlink from instance(vnet_t) list */ 455*1ae08745Sheppo WRITE_ENTER(&vnet_rw); 456*1ae08745Sheppo for (vnetpp = &vnet_headp; *vnetpp; vnetpp = &(*vnetpp)->nextp) { 457*1ae08745Sheppo if (*vnetpp == vnetp) { 458*1ae08745Sheppo *vnetpp = vnetp->nextp; 459*1ae08745Sheppo break; 460*1ae08745Sheppo } 461*1ae08745Sheppo } 462*1ae08745Sheppo RW_EXIT(&vnet_rw); 463*1ae08745Sheppo 464*1ae08745Sheppo /* uninit and free vnet proxy transports */ 465*1ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 466*1ae08745Sheppo while ((vp_tlp = vnetp->tlp) != NULL) { 467*1ae08745Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 468*1ae08745Sheppo /* uninitialize generic transport */ 469*1ae08745Sheppo vgen_uninit(vp_tlp->macp->m_driver); 470*1ae08745Sheppo } 471*1ae08745Sheppo vnet_del_vptl(vnetp, vp_tlp); 472*1ae08745Sheppo } 473*1ae08745Sheppo RW_EXIT(&vnetp->trwlock); 474*1ae08745Sheppo 475*1ae08745Sheppo KMEM_FREE(vnetp->macp); 476*1ae08745Sheppo KMEM_FREE(vnetp); 477*1ae08745Sheppo 478*1ae08745Sheppo return (DDI_SUCCESS); 479*1ae08745Sheppo 480*1ae08745Sheppo vnet_detach_fail: 481*1ae08745Sheppo return (DDI_FAILURE); 482*1ae08745Sheppo } 483*1ae08745Sheppo 484*1ae08745Sheppo /* enable the device for transmit/receive */ 485*1ae08745Sheppo static int 486*1ae08745Sheppo vnet_m_start(void *arg) 487*1ae08745Sheppo { 488*1ae08745Sheppo vnet_t *vnetp = arg; 489*1ae08745Sheppo vp_tl_t *vp_tlp; 490*1ae08745Sheppo mac_t *vp_macp; 491*1ae08745Sheppo 492*1ae08745Sheppo DBG1((vnetp, "vnet_m_start: enter\n")); 493*1ae08745Sheppo 494*1ae08745Sheppo /* 495*1ae08745Sheppo * XXX 496*1ae08745Sheppo * Currently, we only have generic transport. m_start() invokes 497*1ae08745Sheppo * vgen_start() which enables ports/channels in vgen and 498*1ae08745Sheppo * initiates handshake with peer vnets and vsw. In the future when we 499*1ae08745Sheppo * have support for hardware specific transports, this information 500*1ae08745Sheppo * needs to be propagted back to vnet from vgen and we need to revisit 501*1ae08745Sheppo * this code (see comments in vnet_attach()). 502*1ae08745Sheppo * 503*1ae08745Sheppo */ 504*1ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 505*1ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 506*1ae08745Sheppo vp_macp = vp_tlp->macp; 507*1ae08745Sheppo vp_macp->m_start(vp_macp->m_driver); 508*1ae08745Sheppo } 509*1ae08745Sheppo RW_EXIT(&vnetp->trwlock); 510*1ae08745Sheppo 511*1ae08745Sheppo DBG1((vnetp, "vnet_m_start: exit\n")); 512*1ae08745Sheppo return (VNET_SUCCESS); 513*1ae08745Sheppo 514*1ae08745Sheppo } 515*1ae08745Sheppo 516*1ae08745Sheppo /* stop transmit/receive for the device */ 517*1ae08745Sheppo static void 518*1ae08745Sheppo vnet_m_stop(void *arg) 519*1ae08745Sheppo { 520*1ae08745Sheppo vnet_t *vnetp = arg; 521*1ae08745Sheppo vp_tl_t *vp_tlp; 522*1ae08745Sheppo mac_t *vp_macp; 523*1ae08745Sheppo 524*1ae08745Sheppo DBG1((vnetp, "vnet_m_stop: enter\n")); 525*1ae08745Sheppo 526*1ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 527*1ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 528*1ae08745Sheppo vp_macp = vp_tlp->macp; 529*1ae08745Sheppo vp_macp->m_stop(vp_macp->m_driver); 530*1ae08745Sheppo } 531*1ae08745Sheppo RW_EXIT(&vnetp->trwlock); 532*1ae08745Sheppo 533*1ae08745Sheppo DBG1((vnetp, "vnet_m_stop: exit\n")); 534*1ae08745Sheppo } 535*1ae08745Sheppo 536*1ae08745Sheppo /* set the unicast mac address of the device */ 537*1ae08745Sheppo static int 538*1ae08745Sheppo vnet_m_unicst(void *arg, const uint8_t *macaddr) 539*1ae08745Sheppo { 540*1ae08745Sheppo _NOTE(ARGUNUSED(macaddr)) 541*1ae08745Sheppo 542*1ae08745Sheppo vnet_t *vnetp = arg; 543*1ae08745Sheppo 544*1ae08745Sheppo DBG1((vnetp, "vnet_m_unicst: enter\n")); 545*1ae08745Sheppo /* 546*1ae08745Sheppo * XXX: setting mac address dynamically is not supported. 547*1ae08745Sheppo */ 548*1ae08745Sheppo #if 0 549*1ae08745Sheppo bcopy(macaddr, vnetp->curr_macaddr, ETHERADDRL); 550*1ae08745Sheppo #endif 551*1ae08745Sheppo DBG1((vnetp, "vnet_m_unicst: exit\n")); 552*1ae08745Sheppo 553*1ae08745Sheppo return (VNET_SUCCESS); 554*1ae08745Sheppo } 555*1ae08745Sheppo 556*1ae08745Sheppo /* enable/disable a multicast address */ 557*1ae08745Sheppo static int 558*1ae08745Sheppo vnet_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 559*1ae08745Sheppo { 560*1ae08745Sheppo _NOTE(ARGUNUSED(add, mca)) 561*1ae08745Sheppo 562*1ae08745Sheppo vnet_t *vnetp = arg; 563*1ae08745Sheppo vp_tl_t *vp_tlp; 564*1ae08745Sheppo mac_t *vp_macp; 565*1ae08745Sheppo int rv = VNET_SUCCESS; 566*1ae08745Sheppo 567*1ae08745Sheppo DBG1((vnetp, "vnet_m_multicst: enter\n")); 568*1ae08745Sheppo READ_ENTER(&vnetp->trwlock); 569*1ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 570*1ae08745Sheppo if (strcmp(vnetp->vgen_name, vp_tlp->name) == 0) { 571*1ae08745Sheppo vp_macp = vp_tlp->macp; 572*1ae08745Sheppo rv = vp_macp->m_multicst(vp_macp->m_driver, add, mca); 573*1ae08745Sheppo break; 574*1ae08745Sheppo } 575*1ae08745Sheppo } 576*1ae08745Sheppo RW_EXIT(&vnetp->trwlock); 577*1ae08745Sheppo DBG1((vnetp, "vnet_m_multicst: exit\n")); 578*1ae08745Sheppo return (rv); 579*1ae08745Sheppo } 580*1ae08745Sheppo 581*1ae08745Sheppo /* set or clear promiscuous mode on the device */ 582*1ae08745Sheppo static int 583*1ae08745Sheppo vnet_m_promisc(void *arg, boolean_t on) 584*1ae08745Sheppo { 585*1ae08745Sheppo _NOTE(ARGUNUSED(on)) 586*1ae08745Sheppo 587*1ae08745Sheppo vnet_t *vnetp = arg; 588*1ae08745Sheppo DBG1((vnetp, "vnet_m_promisc: enter\n")); 589*1ae08745Sheppo /* 590*1ae08745Sheppo * XXX: setting promiscuous mode is not supported, just return success. 591*1ae08745Sheppo */ 592*1ae08745Sheppo DBG1((vnetp, "vnet_m_promisc: exit\n")); 593*1ae08745Sheppo return (VNET_SUCCESS); 594*1ae08745Sheppo } 595*1ae08745Sheppo 596*1ae08745Sheppo /* 597*1ae08745Sheppo * Transmit a chain of packets. This function provides switching functionality 598*1ae08745Sheppo * based on the destination mac address to reach other guests (within ldoms) or 599*1ae08745Sheppo * external hosts. 600*1ae08745Sheppo */ 601*1ae08745Sheppo mblk_t * 602*1ae08745Sheppo vnet_m_tx(void *arg, mblk_t *mp) 603*1ae08745Sheppo { 604*1ae08745Sheppo vnet_t *vnetp; 605*1ae08745Sheppo mblk_t *next; 606*1ae08745Sheppo uint32_t fdbhash; 607*1ae08745Sheppo fdb_t *fdbp; 608*1ae08745Sheppo fdb_fanout_t *fdbhp; 609*1ae08745Sheppo struct ether_header *ehp; 610*1ae08745Sheppo uint8_t *macaddr; 611*1ae08745Sheppo mblk_t *resid_mp; 612*1ae08745Sheppo 613*1ae08745Sheppo vnetp = (vnet_t *)arg; 614*1ae08745Sheppo DBG1((vnetp, "vnet_m_tx: enter\n")); 615*1ae08745Sheppo ASSERT(mp != NULL); 616*1ae08745Sheppo 617*1ae08745Sheppo while (mp != NULL) { 618*1ae08745Sheppo next = mp->b_next; 619*1ae08745Sheppo mp->b_next = NULL; 620*1ae08745Sheppo 621*1ae08745Sheppo /* get the destination mac address in the eth header */ 622*1ae08745Sheppo ehp = (struct ether_header *)mp->b_rptr; 623*1ae08745Sheppo macaddr = (uint8_t *)&ehp->ether_dhost; 624*1ae08745Sheppo 625*1ae08745Sheppo /* Calculate hash value and fdb fanout */ 626*1ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 627*1ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 628*1ae08745Sheppo 629*1ae08745Sheppo READ_ENTER(&fdbhp->rwlock); 630*1ae08745Sheppo fdbp = vnet_lookup_fdb(fdbhp, macaddr); 631*1ae08745Sheppo if (fdbp) { 632*1ae08745Sheppo /* 633*1ae08745Sheppo * If the destination is in FDB, the destination is 634*1ae08745Sheppo * a vnet device within ldoms and directly reachable, 635*1ae08745Sheppo * invoke the tx function in the fdb entry. 636*1ae08745Sheppo */ 637*1ae08745Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 638*1ae08745Sheppo if (resid_mp != NULL) { 639*1ae08745Sheppo /* m_tx failed */ 640*1ae08745Sheppo mp->b_next = next; 641*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 642*1ae08745Sheppo break; 643*1ae08745Sheppo } 644*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 645*1ae08745Sheppo } else { 646*1ae08745Sheppo /* destination is not in FDB */ 647*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 648*1ae08745Sheppo /* 649*1ae08745Sheppo * If the destination is broadcast/multicast 650*1ae08745Sheppo * or an unknown unicast address, forward the 651*1ae08745Sheppo * packet to vsw, using the last slot in fdb which is 652*1ae08745Sheppo * reserved for default route. 653*1ae08745Sheppo */ 654*1ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 655*1ae08745Sheppo READ_ENTER(&fdbhp->rwlock); 656*1ae08745Sheppo fdbp = fdbhp->headp; 657*1ae08745Sheppo if (fdbp) { 658*1ae08745Sheppo resid_mp = fdbp->m_tx(fdbp->txarg, mp); 659*1ae08745Sheppo if (resid_mp != NULL) { 660*1ae08745Sheppo /* m_tx failed */ 661*1ae08745Sheppo mp->b_next = next; 662*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 663*1ae08745Sheppo break; 664*1ae08745Sheppo } 665*1ae08745Sheppo } else { 666*1ae08745Sheppo /* drop the packet */ 667*1ae08745Sheppo freemsg(mp); 668*1ae08745Sheppo } 669*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 670*1ae08745Sheppo } 671*1ae08745Sheppo 672*1ae08745Sheppo mp = next; 673*1ae08745Sheppo } 674*1ae08745Sheppo 675*1ae08745Sheppo DBG1((vnetp, "vnet_m_tx: exit\n")); 676*1ae08745Sheppo return (mp); 677*1ae08745Sheppo } 678*1ae08745Sheppo 679*1ae08745Sheppo /* register resources with mac layer */ 680*1ae08745Sheppo static void 681*1ae08745Sheppo vnet_m_resources(void *arg) 682*1ae08745Sheppo { 683*1ae08745Sheppo vnet_t *vnetp = arg; 684*1ae08745Sheppo vp_tl_t *vp_tlp; 685*1ae08745Sheppo mac_t *vp_macp; 686*1ae08745Sheppo 687*1ae08745Sheppo DBG1((vnetp, "vnet_m_resources: enter\n")); 688*1ae08745Sheppo 689*1ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 690*1ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 691*1ae08745Sheppo vp_macp = vp_tlp->macp; 692*1ae08745Sheppo vp_macp->m_resources(vp_macp->m_driver); 693*1ae08745Sheppo } 694*1ae08745Sheppo RW_EXIT(&vnetp->trwlock); 695*1ae08745Sheppo 696*1ae08745Sheppo DBG1((vnetp, "vnet_m_resources: exit\n")); 697*1ae08745Sheppo } 698*1ae08745Sheppo 699*1ae08745Sheppo /* 700*1ae08745Sheppo * vnet specific ioctls 701*1ae08745Sheppo */ 702*1ae08745Sheppo static void 703*1ae08745Sheppo vnet_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 704*1ae08745Sheppo { 705*1ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 706*1ae08745Sheppo struct iocblk *iocp; 707*1ae08745Sheppo int cmd; 708*1ae08745Sheppo 709*1ae08745Sheppo DBG1((vnetp, "vnet_m_ioctl: enter\n")); 710*1ae08745Sheppo 711*1ae08745Sheppo iocp = (struct iocblk *)mp->b_rptr; 712*1ae08745Sheppo iocp->ioc_error = 0; 713*1ae08745Sheppo cmd = iocp->ioc_cmd; 714*1ae08745Sheppo switch (cmd) { 715*1ae08745Sheppo default: 716*1ae08745Sheppo miocnak(wq, mp, 0, EINVAL); 717*1ae08745Sheppo break; 718*1ae08745Sheppo } 719*1ae08745Sheppo DBG1((vnetp, "vnet_m_ioctl: exit\n")); 720*1ae08745Sheppo } 721*1ae08745Sheppo 722*1ae08745Sheppo /* get statistics from the device */ 723*1ae08745Sheppo uint64_t 724*1ae08745Sheppo vnet_m_stat(void *arg, enum mac_stat stat) 725*1ae08745Sheppo { 726*1ae08745Sheppo vnet_t *vnetp = arg; 727*1ae08745Sheppo vp_tl_t *vp_tlp; 728*1ae08745Sheppo mac_t *vp_macp; 729*1ae08745Sheppo uint64_t val = 0; 730*1ae08745Sheppo 731*1ae08745Sheppo DBG1((vnetp, "vnet_m_stat: enter\n")); 732*1ae08745Sheppo 733*1ae08745Sheppo /* 734*1ae08745Sheppo * get the specified statistic from each transport 735*1ae08745Sheppo * and return the aggregate val 736*1ae08745Sheppo */ 737*1ae08745Sheppo READ_ENTER(&vnetp->trwlock); 738*1ae08745Sheppo for (vp_tlp = vnetp->tlp; vp_tlp != NULL; vp_tlp = vp_tlp->nextp) { 739*1ae08745Sheppo vp_macp = vp_tlp->macp; 740*1ae08745Sheppo val += vp_macp->m_stat(vp_macp->m_driver, stat); 741*1ae08745Sheppo } 742*1ae08745Sheppo RW_EXIT(&vnetp->trwlock); 743*1ae08745Sheppo 744*1ae08745Sheppo DBG1((vnetp, "vnet_m_stat: exit\n")); 745*1ae08745Sheppo return (val); 746*1ae08745Sheppo } 747*1ae08745Sheppo 748*1ae08745Sheppo /* wrapper function for mac_register() */ 749*1ae08745Sheppo static int 750*1ae08745Sheppo vnet_mac_register(vnet_t *vnetp) 751*1ae08745Sheppo { 752*1ae08745Sheppo mac_info_t *mip; 753*1ae08745Sheppo mac_t *macp; 754*1ae08745Sheppo 755*1ae08745Sheppo macp = vnetp->macp; 756*1ae08745Sheppo 757*1ae08745Sheppo mip = &(macp->m_info); 758*1ae08745Sheppo mip->mi_media = DL_ETHER; 759*1ae08745Sheppo mip->mi_sdu_min = 0; 760*1ae08745Sheppo mip->mi_sdu_max = ETHERMTU; 761*1ae08745Sheppo mip->mi_cksum = 0; 762*1ae08745Sheppo mip->mi_poll = 0; /* DL_CAPAB_POLL ? */ 763*1ae08745Sheppo mip->mi_addr_length = ETHERADDRL; 764*1ae08745Sheppo bcopy(ðerbroadcastaddr, mip->mi_brdcst_addr, ETHERADDRL); 765*1ae08745Sheppo bcopy(vnetp->curr_macaddr, mip->mi_unicst_addr, ETHERADDRL); 766*1ae08745Sheppo 767*1ae08745Sheppo MAC_STAT_MIB(mip->mi_stat); 768*1ae08745Sheppo mip->mi_stat[MAC_STAT_UNKNOWNS] = B_FALSE; 769*1ae08745Sheppo MAC_STAT_ETHER(mip->mi_stat); 770*1ae08745Sheppo mip->mi_stat[MAC_STAT_SQE_ERRORS] = B_FALSE; 771*1ae08745Sheppo mip->mi_stat[MAC_STAT_MACRCV_ERRORS] = B_FALSE; 772*1ae08745Sheppo 773*1ae08745Sheppo macp->m_stat = vnet_m_stat; 774*1ae08745Sheppo macp->m_start = vnet_m_start; 775*1ae08745Sheppo macp->m_stop = vnet_m_stop; 776*1ae08745Sheppo macp->m_promisc = vnet_m_promisc; 777*1ae08745Sheppo macp->m_multicst = vnet_m_multicst; 778*1ae08745Sheppo macp->m_unicst = vnet_m_unicst; 779*1ae08745Sheppo macp->m_resources = vnet_m_resources; 780*1ae08745Sheppo macp->m_ioctl = vnet_m_ioctl; 781*1ae08745Sheppo macp->m_tx = vnet_m_tx; 782*1ae08745Sheppo 783*1ae08745Sheppo macp->m_dip = vnetp->dip; 784*1ae08745Sheppo macp->m_ident = MAC_IDENT; 785*1ae08745Sheppo 786*1ae08745Sheppo /* 787*1ae08745Sheppo * Finally, we're ready to register ourselves with the MAC layer 788*1ae08745Sheppo * interface; if this succeeds, we're all ready to start() 789*1ae08745Sheppo */ 790*1ae08745Sheppo if (mac_register(macp) != 0) { 791*1ae08745Sheppo KMEM_FREE(macp); 792*1ae08745Sheppo return (DDI_FAILURE); 793*1ae08745Sheppo } 794*1ae08745Sheppo 795*1ae08745Sheppo return (DDI_SUCCESS); 796*1ae08745Sheppo } 797*1ae08745Sheppo 798*1ae08745Sheppo /* add vp_tl to the list */ 799*1ae08745Sheppo static void 800*1ae08745Sheppo vnet_add_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 801*1ae08745Sheppo { 802*1ae08745Sheppo vp_tl_t *ttlp; 803*1ae08745Sheppo 804*1ae08745Sheppo WRITE_ENTER(&vnetp->trwlock); 805*1ae08745Sheppo if (vnetp->tlp == NULL) { 806*1ae08745Sheppo vnetp->tlp = vp_tlp; 807*1ae08745Sheppo } else { 808*1ae08745Sheppo ttlp = vnetp->tlp; 809*1ae08745Sheppo while (ttlp->nextp) 810*1ae08745Sheppo ttlp = ttlp->nextp; 811*1ae08745Sheppo ttlp->nextp = vp_tlp; 812*1ae08745Sheppo } 813*1ae08745Sheppo RW_EXIT(&vnetp->trwlock); 814*1ae08745Sheppo } 815*1ae08745Sheppo 816*1ae08745Sheppo /* remove vp_tl from the list */ 817*1ae08745Sheppo static void 818*1ae08745Sheppo vnet_del_vptl(vnet_t *vnetp, vp_tl_t *vp_tlp) 819*1ae08745Sheppo { 820*1ae08745Sheppo vp_tl_t *ttlp, **pretlp; 821*1ae08745Sheppo boolean_t found = B_FALSE; 822*1ae08745Sheppo 823*1ae08745Sheppo pretlp = &vnetp->tlp; 824*1ae08745Sheppo ttlp = *pretlp; 825*1ae08745Sheppo while (ttlp) { 826*1ae08745Sheppo if (ttlp == vp_tlp) { 827*1ae08745Sheppo found = B_TRUE; 828*1ae08745Sheppo (*pretlp) = ttlp->nextp; 829*1ae08745Sheppo ttlp->nextp = NULL; 830*1ae08745Sheppo break; 831*1ae08745Sheppo } 832*1ae08745Sheppo pretlp = &(ttlp->nextp); 833*1ae08745Sheppo ttlp = *pretlp; 834*1ae08745Sheppo } 835*1ae08745Sheppo 836*1ae08745Sheppo if (found) { 837*1ae08745Sheppo KMEM_FREE(vp_tlp); 838*1ae08745Sheppo } 839*1ae08745Sheppo } 840*1ae08745Sheppo 841*1ae08745Sheppo /* get vp_tl corresponding to the given name */ 842*1ae08745Sheppo static vp_tl_t * 843*1ae08745Sheppo vnet_get_vptl(vnet_t *vnetp, const char *name) 844*1ae08745Sheppo { 845*1ae08745Sheppo vp_tl_t *tlp; 846*1ae08745Sheppo 847*1ae08745Sheppo tlp = vnetp->tlp; 848*1ae08745Sheppo while (tlp) { 849*1ae08745Sheppo if (strcmp(tlp->name, name) == 0) { 850*1ae08745Sheppo return (tlp); 851*1ae08745Sheppo } 852*1ae08745Sheppo tlp = tlp->nextp; 853*1ae08745Sheppo } 854*1ae08745Sheppo DWARN((vnetp, 855*1ae08745Sheppo "vnet_get_vptl: can't find vp_tl with name (%s)\n", name)); 856*1ae08745Sheppo return (NULL); 857*1ae08745Sheppo } 858*1ae08745Sheppo 859*1ae08745Sheppo /* read the mac address of the device */ 860*1ae08745Sheppo static int 861*1ae08745Sheppo vnet_read_mac_address(vnet_t *vnetp) 862*1ae08745Sheppo { 863*1ae08745Sheppo uchar_t *macaddr; 864*1ae08745Sheppo uint32_t size; 865*1ae08745Sheppo int rv; 866*1ae08745Sheppo 867*1ae08745Sheppo rv = ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, vnetp->dip, 868*1ae08745Sheppo DDI_PROP_DONTPASS, macaddr_propname, &macaddr, &size); 869*1ae08745Sheppo if ((rv != DDI_PROP_SUCCESS) || (size != ETHERADDRL)) { 870*1ae08745Sheppo DWARN((vnetp, 871*1ae08745Sheppo "vnet_read_mac_address: prop_lookup failed (%s) err (%d)\n", 872*1ae08745Sheppo macaddr_propname, rv)); 873*1ae08745Sheppo return (DDI_FAILURE); 874*1ae08745Sheppo } 875*1ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->vendor_addr, ETHERADDRL); 876*1ae08745Sheppo bcopy(macaddr, (caddr_t)vnetp->curr_macaddr, ETHERADDRL); 877*1ae08745Sheppo ddi_prop_free(macaddr); 878*1ae08745Sheppo 879*1ae08745Sheppo return (DDI_SUCCESS); 880*1ae08745Sheppo } 881*1ae08745Sheppo 882*1ae08745Sheppo 883*1ae08745Sheppo /* 884*1ae08745Sheppo * Functions below are called only by generic transport to add/remove/modify 885*1ae08745Sheppo * entries in forwarding database. See comments in vgen_port_init(vnet_gen.c). 886*1ae08745Sheppo */ 887*1ae08745Sheppo 888*1ae08745Sheppo /* add an entry into the forwarding database */ 889*1ae08745Sheppo void 890*1ae08745Sheppo vnet_add_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 891*1ae08745Sheppo { 892*1ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 893*1ae08745Sheppo uint32_t fdbhash; 894*1ae08745Sheppo fdb_t *fdbp; 895*1ae08745Sheppo fdb_fanout_t *fdbhp; 896*1ae08745Sheppo 897*1ae08745Sheppo /* Calculate hash value and fdb fanout */ 898*1ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 899*1ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 900*1ae08745Sheppo 901*1ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 902*1ae08745Sheppo 903*1ae08745Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 904*1ae08745Sheppo if (fdbp == NULL) { 905*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 906*1ae08745Sheppo return; 907*1ae08745Sheppo } 908*1ae08745Sheppo bcopy(macaddr, (caddr_t)fdbp->macaddr, ETHERADDRL); 909*1ae08745Sheppo fdbp->m_tx = m_tx; 910*1ae08745Sheppo fdbp->txarg = txarg; 911*1ae08745Sheppo fdbp->nextp = fdbhp->headp; 912*1ae08745Sheppo fdbhp->headp = fdbp; 913*1ae08745Sheppo 914*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 915*1ae08745Sheppo } 916*1ae08745Sheppo 917*1ae08745Sheppo /* delete an entry from the forwarding database */ 918*1ae08745Sheppo void 919*1ae08745Sheppo vnet_del_fdb(void *arg, uint8_t *macaddr) 920*1ae08745Sheppo { 921*1ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 922*1ae08745Sheppo uint32_t fdbhash; 923*1ae08745Sheppo fdb_t *fdbp; 924*1ae08745Sheppo fdb_t **pfdbp; 925*1ae08745Sheppo fdb_fanout_t *fdbhp; 926*1ae08745Sheppo 927*1ae08745Sheppo /* Calculate hash value and fdb fanout */ 928*1ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 929*1ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 930*1ae08745Sheppo 931*1ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 932*1ae08745Sheppo 933*1ae08745Sheppo for (pfdbp = &fdbhp->headp; (fdbp = *pfdbp) != NULL; 934*1ae08745Sheppo pfdbp = &fdbp->nextp) { 935*1ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 936*1ae08745Sheppo /* Unlink it from the list */ 937*1ae08745Sheppo *pfdbp = fdbp->nextp; 938*1ae08745Sheppo KMEM_FREE(fdbp); 939*1ae08745Sheppo break; 940*1ae08745Sheppo } 941*1ae08745Sheppo } 942*1ae08745Sheppo 943*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 944*1ae08745Sheppo } 945*1ae08745Sheppo 946*1ae08745Sheppo /* modify an existing entry in the forwarding database */ 947*1ae08745Sheppo void 948*1ae08745Sheppo vnet_modify_fdb(void *arg, uint8_t *macaddr, mac_tx_t m_tx, void *txarg) 949*1ae08745Sheppo { 950*1ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 951*1ae08745Sheppo uint32_t fdbhash; 952*1ae08745Sheppo fdb_t *fdbp; 953*1ae08745Sheppo fdb_fanout_t *fdbhp; 954*1ae08745Sheppo 955*1ae08745Sheppo /* Calculate hash value and fdb fanout */ 956*1ae08745Sheppo fdbhash = MACHASH(macaddr, vnetp->nfdb_hash); 957*1ae08745Sheppo fdbhp = &(vnetp->fdbhp[fdbhash]); 958*1ae08745Sheppo 959*1ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 960*1ae08745Sheppo 961*1ae08745Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 962*1ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 963*1ae08745Sheppo /* change the entry to have new tx params */ 964*1ae08745Sheppo fdbp->m_tx = m_tx; 965*1ae08745Sheppo fdbp->txarg = txarg; 966*1ae08745Sheppo break; 967*1ae08745Sheppo } 968*1ae08745Sheppo } 969*1ae08745Sheppo 970*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 971*1ae08745Sheppo } 972*1ae08745Sheppo 973*1ae08745Sheppo /* look up an fdb entry based on the mac address, caller holds lock */ 974*1ae08745Sheppo static fdb_t * 975*1ae08745Sheppo vnet_lookup_fdb(fdb_fanout_t *fdbhp, uint8_t *macaddr) 976*1ae08745Sheppo { 977*1ae08745Sheppo fdb_t *fdbp = NULL; 978*1ae08745Sheppo 979*1ae08745Sheppo for (fdbp = fdbhp->headp; fdbp != NULL; fdbp = fdbp->nextp) { 980*1ae08745Sheppo if (bcmp(fdbp->macaddr, macaddr, ETHERADDRL) == 0) { 981*1ae08745Sheppo break; 982*1ae08745Sheppo } 983*1ae08745Sheppo } 984*1ae08745Sheppo 985*1ae08745Sheppo return (fdbp); 986*1ae08745Sheppo } 987*1ae08745Sheppo 988*1ae08745Sheppo /* add default route entry into the forwarding database */ 989*1ae08745Sheppo void 990*1ae08745Sheppo vnet_add_def_rte(void *arg, mac_tx_t m_tx, void *txarg) 991*1ae08745Sheppo { 992*1ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 993*1ae08745Sheppo fdb_t *fdbp; 994*1ae08745Sheppo fdb_fanout_t *fdbhp; 995*1ae08745Sheppo 996*1ae08745Sheppo /* 997*1ae08745Sheppo * The last hash list is reserved for default route entry, 998*1ae08745Sheppo * and for now, we have only one entry in this list. 999*1ae08745Sheppo */ 1000*1ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 1001*1ae08745Sheppo 1002*1ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 1003*1ae08745Sheppo 1004*1ae08745Sheppo if (fdbhp->headp) { 1005*1ae08745Sheppo DWARN((vnetp, 1006*1ae08745Sheppo "vnet_add_def_rte: default rte already exists\n")); 1007*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 1008*1ae08745Sheppo return; 1009*1ae08745Sheppo } 1010*1ae08745Sheppo fdbp = kmem_zalloc(sizeof (fdb_t), KM_NOSLEEP); 1011*1ae08745Sheppo if (fdbp == NULL) { 1012*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 1013*1ae08745Sheppo return; 1014*1ae08745Sheppo } 1015*1ae08745Sheppo bzero(fdbp->macaddr, ETHERADDRL); 1016*1ae08745Sheppo fdbp->m_tx = m_tx; 1017*1ae08745Sheppo fdbp->txarg = txarg; 1018*1ae08745Sheppo fdbp->nextp = NULL; 1019*1ae08745Sheppo fdbhp->headp = fdbp; 1020*1ae08745Sheppo 1021*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 1022*1ae08745Sheppo } 1023*1ae08745Sheppo 1024*1ae08745Sheppo /* delete default route entry from the forwarding database */ 1025*1ae08745Sheppo void 1026*1ae08745Sheppo vnet_del_def_rte(void *arg) 1027*1ae08745Sheppo { 1028*1ae08745Sheppo vnet_t *vnetp = (vnet_t *)arg; 1029*1ae08745Sheppo fdb_t *fdbp; 1030*1ae08745Sheppo fdb_fanout_t *fdbhp; 1031*1ae08745Sheppo 1032*1ae08745Sheppo /* 1033*1ae08745Sheppo * The last hash list is reserved for default route entry, 1034*1ae08745Sheppo * and for now, we have only one entry in this list. 1035*1ae08745Sheppo */ 1036*1ae08745Sheppo fdbhp = &(vnetp->fdbhp[vnetp->nfdb_hash]); 1037*1ae08745Sheppo 1038*1ae08745Sheppo WRITE_ENTER(&fdbhp->rwlock); 1039*1ae08745Sheppo 1040*1ae08745Sheppo if (fdbhp->headp == NULL) { 1041*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 1042*1ae08745Sheppo return; 1043*1ae08745Sheppo } 1044*1ae08745Sheppo fdbp = fdbhp->headp; 1045*1ae08745Sheppo KMEM_FREE(fdbp); 1046*1ae08745Sheppo fdbhp->headp = NULL; 1047*1ae08745Sheppo 1048*1ae08745Sheppo RW_EXIT(&fdbhp->rwlock); 1049*1ae08745Sheppo } 1050