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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <string.h> 30 #include <fcntl.h> 31 #include <unistd.h> 32 #include <stropts.h> 33 #include <stdlib.h> 34 #include <errno.h> 35 #include <strings.h> 36 #include <libintl.h> 37 #include <net/if_types.h> 38 #include <net/if_dl.h> 39 #include <sys/dld.h> 40 #include <libdladm_impl.h> 41 #include <libdllink.h> 42 #include <libdlvnic.h> 43 44 /* 45 * VNIC administration library. 46 */ 47 48 /* 49 * Default random MAC address prefix (locally administered). 50 */ 51 static char dladm_vnic_def_prefix[] = {0x02, 0x08, 0x20}; 52 53 static dladm_status_t dladm_vnic_persist_conf(const char *name, 54 dladm_vnic_attr_t *, datalink_class_t); 55 static const char *dladm_vnic_macaddr2str(const uchar_t *, char *); 56 static dladm_status_t dladm_vnic_str2macaddr(const char *, uchar_t *); 57 58 /* 59 * Convert a diagnostic returned by the kernel into a dladm_status_t. 60 */ 61 static dladm_status_t 62 dladm_vnic_diag2status(vnic_ioc_diag_t ioc_diag) 63 { 64 switch (ioc_diag) { 65 case VNIC_IOC_DIAG_MACADDR_INVALID: 66 return (DLADM_STATUS_INVALIDMACADDR); 67 case VNIC_IOC_DIAG_MACADDRLEN_INVALID: 68 return (DLADM_STATUS_INVALIDMACADDRLEN); 69 case VNIC_IOC_DIAG_MACADDR_NIC: 70 return (DLADM_STATUS_INVALIDMACADDRNIC); 71 case VNIC_IOC_DIAG_MACADDR_INUSE: 72 return (DLADM_STATUS_INVALIDMACADDRINUSE); 73 case VNIC_IOC_DIAG_MACFACTORYSLOTINVALID: 74 return (DLADM_STATUS_MACFACTORYSLOTINVALID); 75 case VNIC_IOC_DIAG_MACFACTORYSLOTUSED: 76 return (DLADM_STATUS_MACFACTORYSLOTUSED); 77 case VNIC_IOC_DIAG_MACFACTORYSLOTALLUSED: 78 return (DLADM_STATUS_MACFACTORYSLOTALLUSED); 79 case VNIC_IOC_DIAG_MACFACTORYNOTSUP: 80 return (DLADM_STATUS_MACFACTORYNOTSUP); 81 case VNIC_IOC_DIAG_MACPREFIX_INVALID: 82 return (DLADM_STATUS_INVALIDMACPREFIX); 83 case VNIC_IOC_DIAG_MACPREFIXLEN_INVALID: 84 return (DLADM_STATUS_INVALIDMACPREFIXLEN); 85 case VNIC_IOC_DIAG_MACMARGIN_INVALID: 86 return (DLADM_STATUS_INVALID_MACMARGIN); 87 case VNIC_IOC_DIAG_NO_HWRINGS: 88 return (DLADM_STATUS_NO_HWRINGS); 89 } 90 return (DLADM_STATUS_OK); 91 } 92 93 /* 94 * Send a create command to the VNIC driver. 95 */ 96 dladm_status_t 97 i_dladm_vnic_create_sys(dladm_vnic_attr_t *attr) 98 { 99 int rc, fd; 100 vnic_ioc_create_t ioc; 101 dladm_status_t status = DLADM_STATUS_OK; 102 103 bzero(&ioc, sizeof (ioc)); 104 ioc.vc_vnic_id = attr->va_vnic_id; 105 ioc.vc_link_id = attr->va_link_id; 106 ioc.vc_mac_addr_type = attr->va_mac_addr_type; 107 ioc.vc_mac_len = attr->va_mac_len; 108 ioc.vc_mac_slot = attr->va_mac_slot; 109 ioc.vc_mac_prefix_len = attr->va_mac_prefix_len; 110 ioc.vc_vid = attr->va_vid; 111 ioc.vc_flags = attr->va_force ? VNIC_IOC_CREATE_FORCE : 0; 112 ioc.vc_flags |= attr->va_hwrings ? VNIC_IOC_CREATE_REQ_HWRINGS : 0; 113 114 if (attr->va_mac_len > 0 || ioc.vc_mac_prefix_len > 0) 115 bcopy(attr->va_mac_addr, ioc.vc_mac_addr, MAXMACADDRLEN); 116 bcopy(&attr->va_resource_props, &ioc.vc_resource_props, 117 sizeof (mac_resource_props_t)); 118 if (attr->va_link_id == DATALINK_INVALID_LINKID) 119 ioc.vc_flags |= VNIC_IOC_CREATE_ANCHOR; 120 121 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 122 return (dladm_errno2status(errno)); 123 124 rc = ioctl(fd, VNIC_IOC_CREATE, &ioc); 125 if (rc < 0) 126 status = dladm_errno2status(errno); 127 128 (void) close(fd); 129 if (status != DLADM_STATUS_OK) { 130 if (ioc.vc_diag != VNIC_IOC_DIAG_NONE) 131 status = dladm_vnic_diag2status(ioc.vc_diag); 132 } 133 if (status != DLADM_STATUS_OK) 134 return (status); 135 136 attr->va_mac_addr_type = ioc.vc_mac_addr_type; 137 switch (ioc.vc_mac_addr_type) { 138 case VNIC_MAC_ADDR_TYPE_FACTORY: 139 attr->va_mac_slot = ioc.vc_mac_slot; 140 break; 141 case VNIC_MAC_ADDR_TYPE_RANDOM: 142 bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN); 143 attr->va_mac_len = ioc.vc_mac_len; 144 break; 145 } 146 return (status); 147 } 148 149 /* 150 * Get the configuration information of the given VNIC. 151 */ 152 static dladm_status_t 153 i_dladm_vnic_info_active(datalink_id_t linkid, dladm_vnic_attr_t *attrp) 154 { 155 vnic_ioc_info_t ioc; 156 vnic_info_t *vnic; 157 int rc, fd; 158 dladm_status_t status = DLADM_STATUS_OK; 159 160 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) == -1) 161 return (dladm_errno2status(errno)); 162 163 bzero(&ioc, sizeof (ioc)); 164 vnic = &ioc.vi_info; 165 vnic->vn_vnic_id = linkid; 166 167 rc = ioctl(fd, VNIC_IOC_INFO, &ioc); 168 if (rc != 0) { 169 status = dladm_errno2status(errno); 170 goto bail; 171 } 172 173 attrp->va_vnic_id = vnic->vn_vnic_id; 174 attrp->va_link_id = vnic->vn_link_id; 175 attrp->va_mac_addr_type = vnic->vn_mac_addr_type; 176 bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, MAXMACADDRLEN); 177 attrp->va_mac_len = vnic->vn_mac_len; 178 attrp->va_mac_slot = vnic->vn_mac_slot; 179 attrp->va_mac_prefix_len = vnic->vn_mac_prefix_len; 180 attrp->va_vid = vnic->vn_vid; 181 attrp->va_force = vnic->vn_force; 182 183 bail: 184 (void) close(fd); 185 return (status); 186 } 187 188 static dladm_status_t 189 i_dladm_vnic_info_persist(datalink_id_t linkid, dladm_vnic_attr_t *attrp) 190 { 191 dladm_conf_t conf; 192 dladm_status_t status; 193 char macstr[ETHERADDRL * 3]; 194 uint64_t u64; 195 datalink_class_t class; 196 197 attrp->va_vnic_id = linkid; 198 if ((status = dladm_read_conf(linkid, &conf)) != DLADM_STATUS_OK) 199 return (status); 200 201 status = dladm_get_conf_field(conf, FLINKOVER, &u64, sizeof (u64)); 202 attrp->va_link_id = ((status == DLADM_STATUS_OK) ? 203 (datalink_id_t)u64 : DATALINK_INVALID_LINKID); 204 205 status = dladm_get_conf_field(conf, FHWRINGS, &attrp->va_hwrings, 206 sizeof (boolean_t)); 207 208 if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND) 209 goto done; 210 if (status == DLADM_STATUS_NOTFOUND) 211 attrp->va_hwrings = B_FALSE; 212 213 if ((status = dladm_datalink_id2info(linkid, NULL, &class, 214 NULL, NULL, 0)) != DLADM_STATUS_OK) 215 goto done; 216 217 if (class == DATALINK_CLASS_VLAN) { 218 if (attrp->va_link_id == DATALINK_INVALID_LINKID) { 219 status = DLADM_STATUS_BADARG; 220 goto done; 221 } 222 attrp->va_mac_addr_type = VNIC_MAC_ADDR_TYPE_PRIMARY; 223 attrp->va_mac_len = 0; 224 } else { 225 status = dladm_get_conf_field(conf, FMADDRTYPE, &u64, 226 sizeof (u64)); 227 if (status != DLADM_STATUS_OK) 228 goto done; 229 230 attrp->va_mac_addr_type = (vnic_mac_addr_type_t)u64; 231 232 status = dladm_get_conf_field(conf, FMADDRLEN, &u64, 233 sizeof (u64)); 234 attrp->va_mac_len = ((status == DLADM_STATUS_OK) ? 235 (uint_t)u64 : ETHERADDRL); 236 237 status = dladm_get_conf_field(conf, FMADDRSLOT, &u64, 238 sizeof (u64)); 239 attrp->va_mac_slot = ((status == DLADM_STATUS_OK) ? 240 (int)u64 : -1); 241 242 status = dladm_get_conf_field(conf, FMADDRPREFIXLEN, &u64, 243 sizeof (u64)); 244 attrp->va_mac_prefix_len = ((status == DLADM_STATUS_OK) ? 245 (uint_t)u64 : sizeof (dladm_vnic_def_prefix)); 246 247 status = dladm_get_conf_field(conf, FMACADDR, macstr, 248 sizeof (macstr)); 249 if (status != DLADM_STATUS_OK) 250 goto done; 251 252 status = dladm_vnic_str2macaddr(macstr, attrp->va_mac_addr); 253 if (status != DLADM_STATUS_OK) 254 goto done; 255 } 256 257 status = dladm_get_conf_field(conf, FVLANID, &u64, sizeof (u64)); 258 attrp->va_vid = ((status == DLADM_STATUS_OK) ? (uint16_t)u64 : 0); 259 260 261 status = DLADM_STATUS_OK; 262 done: 263 dladm_destroy_conf(conf); 264 return (status); 265 } 266 267 dladm_status_t 268 dladm_vnic_info(datalink_id_t linkid, dladm_vnic_attr_t *attrp, 269 uint32_t flags) 270 { 271 if (flags == DLADM_OPT_ACTIVE) 272 return (i_dladm_vnic_info_active(linkid, attrp)); 273 else if (flags == DLADM_OPT_PERSIST) 274 return (i_dladm_vnic_info_persist(linkid, attrp)); 275 else 276 return (DLADM_STATUS_BADARG); 277 } 278 279 /* 280 * Remove a VNIC from the kernel. 281 */ 282 dladm_status_t 283 i_dladm_vnic_delete_sys(datalink_id_t linkid) 284 { 285 vnic_ioc_delete_t ioc; 286 dladm_status_t status = DLADM_STATUS_OK; 287 int rc, fd; 288 289 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 290 return (dladm_errno2status(errno)); 291 292 ioc.vd_vnic_id = linkid; 293 294 rc = ioctl(fd, VNIC_IOC_DELETE, &ioc); 295 if (rc < 0) 296 status = dladm_errno2status(errno); 297 298 (void) close(fd); 299 return (status); 300 } 301 302 /* 303 * Convert between MAC address types and their string representations. 304 */ 305 306 typedef struct dladm_vnic_addr_type_s { 307 const char *va_str; 308 vnic_mac_addr_type_t va_type; 309 } dladm_vnic_addr_type_t; 310 311 static dladm_vnic_addr_type_t addr_types[] = { 312 {"fixed", VNIC_MAC_ADDR_TYPE_FIXED}, 313 {"random", VNIC_MAC_ADDR_TYPE_RANDOM}, 314 {"factory", VNIC_MAC_ADDR_TYPE_FACTORY}, 315 {"auto", VNIC_MAC_ADDR_TYPE_AUTO}, 316 {"fixed", VNIC_MAC_ADDR_TYPE_PRIMARY} 317 }; 318 319 #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t)) 320 321 static const char * 322 dladm_vnic_macaddrtype2str(vnic_mac_addr_type_t type) 323 { 324 int i; 325 326 for (i = 0; i < NADDR_TYPES; i++) { 327 if (type == addr_types[i].va_type) 328 return (addr_types[i].va_str); 329 } 330 return (NULL); 331 } 332 333 dladm_status_t 334 dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val) 335 { 336 int i; 337 dladm_vnic_addr_type_t *type; 338 339 for (i = 0; i < NADDR_TYPES; i++) { 340 type = &addr_types[i]; 341 if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) { 342 *val = type->va_type; 343 return (DLADM_STATUS_OK); 344 } 345 } 346 return (DLADM_STATUS_BADARG); 347 } 348 349 350 351 /* 352 * Create a new VNIC / VLAN. Update the configuration file and bring it up. 353 */ 354 dladm_status_t 355 dladm_vnic_create(const char *vnic, datalink_id_t linkid, 356 vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len, 357 int *mac_slot, uint_t mac_prefix_len, uint16_t vid, 358 datalink_id_t *vnic_id_out, dladm_arg_list_t *proplist, uint32_t flags) 359 { 360 dladm_vnic_attr_t attr; 361 datalink_id_t vnic_id; 362 datalink_class_t class; 363 uint32_t media = DL_ETHER; 364 char name[MAXLINKNAMELEN]; 365 uchar_t tmp_addr[MAXMACADDRLEN]; 366 dladm_status_t status; 367 boolean_t is_vlan; 368 boolean_t is_etherstub; 369 int i; 370 371 /* 372 * Sanity test arguments. 373 */ 374 if ((flags & DLADM_OPT_ACTIVE) == 0) 375 return (DLADM_STATUS_NOTSUP); 376 377 is_vlan = ((flags & DLADM_OPT_VLAN) != 0); 378 if (is_vlan && ((vid < 1 || vid > 4094))) 379 return (DLADM_STATUS_VIDINVAL); 380 381 is_etherstub = (linkid == DATALINK_INVALID_LINKID); 382 383 if (mac_len > MAXMACADDRLEN) 384 return (DLADM_STATUS_INVALIDMACADDRLEN); 385 386 if (!dladm_vnic_macaddrtype2str(mac_addr_type)) 387 return (DLADM_STATUS_INVALIDMACADDRTYPE); 388 389 /* 390 * If a random address might be generated, but no prefix 391 * was specified by the caller, use the default MAC address 392 * prefix. 393 */ 394 if ((mac_addr_type == VNIC_MAC_ADDR_TYPE_RANDOM || 395 mac_addr_type == VNIC_MAC_ADDR_TYPE_AUTO) && 396 mac_prefix_len == 0) { 397 mac_prefix_len = sizeof (dladm_vnic_def_prefix); 398 mac_addr = tmp_addr; 399 bcopy(dladm_vnic_def_prefix, mac_addr, mac_prefix_len); 400 } 401 402 if ((flags & DLADM_OPT_ANCHOR) == 0) { 403 if ((status = dladm_datalink_id2info(linkid, NULL, &class, 404 &media, NULL, 0)) != DLADM_STATUS_OK) 405 return (status); 406 407 if (class == DATALINK_CLASS_VNIC || 408 class == DATALINK_CLASS_VLAN) 409 return (DLADM_STATUS_BADARG); 410 } else { 411 /* it's an anchor VNIC */ 412 if (linkid != DATALINK_INVALID_LINKID || vid != 0) 413 return (DLADM_STATUS_BADARG); 414 } 415 416 if (vnic == NULL) { 417 flags |= DLADM_OPT_PREFIX; 418 (void) strlcpy(name, "vnic", sizeof (name)); 419 } else { 420 (void) strlcpy(name, vnic, sizeof (name)); 421 } 422 423 class = is_vlan ? DATALINK_CLASS_VLAN : 424 (is_etherstub ? DATALINK_CLASS_ETHERSTUB : DATALINK_CLASS_VNIC); 425 if ((status = dladm_create_datalink_id(name, class, 426 media, flags, &vnic_id)) != DLADM_STATUS_OK) 427 return (status); 428 429 if ((flags & DLADM_OPT_PREFIX) != 0) { 430 (void) snprintf(name + 4, sizeof (name), "%llu", vnic_id); 431 flags &= ~DLADM_OPT_PREFIX; 432 } 433 434 bzero(&attr, sizeof (attr)); 435 436 /* Extract resource_ctl and cpu_list from proplist */ 437 if (proplist != NULL) { 438 status = dladm_link_proplist_extract(proplist, 439 &attr.va_resource_props); 440 if (status != DLADM_STATUS_OK) 441 goto done; 442 } 443 444 attr.va_vnic_id = vnic_id; 445 attr.va_link_id = linkid; 446 attr.va_mac_addr_type = mac_addr_type; 447 attr.va_mac_len = mac_len; 448 if (mac_slot != NULL) 449 attr.va_mac_slot = *mac_slot; 450 if (mac_len > 0) 451 bcopy(mac_addr, attr.va_mac_addr, mac_len); 452 else if (mac_prefix_len > 0) 453 bcopy(mac_addr, attr.va_mac_addr, mac_prefix_len); 454 attr.va_mac_prefix_len = mac_prefix_len; 455 attr.va_vid = vid; 456 attr.va_force = (flags & DLADM_OPT_FORCE) != 0; 457 attr.va_hwrings = (flags & DLADM_OPT_HWRINGS) != 0; 458 459 status = i_dladm_vnic_create_sys(&attr); 460 if (status != DLADM_STATUS_OK) 461 goto done; 462 463 /* Save vnic configuration and its properties */ 464 if (!(flags & DLADM_OPT_PERSIST)) 465 goto done; 466 467 status = dladm_vnic_persist_conf(name, &attr, class); 468 if (status != DLADM_STATUS_OK) { 469 (void) i_dladm_vnic_delete_sys(vnic_id); 470 goto done; 471 } 472 473 if (proplist != NULL) { 474 for (i = 0; i < proplist->al_count; i++) { 475 dladm_arg_info_t *aip = &proplist->al_info[i]; 476 477 status = dladm_set_linkprop(vnic_id, aip->ai_name, 478 aip->ai_val, aip->ai_count, DLADM_OPT_PERSIST); 479 if (status != DLADM_STATUS_OK) 480 break; 481 } 482 483 if (status != DLADM_STATUS_OK) { 484 (void) dladm_remove_conf(vnic_id); 485 (void) i_dladm_vnic_delete_sys(vnic_id); 486 } 487 } 488 489 done: 490 if (status != DLADM_STATUS_OK) { 491 (void) dladm_destroy_datalink_id(vnic_id, flags); 492 } else { 493 if (vnic_id_out != NULL) 494 *vnic_id_out = vnic_id; 495 if (mac_slot != NULL) 496 *mac_slot = attr.va_mac_slot; 497 } 498 return (status); 499 } 500 501 /* 502 * Delete a VNIC / VLAN. 503 */ 504 dladm_status_t 505 dladm_vnic_delete(datalink_id_t linkid, uint32_t flags) 506 { 507 dladm_status_t status; 508 datalink_class_t class; 509 510 if (flags == 0) 511 return (DLADM_STATUS_BADARG); 512 513 if ((dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0) != 514 DLADM_STATUS_OK)) 515 return (DLADM_STATUS_BADARG); 516 517 if ((flags & DLADM_OPT_VLAN) != 0) { 518 if (class != DATALINK_CLASS_VLAN) 519 return (DLADM_STATUS_BADARG); 520 } else { 521 if (class != DATALINK_CLASS_VNIC && 522 class != DATALINK_CLASS_ETHERSTUB) 523 return (DLADM_STATUS_BADARG); 524 } 525 526 if ((flags & DLADM_OPT_ACTIVE) != 0) { 527 status = i_dladm_vnic_delete_sys(linkid); 528 if (status == DLADM_STATUS_OK) { 529 (void) dladm_set_linkprop(linkid, NULL, NULL, 0, 530 DLADM_OPT_ACTIVE); 531 (void) dladm_destroy_datalink_id(linkid, 532 DLADM_OPT_ACTIVE); 533 } else if (status != DLADM_STATUS_NOTFOUND || 534 !(flags & DLADM_OPT_PERSIST)) { 535 return (status); 536 } 537 } 538 if ((flags & DLADM_OPT_PERSIST) != 0) { 539 (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); 540 (void) dladm_remove_conf(linkid); 541 } 542 return (DLADM_STATUS_OK); 543 } 544 545 static const char * 546 dladm_vnic_macaddr2str(const uchar_t *mac, char *buf) 547 { 548 static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; 549 550 if (buf == NULL) 551 return (NULL); 552 553 if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) 554 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 555 else 556 return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); 557 558 return (buf); 559 } 560 561 static dladm_status_t 562 dladm_vnic_str2macaddr(const char *str, uchar_t *buf) 563 { 564 int len = 0; 565 uchar_t *b = _link_aton(str, &len); 566 567 if (b == NULL || len >= MAXMACADDRLEN) 568 return (DLADM_STATUS_BADARG); 569 570 bcopy(b, buf, len); 571 free(b); 572 return (DLADM_STATUS_OK); 573 } 574 575 576 static dladm_status_t 577 dladm_vnic_persist_conf(const char *name, dladm_vnic_attr_t *attrp, 578 datalink_class_t class) 579 { 580 dladm_conf_t conf = DLADM_INVALID_CONF; 581 dladm_status_t status; 582 char macstr[ETHERADDRL * 3]; 583 uint64_t u64; 584 585 if ((status = dladm_create_conf(name, attrp->va_vnic_id, 586 class, DL_ETHER, &conf)) != DLADM_STATUS_OK) 587 return (status); 588 589 if (attrp->va_link_id != DATALINK_INVALID_LINKID) { 590 u64 = attrp->va_link_id; 591 status = dladm_set_conf_field(conf, FLINKOVER, 592 DLADM_TYPE_UINT64, &u64); 593 if (status != DLADM_STATUS_OK) 594 goto done; 595 } 596 597 if (class != DATALINK_CLASS_VLAN) { 598 u64 = attrp->va_mac_addr_type; 599 status = dladm_set_conf_field(conf, FMADDRTYPE, 600 DLADM_TYPE_UINT64, &u64); 601 if (status != DLADM_STATUS_OK) 602 goto done; 603 604 if (attrp->va_mac_len != ETHERADDRL) { 605 u64 = attrp->va_mac_len; 606 status = dladm_set_conf_field(conf, FMADDRLEN, 607 DLADM_TYPE_UINT64, &u64); 608 if (status != DLADM_STATUS_OK) 609 goto done; 610 } 611 } 612 613 if (attrp->va_hwrings) { 614 boolean_t hwrings = attrp->va_hwrings; 615 status = dladm_set_conf_field(conf, FHWRINGS, 616 DLADM_TYPE_BOOLEAN, &hwrings); 617 if (status != DLADM_STATUS_OK) 618 goto done; 619 } 620 621 if (class != DATALINK_CLASS_VLAN) { 622 if (attrp->va_mac_slot != -1) { 623 u64 = attrp->va_mac_slot; 624 status = dladm_set_conf_field(conf, FMADDRSLOT, 625 DLADM_TYPE_UINT64, &u64); 626 if (status != DLADM_STATUS_OK) 627 goto done; 628 } 629 630 if (attrp->va_mac_prefix_len != 631 sizeof (dladm_vnic_def_prefix)) { 632 u64 = attrp->va_mac_prefix_len; 633 status = dladm_set_conf_field(conf, FMADDRPREFIXLEN, 634 DLADM_TYPE_UINT64, &u64); 635 if (status != DLADM_STATUS_OK) 636 goto done; 637 } 638 639 (void) dladm_vnic_macaddr2str(attrp->va_mac_addr, macstr); 640 status = dladm_set_conf_field(conf, FMACADDR, DLADM_TYPE_STR, 641 macstr); 642 if (status != DLADM_STATUS_OK) 643 goto done; 644 } 645 646 if (attrp->va_vid != 0) { 647 u64 = attrp->va_vid; 648 status = dladm_set_conf_field(conf, FVLANID, 649 DLADM_TYPE_UINT64, &u64); 650 if (status != DLADM_STATUS_OK) 651 goto done; 652 } 653 654 /* 655 * Commit the link configuration. 656 */ 657 status = dladm_write_conf(conf); 658 659 done: 660 dladm_destroy_conf(conf); 661 return (status); 662 } 663 664 typedef struct dladm_vnic_up_arg_s { 665 uint32_t flags; 666 dladm_status_t status; 667 } dladm_vnic_up_arg_t; 668 669 #define DLADM_VNIC_UP_FIRST_WALK 0x1 670 #define DLADM_VNIC_UP_SECOND_WALK 0x2 671 672 static int 673 i_dladm_vnic_up(datalink_id_t linkid, void *arg) 674 { 675 dladm_status_t *statusp = &(((dladm_vnic_up_arg_t *)arg)->status); 676 dladm_vnic_attr_t attr; 677 dladm_status_t status; 678 dladm_arg_list_t *proplist; 679 uint32_t flags = ((dladm_vnic_up_arg_t *)arg)->flags; 680 681 bzero(&attr, sizeof (attr)); 682 683 status = dladm_vnic_info(linkid, &attr, DLADM_OPT_PERSIST); 684 if (status != DLADM_STATUS_OK) 685 goto done; 686 687 /* 688 * Create the vnics that request hardware group first 689 * Create the vnics that don't request hardware group in the second walk 690 */ 691 if ((flags == DLADM_VNIC_UP_FIRST_WALK && !attr.va_hwrings) || 692 (flags == DLADM_VNIC_UP_SECOND_WALK && attr.va_hwrings)) 693 goto done; 694 695 /* Get all properties for this vnic */ 696 status = dladm_link_get_proplist(linkid, &proplist); 697 if (status != DLADM_STATUS_OK) 698 goto done; 699 700 if (proplist != NULL) { 701 status = dladm_link_proplist_extract(proplist, 702 &attr.va_resource_props); 703 } 704 705 status = i_dladm_vnic_create_sys(&attr); 706 if (status != DLADM_STATUS_OK) 707 goto done; 708 709 if ((status = dladm_up_datalink_id(linkid)) != DLADM_STATUS_OK) { 710 (void) i_dladm_vnic_delete_sys(linkid); 711 goto done; 712 } 713 done: 714 *statusp = status; 715 return (DLADM_WALK_CONTINUE); 716 } 717 718 dladm_status_t 719 dladm_vnic_up(datalink_id_t linkid, uint32_t flags) 720 { 721 dladm_vnic_up_arg_t vnic_arg; 722 datalink_class_t class; 723 724 class = ((flags & DLADM_OPT_VLAN) != 0) ? DATALINK_CLASS_VLAN : 725 (DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB); 726 727 if (linkid == DATALINK_ALL_LINKID) { 728 vnic_arg.flags = DLADM_VNIC_UP_FIRST_WALK; 729 (void) dladm_walk_datalink_id(i_dladm_vnic_up, &vnic_arg, 730 class, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 731 vnic_arg.flags = DLADM_VNIC_UP_SECOND_WALK; 732 (void) dladm_walk_datalink_id(i_dladm_vnic_up, &vnic_arg, 733 class, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 734 return (DLADM_STATUS_OK); 735 } else { 736 (void) i_dladm_vnic_up(linkid, &vnic_arg); 737 return (vnic_arg.status); 738 } 739 } 740