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