xref: /illumos-gate/usr/src/lib/libdladm/common/libdloverlay.c (revision 77c0a660417a046bfab6c8ef58d00c181c0264b3)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright (c) 2015 Joyent, Inc.
14  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
15  */
16 
17 #include <libdladm_impl.h>
18 #include <libdllink.h>
19 #include <libdloverlay.h>
20 #include <sys/dld.h>
21 #include <sys/overlay.h>
22 #include <strings.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <limits.h>
29 #include <libscf.h>
30 #include <libvarpd_client.h>
31 
32 #define	VARPD_PROPERTY_NAME	"varpd/id"
33 #define	VARPD_SERVICE		"network/varpd:default"
34 
35 static const char *dladm_overlay_doorpath = "/var/run/varpd/varpd.door";
36 
37 static boolean_t
38 varpd_svc_isonline(void)
39 {
40 	boolean_t isonline = B_FALSE;
41 	char *s;
42 
43 	if ((s = smf_get_state(VARPD_SERVICE)) != NULL) {
44 		if (strcmp(s, SCF_STATE_STRING_ONLINE) == 0)
45 			isonline = B_TRUE;
46 		free(s);
47 	}
48 
49 	return (isonline);
50 }
51 
52 #define	MAX_WAIT_TIME	15
53 
54 static dladm_status_t
55 varpd_enable_service(void)
56 {
57 	uint_t i;
58 
59 	if (varpd_svc_isonline())
60 		return (DLADM_STATUS_OK);
61 
62 	if (smf_enable_instance(VARPD_SERVICE, 0) == -1) {
63 		if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
64 			return (DLADM_STATUS_DENIED);
65 		return (DLADM_STATUS_NOTFOUND);
66 	}
67 
68 	/*
69 	 * Wait up to MAX_WAIT_TIME seconds for the service
70 	 */
71 	for (i = 0; i < MAX_WAIT_TIME; i++) {
72 		if (varpd_svc_isonline())
73 			return (DLADM_STATUS_OK);
74 		(void) sleep(1);
75 	}
76 	return (DLADM_STATUS_FAILED);
77 }
78 
79 static int
80 dladm_overlay_count_cb(dladm_handle_t handle, datalink_id_t linkid, void *arg)
81 {
82 	(*(uint32_t *)arg)++;
83 	return (DLADM_WALK_CONTINUE);
84 }
85 
86 /*
87  * Disable the varpd service if there are no overlays left.
88  */
89 static void
90 varpd_disable_service_when_no_overlays(dladm_handle_t handle)
91 {
92 	uint32_t cnt = 0;
93 
94 	/*
95 	 * Get the number of the existing overlays. If there are no overlays
96 	 * left, disable the service.
97 	 */
98 
99 	(void) dladm_walk_datalink_id(dladm_overlay_count_cb, handle,
100 	    &cnt, DATALINK_CLASS_OVERLAY, DATALINK_ANY_MEDIATYPE,
101 	    DLADM_OPT_ACTIVE);
102 
103 	if (cnt == 0)
104 		(void) smf_disable_instance(VARPD_SERVICE, 0);
105 }
106 
107 typedef struct dladm_overlay_propinfo {
108 	boolean_t dop_isvarpd;
109 	union {
110 		overlay_ioc_propinfo_t *dop_overlay;
111 		varpd_client_prop_handle_t *dop_varpd;
112 	} dop_un;
113 } dladm_overlay_propinfo_t;
114 
115 dladm_status_t
116 dladm_overlay_prop_info(dladm_overlay_propinfo_handle_t phdl,
117     const char **namep, uint_t *typep, uint_t *protp, const void **defp,
118     uint32_t *sizep, const mac_propval_range_t **possp)
119 {
120 	dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)phdl;
121 	overlay_ioc_propinfo_t *oinfop = infop->dop_un.dop_overlay;
122 
123 	if (infop->dop_isvarpd == B_FALSE) {
124 		if (namep != NULL)
125 			*namep = oinfop->oipi_name;
126 		if (typep != NULL)
127 			*typep = oinfop->oipi_type;
128 		if (protp != NULL)
129 			*protp = oinfop->oipi_prot;
130 		if (defp != NULL)
131 			*defp = oinfop->oipi_default;
132 		if (sizep != NULL)
133 			*sizep = oinfop->oipi_defsize;
134 		if (possp != NULL) {
135 			*possp = (const mac_propval_range_t *)oinfop->oipi_poss;
136 		}
137 
138 	} else {
139 		int ret;
140 		ret = libvarpd_c_prop_info(infop->dop_un.dop_varpd, namep,
141 		    typep, protp, defp, sizep, possp);
142 		if (ret != 0)
143 			return (dladm_errno2status(ret));
144 
145 	}
146 
147 	return (DLADM_STATUS_OK);
148 }
149 
150 static dladm_status_t
151 dladm_overlay_parse_prop(overlay_prop_type_t type, void *buf, uint32_t *sizep,
152     const char *val)
153 {
154 	int ret;
155 	int64_t ival;
156 	uint64_t uval;
157 	char *eptr;
158 	struct in6_addr ipv6;
159 	struct in_addr ip;
160 
161 	switch (type) {
162 	case OVERLAY_PROP_T_INT:
163 		errno = 0;
164 		ival = strtol(val, &eptr, 10);
165 		if ((ival == 0 && errno == EINVAL) ||
166 		    ((ival == LONG_MAX || ival == LONG_MIN) &&
167 		    errno == ERANGE))
168 			return (DLADM_STATUS_BADARG);
169 		bcopy(&ival, buf, sizeof (int64_t));
170 		*sizep = sizeof (int64_t);
171 		break;
172 	case OVERLAY_PROP_T_UINT:
173 		errno = 0;
174 		uval = strtol(val, &eptr, 10);
175 		if ((uval == 0 && errno == EINVAL) ||
176 		    (uval == ULONG_MAX && errno == ERANGE))
177 			return (DLADM_STATUS_BADARG);
178 		bcopy(&uval, buf, sizeof (uint64_t));
179 		*sizep = sizeof (uint64_t);
180 		break;
181 	case OVERLAY_PROP_T_STRING:
182 		ret = strlcpy((char *)buf, val, OVERLAY_PROP_SIZEMAX);
183 		if (ret >= OVERLAY_PROP_SIZEMAX)
184 			return (DLADM_STATUS_BADARG);
185 		*sizep = ret + 1;
186 		break;
187 	case OVERLAY_PROP_T_IP:
188 		/*
189 		 * Always try to parse the IP as an IPv6 address. If that fails,
190 		 * try to interpret it as an IPv4 address and transform it into
191 		 * an IPv6 mapped IPv4 address.
192 		 */
193 		if (inet_pton(AF_INET6, val, &ipv6) != 1) {
194 			if (inet_pton(AF_INET, val, &ip) != 1)
195 				return (DLADM_STATUS_BADARG);
196 
197 			IN6_INADDR_TO_V4MAPPED(&ip, &ipv6);
198 		}
199 		bcopy(&ipv6, buf, sizeof (struct in6_addr));
200 		*sizep = sizeof (struct in6_addr);
201 		break;
202 	default:
203 		abort();
204 	}
205 
206 	return (DLADM_STATUS_OK);
207 }
208 
209 static dladm_status_t
210 i_dladm_overlay_setprop_db(dladm_handle_t handle, datalink_id_t linkid,
211     const char *name, char *const *valp, uint_t cnt)
212 {
213 	dladm_conf_t	conf;
214 	dladm_status_t	status;
215 
216 	if (linkid == DATALINK_INVALID_LINKID ||
217 	    name == NULL || valp == NULL || cnt != 1) {
218 		return (DLADM_STATUS_BADARG);
219 	}
220 
221 	status = dladm_open_conf(handle, linkid, &conf);
222 	if (status != DLADM_STATUS_OK)
223 		return (status);
224 
225 	status = dladm_set_conf_field(handle, conf, name, DLADM_TYPE_STR,
226 	    valp[0]);
227 	if (status == DLADM_STATUS_OK)
228 		status = dladm_write_conf(handle, conf);
229 
230 	dladm_destroy_conf(handle, conf);
231 	return (status);
232 }
233 
234 static dladm_status_t
235 dladm_overlay_varpd_setprop(dladm_handle_t handle,
236     varpd_client_handle_t *chdl, uint64_t inst, datalink_id_t linkid,
237     const char *name, char *const *valp, uint_t cnt)
238 {
239 	int ret;
240 	uint32_t size;
241 	uint8_t buf[LIBVARPD_PROP_SIZEMAX];
242 	varpd_client_prop_handle_t *phdl;
243 	uint_t type;
244 	dladm_status_t status;
245 
246 	if ((ret = libvarpd_c_prop_handle_alloc(chdl, inst, &phdl)) != 0)
247 		return (dladm_errno2status(ret));
248 
249 	if ((ret = libvarpd_c_prop_info_fill_by_name(phdl, name)) != 0) {
250 		libvarpd_c_prop_handle_free(phdl);
251 		return (dladm_errno2status(ret));
252 	}
253 
254 	if ((ret = libvarpd_c_prop_info(phdl, NULL, &type, NULL, NULL, NULL,
255 	    NULL)) != 0) {
256 		libvarpd_c_prop_handle_free(phdl);
257 		return (dladm_errno2status(ret));
258 	}
259 
260 	if ((status = dladm_overlay_parse_prop(type, buf, &size, valp[0])) !=
261 	    DLADM_STATUS_OK) {
262 		libvarpd_c_prop_handle_free(phdl);
263 		return (status);
264 	}
265 
266 	status = DLADM_STATUS_OK;
267 	ret = libvarpd_c_prop_set(phdl, buf, size);
268 	libvarpd_c_prop_handle_free(phdl);
269 	if (ret != 0)
270 		status = dladm_errno2status(ret);
271 
272 	if (status != DLADM_STATUS_OK)
273 		return (status);
274 
275 	return (status);
276 }
277 
278 static dladm_status_t
279 dladm_overlay_setprop(dladm_handle_t handle, datalink_id_t linkid,
280     const char *name, char *const *valp, uint_t cnt)
281 {
282 	int			ret;
283 	dladm_status_t		status;
284 	overlay_ioc_propinfo_t	info;
285 	overlay_ioc_prop_t	prop;
286 
287 	if (linkid == DATALINK_INVALID_LINKID ||
288 	    name == NULL || valp == NULL || cnt != 1)
289 		return (DLADM_STATUS_BADARG);
290 
291 	bzero(&info, sizeof (overlay_ioc_propinfo_t));
292 	info.oipi_linkid = linkid;
293 	info.oipi_id = -1;
294 	if (strlcpy(info.oipi_name, name, OVERLAY_PROP_NAMELEN) >=
295 	    OVERLAY_PROP_NAMELEN)
296 		return (DLADM_STATUS_BADARG);
297 
298 	status = DLADM_STATUS_OK;
299 	ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &info);
300 	if (ret != 0)
301 		status = dladm_errno2status(errno);
302 
303 	if (status != DLADM_STATUS_OK)
304 		return (status);
305 
306 	prop.oip_linkid = linkid;
307 	prop.oip_id = info.oipi_id;
308 	prop.oip_name[0] = '\0';
309 	if ((status = dladm_overlay_parse_prop(info.oipi_type, prop.oip_value,
310 	    &prop.oip_size, valp[0])) != DLADM_STATUS_OK)
311 		return (status);
312 
313 	status = DLADM_STATUS_OK;
314 	ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_SETPROP, &prop);
315 	if (ret != 0)
316 		status = dladm_errno2status(errno);
317 
318 	if (status != DLADM_STATUS_OK)
319 		return (status);
320 
321 	return (status);
322 }
323 
324 /*
325  * Tell the user about any unset required properties.
326  */
327 static int
328 dladm_overlay_activate_cb(dladm_handle_t handle, datalink_id_t linkid,
329     dladm_overlay_propinfo_handle_t phdl, void *arg)
330 {
331 	dladm_status_t status;
332 	uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX];
333 	uint_t prot;
334 	size_t size = sizeof (buf);
335 	const char *name;
336 	dladm_errlist_t *errs = arg;
337 
338 	if ((status = dladm_overlay_prop_info(phdl, &name, NULL, &prot, NULL,
339 	    NULL, NULL)) != DLADM_STATUS_OK)
340 		return (status);
341 
342 	if ((prot & OVERLAY_PROP_PERM_REQ) == 0)
343 		return (DLADM_WALK_CONTINUE);
344 
345 	if (dladm_overlay_get_prop(handle, linkid, phdl, buf, &size) !=
346 	    DLADM_STATUS_OK)
347 		return (DLADM_WALK_CONTINUE);
348 
349 	if (size == 0)
350 		(void) dladm_errlist_append(errs, "unset required property: %s",
351 		    name);
352 
353 	return (DLADM_WALK_CONTINUE);
354 }
355 
356 /*
357  * We need to clean up the world here. The problem is that we may or may not
358  * actually have everything created. While in the normal case, we'd always have
359  * an overlay device, assigned datalink id, and a varpd instance, we might not
360  * have any of those, except for the datalink instance. Therefore, as long as
361  * the id refers to a valid overlay, we should try to clean up as much of the
362  * state as possible and most importantly, we need to make sure we delete the
363  * datalink id. If we fail to do that, then that name will become lost to time.
364  */
365 dladm_status_t
366 dladm_overlay_delete(dladm_handle_t handle, datalink_id_t linkid,
367     uint32_t flags)
368 {
369 	datalink_class_t class;
370 	overlay_ioc_delete_t oid;
371 	varpd_client_handle_t *chdl;
372 	int ret;
373 	uint64_t varpdid;
374 
375 	if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
376 	    NULL, 0) != DLADM_STATUS_OK) {
377 		return (DLADM_STATUS_BADARG);
378 	}
379 
380 	if (class != DATALINK_CLASS_OVERLAY)
381 		return (DLADM_STATUS_BADARG);
382 
383 	oid.oid_linkid = linkid;
384 	ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_DELETE, &oid);
385 	if (ret != 0 && errno != ENOENT) {
386 		return (dladm_errno2status(errno));
387 	}
388 
389 	if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) {
390 		return (dladm_errno2status(ret));
391 	}
392 
393 	if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
394 		if (ret == ENOENT) {
395 			goto finish;
396 		}
397 		(void) libvarpd_c_destroy(chdl);
398 		return (dladm_errno2status(ret));
399 	}
400 
401 	ret = libvarpd_c_instance_destroy(chdl, varpdid);
402 finish:
403 	(void) libvarpd_c_destroy(chdl);
404 	if ((flags & DLADM_OPT_PERSIST) != 0) {
405 		(void) dladm_remove_conf(handle, linkid);
406 		(void) dladm_destroy_datalink_id(handle, linkid, flags);
407 	}
408 
409 	(void) varpd_disable_service_when_no_overlays(handle);
410 
411 	return (dladm_errno2status(ret));
412 }
413 
414 dladm_status_t
415 dladm_overlay_get_prop(dladm_handle_t handle, datalink_id_t linkid,
416     dladm_overlay_propinfo_handle_t infohdl, void *buf, size_t *sizep)
417 {
418 	int ret;
419 	overlay_ioc_prop_t oip;
420 	dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)infohdl;
421 
422 	/*
423 	 * It'd be nice if we had a better or more specific error for this. If
424 	 * this kind of error becomes common place, let's get a better dladm
425 	 * error.
426 	 */
427 	if (*sizep < DLADM_OVERLAY_PROP_SIZEMAX)
428 		return (dladm_errno2status(ERANGE));
429 
430 	if (infop->dop_isvarpd == B_FALSE) {
431 		bzero(&oip, sizeof (overlay_ioc_prop_t));
432 		oip.oip_linkid = linkid;
433 		oip.oip_id = infop->dop_un.dop_overlay->oipi_id;
434 		ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_GETPROP, &oip);
435 		if (ret != 0)
436 			return (dladm_errno2status(errno));
437 		bcopy(oip.oip_value, buf, DLADM_OVERLAY_PROP_SIZEMAX);
438 		*sizep = oip.oip_size;
439 	} else {
440 		uint32_t size = *sizep;
441 
442 		ret = libvarpd_c_prop_get(infop->dop_un.dop_varpd, buf, &size);
443 		if (ret != 0)
444 			return (dladm_errno2status(errno));
445 		*sizep = size;
446 	}
447 
448 	return (DLADM_STATUS_OK);
449 }
450 
451 static dladm_status_t
452 dladm_overlay_walk_varpd_prop(dladm_handle_t handle, datalink_id_t linkid,
453     uint64_t varpdid, dladm_overlay_prop_f func, void *arg)
454 {
455 	int ret, i;
456 	varpd_client_handle_t *chdl;
457 	varpd_client_prop_handle_t *phdl;
458 	uint_t nprops;
459 	dladm_status_t status;
460 
461 	if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
462 		return (dladm_errno2status(ret));
463 
464 	if ((ret = libvarpd_c_prop_handle_alloc(chdl, varpdid, &phdl)) != 0) {
465 		(void) libvarpd_c_destroy(chdl);
466 		return (dladm_errno2status(ret));
467 	}
468 
469 	if ((ret = libvarpd_c_prop_nprops(chdl, varpdid, &nprops)) != 0) {
470 		libvarpd_c_prop_handle_free(phdl);
471 		(void) libvarpd_c_destroy(chdl);
472 		return (dladm_errno2status(ret));
473 	}
474 
475 	status = DLADM_STATUS_OK;
476 	for (i = 0; i < nprops; i++) {
477 		dladm_overlay_propinfo_t dop;
478 
479 		bzero(&dop, sizeof (dop));
480 		dop.dop_isvarpd = B_TRUE;
481 		dop.dop_un.dop_varpd = phdl;
482 
483 		if ((ret = libvarpd_c_prop_info_fill(phdl, i)) != 0) {
484 			status = dladm_errno2status(ret);
485 			break;
486 		}
487 
488 		ret = func(handle, linkid,
489 		    (dladm_overlay_propinfo_handle_t)&dop, arg);
490 		if (ret == DLADM_WALK_TERMINATE)
491 			break;
492 	}
493 
494 	libvarpd_c_prop_handle_free(phdl);
495 	libvarpd_c_destroy(chdl);
496 
497 	return (status);
498 }
499 
500 dladm_status_t
501 dladm_overlay_walk_prop(dladm_handle_t handle, datalink_id_t linkid,
502     dladm_overlay_prop_f func, void *arg, dladm_errlist_t *errs)
503 {
504 	int i, ret;
505 	char buf[MAXLINKNAMELEN];
506 	char errmsg[DLADM_STRSIZE];
507 	datalink_class_t class;
508 	dladm_status_t info_status;
509 	overlay_ioc_nprops_t oin;
510 	overlay_ioc_propinfo_t oipi;
511 	dladm_overlay_propinfo_t dop;
512 	uint64_t varpdid = UINT64_MAX;
513 
514 	if ((info_status = dladm_datalink_id2info(handle, linkid, NULL, &class,
515 	    NULL, buf, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
516 		(void) dladm_errlist_append(errs, "failed to get info for "
517 		    "datalink id %u: %s",
518 		    linkid, dladm_status2str(info_status, errmsg));
519 		return (DLADM_STATUS_BADARG);
520 	}
521 
522 	if (class != DATALINK_CLASS_OVERLAY) {
523 		(void) dladm_errlist_append(errs, "%s is not an overlay", buf);
524 		return (DLADM_STATUS_BADARG);
525 	}
526 
527 	bzero(&oin, sizeof (overlay_ioc_nprops_t));
528 	oin.oipn_linkid = linkid;
529 	ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_NPROPS, &oin);
530 	if (ret != 0) {
531 		(void) dladm_errlist_append(errs, "failed to get "
532 		    "overlay properties for overlay %s: %s",
533 		    buf, strerror(errno));
534 		return (dladm_errno2status(errno));
535 	}
536 
537 	for (i = 0; i < oin.oipn_nprops; i++) {
538 		bzero(&dop, sizeof (dladm_overlay_propinfo_t));
539 		bzero(&oipi, sizeof (overlay_ioc_propinfo_t));
540 		oipi.oipi_linkid = linkid;
541 		oipi.oipi_id = i;
542 		ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &oipi);
543 		if (ret != 0) {
544 			(void) dladm_errlist_append(errs, "failed to get "
545 			    "propinfo for overlay %s, property %d: %s",
546 			    buf, i, strerror(errno));
547 			return (dladm_errno2status(errno));
548 		}
549 
550 		dop.dop_isvarpd = B_FALSE;
551 		dop.dop_un.dop_overlay = &oipi;
552 		ret = func(handle, linkid,
553 		    (dladm_overlay_propinfo_handle_t)&dop, arg);
554 		if (ret == DLADM_WALK_TERMINATE)
555 			break;
556 
557 		if (strcmp(oipi.oipi_name, VARPD_PROPERTY_NAME) == 0) {
558 			uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX];
559 			size_t bufsize = sizeof (buf);
560 			uint64_t *vp;
561 
562 			if (dladm_overlay_get_prop(handle, linkid,
563 			    (dladm_overlay_propinfo_handle_t)&dop, buf,
564 			    &bufsize) != DLADM_STATUS_OK)
565 				continue;
566 
567 			vp = (uint64_t *)buf;
568 			varpdid = *vp;
569 		}
570 	}
571 
572 	/* Should this really be possible? */
573 	if (varpdid == UINT64_MAX)
574 		return (DLADM_STATUS_OK);
575 
576 	ret = dladm_overlay_walk_varpd_prop(handle, linkid, varpdid, func,
577 	    arg);
578 	if (ret != DLADM_STATUS_OK) {
579 		(void) dladm_errlist_append(errs,
580 		    "failed to get varpd props for "
581 		    "overlay %s, varpd id %llu: %s",
582 		    buf, varpdid, dladm_status2str(info_status, errmsg));
583 	}
584 	return (ret);
585 }
586 
587 static dladm_status_t
588 dladm_overlay_persist_config(dladm_handle_t handle, dladm_overlay_attr_t *attr)
589 {
590 	dladm_conf_t conf;
591 	dladm_status_t status;
592 
593 	if ((status = dladm_create_conf(handle, attr->oa_name, attr->oa_linkid,
594 	    DATALINK_CLASS_OVERLAY, DL_ETHER, &conf)) != DLADM_STATUS_OK) {
595 		return (status);
596 	}
597 
598 	status = dladm_set_conf_field(handle, conf, FVNETID,
599 	    DLADM_TYPE_UINT64, &attr->oa_vid);
600 	if (status != DLADM_STATUS_OK)
601 		goto done;
602 
603 	status = dladm_set_conf_field(handle, conf, FENCAP,
604 	    DLADM_TYPE_STR, attr->oa_encap);
605 	if (status != DLADM_STATUS_OK)
606 		goto done;
607 
608 	status = dladm_set_conf_field(handle, conf, FSEARCH,
609 	    DLADM_TYPE_STR, attr->oa_search);
610 	if (status != DLADM_STATUS_OK)
611 		goto done;
612 
613 	status = dladm_write_conf(handle, conf);
614 
615 done:
616 	dladm_destroy_conf(handle, conf);
617 	return (status);
618 }
619 
620 static dladm_status_t
621 i_dladm_overlay_create_sys(dladm_handle_t handle, dladm_overlay_attr_t *attr)
622 {
623 	overlay_ioc_create_t oic;
624 	dladm_status_t status;
625 	int ret;
626 
627 	bzero(&oic, sizeof (oic));
628 	oic.oic_linkid = attr->oa_linkid;
629 	oic.oic_vnetid = attr->oa_vid;
630 	(void) strlcpy(oic.oic_encap, attr->oa_encap, MAXLINKNAMELEN);
631 
632 	status = DLADM_STATUS_OK;
633 	ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_CREATE, &oic);
634 	if (ret != 0) {
635 		/*
636 		 * It'd be nice if we had private errors so we could better
637 		 * distinguish between different classes of errors.
638 		 */
639 		status = dladm_errno2status(errno);
640 	}
641 
642 	return (status);
643 }
644 
645 static dladm_status_t
646 i_dladm_overlay_commit_sys(dladm_handle_t handle, dladm_overlay_attr_t *attr,
647     dladm_arg_list_t *props, dladm_errlist_t *errs)
648 {
649 	overlay_ioc_activate_t oia;
650 	varpd_client_handle_t *vch;
651 	dladm_status_t status;
652 	size_t slen;
653 	uint64_t id;
654 	int ret;
655 	uint_t i;
656 
657 	slen = strlen(attr->oa_search);
658 	for (i = 0; props != NULL && i < props->al_count; i++) {
659 		dladm_arg_info_t	*aip = &props->al_info[i];
660 
661 		/*
662 		 * If it's a property for the search plugin, eg. it has the
663 		 * prefix '<search>/', then we don't set the property on the
664 		 * overlay device and instead set it on the varpd instance.
665 		 */
666 		if (strncmp(aip->ai_name, attr->oa_search, slen) == 0 &&
667 		    aip->ai_name[slen] == '/')
668 			continue;
669 		status = dladm_overlay_setprop(handle, attr->oa_linkid,
670 		    aip->ai_name, aip->ai_val, aip->ai_count);
671 		if (status != DLADM_STATUS_OK) {
672 			(void) dladm_errlist_append(errs,
673 			    "failed to set property %s", aip->ai_name);
674 			return (status);
675 		}
676 
677 		if (attr->oa_flags & DLADM_OPT_PERSIST) {
678 			status = i_dladm_overlay_setprop_db(handle,
679 			    attr->oa_linkid, aip->ai_name, aip->ai_val,
680 			    aip->ai_count);
681 			if (status != DLADM_STATUS_OK) {
682 				(void) dladm_errlist_append(errs,
683 				    "failed to persistently set property %s",
684 				    aip->ai_name);
685 				return (status);
686 			}
687 		}
688 	}
689 
690 	if ((ret = libvarpd_c_create(&vch, dladm_overlay_doorpath)) != 0) {
691 		(void) dladm_errlist_append(errs,
692 		    "failed to create libvarpd handle: %s", strerror(ret));
693 		return (dladm_errno2status(ret));
694 	}
695 
696 	if ((ret = libvarpd_c_instance_create(vch, attr->oa_linkid,
697 	    attr->oa_search, &id)) != 0) {
698 		(void) dladm_errlist_append(errs,
699 		    "failed to create varpd instance: %s", strerror(ret));
700 		libvarpd_c_destroy(vch);
701 		return (dladm_errno2status(ret));
702 	}
703 
704 	for (i = 0; props != NULL && i < props->al_count; i++) {
705 		dladm_arg_info_t	*aip = &props->al_info[i];
706 
707 		/*
708 		 * Skip arguments we've processed already.
709 		 */
710 		if (strncmp(aip->ai_name, attr->oa_search, slen) != 0 ||
711 		    aip->ai_name[slen] != '/')
712 			continue;
713 
714 		ret = dladm_overlay_varpd_setprop(handle, vch, id,
715 		    attr->oa_linkid, aip->ai_name, aip->ai_val, aip->ai_count);
716 		if (ret != 0) {
717 			(void) dladm_errlist_append(errs,
718 			    "failed to set varpd prop: %s\n", aip->ai_name);
719 			(void) libvarpd_c_instance_destroy(vch, id);
720 			libvarpd_c_destroy(vch);
721 			return (dladm_errno2status(ret));
722 		}
723 
724 		if (attr->oa_flags & DLADM_OPT_PERSIST) {
725 			status = i_dladm_overlay_setprop_db(handle,
726 			    attr->oa_linkid, aip->ai_name, aip->ai_val,
727 			    aip->ai_count);
728 			if (status != DLADM_STATUS_OK) {
729 				(void) dladm_errlist_append(errs, "failed to "
730 				    "persistently set varpd prop: %s\n",
731 				    aip->ai_name);
732 				(void) libvarpd_c_instance_destroy(vch, id);
733 				libvarpd_c_destroy(vch);
734 				return (status);
735 			}
736 		}
737 	}
738 
739 	if ((ret = libvarpd_c_instance_activate(vch, id)) != 0) {
740 		(void) dladm_errlist_append(errs,
741 		    "failed to activate varpd instance: %s", strerror(ret));
742 		(void) dladm_overlay_walk_varpd_prop(handle, attr->oa_linkid,
743 		    id, dladm_overlay_activate_cb, errs);
744 		(void) libvarpd_c_instance_destroy(vch, id);
745 		libvarpd_c_destroy(vch);
746 		return (dladm_errno2status(ret));
747 
748 	}
749 
750 	bzero(&oia, sizeof (oia));
751 	oia.oia_linkid = attr->oa_linkid;
752 	status = DLADM_STATUS_OK;
753 	ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_ACTIVATE, &oia);
754 	if (ret != 0) {
755 		ret = errno;
756 		(void) dladm_errlist_append(errs, "failed to activate "
757 		    "device: %s", strerror(ret));
758 		(void) libvarpd_c_instance_destroy(vch, id);
759 		(void) dladm_overlay_walk_prop(handle, attr->oa_linkid,
760 		    dladm_overlay_activate_cb, errs, errs);
761 		status = dladm_errno2status(ret);
762 	}
763 
764 	libvarpd_c_destroy(vch);
765 
766 	return (status);
767 }
768 
769 dladm_status_t
770 dladm_overlay_create(dladm_handle_t handle, const char *name,
771     const char *encap, const char *search, uint64_t vid,
772     dladm_arg_list_t *props, dladm_errlist_t *errs, uint32_t flags)
773 {
774 	dladm_status_t status;
775 	datalink_id_t linkid;
776 	dladm_overlay_attr_t attr;
777 	char errmsg[DLADM_STRSIZE];
778 
779 	if (strlcpy(attr.oa_name, name, sizeof (attr.oa_name)) >=
780 	    sizeof (attr.oa_name)) {
781 		return (DLADM_STATUS_BADARG);
782 	}
783 	if (strlcpy(attr.oa_encap, encap, sizeof (attr.oa_encap)) >=
784 	    sizeof (attr.oa_encap)) {
785 		return (DLADM_STATUS_BADARG);
786 	}
787 	if (strlcpy(attr.oa_search, search, sizeof (attr.oa_search)) >=
788 	    sizeof (attr.oa_search)) {
789 		return (DLADM_STATUS_BADARG);
790 	}
791 
792 	status = varpd_enable_service();
793 	if (status != DLADM_STATUS_OK)
794 		return (status);
795 
796 	status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_OVERLAY,
797 	    DL_ETHER, flags, &linkid);
798 	if (status != DLADM_STATUS_OK)
799 		return (status);
800 
801 	attr.oa_linkid = linkid;
802 	attr.oa_vid = vid;
803 	attr.oa_flags = flags;
804 
805 	status = i_dladm_overlay_create_sys(handle, &attr);
806 
807 	if (status != DLADM_STATUS_OK) {
808 		(void) dladm_destroy_datalink_id(handle, linkid, flags);
809 		return (status);
810 	}
811 
812 	if ((flags & DLADM_OPT_PERSIST) != 0) {
813 		status = dladm_overlay_persist_config(handle, &attr);
814 		if (status != DLADM_STATUS_OK) {
815 			(void) dladm_errlist_append(errs, "failed to create "
816 			    "persistent configuration for %s: %s",
817 			    attr.oa_name, dladm_status2str(status, errmsg));
818 		}
819 	}
820 
821 	if (status == DLADM_STATUS_OK)
822 		status = i_dladm_overlay_commit_sys(handle, &attr, props, errs);
823 
824 	if (status != DLADM_STATUS_OK) {
825 		(void) dladm_overlay_delete(handle, linkid, flags);
826 		(void) dladm_destroy_datalink_id(handle, linkid, flags);
827 	}
828 
829 	return (status);
830 }
831 
832 typedef struct overlay_walk_cb {
833 	dladm_handle_t		owc_handle;
834 	datalink_id_t		owc_linkid;
835 	void			*owc_arg;
836 	dladm_overlay_cache_f	owc_func;
837 	uint_t			owc_mode;
838 	uint_t			owc_dest;
839 } overlay_walk_cb_t;
840 
841 static int
842 dladm_overlay_walk_cache_cb(varpd_client_handle_t *chdl, uint64_t varpdid,
843     const struct ether_addr *key, const varpd_client_cache_entry_t *entry,
844     void *arg)
845 {
846 	overlay_walk_cb_t *owc = arg;
847 	dladm_overlay_point_t point;
848 
849 	bzero(&point, sizeof (dladm_overlay_point_t));
850 	point.dop_dest = owc->owc_dest;
851 	point.dop_mac = entry->vcp_mac;
852 	point.dop_flags = entry->vcp_flags;
853 	point.dop_ip = entry->vcp_ip;
854 	point.dop_port = entry->vcp_port;
855 
856 	if (owc->owc_mode == OVERLAY_TARGET_POINT)
857 		point.dop_flags |= DLADM_OVERLAY_F_DEFAULT;
858 
859 	if (owc->owc_func(owc->owc_handle, owc->owc_linkid, key, &point,
860 	    owc->owc_arg) == DLADM_WALK_TERMINATE)
861 		return (1);
862 	return (0);
863 }
864 
865 dladm_status_t
866 dladm_overlay_walk_cache(dladm_handle_t handle, datalink_id_t linkid,
867     dladm_overlay_cache_f func, void *arg)
868 {
869 	int ret;
870 	uint_t mode, dest;
871 	uint64_t varpdid;
872 	varpd_client_handle_t *chdl;
873 	overlay_walk_cb_t cbarg;
874 
875 	if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
876 		return (dladm_errno2status(ret));
877 
878 	if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
879 		libvarpd_c_destroy(chdl);
880 		return (dladm_errno2status(ret));
881 	}
882 
883 	if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid,
884 	    &dest, &mode)) != 0) {
885 		libvarpd_c_destroy(chdl);
886 		return (dladm_errno2status(ret));
887 	}
888 
889 	cbarg.owc_handle = handle;
890 	cbarg.owc_linkid = linkid;
891 	cbarg.owc_arg = arg;
892 	cbarg.owc_func = func;
893 	cbarg.owc_dest = dest;
894 	cbarg.owc_mode = mode;
895 	ret = libvarpd_c_instance_cache_walk(chdl, varpdid,
896 	    dladm_overlay_walk_cache_cb, &cbarg);
897 	libvarpd_c_destroy(chdl);
898 
899 	return (dladm_errno2status(ret));
900 }
901 
902 dladm_status_t
903 dladm_overlay_cache_flush(dladm_handle_t handle, datalink_id_t linkid)
904 {
905 	int ret;
906 	uint64_t varpdid;
907 	varpd_client_handle_t *chdl;
908 
909 	if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
910 		return (dladm_errno2status(ret));
911 
912 	if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
913 		libvarpd_c_destroy(chdl);
914 		return (dladm_errno2status(ret));
915 	}
916 
917 	ret = libvarpd_c_instance_cache_flush(chdl, varpdid);
918 	libvarpd_c_destroy(chdl);
919 
920 	return (dladm_errno2status(ret));
921 }
922 
923 dladm_status_t
924 dladm_overlay_cache_delete(dladm_handle_t handle, datalink_id_t linkid,
925     const struct ether_addr *key)
926 {
927 	int ret;
928 	uint64_t varpdid;
929 	varpd_client_handle_t *chdl;
930 
931 	if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
932 		return (dladm_errno2status(ret));
933 
934 	if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
935 		libvarpd_c_destroy(chdl);
936 		return (dladm_errno2status(ret));
937 	}
938 
939 	ret = libvarpd_c_instance_cache_delete(chdl, varpdid, key);
940 	libvarpd_c_destroy(chdl);
941 
942 	return (dladm_errno2status(ret));
943 }
944 
945 dladm_status_t
946 dladm_overlay_cache_set(dladm_handle_t handle, datalink_id_t linkid,
947     const struct ether_addr *key, char *val)
948 {
949 	int ret;
950 	uint_t dest;
951 	uint64_t varpdid;
952 	char *ip, *port = NULL;
953 	varpd_client_handle_t *chdl;
954 	varpd_client_cache_entry_t vcp;
955 
956 
957 	if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
958 		return (dladm_errno2status(ret));
959 
960 	if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
961 		libvarpd_c_destroy(chdl);
962 		return (dladm_errno2status(ret));
963 	}
964 
965 	if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid,
966 	    &dest, NULL)) != 0) {
967 		libvarpd_c_destroy(chdl);
968 		return (dladm_errno2status(ret));
969 	}
970 
971 	/*
972 	 * Mode tells us what we should expect in val. It we have more than one
973 	 * thing listed, the canonical format of it right now is mac,ip:port.
974 	 */
975 	bzero(&vcp, sizeof (varpd_client_cache_entry_t));
976 
977 	if (strcasecmp(val, "drop") == 0) {
978 		vcp.vcp_flags = OVERLAY_TARGET_CACHE_DROP;
979 		goto send;
980 	}
981 
982 	if (dest & OVERLAY_PLUGIN_D_ETHERNET) {
983 		if (ether_aton_r(val, &vcp.vcp_mac) == NULL) {
984 			libvarpd_c_destroy(chdl);
985 			return (dladm_errno2status(EINVAL));
986 		}
987 	}
988 
989 	if (dest & OVERLAY_PLUGIN_D_IP) {
990 		if (dest & OVERLAY_PLUGIN_D_ETHERNET) {
991 			if ((ip = strchr(val, ',')) == NULL) {
992 				libvarpd_c_destroy(chdl);
993 				return (dladm_errno2status(ret));
994 			}
995 			ip++;
996 		} else {
997 			ip = val;
998 		}
999 
1000 		if (dest & OVERLAY_PLUGIN_D_PORT) {
1001 			if ((port = strchr(val, ':')) == NULL) {
1002 				libvarpd_c_destroy(chdl);
1003 				return (dladm_errno2status(ret));
1004 			}
1005 			*port = '\0';
1006 			port++;
1007 		}
1008 
1009 		/* Try v6, then fall back to v4 */
1010 		ret = inet_pton(AF_INET6, ip, &vcp.vcp_ip);
1011 		if (ret == -1)
1012 			abort();
1013 		if (ret == 0) {
1014 			struct in_addr v4;
1015 
1016 			ret = inet_pton(AF_INET, ip, &v4);
1017 			if (ret == -1)
1018 				abort();
1019 			if (ret == 0) {
1020 				libvarpd_c_destroy(chdl);
1021 				return (dladm_errno2status(ret));
1022 			}
1023 			IN6_INADDR_TO_V4MAPPED(&v4, &vcp.vcp_ip);
1024 		}
1025 	}
1026 
1027 	if (dest & OVERLAY_PLUGIN_D_PORT) {
1028 		char *eptr;
1029 		unsigned long l;
1030 		if (port == NULL && (dest & OVERLAY_PLUGIN_D_ETHERNET)) {
1031 			if ((port = strchr(val, ',')) == NULL) {
1032 				libvarpd_c_destroy(chdl);
1033 				return (dladm_errno2status(EINVAL));
1034 			}
1035 		} else if (port == NULL)
1036 			port = val;
1037 
1038 		errno = 0;
1039 		l = strtoul(port, &eptr, 10);
1040 		if (errno != 0 || *eptr != '\0') {
1041 			libvarpd_c_destroy(chdl);
1042 			return (dladm_errno2status(EINVAL));
1043 		}
1044 		if (l == 0 || l > UINT16_MAX) {
1045 			libvarpd_c_destroy(chdl);
1046 			return (dladm_errno2status(EINVAL));
1047 		}
1048 		vcp.vcp_port = l;
1049 	}
1050 
1051 send:
1052 	ret = libvarpd_c_instance_cache_set(chdl, varpdid, key, &vcp);
1053 
1054 	libvarpd_c_destroy(chdl);
1055 	return (dladm_errno2status(ret));
1056 }
1057 
1058 dladm_status_t
1059 dladm_overlay_cache_get(dladm_handle_t handle, datalink_id_t linkid,
1060     const struct ether_addr *key, dladm_overlay_point_t *point)
1061 {
1062 	int ret;
1063 	uint_t dest, mode;
1064 	uint64_t varpdid;
1065 	varpd_client_handle_t *chdl;
1066 	varpd_client_cache_entry_t entry;
1067 
1068 	if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0)
1069 		return (dladm_errno2status(ret));
1070 
1071 	if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) {
1072 		libvarpd_c_destroy(chdl);
1073 		return (dladm_errno2status(ret));
1074 	}
1075 
1076 	if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid,
1077 	    &dest, &mode)) != 0) {
1078 		libvarpd_c_destroy(chdl);
1079 		return (dladm_errno2status(ret));
1080 	}
1081 
1082 	ret = libvarpd_c_instance_cache_get(chdl, varpdid, key, &entry);
1083 	if (ret == 0) {
1084 		point->dop_dest = dest;
1085 		point->dop_mac = entry.vcp_mac;
1086 		point->dop_flags = entry.vcp_flags;
1087 		point->dop_ip = entry.vcp_ip;
1088 		point->dop_port = entry.vcp_port;
1089 		if (mode == OVERLAY_TARGET_POINT)
1090 			point->dop_flags |= DLADM_OVERLAY_F_DEFAULT;
1091 	}
1092 
1093 	libvarpd_c_destroy(chdl);
1094 	return (dladm_errno2status(ret));
1095 }
1096 
1097 dladm_status_t
1098 dladm_overlay_status(dladm_handle_t handle, datalink_id_t linkid,
1099     dladm_overlay_status_f func, void *arg)
1100 {
1101 	int ret;
1102 	dladm_status_t status;
1103 	overlay_ioc_status_t ois;
1104 	dladm_overlay_status_t dos;
1105 
1106 	ois.ois_linkid = linkid;
1107 	status = DLADM_STATUS_OK;
1108 	ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_STATUS, &ois);
1109 	if (ret != 0)
1110 		status = dladm_errno2status(errno);
1111 	if (status != DLADM_STATUS_OK)
1112 		return (status);
1113 
1114 	dos.dos_degraded = ois.ois_status == OVERLAY_I_DEGRADED ? B_TRUE :
1115 	    B_FALSE;
1116 	(void) strlcpy(dos.dos_fmamsg, ois.ois_message,
1117 	    sizeof (dos.dos_fmamsg));
1118 	func(handle, linkid, &dos, arg);
1119 	return (DLADM_STATUS_OK);
1120 }
1121 
1122 /*
1123  * dladm_parse_args() usually creates a dladm_arg_list_t by tokenising a
1124  * delimited string and storing pointers to pieces of that string in the
1125  * dladm_arg_info_t structure. Those pointers do not need to be individually
1126  * freed.
1127  *
1128  * This function deals with property lists which have instead been built from
1129  * the persistent datalink configuration database, in order to bring up an
1130  * overlay at boot time. In this case, the properties have been retrieved
1131  * one-by-one, duplicated with strdup(), and added to the list. When the list
1132  * is finished with, this function takes care of freeing the memory.
1133  */
1134 static void
1135 i_dladm_overlay_props_free(dladm_handle_t handle, dladm_arg_list_t *props)
1136 {
1137 	uint_t i, j;
1138 
1139 	for (i = 0; props != NULL && i < props->al_count; i++) {
1140 		dladm_arg_info_t *aip = &props->al_info[i];
1141 
1142 		/* For ai_name, we need to cast away the 'const' qualifier. */
1143 		free((char *)aip->ai_name);
1144 		for (j = 0; j < aip->ai_count; j++)
1145 			free(aip->ai_val[j]);
1146 	}
1147 	free(props);
1148 }
1149 
1150 static dladm_status_t
1151 i_dladm_overlay_fetch_persistent_config(dladm_handle_t handle,
1152     datalink_id_t linkid, dladm_overlay_attr_t *attrp,
1153     dladm_arg_list_t **props)
1154 {
1155 	dladm_conf_t conf;
1156 	dladm_status_t status;
1157 	char attr[MAXLINKATTRLEN], last_attr[MAXLINKATTRLEN];
1158 	char attrval[OVERLAY_PROP_SIZEMAX];
1159 	size_t attrsz;
1160 	dladm_arg_list_t *list = NULL;
1161 
1162 	*props = NULL;
1163 
1164 	if ((status = dladm_getsnap_conf(handle, linkid, &conf)) !=
1165 	    DLADM_STATUS_OK) {
1166 		return (status);
1167 	}
1168 
1169 	attrp->oa_linkid = linkid;
1170 
1171 	status = dladm_get_conf_field(handle, conf, FVNETID, &attrp->oa_vid,
1172 	    sizeof (attrp->oa_vid));
1173 	if (status != DLADM_STATUS_OK)
1174 		goto done;
1175 
1176 	status = dladm_get_conf_field(handle, conf, FENCAP,
1177 	    attrp->oa_encap, sizeof (attrp->oa_encap));
1178 	if (status != DLADM_STATUS_OK)
1179 		goto done;
1180 
1181 	status = dladm_get_conf_field(handle, conf, FSEARCH,
1182 	    attrp->oa_search, sizeof (attrp->oa_search));
1183 	if (status != DLADM_STATUS_OK)
1184 		goto done;
1185 
1186 	list = calloc(1, sizeof (dladm_arg_list_t));
1187 
1188 	*last_attr = '\0';
1189 	while (dladm_getnext_conf_linkprop(handle, conf, last_attr,
1190 	    attr, attrval, sizeof (attrval), &attrsz) == DLADM_STATUS_OK) {
1191 		dladm_arg_info_t *aip;
1192 
1193 		(void) strlcpy(last_attr, attr, sizeof (last_attr));
1194 		if (strchr(attr, '/') == NULL)
1195 			continue;
1196 
1197 		aip = &list->al_info[list->al_count];
1198 		bzero(aip, sizeof (dladm_arg_info_t));
1199 		if ((aip->ai_name = strdup(attr)) == NULL) {
1200 			status = dladm_errno2status(errno);
1201 			break;
1202 		}
1203 		if ((aip->ai_val[0] = strdup(attrval)) == NULL) {
1204 			status = dladm_errno2status(errno);
1205 			break;
1206 		}
1207 		aip->ai_count = 1;
1208 		list->al_count++;
1209 		if (list->al_count >= DLADM_MAX_ARG_CNT) {
1210 			status = DLADM_STATUS_TOOMANYELEMENTS;
1211 			break;
1212 		}
1213 	}
1214 
1215 done:
1216 
1217 	dladm_destroy_conf(handle, conf);
1218 
1219 	if (status != DLADM_STATUS_OK) {
1220 		if (list != NULL)
1221 			i_dladm_overlay_props_free(handle, list);
1222 		return (status);
1223 	}
1224 
1225 	*props = list;
1226 	return (DLADM_STATUS_OK);
1227 }
1228 
1229 typedef struct dladm_overlay_up_arg_s {
1230 	dladm_errlist_t	*errlist;
1231 } dladm_overlay_up_arg_t;
1232 
1233 static int
1234 i_dladm_overlay_up(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1235 {
1236 	dladm_overlay_up_arg_t *argp = arg;
1237 	dladm_errlist_t *errs = argp->errlist;
1238 	datalink_class_t class;
1239 	dladm_status_t status;
1240 	dladm_overlay_attr_t attr;
1241 	dladm_arg_list_t *props;
1242 	char errmsg[DLADM_STRSIZE];
1243 
1244 	bzero(&attr, sizeof (attr));
1245 
1246 	status = dladm_datalink_id2info(handle, linkid, NULL, &class,
1247 	    NULL, attr.oa_name, sizeof (attr.oa_name));
1248 	if (status != DLADM_STATUS_OK) {
1249 		(void) dladm_errlist_append(errs, "failed to get info for "
1250 		    "datalink id %u: %s",
1251 		    linkid, dladm_status2str(status, errmsg));
1252 		return (DLADM_STATUS_BADARG);
1253 	}
1254 
1255 	if (class != DATALINK_CLASS_OVERLAY) {
1256 		(void) dladm_errlist_append(errs, "%s is not an overlay",
1257 		    attr.oa_name);
1258 		return (DLADM_STATUS_BADARG);
1259 	}
1260 
1261 	status = varpd_enable_service();
1262 	if (status != DLADM_STATUS_OK) {
1263 		(void) dladm_errlist_append(errs, "failed to enable svc:/%s",
1264 		    VARPD_SERVICE);
1265 		return (DLADM_WALK_TERMINATE);
1266 	}
1267 
1268 	status = i_dladm_overlay_fetch_persistent_config(handle, linkid,
1269 	    &attr, &props);
1270 	if (status != DLADM_STATUS_OK) {
1271 		(void) dladm_errlist_append(errs, "failed to retrieve "
1272 		    "persistent configuration for %s: %s",
1273 		    attr.oa_name, dladm_status2str(status, errmsg));
1274 		return (DLADM_WALK_CONTINUE);
1275 	}
1276 
1277 	status = i_dladm_overlay_create_sys(handle, &attr);
1278 	if (status != DLADM_STATUS_OK) {
1279 		(void) dladm_errlist_append(errs,
1280 		    "failed to create overlay device %s: %s",
1281 		    attr.oa_name, dladm_status2str(status, errmsg));
1282 		goto out;
1283 	}
1284 
1285 	status = i_dladm_overlay_commit_sys(handle, &attr, props, errs);
1286 	if (status != DLADM_STATUS_OK) {
1287 		(void) dladm_errlist_append(errs,
1288 		    "failed to set properties for overlay device %s: %s",
1289 		    attr.oa_name, dladm_status2str(status, errmsg));
1290 		dladm_overlay_delete(handle, linkid, 0);
1291 		goto out;
1292 	}
1293 
1294 	status = dladm_up_datalink_id(handle, linkid);
1295 	if (status != DLADM_STATUS_OK) {
1296 		(void) dladm_errlist_append(errs,
1297 		    "failed to bring datalink up for overlay device %s: %s",
1298 		    attr.oa_name, dladm_status2str(status, errmsg));
1299 		dladm_overlay_delete(handle, linkid, 0);
1300 		goto out;
1301 	}
1302 
1303 out:
1304 	i_dladm_overlay_props_free(handle, props);
1305 
1306 	return (DLADM_WALK_CONTINUE);
1307 }
1308 
1309 dladm_status_t
1310 dladm_overlay_up(dladm_handle_t handle, datalink_id_t linkid,
1311     dladm_errlist_t *errs)
1312 {
1313 	dladm_overlay_up_arg_t overlay_arg = {
1314 		.errlist	= errs
1315 	};
1316 
1317 	if (linkid == DATALINK_ALL_LINKID) {
1318 		(void) dladm_walk_datalink_id(i_dladm_overlay_up, handle,
1319 		    &overlay_arg, DATALINK_CLASS_OVERLAY,
1320 		    DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
1321 	} else {
1322 		(void) i_dladm_overlay_up(handle, linkid, &overlay_arg);
1323 	}
1324 
1325 	if (dladm_errlist_count(errs) == 0)
1326 		return (DLADM_STATUS_OK);
1327 
1328 	return (DLADM_STATUS_FAILED);
1329 }
1330