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
shut_down_scf(scf_state_t * sstate)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 *
alloc_fmri(const char * service,const char * instance_name)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
bind_instance(const char * service,const char * instance_name,scf_state_t * sstate)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
exact_instance(const char * fmri,scf_state_t * sstate)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
drop_composed(scf_state_t * sstate)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
get_composed_properties(const char * lpg,boolean_t snap,scf_state_t * sstate)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
get_count(const char * lprop,scf_state_t * sstate,uint64_t * answer)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
get_boolean(const char * lprop,scf_state_t * sstate,boolean_t * answer)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
bridge_door_call(const char * instname,bridge_door_type_t dtype,datalink_id_t linkid,void ** bufp,size_t inlen,size_t * buflenp,boolean_t is_list)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
port_door_call(dladm_handle_t handle,datalink_id_t linkid,bridge_door_type_t dtype,void * buf,size_t inlen,size_t buflen)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
bridge_refresh(const char * bridge)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
dladm_bridge_get_properties(const char * instance_name,UID_STP_CFG_T * cfg,dladm_bridge_prot_t * brprotp)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
dladm_bridge_get_privprop(const char * instance_name,boolean_t * debugp,uint32_t * tablemaxp)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
set_count_property(scf_handle_t * handle,scf_transaction_t * tran,const char * propname,uint64_t propval)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
set_string_property(scf_handle_t * handle,scf_transaction_t * tran,const char * propname,const char * propval)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
set_fmri_property(scf_handle_t * handle,scf_transaction_t * tran,const char * propname,const char * propval)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
dladm_bridge_persist_conf(dladm_handle_t handle,const char * link,datalink_id_t linkid)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
dladm_bridge_str2prot(const char * str,dladm_bridge_prot_t * brprotp)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 *
dladm_bridge_prot2str(dladm_bridge_prot_t brprot)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
enable_instance(const char * service_name,const char * instance)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
shut_down_instance(const char * service_name,const char * instance,uint32_t flags)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
disable_trill(const char * instance,uint32_t flags)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
enable_trill(const char * instance)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
dladm_bridge_configure(dladm_handle_t handle,const char * name,const UID_STP_CFG_T * cfg,dladm_bridge_prot_t brprot,uint32_t flags)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
dladm_bridge_enable(const char * name)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
dladm_bridge_setlink(dladm_handle_t handle,datalink_id_t linkid,const char * bridge)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
dladm_bridge_getlink(dladm_handle_t handle,datalink_id_t linkid,char * bridge,size_t bridgelen)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
dladm_bridge_refresh(dladm_handle_t handle,datalink_id_t linkid)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
i_dladm_bridge_is_held(dladm_handle_t handle,datalink_id_t linkid,void * arg)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
dladm_bridge_delete(dladm_handle_t handle,const char * bridge,uint32_t flags)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
dladm_valid_bridgename(const char * bridge)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
dladm_observe_to_bridge(char * link)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
dladm_bridge_run_properties(const char * instname,UID_STP_CFG_T * smcfg,dladm_bridge_prot_t * brprotp)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
dladm_bridge_state(const char * instname,UID_STP_STATE_T * statep)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 *
dladm_bridge_get_portlist(const char * instname,uint_t * nports)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
dladm_bridge_free_portlist(datalink_id_t * dlp)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
dladm_bridge_get_port_cfg(dladm_handle_t handle,datalink_id_t linkid,int field,int * valuep)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
dladm_bridge_link_state(dladm_handle_t handle,datalink_id_t linkid,UID_STP_PORT_STATE_T * spsp)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
dladm_bridge_get_forwarding(dladm_handle_t handle,datalink_id_t linkid,uint_t * valuep)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 *
dladm_bridge_get_fwdtable(dladm_handle_t handle,const char * bridge,uint_t * nfwd)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
dladm_bridge_free_fwdtable(bridge_listfwd_t * blf)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 *
dladm_bridge_get_trillnick(const char * bridge,uint_t * nnick)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
dladm_bridge_free_trillnick(trill_listnick_t * tln)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
dladm_bridge_get_nick(const char * bridge)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
dladm_bridge_set_nick(const char * bridge,uint16_t nick)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