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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <stdio.h> 26 #include <sys/types.h> 27 #include <string.h> 28 #include <fcntl.h> 29 #include <unistd.h> 30 #include <stropts.h> 31 #include <ctype.h> 32 #include <errno.h> 33 #include <stdlib.h> 34 #include <door.h> 35 #include <sys/mman.h> 36 #include <libscf.h> 37 #include <libscf_priv.h> 38 #include <libdllink.h> 39 #include <libdlbridge.h> 40 #include <libdladm_impl.h> 41 #include <stp_in.h> 42 #include <net/bridge.h> 43 #include <net/trill.h> 44 #include <sys/socket.h> 45 #include <sys/dld_ioc.h> 46 47 /* 48 * Bridge Administration Library. 49 * 50 * This library is used by administration tools such as dladm(8) to configure 51 * bridges, and by the bridge daemon to retrieve configuration information. 52 */ 53 54 #define BRIDGE_SVC_NAME "network/bridge" 55 #define TRILL_SVC_NAME "network/routing/trill" 56 57 #define DEFAULT_TIMEOUT 60000000 58 #define INIT_WAIT_USECS 50000 59 #define MAXPORTS 256 60 61 typedef struct scf_state { 62 scf_handle_t *ss_handle; 63 scf_instance_t *ss_inst; 64 scf_service_t *ss_svc; 65 scf_snapshot_t *ss_snap; 66 scf_propertygroup_t *ss_pg; 67 scf_property_t *ss_prop; 68 } scf_state_t; 69 70 static void 71 shut_down_scf(scf_state_t *sstate) 72 { 73 scf_instance_destroy(sstate->ss_inst); 74 (void) scf_handle_unbind(sstate->ss_handle); 75 scf_handle_destroy(sstate->ss_handle); 76 } 77 78 static char * 79 alloc_fmri(const char *service, const char *instance_name) 80 { 81 ssize_t max_fmri; 82 char *fmri; 83 84 /* If the limit is unknown, then use an arbitrary value */ 85 if ((max_fmri = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == -1) 86 max_fmri = 1024; 87 if ((fmri = malloc(max_fmri)) != NULL) { 88 (void) snprintf(fmri, max_fmri, "svc:/%s:%s", service, 89 instance_name); 90 } 91 return (fmri); 92 } 93 94 /* 95 * Start up SCF and bind the requested instance alone. 96 */ 97 static int 98 bind_instance(const char *service, const char *instance_name, 99 scf_state_t *sstate) 100 { 101 char *fmri = NULL; 102 103 (void) memset(sstate, 0, sizeof (*sstate)); 104 105 if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 106 return (-1); 107 108 if (scf_handle_bind(sstate->ss_handle) != 0) 109 goto failure; 110 sstate->ss_inst = scf_instance_create(sstate->ss_handle); 111 if (sstate->ss_inst == NULL) 112 goto failure; 113 114 fmri = alloc_fmri(service, instance_name); 115 116 if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, NULL, 117 sstate->ss_inst, NULL, NULL, 118 SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) 119 goto failure; 120 free(fmri); 121 return (0); 122 123 failure: 124 free(fmri); 125 shut_down_scf(sstate); 126 return (-1); 127 } 128 129 /* 130 * Start up SCF and an exact FMRI. This is used for creating new instances and 131 * enable/disable actions. 132 */ 133 static dladm_status_t 134 exact_instance(const char *fmri, scf_state_t *sstate) 135 { 136 dladm_status_t status; 137 138 (void) memset(sstate, 0, sizeof (*sstate)); 139 140 if ((sstate->ss_handle = scf_handle_create(SCF_VERSION)) == NULL) 141 return (DLADM_STATUS_NOMEM); 142 143 status = DLADM_STATUS_FAILED; 144 if (scf_handle_bind(sstate->ss_handle) != 0) 145 goto failure; 146 sstate->ss_svc = scf_service_create(sstate->ss_handle); 147 if (sstate->ss_svc == NULL) 148 goto failure; 149 if (scf_handle_decode_fmri(sstate->ss_handle, fmri, NULL, 150 sstate->ss_svc, NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) { 151 if (scf_error() == SCF_ERROR_NOT_FOUND) 152 status = DLADM_STATUS_OPTMISSING; 153 goto failure; 154 } 155 sstate->ss_inst = scf_instance_create(sstate->ss_handle); 156 if (sstate->ss_inst == NULL) 157 goto failure; 158 return (DLADM_STATUS_OK); 159 160 failure: 161 shut_down_scf(sstate); 162 return (status); 163 } 164 165 static void 166 drop_composed(scf_state_t *sstate) 167 { 168 scf_property_destroy(sstate->ss_prop); 169 scf_pg_destroy(sstate->ss_pg); 170 scf_snapshot_destroy(sstate->ss_snap); 171 } 172 173 /* 174 * This function sets up a composed view of the configuration information for 175 * the specified instance. When this is done, the get_property() function 176 * should be able to return individual parameters. 177 */ 178 static int 179 get_composed_properties(const char *lpg, boolean_t snap, scf_state_t *sstate) 180 { 181 sstate->ss_snap = NULL; 182 sstate->ss_pg = NULL; 183 sstate->ss_prop = NULL; 184 185 if (snap) { 186 sstate->ss_snap = scf_snapshot_create(sstate->ss_handle); 187 if (sstate->ss_snap == NULL) 188 goto failure; 189 if (scf_instance_get_snapshot(sstate->ss_inst, "running", 190 sstate->ss_snap) != 0) 191 goto failure; 192 } 193 if ((sstate->ss_pg = scf_pg_create(sstate->ss_handle)) == NULL) 194 goto failure; 195 if (scf_instance_get_pg_composed(sstate->ss_inst, sstate->ss_snap, lpg, 196 sstate->ss_pg) != 0) 197 goto failure; 198 if ((sstate->ss_prop = scf_property_create(sstate->ss_handle)) == 199 NULL) 200 goto failure; 201 return (0); 202 203 failure: 204 drop_composed(sstate); 205 return (-1); 206 } 207 208 static int 209 get_count(const char *lprop, scf_state_t *sstate, uint64_t *answer) 210 { 211 scf_value_t *val; 212 int retv; 213 214 if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 215 return (-1); 216 if ((val = scf_value_create(sstate->ss_handle)) == NULL) 217 return (-1); 218 219 if (scf_property_get_value(sstate->ss_prop, val) == 0 && 220 scf_value_get_count(val, answer) == 0) 221 retv = 0; 222 else 223 retv = -1; 224 scf_value_destroy(val); 225 return (retv); 226 } 227 228 static int 229 get_boolean(const char *lprop, scf_state_t *sstate, boolean_t *answer) 230 { 231 scf_value_t *val; 232 int retv; 233 uint8_t bval; 234 235 if (scf_pg_get_property(sstate->ss_pg, lprop, sstate->ss_prop) != 0) 236 return (-1); 237 if ((val = scf_value_create(sstate->ss_handle)) == NULL) 238 return (-1); 239 240 if (scf_property_get_value(sstate->ss_prop, val) == 0 && 241 scf_value_get_boolean(val, &bval) == 0) { 242 retv = 0; 243 *answer = bval != 0; 244 } else { 245 retv = -1; 246 } 247 scf_value_destroy(val); 248 return (retv); 249 } 250 251 static dladm_status_t 252 bridge_door_call(const char *instname, bridge_door_type_t dtype, 253 datalink_id_t linkid, void **bufp, size_t inlen, size_t *buflenp, 254 boolean_t is_list) 255 { 256 char doorname[MAXPATHLEN]; 257 int did, retv, etmp; 258 bridge_door_cmd_t *bdc; 259 door_arg_t arg; 260 261 (void) snprintf(doorname, sizeof (doorname), "%s/%s", DOOR_DIRNAME, 262 instname); 263 264 /* Knock on the door */ 265 did = open(doorname, O_RDONLY | O_NOFOLLOW | O_NONBLOCK); 266 if (did == -1) 267 return (dladm_errno2status(errno)); 268 269 if ((bdc = malloc(sizeof (*bdc) + inlen)) == NULL) { 270 (void) close(did); 271 return (DLADM_STATUS_NOMEM); 272 } 273 bdc->bdc_type = dtype; 274 bdc->bdc_linkid = linkid; 275 if (inlen != 0) 276 (void) memcpy(bdc + 1, *bufp, inlen); 277 278 (void) memset(&arg, 0, sizeof (arg)); 279 arg.data_ptr = (char *)bdc; 280 arg.data_size = sizeof (*bdc) + inlen; 281 arg.rbuf = *bufp; 282 arg.rsize = *buflenp; 283 284 /* The door_call function doesn't restart, so take care of that */ 285 do { 286 errno = 0; 287 if ((retv = door_call(did, &arg)) == 0) 288 break; 289 } while (errno == EINTR); 290 291 /* If we get an unexpected response, then return an error */ 292 if (retv == 0) { 293 /* The daemon returns a single int for errors */ 294 /* LINTED: pointer alignment */ 295 if (arg.data_size == sizeof (int) && *(int *)arg.rbuf != 0) { 296 retv = -1; 297 /* LINTED: pointer alignment */ 298 errno = *(int *)arg.rbuf; 299 } 300 /* Terminated daemon returns with zero data */ 301 if (arg.data_size == 0) { 302 retv = -1; 303 errno = EBADF; 304 } 305 } 306 307 if (retv == 0) { 308 if (arg.rbuf != *bufp) { 309 if (is_list) { 310 void *newp; 311 312 newp = realloc(*bufp, arg.data_size); 313 if (newp == NULL) { 314 retv = -1; 315 } else { 316 *bufp = newp; 317 (void) memcpy(*bufp, arg.rbuf, 318 arg.data_size); 319 } 320 } 321 (void) munmap(arg.rbuf, arg.rsize); 322 } 323 if (is_list) { 324 *buflenp = arg.data_size; 325 } else if (arg.data_size != *buflenp || arg.rbuf != *bufp) { 326 errno = EINVAL; 327 retv = -1; 328 } 329 } 330 331 etmp = errno; 332 (void) close(did); 333 334 /* Revoked door is the same as no door at all */ 335 if (etmp == EBADF) 336 etmp = ENOENT; 337 338 return (retv == 0 ? DLADM_STATUS_OK : dladm_errno2status(etmp)); 339 } 340 341 /* 342 * Wrapper function for making per-port calls. 343 */ 344 static dladm_status_t 345 port_door_call(dladm_handle_t handle, datalink_id_t linkid, 346 bridge_door_type_t dtype, void *buf, size_t inlen, size_t buflen) 347 { 348 char bridge[MAXLINKNAMELEN]; 349 dladm_status_t status; 350 351 status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 352 if (status != DLADM_STATUS_OK) 353 return (status); 354 return (bridge_door_call(bridge, dtype, linkid, &buf, inlen, &buflen, 355 B_FALSE)); 356 } 357 358 static dladm_status_t 359 bridge_refresh(const char *bridge) 360 { 361 dladm_status_t status; 362 int twoints[2]; 363 void *bdptr; 364 size_t buflen; 365 char *fmri; 366 int refresh_count; 367 368 buflen = sizeof (twoints); 369 bdptr = twoints; 370 status = bridge_door_call(bridge, bdcBridgeGetRefreshCount, 371 DATALINK_INVALID_LINKID, &bdptr, 0, &buflen, B_FALSE); 372 if (status == DLADM_STATUS_NOTFOUND) 373 return (DLADM_STATUS_OK); 374 if (status != DLADM_STATUS_OK) 375 return (status); 376 refresh_count = twoints[0]; 377 if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, bridge)) == NULL) 378 return (DLADM_STATUS_NOMEM); 379 status = smf_refresh_instance(fmri) == 0 ? 380 DLADM_STATUS_OK : DLADM_STATUS_FAILED; 381 free(fmri); 382 if (status == DLADM_STATUS_OK) { 383 int i = 0; 384 385 /* 386 * SMF doesn't give any synchronous behavior or dependency 387 * ordering for refresh operations, so we have to invent our 388 * own mechanism here. Get the refresh counter from the 389 * daemon, and wait for it to change. It's not pretty, but 390 * it's sufficient. 391 */ 392 while (++i <= 10) { 393 buflen = sizeof (twoints); 394 bdptr = twoints; 395 status = bridge_door_call(bridge, 396 bdcBridgeGetRefreshCount, DATALINK_INVALID_LINKID, 397 &bdptr, 0, &buflen, B_FALSE); 398 if (status != DLADM_STATUS_OK) 399 break; 400 if (twoints[0] != refresh_count) 401 break; 402 (void) usleep(100000); 403 } 404 fmri = alloc_fmri(TRILL_SVC_NAME, bridge); 405 if (fmri == NULL) 406 return (DLADM_STATUS_NOMEM); 407 status = smf_refresh_instance(fmri) == 0 || 408 scf_error() == SCF_ERROR_NOT_FOUND ? 409 DLADM_STATUS_OK : DLADM_STATUS_FAILED; 410 free(fmri); 411 } 412 return (status); 413 } 414 415 /* 416 * Look up bridge property values from SCF and return them. 417 */ 418 dladm_status_t 419 dladm_bridge_get_properties(const char *instance_name, UID_STP_CFG_T *cfg, 420 dladm_bridge_prot_t *brprotp) 421 { 422 scf_state_t sstate; 423 uint64_t value; 424 boolean_t trill_enabled; 425 426 cfg->field_mask = 0; 427 cfg->bridge_priority = DEF_BR_PRIO; 428 cfg->max_age = DEF_BR_MAXAGE; 429 cfg->hello_time = DEF_BR_HELLOT; 430 cfg->forward_delay = DEF_BR_FWDELAY; 431 cfg->force_version = DEF_FORCE_VERS; 432 433 (void) strlcpy(cfg->vlan_name, instance_name, sizeof (cfg->vlan_name)); 434 435 *brprotp = DLADM_BRIDGE_PROT_STP; 436 437 /* It's ok for this to be missing; it's installed separately */ 438 if (bind_instance(TRILL_SVC_NAME, instance_name, &sstate) == 0) { 439 trill_enabled = B_FALSE; 440 if (get_composed_properties(SCF_PG_GENERAL, B_FALSE, &sstate) == 441 0) { 442 (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 443 &trill_enabled); 444 if (trill_enabled) 445 *brprotp = DLADM_BRIDGE_PROT_TRILL; 446 drop_composed(&sstate); 447 } 448 if (get_composed_properties(SCF_PG_GENERAL_OVR, B_FALSE, 449 &sstate) == 0) { 450 (void) get_boolean(SCF_PROPERTY_ENABLED, &sstate, 451 &trill_enabled); 452 if (trill_enabled) 453 *brprotp = DLADM_BRIDGE_PROT_TRILL; 454 drop_composed(&sstate); 455 } 456 shut_down_scf(&sstate); 457 } 458 459 cfg->stp_enabled = (*brprotp == DLADM_BRIDGE_PROT_STP) ? 460 STP_ENABLED : STP_DISABLED; 461 cfg->field_mask |= BR_CFG_STATE; 462 463 if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 464 return (DLADM_STATUS_REPOSITORYINVAL); 465 466 if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 467 shut_down_scf(&sstate); 468 return (DLADM_STATUS_REPOSITORYINVAL); 469 } 470 471 if (get_count("priority", &sstate, &value) == 0) { 472 cfg->bridge_priority = value; 473 cfg->field_mask |= BR_CFG_PRIO; 474 } 475 if (get_count("max-age", &sstate, &value) == 0) { 476 cfg->max_age = value / IEEE_TIMER_SCALE; 477 cfg->field_mask |= BR_CFG_AGE; 478 } 479 if (get_count("hello-time", &sstate, &value) == 0) { 480 cfg->hello_time = value / IEEE_TIMER_SCALE; 481 cfg->field_mask |= BR_CFG_HELLO; 482 } 483 if (get_count("forward-delay", &sstate, &value) == 0) { 484 cfg->forward_delay = value / IEEE_TIMER_SCALE; 485 cfg->field_mask |= BR_CFG_DELAY; 486 } 487 if (get_count("force-protocol", &sstate, &value) == 0) { 488 cfg->force_version = value; 489 cfg->field_mask |= BR_CFG_FORCE_VER; 490 } 491 492 drop_composed(&sstate); 493 shut_down_scf(&sstate); 494 return (DLADM_STATUS_OK); 495 } 496 497 /* 498 * Retrieve special non-settable and undocumented parameters. 499 */ 500 dladm_status_t 501 dladm_bridge_get_privprop(const char *instance_name, boolean_t *debugp, 502 uint32_t *tablemaxp) 503 { 504 scf_state_t sstate; 505 uint64_t value; 506 507 *debugp = B_FALSE; 508 *tablemaxp = 10000; 509 510 if (bind_instance(BRIDGE_SVC_NAME, instance_name, &sstate) != 0) 511 return (DLADM_STATUS_REPOSITORYINVAL); 512 513 if (get_composed_properties("config", B_TRUE, &sstate) != 0) { 514 shut_down_scf(&sstate); 515 return (DLADM_STATUS_REPOSITORYINVAL); 516 } 517 518 (void) get_boolean("debug", &sstate, debugp); 519 if (get_count("table-maximum", &sstate, &value) == 0) 520 *tablemaxp = (uint32_t)value; 521 522 drop_composed(&sstate); 523 shut_down_scf(&sstate); 524 return (DLADM_STATUS_OK); 525 } 526 527 static boolean_t 528 set_count_property(scf_handle_t *handle, scf_transaction_t *tran, 529 const char *propname, uint64_t propval) 530 { 531 scf_transaction_entry_t *entry; 532 scf_value_t *value = NULL; 533 534 if ((entry = scf_entry_create(handle)) == NULL) 535 return (B_FALSE); 536 537 if ((value = scf_value_create(handle)) == NULL) 538 goto out; 539 if (scf_transaction_property_new(tran, entry, propname, 540 SCF_TYPE_COUNT) != 0 && 541 scf_transaction_property_change(tran, entry, propname, 542 SCF_TYPE_COUNT) != 0) 543 goto out; 544 scf_value_set_count(value, propval); 545 if (scf_entry_add_value(entry, value) == 0) 546 return (B_TRUE); 547 548 out: 549 if (value != NULL) 550 scf_value_destroy(value); 551 552 scf_entry_destroy_children(entry); 553 scf_entry_destroy(entry); 554 555 return (B_FALSE); 556 } 557 558 static boolean_t 559 set_string_property(scf_handle_t *handle, scf_transaction_t *tran, 560 const char *propname, const char *propval) 561 { 562 scf_transaction_entry_t *entry; 563 scf_value_t *value = NULL; 564 565 if ((entry = scf_entry_create(handle)) == NULL) 566 return (B_FALSE); 567 568 if ((value = scf_value_create(handle)) == NULL) 569 goto out; 570 if (scf_transaction_property_new(tran, entry, propname, 571 SCF_TYPE_ASTRING) != 0 && 572 scf_transaction_property_change(tran, entry, propname, 573 SCF_TYPE_ASTRING) != 0) 574 goto out; 575 if (scf_value_set_astring(value, propval) != 0) 576 goto out; 577 if (scf_entry_add_value(entry, value) == 0) 578 return (B_TRUE); 579 580 out: 581 if (value != NULL) 582 scf_value_destroy(value); 583 584 scf_entry_destroy_children(entry); 585 scf_entry_destroy(entry); 586 587 return (B_FALSE); 588 } 589 590 static boolean_t 591 set_fmri_property(scf_handle_t *handle, scf_transaction_t *tran, 592 const char *propname, const char *propval) 593 { 594 scf_transaction_entry_t *entry; 595 scf_value_t *value = NULL; 596 597 if ((entry = scf_entry_create(handle)) == NULL) 598 return (B_FALSE); 599 600 if ((value = scf_value_create(handle)) == NULL) 601 goto out; 602 if (scf_transaction_property_new(tran, entry, propname, 603 SCF_TYPE_FMRI) != 0 && 604 scf_transaction_property_change(tran, entry, propname, 605 SCF_TYPE_FMRI) != 0) 606 goto out; 607 if (scf_value_set_from_string(value, SCF_TYPE_FMRI, propval) != 0) 608 goto out; 609 if (scf_entry_add_value(entry, value) == 0) 610 return (B_TRUE); 611 612 out: 613 if (value != NULL) 614 scf_value_destroy(value); 615 616 scf_entry_destroy_children(entry); 617 scf_entry_destroy(entry); 618 619 return (B_FALSE); 620 } 621 622 static dladm_status_t 623 dladm_bridge_persist_conf(dladm_handle_t handle, const char *link, 624 datalink_id_t linkid) 625 { 626 dladm_conf_t conf; 627 dladm_status_t status; 628 629 status = dladm_create_conf(handle, link, linkid, DATALINK_CLASS_BRIDGE, 630 DL_ETHER, &conf); 631 if (status == DLADM_STATUS_OK) { 632 /* 633 * Create the datalink entry for the bridge. Note that all of 634 * the real configuration information is in SMF. 635 */ 636 status = dladm_write_conf(handle, conf); 637 dladm_destroy_conf(handle, conf); 638 } 639 return (status); 640 } 641 642 /* Convert bridge protection option string to dladm_bridge_prot_t */ 643 dladm_status_t 644 dladm_bridge_str2prot(const char *str, dladm_bridge_prot_t *brprotp) 645 { 646 if (strcmp(str, "stp") == 0) 647 *brprotp = DLADM_BRIDGE_PROT_STP; 648 else if (strcmp(str, "trill") == 0) 649 *brprotp = DLADM_BRIDGE_PROT_TRILL; 650 else 651 return (DLADM_STATUS_BADARG); 652 return (DLADM_STATUS_OK); 653 } 654 655 /* Convert bridge protection option from dladm_bridge_prot_t to string */ 656 const char * 657 dladm_bridge_prot2str(dladm_bridge_prot_t brprot) 658 { 659 switch (brprot) { 660 case DLADM_BRIDGE_PROT_STP: 661 return ("stp"); 662 case DLADM_BRIDGE_PROT_TRILL: 663 return ("trill"); 664 default: 665 return ("unknown"); 666 } 667 } 668 669 static dladm_status_t 670 enable_instance(const char *service_name, const char *instance) 671 { 672 dladm_status_t status; 673 char *fmri = alloc_fmri(service_name, instance); 674 675 if (fmri == NULL) 676 return (DLADM_STATUS_NOMEM); 677 status = smf_enable_instance(fmri, 0) == 0 ? 678 DLADM_STATUS_OK : DLADM_STATUS_FAILED; 679 free(fmri); 680 return (status); 681 } 682 683 /* 684 * Shut down a possibly-running service instance. If this is a permanent 685 * change, then delete it from the system. 686 */ 687 static dladm_status_t 688 shut_down_instance(const char *service_name, const char *instance, 689 uint32_t flags) 690 { 691 dladm_status_t status; 692 char *fmri = alloc_fmri(service_name, instance); 693 char *state; 694 scf_state_t sstate; 695 696 if (fmri == NULL) 697 return (DLADM_STATUS_NOMEM); 698 699 if (smf_disable_instance(fmri, 700 flags & DLADM_OPT_PERSIST ? 0 : SMF_TEMPORARY) == 0) { 701 useconds_t usecs, umax; 702 703 /* If we can disable, then wait for it to happen. */ 704 umax = DEFAULT_TIMEOUT; 705 for (usecs = INIT_WAIT_USECS; umax != 0; umax -= usecs) { 706 state = smf_get_state(fmri); 707 if (state != NULL && 708 strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 709 break; 710 free(state); 711 usecs *= 2; 712 if (usecs > umax) 713 usecs = umax; 714 (void) usleep(usecs); 715 } 716 if (umax == 0) { 717 state = smf_get_state(fmri); 718 if (state != NULL && 719 strcmp(state, SCF_STATE_STRING_DISABLED) == 0) 720 umax = 1; 721 } 722 free(state); 723 status = umax != 0 ? DLADM_STATUS_OK : DLADM_STATUS_FAILED; 724 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 725 free(fmri); 726 return (DLADM_STATUS_OK); 727 } else { 728 status = DLADM_STATUS_FAILED; 729 } 730 731 free(fmri); 732 if (status == DLADM_STATUS_OK && (flags & DLADM_OPT_PERSIST) && 733 bind_instance(service_name, instance, &sstate) == 0) { 734 (void) scf_instance_delete(sstate.ss_inst); 735 shut_down_scf(&sstate); 736 } 737 738 return (status); 739 } 740 741 static dladm_status_t 742 disable_trill(const char *instance, uint32_t flags) 743 { 744 return (shut_down_instance(TRILL_SVC_NAME, instance, flags)); 745 } 746 747 /* 748 * To enable TRILL, we must create a new instance of the TRILL service, then 749 * add proper dependencies to it, and finally mark it as enabled. The 750 * dependencies will keep it from going on-line until the bridge is running. 751 */ 752 static dladm_status_t 753 enable_trill(const char *instance) 754 { 755 dladm_status_t status = DLADM_STATUS_FAILED; 756 char *fmri = NULL; 757 scf_state_t sstate; 758 scf_transaction_t *tran = NULL; 759 boolean_t new_instance = B_FALSE; 760 boolean_t new_pg = B_FALSE; 761 int rv; 762 763 /* 764 * This check is here in case the user has installed and then removed 765 * the package. SMF should remove the manifest, but currently does 766 * not. 767 */ 768 if (access("/usr/sbin/trilld", F_OK) != 0) 769 return (DLADM_STATUS_OPTMISSING); 770 771 if ((status = exact_instance(TRILL_SVC_NAME, &sstate)) != 772 DLADM_STATUS_OK) 773 goto out; 774 775 status = DLADM_STATUS_FAILED; 776 if (scf_service_get_instance(sstate.ss_svc, instance, sstate.ss_inst) != 777 0) { 778 if (scf_service_add_instance(sstate.ss_svc, instance, 779 sstate.ss_inst) != 0) 780 goto out; 781 new_instance = B_TRUE; 782 } 783 784 if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 785 goto out; 786 787 if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 788 goto out; 789 790 if (scf_instance_get_pg(sstate.ss_inst, "bridging", 791 sstate.ss_pg) == 0) { 792 status = DLADM_STATUS_OK; 793 goto out; 794 } 795 796 if ((fmri = alloc_fmri(BRIDGE_SVC_NAME, instance)) == NULL) 797 goto out; 798 799 if (scf_instance_add_pg(sstate.ss_inst, "bridging", 800 SCF_GROUP_DEPENDENCY, 0, sstate.ss_pg) != 0) 801 goto out; 802 803 new_pg = B_TRUE; 804 do { 805 if (scf_transaction_start(tran, sstate.ss_pg) != 0) 806 goto out; 807 808 if (!set_string_property(sstate.ss_handle, tran, 809 SCF_PROPERTY_GROUPING, SCF_DEP_REQUIRE_ALL)) 810 goto out; 811 if (!set_string_property(sstate.ss_handle, tran, 812 SCF_PROPERTY_RESTART_ON, SCF_DEP_RESET_ON_RESTART)) 813 goto out; 814 if (!set_string_property(sstate.ss_handle, tran, 815 SCF_PROPERTY_TYPE, "service")) 816 goto out; 817 if (!set_fmri_property(sstate.ss_handle, tran, 818 SCF_PROPERTY_ENTITIES, fmri)) 819 goto out; 820 821 rv = scf_transaction_commit(tran); 822 scf_transaction_reset(tran); 823 if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 824 goto out; 825 } while (rv == 0); 826 if (rv != 1) 827 goto out; 828 829 status = DLADM_STATUS_OK; 830 831 out: 832 free(fmri); 833 if (tran != NULL) { 834 scf_transaction_destroy_children(tran); 835 scf_transaction_destroy(tran); 836 } 837 838 if (status != DLADM_STATUS_OK && new_pg) 839 (void) scf_pg_delete(sstate.ss_pg); 840 841 drop_composed(&sstate); 842 843 /* 844 * If we created an instance and then failed, then remove the instance 845 * from the system. 846 */ 847 if (status != DLADM_STATUS_OK && new_instance) 848 (void) scf_instance_delete(sstate.ss_inst); 849 850 shut_down_scf(&sstate); 851 852 if (status == DLADM_STATUS_OK) 853 status = enable_instance(TRILL_SVC_NAME, instance); 854 855 return (status); 856 } 857 858 /* 859 * Create a new bridge or modify an existing one. Update the SMF configuration 860 * and add links. 861 * 862 * Input timer values are in IEEE scaled (* 256) format. 863 */ 864 dladm_status_t 865 dladm_bridge_configure(dladm_handle_t handle, const char *name, 866 const UID_STP_CFG_T *cfg, dladm_bridge_prot_t brprot, uint32_t flags) 867 { 868 dladm_status_t status; 869 scf_state_t sstate; 870 scf_transaction_t *tran = NULL; 871 boolean_t new_instance = B_FALSE; 872 boolean_t new_pg = B_FALSE; 873 datalink_id_t linkid = DATALINK_INVALID_LINKID; 874 char linkname[MAXLINKNAMELEN]; 875 int rv; 876 877 if (!dladm_valid_bridgename(name)) 878 return (DLADM_STATUS_FAILED); 879 880 if (flags & DLADM_OPT_CREATE) { 881 /* 882 * This check is here in case the user has installed and then 883 * removed the package. SMF should remove the manifest, but 884 * currently does not. 885 */ 886 if (access("/usr/lib/bridged", F_OK) != 0) 887 return (DLADM_STATUS_OPTMISSING); 888 889 (void) snprintf(linkname, sizeof (linkname), "%s0", name); 890 status = dladm_create_datalink_id(handle, linkname, 891 DATALINK_CLASS_BRIDGE, DL_ETHER, 892 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &linkid); 893 if (status != DLADM_STATUS_OK) 894 return (status); 895 896 if ((flags & DLADM_OPT_PERSIST) && 897 (status = dladm_bridge_persist_conf(handle, linkname, 898 linkid) != DLADM_STATUS_OK)) 899 goto dladm_fail; 900 } 901 902 if (brprot == DLADM_BRIDGE_PROT_TRILL) 903 status = enable_trill(name); 904 else 905 status = disable_trill(name, flags); 906 if (status != DLADM_STATUS_OK) 907 goto dladm_fail; 908 909 if ((status = exact_instance(BRIDGE_SVC_NAME, &sstate)) != 910 DLADM_STATUS_OK) 911 goto out; 912 913 /* set up for a series of scf calls */ 914 status = DLADM_STATUS_FAILED; 915 916 if (scf_service_get_instance(sstate.ss_svc, name, sstate.ss_inst) == 917 0) { 918 if (flags & DLADM_OPT_CREATE) { 919 status = DLADM_STATUS_EXIST; 920 goto out; 921 } 922 } else { 923 if (!(flags & DLADM_OPT_CREATE)) { 924 status = DLADM_STATUS_NOTFOUND; 925 goto out; 926 } 927 if (scf_service_add_instance(sstate.ss_svc, name, 928 sstate.ss_inst) != 0) 929 goto out; 930 new_instance = B_TRUE; 931 } 932 933 if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 934 goto out; 935 936 if (cfg->field_mask & (BR_CFG_ALL)) { 937 if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 938 goto out; 939 if (scf_instance_add_pg(sstate.ss_inst, "config", 940 SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 941 new_pg = B_TRUE; 942 } else if (scf_instance_get_pg(sstate.ss_inst, "config", 943 sstate.ss_pg) != 0) { 944 goto out; 945 } 946 do { 947 if (scf_transaction_start(tran, sstate.ss_pg) != 0) 948 goto out; 949 950 if ((cfg->field_mask & BR_CFG_PRIO) && 951 !set_count_property(sstate.ss_handle, tran, 952 "priority", cfg->bridge_priority)) 953 goto out; 954 if ((cfg->field_mask & BR_CFG_AGE) && 955 !set_count_property(sstate.ss_handle, tran, 956 "max-age", cfg->max_age * IEEE_TIMER_SCALE)) 957 goto out; 958 if ((cfg->field_mask & BR_CFG_HELLO) && 959 !set_count_property(sstate.ss_handle, tran, 960 "hello-time", cfg->hello_time * IEEE_TIMER_SCALE)) 961 goto out; 962 if ((cfg->field_mask & BR_CFG_DELAY) && 963 !set_count_property(sstate.ss_handle, tran, 964 "forward-delay", 965 cfg->forward_delay * IEEE_TIMER_SCALE)) 966 goto out; 967 if ((cfg->field_mask & BR_CFG_FORCE_VER) && 968 !set_count_property(sstate.ss_handle, tran, 969 "force-protocol", cfg->force_version)) 970 goto out; 971 972 rv = scf_transaction_commit(tran); 973 scf_transaction_reset(tran); 974 if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 975 goto out; 976 } while (rv == 0); 977 if (rv != 1) 978 goto out; 979 } 980 981 /* 982 * If we're modifying an existing and running bridge, then tell the 983 * daemon to update the requested values. 984 */ 985 if ((flags & DLADM_OPT_ACTIVE) && !(flags & DLADM_OPT_CREATE)) 986 status = bridge_refresh(name); 987 else 988 status = DLADM_STATUS_OK; 989 990 out: 991 if (tran != NULL) { 992 scf_transaction_destroy_children(tran); 993 scf_transaction_destroy(tran); 994 } 995 996 if (status != DLADM_STATUS_OK && new_pg) 997 (void) scf_pg_delete(sstate.ss_pg); 998 999 drop_composed(&sstate); 1000 1001 /* 1002 * If we created an instance and then failed, then remove the instance 1003 * from the system. 1004 */ 1005 if (status != DLADM_STATUS_OK && new_instance) 1006 (void) scf_instance_delete(sstate.ss_inst); 1007 1008 shut_down_scf(&sstate); 1009 1010 /* 1011 * Remove the bridge linkid if we've allocated one in this function but 1012 * we've failed to set up the SMF properties. 1013 */ 1014 dladm_fail: 1015 if (status != DLADM_STATUS_OK && linkid != DATALINK_INVALID_LINKID) { 1016 (void) dladm_remove_conf(handle, linkid); 1017 (void) dladm_destroy_datalink_id(handle, linkid, flags); 1018 } 1019 1020 return (status); 1021 } 1022 1023 /* 1024 * Enable a newly-created bridge in SMF by creating "general/enabled" and 1025 * deleting any "general_ovr/enabled" (used for temporary services). 1026 */ 1027 dladm_status_t 1028 dladm_bridge_enable(const char *name) 1029 { 1030 return (enable_instance(BRIDGE_SVC_NAME, name)); 1031 } 1032 1033 /* 1034 * Set a link as a member of a bridge, or remove bridge membership. If the 1035 * DLADM_OPT_CREATE flag is set, then we assume that the daemon isn't running. 1036 * In all other cases, we must tell the daemon to add or delete the link in 1037 * order to stay in sync. 1038 */ 1039 dladm_status_t 1040 dladm_bridge_setlink(dladm_handle_t handle, datalink_id_t linkid, 1041 const char *bridge) 1042 { 1043 dladm_status_t status; 1044 dladm_conf_t conf; 1045 char oldbridge[MAXLINKNAMELEN]; 1046 boolean_t has_oldbridge; 1047 boolean_t changed = B_FALSE; 1048 1049 if (*bridge != '\0' && !dladm_valid_bridgename(bridge)) 1050 return (DLADM_STATUS_FAILED); 1051 1052 status = dladm_open_conf(handle, linkid, &conf); 1053 if (status != DLADM_STATUS_OK) 1054 return (status); 1055 1056 has_oldbridge = B_FALSE; 1057 status = dladm_get_conf_field(handle, conf, FBRIDGE, oldbridge, 1058 sizeof (oldbridge)); 1059 if (status == DLADM_STATUS_OK) { 1060 /* 1061 * Don't allow a link to be reassigned directly from one bridge 1062 * to another. It must be removed first. 1063 */ 1064 if (*oldbridge != '\0' && *bridge != '\0') { 1065 status = DLADM_STATUS_EXIST; 1066 goto out; 1067 } 1068 has_oldbridge = B_TRUE; 1069 } else if (status != DLADM_STATUS_NOTFOUND) { 1070 goto out; 1071 } 1072 1073 if (*bridge != '\0') { 1074 status = dladm_set_conf_field(handle, conf, FBRIDGE, 1075 DLADM_TYPE_STR, bridge); 1076 changed = B_TRUE; 1077 } else if (has_oldbridge) { 1078 status = dladm_unset_conf_field(handle, conf, FBRIDGE); 1079 changed = B_TRUE; 1080 } else { 1081 status = DLADM_STATUS_OK; 1082 goto out; 1083 } 1084 if (status == DLADM_STATUS_OK) 1085 status = dladm_write_conf(handle, conf); 1086 1087 out: 1088 dladm_destroy_conf(handle, conf); 1089 if (changed && status == DLADM_STATUS_OK) { 1090 if (bridge[0] == '\0') 1091 bridge = oldbridge; 1092 status = bridge_refresh(bridge); 1093 } 1094 return (status); 1095 } 1096 1097 /* 1098 * Get the name of the bridge of which the given linkid is a member. 1099 */ 1100 dladm_status_t 1101 dladm_bridge_getlink(dladm_handle_t handle, datalink_id_t linkid, char *bridge, 1102 size_t bridgelen) 1103 { 1104 dladm_status_t status; 1105 dladm_conf_t conf; 1106 1107 if ((status = dladm_getsnap_conf(handle, linkid, &conf)) != 1108 DLADM_STATUS_OK) 1109 return (status); 1110 1111 *bridge = '\0'; 1112 status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, bridgelen); 1113 if (status == DLADM_STATUS_OK && *bridge == '\0') 1114 status = DLADM_STATUS_NOTFOUND; 1115 1116 dladm_destroy_conf(handle, conf); 1117 return (status); 1118 } 1119 1120 dladm_status_t 1121 dladm_bridge_refresh(dladm_handle_t handle, datalink_id_t linkid) 1122 { 1123 char bridge[MAXLINKNAMELEN]; 1124 dladm_status_t status; 1125 1126 status = dladm_bridge_getlink(handle, linkid, bridge, sizeof (bridge)); 1127 if (status == DLADM_STATUS_NOTFOUND) 1128 return (DLADM_STATUS_OK); 1129 if (status == DLADM_STATUS_OK) 1130 status = bridge_refresh(bridge); 1131 return (status); 1132 } 1133 1134 typedef struct bridge_held_arg_s { 1135 const char *bha_bridge; 1136 boolean_t bha_isheld; 1137 } bridge_held_arg_t; 1138 1139 static int 1140 i_dladm_bridge_is_held(dladm_handle_t handle, datalink_id_t linkid, void *arg) 1141 { 1142 dladm_status_t status = DLADM_STATUS_FAILED; 1143 dladm_conf_t conf; 1144 char bridge[MAXLINKNAMELEN]; 1145 bridge_held_arg_t *bha = arg; 1146 1147 if ((status = dladm_getsnap_conf(handle, linkid, &conf)) != 1148 DLADM_STATUS_OK) 1149 return (DLADM_WALK_CONTINUE); 1150 status = dladm_get_conf_field(handle, conf, FBRIDGE, bridge, 1151 sizeof (bridge)); 1152 if (status == DLADM_STATUS_OK && strcmp(bha->bha_bridge, bridge) == 0) { 1153 bha->bha_isheld = B_TRUE; 1154 dladm_destroy_conf(handle, conf); 1155 return (DLADM_WALK_TERMINATE); 1156 } else { 1157 dladm_destroy_conf(handle, conf); 1158 return (DLADM_WALK_CONTINUE); 1159 } 1160 } 1161 1162 /* 1163 * Delete a previously created bridge. 1164 */ 1165 dladm_status_t 1166 dladm_bridge_delete(dladm_handle_t handle, const char *bridge, uint32_t flags) 1167 { 1168 datalink_id_t linkid; 1169 datalink_class_t class; 1170 dladm_status_t status; 1171 char linkname[MAXLINKNAMELEN]; 1172 1173 if (!dladm_valid_bridgename(bridge)) 1174 return (DLADM_STATUS_LINKINVAL); 1175 1176 /* Get the datalink ID for this bridge */ 1177 (void) snprintf(linkname, sizeof (linkname), "%s0", bridge); 1178 if (dladm_name2info(handle, linkname, &linkid, NULL, NULL, NULL) != 1179 DLADM_STATUS_OK) 1180 linkid = DATALINK_INVALID_LINKID; 1181 else if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 1182 NULL, 0) != DLADM_STATUS_OK) 1183 linkid = DATALINK_INVALID_LINKID; 1184 else if (class != DATALINK_CLASS_BRIDGE) 1185 return (DLADM_STATUS_BADARG); 1186 1187 if ((flags & DLADM_OPT_ACTIVE) && linkid == DATALINK_INVALID_LINKID) 1188 return (DLADM_STATUS_BADARG); 1189 1190 if (flags & DLADM_OPT_PERSIST) { 1191 bridge_held_arg_t arg; 1192 1193 arg.bha_bridge = bridge; 1194 arg.bha_isheld = B_FALSE; 1195 1196 /* 1197 * See whether there are any persistent links using this 1198 * bridge. If so, we fail the operation. 1199 */ 1200 (void) dladm_walk_datalink_id(i_dladm_bridge_is_held, handle, 1201 &arg, DATALINK_CLASS_PHYS | DATALINK_CLASS_AGGR | 1202 DATALINK_CLASS_ETHERSTUB | DATALINK_CLASS_SIMNET, 1203 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 1204 if (arg.bha_isheld) 1205 return (DLADM_STATUS_LINKBUSY); 1206 } 1207 1208 if ((status = disable_trill(bridge, flags)) != DLADM_STATUS_OK) 1209 goto out; 1210 1211 /* Disable or remove the SMF instance */ 1212 status = shut_down_instance(BRIDGE_SVC_NAME, bridge, flags); 1213 if (status != DLADM_STATUS_OK) 1214 goto out; 1215 1216 if (flags & DLADM_OPT_ACTIVE) { 1217 /* 1218 * Delete ACTIVE linkprop now that daemon is gone. 1219 */ 1220 (void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0, 1221 DLADM_OPT_ACTIVE); 1222 (void) dladm_destroy_datalink_id(handle, linkid, 1223 DLADM_OPT_ACTIVE); 1224 } 1225 1226 if (flags & DLADM_OPT_PERSIST) { 1227 (void) dladm_remove_conf(handle, linkid); 1228 (void) dladm_destroy_datalink_id(handle, linkid, 1229 DLADM_OPT_PERSIST); 1230 } 1231 1232 out: 1233 1234 return (status); 1235 } 1236 1237 /* Check if given name is valid for bridges */ 1238 boolean_t 1239 dladm_valid_bridgename(const char *bridge) 1240 { 1241 size_t len = strnlen(bridge, MAXLINKNAMELEN); 1242 const char *cp; 1243 1244 if (len == MAXLINKNAMELEN) 1245 return (B_FALSE); 1246 1247 /* 1248 * The bridge name cannot start or end with a digit. 1249 */ 1250 if (isdigit(bridge[0]) || isdigit(bridge[len - 1])) 1251 return (B_FALSE); 1252 1253 /* 1254 * The legal characters within a bridge name are: 1255 * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 1256 */ 1257 for (cp = bridge; *cp != '\0'; cp++) { 1258 if (!isalnum(*cp) && *cp != '_') 1259 return (B_FALSE); 1260 } 1261 1262 return (B_TRUE); 1263 } 1264 1265 /* 1266 * Convert a bridge-related observability node name back into the name of the 1267 * bridge. Returns B_FALSE without making changes if the input name is not in 1268 * a legal format. 1269 */ 1270 boolean_t 1271 dladm_observe_to_bridge(char *link) 1272 { 1273 int llen; 1274 1275 llen = strnlen(link, MAXLINKNAMELEN); 1276 if (llen < 2 || link[llen - 1] != '0' || isdigit(link[llen - 2])) 1277 return (B_FALSE); 1278 link[llen - 1] = '\0'; 1279 return (B_TRUE); 1280 } 1281 1282 /* 1283 * Get bridge property values from the running daemon and return them in a 1284 * common structure. 1285 */ 1286 dladm_status_t 1287 dladm_bridge_run_properties(const char *instname, UID_STP_CFG_T *smcfg, 1288 dladm_bridge_prot_t *brprotp) 1289 { 1290 dladm_status_t status; 1291 bridge_door_cfg_t bdcf; 1292 bridge_door_cfg_t *bdcfp = &bdcf; 1293 size_t buflen = sizeof (bdcf); 1294 1295 status = bridge_door_call(instname, bdcBridgeGetConfig, 1296 DATALINK_INVALID_LINKID, (void **)&bdcfp, 0, &buflen, B_FALSE); 1297 if (status == DLADM_STATUS_OK) { 1298 *smcfg = bdcfp->bdcf_cfg; 1299 *brprotp = bdcfp->bdcf_prot; 1300 } else { 1301 smcfg->field_mask = 0; 1302 *brprotp = DLADM_BRIDGE_PROT_STP; 1303 } 1304 return (status); 1305 } 1306 1307 /* 1308 * Get bridge state from the running daemon and return in structure borrowed 1309 * from librstp. 1310 */ 1311 dladm_status_t 1312 dladm_bridge_state(const char *instname, UID_STP_STATE_T *statep) 1313 { 1314 size_t buflen = sizeof (*statep); 1315 1316 return (bridge_door_call(instname, bdcBridgeGetState, 1317 DATALINK_INVALID_LINKID, (void **)&statep, 0, &buflen, B_FALSE)); 1318 } 1319 1320 /* Returns list of ports (datalink_id_t values) assigned to a bridge instance */ 1321 datalink_id_t * 1322 dladm_bridge_get_portlist(const char *instname, uint_t *nports) 1323 { 1324 size_t buflen = sizeof (int) + MAXPORTS * sizeof (datalink_id_t); 1325 int *rbuf; 1326 1327 if ((rbuf = malloc(buflen)) == NULL) 1328 return (NULL); 1329 if (bridge_door_call(instname, bdcBridgeGetPorts, 1330 DATALINK_INVALID_LINKID, (void **)&rbuf, 0, &buflen, B_TRUE) != 1331 DLADM_STATUS_OK) { 1332 free(rbuf); 1333 return (NULL); 1334 } else { 1335 /* 1336 * Returns an array of datalink_id_t values for all the ports 1337 * part of the bridge instance. First entry in the array is the 1338 * number of ports. 1339 */ 1340 *nports = *rbuf; 1341 return ((datalink_id_t *)(rbuf + 1)); 1342 } 1343 } 1344 1345 void 1346 dladm_bridge_free_portlist(datalink_id_t *dlp) 1347 { 1348 free((int *)dlp - 1); 1349 } 1350 1351 /* Retrieve Bridge port configuration values */ 1352 dladm_status_t 1353 dladm_bridge_get_port_cfg(dladm_handle_t handle, datalink_id_t linkid, 1354 int field, int *valuep) 1355 { 1356 UID_STP_PORT_CFG_T portcfg; 1357 dladm_status_t status; 1358 1359 status = port_door_call(handle, linkid, bdcPortGetConfig, &portcfg, 1360 0, sizeof (portcfg)); 1361 if (status != DLADM_STATUS_OK) 1362 return (status); 1363 1364 switch (field) { 1365 case PT_CFG_COST: 1366 *valuep = portcfg.admin_port_path_cost; 1367 break; 1368 case PT_CFG_PRIO: 1369 *valuep = portcfg.port_priority; 1370 break; 1371 case PT_CFG_P2P: 1372 *valuep = portcfg.admin_point2point; 1373 break; 1374 case PT_CFG_EDGE: 1375 *valuep = portcfg.admin_edge; 1376 break; 1377 case PT_CFG_NON_STP: 1378 *valuep = !portcfg.admin_non_stp; 1379 break; 1380 case PT_CFG_MCHECK: 1381 *valuep = (portcfg.field_mask & PT_CFG_MCHECK) ? 1 : 0; 1382 break; 1383 } 1384 return (status); 1385 } 1386 1387 /* Retreive Bridge port status (disabled, bad SDU etc.) */ 1388 dladm_status_t 1389 dladm_bridge_link_state(dladm_handle_t handle, datalink_id_t linkid, 1390 UID_STP_PORT_STATE_T *spsp) 1391 { 1392 return (port_door_call(handle, linkid, bdcPortGetState, spsp, 0, 1393 sizeof (*spsp))); 1394 } 1395 1396 /* Retrieve Bridge forwarding status of the given link */ 1397 dladm_status_t 1398 dladm_bridge_get_forwarding(dladm_handle_t handle, datalink_id_t linkid, 1399 uint_t *valuep) 1400 { 1401 int twoints[2]; 1402 dladm_status_t status; 1403 1404 status = port_door_call(handle, linkid, bdcPortGetForwarding, twoints, 1405 0, sizeof (twoints)); 1406 if (status == DLADM_STATUS_OK) 1407 *valuep = twoints[0]; 1408 return (status); 1409 } 1410 1411 /* Retrieve Bridge forwarding table entries */ 1412 bridge_listfwd_t * 1413 dladm_bridge_get_fwdtable(dladm_handle_t handle, const char *bridge, 1414 uint_t *nfwd) 1415 { 1416 bridge_listfwd_t *blf = NULL, *newblf, blfread; 1417 uint_t nblf = 0, maxblf = 0; 1418 static uint8_t zero_addr[ETHERADDRL]; 1419 int rc; 1420 1421 (void) memset(&blfread, 0, sizeof (blfread)); 1422 (void) snprintf(blfread.blf_name, sizeof (blfread.blf_name), 1423 "%s0", bridge); 1424 for (;;) { 1425 if (nblf >= maxblf) { 1426 maxblf = maxblf == 0 ? 64 : (maxblf << 1); 1427 newblf = realloc(blf, maxblf * sizeof (*blf)); 1428 if (newblf == NULL) { 1429 free(blf); 1430 blf = NULL; 1431 break; 1432 } 1433 blf = newblf; 1434 } 1435 rc = ioctl(dladm_dld_fd(handle), BRIDGE_IOC_LISTFWD, &blfread); 1436 if (rc != 0) { 1437 free(blf); 1438 blf = NULL; 1439 break; 1440 } 1441 if (memcmp(blfread.blf_dest, zero_addr, ETHERADDRL) == 0) 1442 break; 1443 blf[nblf++] = blfread; 1444 } 1445 if (blf != NULL) 1446 *nfwd = nblf; 1447 return (blf); 1448 } 1449 1450 void 1451 dladm_bridge_free_fwdtable(bridge_listfwd_t *blf) 1452 { 1453 free(blf); 1454 } 1455 1456 /* Retrieve list of TRILL nicknames from the TRILL module */ 1457 trill_listnick_t * 1458 dladm_bridge_get_trillnick(const char *bridge, uint_t *nnick) 1459 { 1460 int fd; 1461 char brcopy[MAXLINKNAMELEN]; 1462 trill_listnick_t *tln = NULL, *newtln, tlnread; 1463 uint_t ntln = 0, maxtln = 0; 1464 1465 if ((fd = socket(PF_TRILL, SOCK_DGRAM, 0)) == -1) 1466 return (NULL); 1467 (void) strlcpy(brcopy, bridge, sizeof (brcopy)); 1468 if (ioctl(fd, TRILL_GETBRIDGE, &brcopy) < 0) { 1469 (void) close(fd); 1470 return (NULL); 1471 } 1472 (void) memset(&tlnread, 0, sizeof (tlnread)); 1473 for (;;) { 1474 if (ntln >= maxtln) { 1475 maxtln = maxtln == 0 ? 64 : (maxtln << 1); 1476 newtln = realloc(tln, maxtln * sizeof (*tln)); 1477 if (newtln == NULL) { 1478 free(tln); 1479 tln = NULL; 1480 break; 1481 } 1482 tln = newtln; 1483 } 1484 if (ioctl(fd, TRILL_LISTNICK, &tlnread) == -1) { 1485 free(tln); 1486 tln = NULL; 1487 break; 1488 } 1489 if (tlnread.tln_nick == 0) 1490 break; 1491 tln[ntln++] = tlnread; 1492 } 1493 (void) close(fd); 1494 if (tln != NULL) 1495 *nnick = ntln; 1496 return (tln); 1497 } 1498 1499 void 1500 dladm_bridge_free_trillnick(trill_listnick_t *tln) 1501 { 1502 free(tln); 1503 } 1504 1505 /* Retrieve any stored TRILL nickname from TRILL SMF service */ 1506 uint16_t 1507 dladm_bridge_get_nick(const char *bridge) 1508 { 1509 scf_state_t sstate; 1510 uint64_t value; 1511 uint16_t nickname = RBRIDGE_NICKNAME_NONE; 1512 1513 if (bind_instance(TRILL_SVC_NAME, bridge, &sstate) != 0) 1514 return (nickname); 1515 1516 if (get_composed_properties("config", B_TRUE, &sstate) == 0 && 1517 get_count("nickname", &sstate, &value) == 0) 1518 nickname = value; 1519 shut_down_scf(&sstate); 1520 return (nickname); 1521 } 1522 1523 /* Stores TRILL nickname in SMF configuraiton for the TRILL service */ 1524 void 1525 dladm_bridge_set_nick(const char *bridge, uint16_t nick) 1526 { 1527 scf_state_t sstate; 1528 scf_transaction_t *tran = NULL; 1529 boolean_t new_pg = B_FALSE; 1530 int rv = 0; 1531 char *fmri; 1532 1533 if (exact_instance(TRILL_SVC_NAME, &sstate) != DLADM_STATUS_OK) 1534 return; 1535 1536 if (scf_service_get_instance(sstate.ss_svc, bridge, sstate.ss_inst) != 1537 0) 1538 goto out; 1539 if ((tran = scf_transaction_create(sstate.ss_handle)) == NULL) 1540 goto out; 1541 if ((sstate.ss_pg = scf_pg_create(sstate.ss_handle)) == NULL) 1542 goto out; 1543 if (scf_instance_add_pg(sstate.ss_inst, "config", 1544 SCF_GROUP_APPLICATION, 0, sstate.ss_pg) == 0) { 1545 new_pg = B_TRUE; 1546 } else if (scf_instance_get_pg(sstate.ss_inst, "config", 1547 sstate.ss_pg) != 0) { 1548 goto out; 1549 } 1550 do { 1551 if (scf_transaction_start(tran, sstate.ss_pg) != 0) 1552 goto out; 1553 if (!set_count_property(sstate.ss_handle, tran, "nickname", 1554 nick)) 1555 goto out; 1556 rv = scf_transaction_commit(tran); 1557 scf_transaction_reset(tran); 1558 if (rv == 0 && scf_pg_update(sstate.ss_pg) == -1) 1559 goto out; 1560 } while (rv == 0); 1561 1562 out: 1563 if (tran != NULL) { 1564 scf_transaction_destroy_children(tran); 1565 scf_transaction_destroy(tran); 1566 } 1567 1568 if (rv != 1 && new_pg) 1569 (void) scf_pg_delete(sstate.ss_pg); 1570 1571 drop_composed(&sstate); 1572 shut_down_scf(&sstate); 1573 if (rv == 1 && (fmri = alloc_fmri(TRILL_SVC_NAME, bridge)) != NULL) { 1574 (void) smf_refresh_instance(fmri); 1575 free(fmri); 1576 } 1577 } 1578