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