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