xref: /illumos-gate/usr/src/lib/libdladm/common/libdlbridge.c (revision 0663b557d8c7575927b005cab08d9f19c8b98c25)
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