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