1*d62bc4baSyz147064 /* 2*d62bc4baSyz147064 * CDDL HEADER START 3*d62bc4baSyz147064 * 4*d62bc4baSyz147064 * The contents of this file are subject to the terms of the 5*d62bc4baSyz147064 * Common Development and Distribution License (the "License"). 6*d62bc4baSyz147064 * You may not use this file except in compliance with the License. 7*d62bc4baSyz147064 * 8*d62bc4baSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*d62bc4baSyz147064 * or http://www.opensolaris.org/os/licensing. 10*d62bc4baSyz147064 * See the License for the specific language governing permissions 11*d62bc4baSyz147064 * and limitations under the License. 12*d62bc4baSyz147064 * 13*d62bc4baSyz147064 * When distributing Covered Code, include this CDDL HEADER in each 14*d62bc4baSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*d62bc4baSyz147064 * If applicable, add the following below this CDDL HEADER, with the 16*d62bc4baSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying 17*d62bc4baSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 18*d62bc4baSyz147064 * 19*d62bc4baSyz147064 * CDDL HEADER END 20*d62bc4baSyz147064 */ 21*d62bc4baSyz147064 /* 22*d62bc4baSyz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*d62bc4baSyz147064 * Use is subject to license terms. 24*d62bc4baSyz147064 */ 25*d62bc4baSyz147064 26*d62bc4baSyz147064 #pragma ident "%Z%%M% %I% %E% SMI" 27*d62bc4baSyz147064 28*d62bc4baSyz147064 #include <sys/types.h> 29*d62bc4baSyz147064 #include <sys/stat.h> 30*d62bc4baSyz147064 #include <fcntl.h> 31*d62bc4baSyz147064 #include <unistd.h> 32*d62bc4baSyz147064 #include <errno.h> 33*d62bc4baSyz147064 #include <assert.h> 34*d62bc4baSyz147064 #include <sys/dld.h> 35*d62bc4baSyz147064 #include <libdladm_impl.h> 36*d62bc4baSyz147064 #include <libdllink.h> 37*d62bc4baSyz147064 #include <libdlvlan.h> 38*d62bc4baSyz147064 39*d62bc4baSyz147064 /* 40*d62bc4baSyz147064 * VLAN Administration Library. 41*d62bc4baSyz147064 * 42*d62bc4baSyz147064 * This library is used by administration tools such as dladm(1M) to 43*d62bc4baSyz147064 * configure VLANs. 44*d62bc4baSyz147064 */ 45*d62bc4baSyz147064 46*d62bc4baSyz147064 /* 47*d62bc4baSyz147064 * Returns the current attributes of the specified VLAN. 48*d62bc4baSyz147064 */ 49*d62bc4baSyz147064 static dladm_status_t 50*d62bc4baSyz147064 i_dladm_vlan_info_active(datalink_id_t vlanid, dladm_vlan_attr_t *dvap) 51*d62bc4baSyz147064 { 52*d62bc4baSyz147064 int fd; 53*d62bc4baSyz147064 dld_ioc_vlan_attr_t div; 54*d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 55*d62bc4baSyz147064 56*d62bc4baSyz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 57*d62bc4baSyz147064 return (dladm_errno2status(errno)); 58*d62bc4baSyz147064 59*d62bc4baSyz147064 div.div_vlanid = vlanid; 60*d62bc4baSyz147064 61*d62bc4baSyz147064 if (i_dladm_ioctl(fd, DLDIOC_VLAN_ATTR, &div, sizeof (div)) < 0) 62*d62bc4baSyz147064 status = dladm_errno2status(errno); 63*d62bc4baSyz147064 64*d62bc4baSyz147064 dvap->dv_vid = div.div_vid; 65*d62bc4baSyz147064 dvap->dv_linkid = div.div_linkid; 66*d62bc4baSyz147064 dvap->dv_force = div.div_force; 67*d62bc4baSyz147064 dvap->dv_implicit = div.div_implicit; 68*d62bc4baSyz147064 done: 69*d62bc4baSyz147064 (void) close(fd); 70*d62bc4baSyz147064 return (status); 71*d62bc4baSyz147064 } 72*d62bc4baSyz147064 73*d62bc4baSyz147064 /* 74*d62bc4baSyz147064 * Returns the persistent attributes of the specified VLAN. 75*d62bc4baSyz147064 */ 76*d62bc4baSyz147064 static dladm_status_t 77*d62bc4baSyz147064 i_dladm_vlan_info_persist(datalink_id_t vlanid, dladm_vlan_attr_t *dvap) 78*d62bc4baSyz147064 { 79*d62bc4baSyz147064 dladm_conf_t conf = DLADM_INVALID_CONF; 80*d62bc4baSyz147064 dladm_status_t status; 81*d62bc4baSyz147064 uint64_t u64; 82*d62bc4baSyz147064 83*d62bc4baSyz147064 if ((status = dladm_read_conf(vlanid, &conf)) != DLADM_STATUS_OK) 84*d62bc4baSyz147064 return (status); 85*d62bc4baSyz147064 86*d62bc4baSyz147064 status = dladm_get_conf_field(conf, FLINKOVER, &u64, sizeof (u64)); 87*d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 88*d62bc4baSyz147064 goto done; 89*d62bc4baSyz147064 dvap->dv_linkid = (datalink_id_t)u64; 90*d62bc4baSyz147064 91*d62bc4baSyz147064 status = dladm_get_conf_field(conf, FFORCE, &dvap->dv_force, 92*d62bc4baSyz147064 sizeof (boolean_t)); 93*d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 94*d62bc4baSyz147064 goto done; 95*d62bc4baSyz147064 96*d62bc4baSyz147064 dvap->dv_implicit = B_FALSE; 97*d62bc4baSyz147064 98*d62bc4baSyz147064 status = dladm_get_conf_field(conf, FVLANID, &u64, sizeof (u64)); 99*d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 100*d62bc4baSyz147064 goto done; 101*d62bc4baSyz147064 dvap->dv_vid = (uint16_t)u64; 102*d62bc4baSyz147064 103*d62bc4baSyz147064 done: 104*d62bc4baSyz147064 dladm_destroy_conf(conf); 105*d62bc4baSyz147064 return (status); 106*d62bc4baSyz147064 } 107*d62bc4baSyz147064 108*d62bc4baSyz147064 dladm_status_t 109*d62bc4baSyz147064 dladm_vlan_info(datalink_id_t vlanid, dladm_vlan_attr_t *dvap, uint32_t flags) 110*d62bc4baSyz147064 { 111*d62bc4baSyz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 112*d62bc4baSyz147064 if (flags == DLADM_OPT_ACTIVE) 113*d62bc4baSyz147064 return (i_dladm_vlan_info_active(vlanid, dvap)); 114*d62bc4baSyz147064 else 115*d62bc4baSyz147064 return (i_dladm_vlan_info_persist(vlanid, dvap)); 116*d62bc4baSyz147064 } 117*d62bc4baSyz147064 118*d62bc4baSyz147064 static dladm_status_t 119*d62bc4baSyz147064 dladm_persist_vlan_conf(const char *vlan, datalink_id_t vlanid, 120*d62bc4baSyz147064 boolean_t force, datalink_id_t linkid, uint16_t vid) 121*d62bc4baSyz147064 { 122*d62bc4baSyz147064 dladm_conf_t conf = DLADM_INVALID_CONF; 123*d62bc4baSyz147064 dladm_status_t status; 124*d62bc4baSyz147064 uint64_t u64; 125*d62bc4baSyz147064 126*d62bc4baSyz147064 if ((status = dladm_create_conf(vlan, vlanid, DATALINK_CLASS_VLAN, 127*d62bc4baSyz147064 DL_ETHER, &conf)) != DLADM_STATUS_OK) { 128*d62bc4baSyz147064 return (status); 129*d62bc4baSyz147064 } 130*d62bc4baSyz147064 131*d62bc4baSyz147064 u64 = linkid; 132*d62bc4baSyz147064 status = dladm_set_conf_field(conf, FLINKOVER, DLADM_TYPE_UINT64, &u64); 133*d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 134*d62bc4baSyz147064 goto done; 135*d62bc4baSyz147064 136*d62bc4baSyz147064 status = dladm_set_conf_field(conf, FFORCE, DLADM_TYPE_BOOLEAN, &force); 137*d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 138*d62bc4baSyz147064 goto done; 139*d62bc4baSyz147064 140*d62bc4baSyz147064 u64 = vid; 141*d62bc4baSyz147064 status = dladm_set_conf_field(conf, FVLANID, DLADM_TYPE_UINT64, &u64); 142*d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 143*d62bc4baSyz147064 goto done; 144*d62bc4baSyz147064 145*d62bc4baSyz147064 status = dladm_write_conf(conf); 146*d62bc4baSyz147064 147*d62bc4baSyz147064 done: 148*d62bc4baSyz147064 dladm_destroy_conf(conf); 149*d62bc4baSyz147064 return (status); 150*d62bc4baSyz147064 } 151*d62bc4baSyz147064 152*d62bc4baSyz147064 /* 153*d62bc4baSyz147064 * Create a VLAN on given link. 154*d62bc4baSyz147064 */ 155*d62bc4baSyz147064 dladm_status_t 156*d62bc4baSyz147064 dladm_vlan_create(const char *vlan, datalink_id_t linkid, uint16_t vid, 157*d62bc4baSyz147064 uint32_t flags) 158*d62bc4baSyz147064 { 159*d62bc4baSyz147064 dld_ioc_create_vlan_t dic; 160*d62bc4baSyz147064 int fd; 161*d62bc4baSyz147064 datalink_id_t vlanid = DATALINK_INVALID_LINKID; 162*d62bc4baSyz147064 uint_t media; 163*d62bc4baSyz147064 datalink_class_t class; 164*d62bc4baSyz147064 dladm_status_t status; 165*d62bc4baSyz147064 166*d62bc4baSyz147064 if (vid < 1 || vid > 4094) 167*d62bc4baSyz147064 return (DLADM_STATUS_VIDINVAL); 168*d62bc4baSyz147064 169*d62bc4baSyz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 170*d62bc4baSyz147064 return (dladm_errno2status(errno)); 171*d62bc4baSyz147064 172*d62bc4baSyz147064 status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); 173*d62bc4baSyz147064 if (status != DLADM_STATUS_OK || media != DL_ETHER || 174*d62bc4baSyz147064 class == DATALINK_CLASS_VLAN) { 175*d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 176*d62bc4baSyz147064 } 177*d62bc4baSyz147064 178*d62bc4baSyz147064 status = dladm_create_datalink_id(vlan, DATALINK_CLASS_VLAN, DL_ETHER, 179*d62bc4baSyz147064 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &vlanid); 180*d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 181*d62bc4baSyz147064 goto fail; 182*d62bc4baSyz147064 183*d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) { 184*d62bc4baSyz147064 status = dladm_persist_vlan_conf(vlan, vlanid, 185*d62bc4baSyz147064 (flags & DLADM_OPT_FORCE) != 0, linkid, vid); 186*d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 187*d62bc4baSyz147064 goto fail; 188*d62bc4baSyz147064 } 189*d62bc4baSyz147064 190*d62bc4baSyz147064 if (flags & DLADM_OPT_ACTIVE) { 191*d62bc4baSyz147064 dic.dic_vlanid = vlanid; 192*d62bc4baSyz147064 dic.dic_linkid = linkid; 193*d62bc4baSyz147064 dic.dic_vid = vid; 194*d62bc4baSyz147064 dic.dic_force = (flags & DLADM_OPT_FORCE) != 0; 195*d62bc4baSyz147064 196*d62bc4baSyz147064 if (i_dladm_ioctl(fd, DLDIOC_CREATE_VLAN, &dic, 197*d62bc4baSyz147064 sizeof (dic)) < 0) { 198*d62bc4baSyz147064 status = dladm_errno2status(errno); 199*d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) 200*d62bc4baSyz147064 (void) dladm_remove_conf(vlanid); 201*d62bc4baSyz147064 goto fail; 202*d62bc4baSyz147064 } 203*d62bc4baSyz147064 } 204*d62bc4baSyz147064 205*d62bc4baSyz147064 (void) close(fd); 206*d62bc4baSyz147064 return (DLADM_STATUS_OK); 207*d62bc4baSyz147064 208*d62bc4baSyz147064 fail: 209*d62bc4baSyz147064 if (vlanid != DATALINK_INVALID_LINKID) { 210*d62bc4baSyz147064 (void) dladm_destroy_datalink_id(vlanid, 211*d62bc4baSyz147064 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)); 212*d62bc4baSyz147064 } 213*d62bc4baSyz147064 (void) close(fd); 214*d62bc4baSyz147064 return (status); 215*d62bc4baSyz147064 } 216*d62bc4baSyz147064 217*d62bc4baSyz147064 /* 218*d62bc4baSyz147064 * Delete a given VLAN. 219*d62bc4baSyz147064 */ 220*d62bc4baSyz147064 dladm_status_t 221*d62bc4baSyz147064 dladm_vlan_delete(datalink_id_t vlanid, uint32_t flags) 222*d62bc4baSyz147064 { 223*d62bc4baSyz147064 dld_ioc_delete_vlan_t did; 224*d62bc4baSyz147064 int fd; 225*d62bc4baSyz147064 datalink_class_t class; 226*d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 227*d62bc4baSyz147064 228*d62bc4baSyz147064 if ((dladm_datalink_id2info(vlanid, NULL, &class, NULL, NULL, 0) != 229*d62bc4baSyz147064 DLADM_STATUS_OK) || (class != DATALINK_CLASS_VLAN)) { 230*d62bc4baSyz147064 return (DLADM_STATUS_BADARG); 231*d62bc4baSyz147064 } 232*d62bc4baSyz147064 233*d62bc4baSyz147064 if (flags & DLADM_OPT_ACTIVE) { 234*d62bc4baSyz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 235*d62bc4baSyz147064 return (dladm_errno2status(errno)); 236*d62bc4baSyz147064 237*d62bc4baSyz147064 did.did_linkid = vlanid; 238*d62bc4baSyz147064 if ((i_dladm_ioctl(fd, DLDIOC_DELETE_VLAN, &did, 239*d62bc4baSyz147064 sizeof (did)) < 0) && 240*d62bc4baSyz147064 ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) { 241*d62bc4baSyz147064 (void) close(fd); 242*d62bc4baSyz147064 return (dladm_errno2status(errno)); 243*d62bc4baSyz147064 } 244*d62bc4baSyz147064 (void) close(fd); 245*d62bc4baSyz147064 246*d62bc4baSyz147064 /* 247*d62bc4baSyz147064 * Delete active linkprop before this active link is deleted. 248*d62bc4baSyz147064 */ 249*d62bc4baSyz147064 (void) dladm_set_linkprop(vlanid, NULL, NULL, 0, 250*d62bc4baSyz147064 DLADM_OPT_ACTIVE); 251*d62bc4baSyz147064 } 252*d62bc4baSyz147064 253*d62bc4baSyz147064 (void) dladm_destroy_datalink_id(vlanid, 254*d62bc4baSyz147064 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)); 255*d62bc4baSyz147064 256*d62bc4baSyz147064 if (flags & DLADM_OPT_PERSIST) 257*d62bc4baSyz147064 (void) dladm_remove_conf(vlanid); 258*d62bc4baSyz147064 259*d62bc4baSyz147064 return (status); 260*d62bc4baSyz147064 } 261*d62bc4baSyz147064 262*d62bc4baSyz147064 /* 263*d62bc4baSyz147064 * Callback used by dladm_vlan_up() 264*d62bc4baSyz147064 */ 265*d62bc4baSyz147064 static int 266*d62bc4baSyz147064 i_dladm_vlan_up(datalink_id_t vlanid, void *arg) 267*d62bc4baSyz147064 { 268*d62bc4baSyz147064 dladm_vlan_attr_t dva; 269*d62bc4baSyz147064 dld_ioc_create_vlan_t dic; 270*d62bc4baSyz147064 dladm_status_t *statusp = arg; 271*d62bc4baSyz147064 uint32_t flags; 272*d62bc4baSyz147064 int fd; 273*d62bc4baSyz147064 dladm_status_t status; 274*d62bc4baSyz147064 275*d62bc4baSyz147064 status = dladm_vlan_info(vlanid, &dva, DLADM_OPT_PERSIST); 276*d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 277*d62bc4baSyz147064 goto done; 278*d62bc4baSyz147064 279*d62bc4baSyz147064 /* 280*d62bc4baSyz147064 * Validate (and delete) the link associated with this VLAN, see if 281*d62bc4baSyz147064 * the specific hardware has been removed during system shutdown. 282*d62bc4baSyz147064 */ 283*d62bc4baSyz147064 if ((status = dladm_datalink_id2info(dva.dv_linkid, &flags, NULL, 284*d62bc4baSyz147064 NULL, NULL, 0)) != DLADM_STATUS_OK) { 285*d62bc4baSyz147064 goto done; 286*d62bc4baSyz147064 } 287*d62bc4baSyz147064 288*d62bc4baSyz147064 if (!(flags & DLADM_OPT_ACTIVE)) { 289*d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 290*d62bc4baSyz147064 goto done; 291*d62bc4baSyz147064 } 292*d62bc4baSyz147064 293*d62bc4baSyz147064 dic.dic_linkid = dva.dv_linkid; 294*d62bc4baSyz147064 dic.dic_force = dva.dv_force; 295*d62bc4baSyz147064 dic.dic_vid = dva.dv_vid; 296*d62bc4baSyz147064 297*d62bc4baSyz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { 298*d62bc4baSyz147064 status = dladm_errno2status(errno); 299*d62bc4baSyz147064 goto done; 300*d62bc4baSyz147064 } 301*d62bc4baSyz147064 302*d62bc4baSyz147064 dic.dic_vlanid = vlanid; 303*d62bc4baSyz147064 if (i_dladm_ioctl(fd, DLDIOC_CREATE_VLAN, &dic, sizeof (dic)) < 0) { 304*d62bc4baSyz147064 status = dladm_errno2status(errno); 305*d62bc4baSyz147064 goto done; 306*d62bc4baSyz147064 } 307*d62bc4baSyz147064 308*d62bc4baSyz147064 if ((status = dladm_up_datalink_id(vlanid)) != DLADM_STATUS_OK) { 309*d62bc4baSyz147064 dld_ioc_delete_vlan_t did; 310*d62bc4baSyz147064 311*d62bc4baSyz147064 did.did_linkid = vlanid; 312*d62bc4baSyz147064 (void) i_dladm_ioctl(fd, DLDIOC_DELETE_VLAN, &did, 313*d62bc4baSyz147064 sizeof (did)); 314*d62bc4baSyz147064 } else { 315*d62bc4baSyz147064 /* 316*d62bc4baSyz147064 * Reset the active linkprop of this specific link. 317*d62bc4baSyz147064 */ 318*d62bc4baSyz147064 (void) dladm_init_linkprop(vlanid); 319*d62bc4baSyz147064 } 320*d62bc4baSyz147064 321*d62bc4baSyz147064 (void) close(fd); 322*d62bc4baSyz147064 done: 323*d62bc4baSyz147064 *statusp = status; 324*d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 325*d62bc4baSyz147064 } 326*d62bc4baSyz147064 327*d62bc4baSyz147064 /* 328*d62bc4baSyz147064 * Bring up one VLAN, or all persistent VLANs. In the latter case, the 329*d62bc4baSyz147064 * walk may terminate early if bringup of a VLAN fails. 330*d62bc4baSyz147064 */ 331*d62bc4baSyz147064 dladm_status_t 332*d62bc4baSyz147064 dladm_vlan_up(datalink_id_t linkid) 333*d62bc4baSyz147064 { 334*d62bc4baSyz147064 dladm_status_t status; 335*d62bc4baSyz147064 336*d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 337*d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_up, &status, 338*d62bc4baSyz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 339*d62bc4baSyz147064 DLADM_OPT_PERSIST); 340*d62bc4baSyz147064 return (DLADM_STATUS_OK); 341*d62bc4baSyz147064 } else { 342*d62bc4baSyz147064 (void) i_dladm_vlan_up(linkid, &status); 343*d62bc4baSyz147064 return (status); 344*d62bc4baSyz147064 } 345*d62bc4baSyz147064 } 346