6659 nvlist_free(NULL) is a no-op
[illumos-gate.git] / usr / src / lib / libdladm / common / libdlsim.c
blob7b8c515875fa90d7bd2984432653e10469a267d8
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/types.h>
26 #include <string.h>
27 #include <strings.h>
28 #include <sys/mac.h>
29 #include <sys/dls_mgmt.h>
30 #include <sys/dlpi.h>
31 #include <net/simnet.h>
32 #include <errno.h>
33 #include <unistd.h>
35 #include <libdladm_impl.h>
36 #include <libdllink.h>
37 #include <libdlaggr.h>
38 #include <libdlsim.h>
40 static dladm_status_t dladm_simnet_persist_conf(dladm_handle_t, const char *,
41 dladm_simnet_attr_t *);
43 /* New simnet instance creation */
44 static dladm_status_t
45 i_dladm_create_simnet(dladm_handle_t handle, dladm_simnet_attr_t *attrp)
47 int rc;
48 dladm_status_t status = DLADM_STATUS_OK;
49 simnet_ioc_create_t ioc;
51 bzero(&ioc, sizeof (ioc));
52 ioc.sic_link_id = attrp->sna_link_id;
53 ioc.sic_type = attrp->sna_type;
54 if (attrp->sna_mac_len > 0 && attrp->sna_mac_len <= MAXMACADDRLEN) {
55 ioc.sic_mac_len = attrp->sna_mac_len;
56 bcopy(attrp->sna_mac_addr, ioc.sic_mac_addr, ioc.sic_mac_len);
59 rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_CREATE, &ioc);
60 if (rc < 0)
61 status = dladm_errno2status(errno);
63 if (status != DLADM_STATUS_OK)
64 return (status);
66 bcopy(ioc.sic_mac_addr, attrp->sna_mac_addr, MAXMACADDRLEN);
67 attrp->sna_mac_len = ioc.sic_mac_len;
68 return (status);
71 /* Modify existing simnet instance */
72 static dladm_status_t
73 i_dladm_modify_simnet(dladm_handle_t handle, dladm_simnet_attr_t *attrp)
75 int rc;
76 dladm_status_t status = DLADM_STATUS_OK;
77 simnet_ioc_modify_t ioc;
79 bzero(&ioc, sizeof (ioc));
80 ioc.sim_link_id = attrp->sna_link_id;
81 ioc.sim_peer_link_id = attrp->sna_peer_link_id;
83 rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_MODIFY, &ioc);
84 if (rc < 0)
85 status = dladm_errno2status(errno);
87 return (status);
90 /* Delete simnet instance */
91 static dladm_status_t
92 i_dladm_delete_simnet(dladm_handle_t handle, dladm_simnet_attr_t *attrp)
94 int rc;
95 dladm_status_t status = DLADM_STATUS_OK;
96 simnet_ioc_delete_t ioc;
98 bzero(&ioc, sizeof (ioc));
99 ioc.sid_link_id = attrp->sna_link_id;
101 rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_DELETE, &ioc);
102 if (rc < 0)
103 status = dladm_errno2status(errno);
105 return (status);
108 /* Retrieve simnet instance information */
109 static dladm_status_t
110 i_dladm_get_simnet_info(dladm_handle_t handle, dladm_simnet_attr_t *attrp)
112 int rc;
113 dladm_status_t status = DLADM_STATUS_OK;
114 simnet_ioc_info_t ioc;
116 bzero(&ioc, sizeof (ioc));
117 ioc.sii_link_id = attrp->sna_link_id;
119 rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_INFO, &ioc);
120 if (rc < 0) {
121 status = dladm_errno2status(errno);
122 return (status);
125 bcopy(ioc.sii_mac_addr, attrp->sna_mac_addr, MAXMACADDRLEN);
126 attrp->sna_mac_len = ioc.sii_mac_len;
127 attrp->sna_peer_link_id = ioc.sii_peer_link_id;
128 attrp->sna_type = ioc.sii_type;
129 return (status);
132 /* Retrieve simnet configuratin */
133 static dladm_status_t
134 i_dladm_get_simnet_info_persist(dladm_handle_t handle,
135 dladm_simnet_attr_t *attrp)
137 dladm_conf_t conf;
138 dladm_status_t status;
139 char macstr[ETHERADDRL * 3];
140 char simnetpeer[MAXLINKNAMELEN];
141 uint64_t u64;
142 boolean_t mac_fixed;
144 if ((status = dladm_getsnap_conf(handle, attrp->sna_link_id,
145 &conf)) != DLADM_STATUS_OK)
146 return (status);
148 status = dladm_get_conf_field(handle, conf, FSIMNETTYPE, &u64,
149 sizeof (u64));
150 if (status != DLADM_STATUS_OK)
151 goto done;
152 attrp->sna_type = (uint_t)u64;
154 status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64,
155 sizeof (u64));
156 if (status != DLADM_STATUS_OK)
157 goto done;
158 attrp->sna_mac_len = (uint_t)u64;
160 status = dladm_get_conf_field(handle, conf, FMACADDR, macstr,
161 sizeof (macstr));
162 if (status != DLADM_STATUS_OK)
163 goto done;
164 (void) dladm_aggr_str2macaddr(macstr, &mac_fixed, attrp->sna_mac_addr);
166 /* Peer field is optional and only set when peer is attached */
167 if (dladm_get_conf_field(handle, conf, FSIMNETPEER, simnetpeer,
168 sizeof (simnetpeer)) == DLADM_STATUS_OK) {
169 status = dladm_name2info(handle, simnetpeer,
170 &attrp->sna_peer_link_id, NULL, NULL, NULL);
171 } else {
172 attrp->sna_peer_link_id = DATALINK_INVALID_LINKID;
174 done:
175 dladm_destroy_conf(handle, conf);
176 return (status);
179 dladm_status_t
180 dladm_simnet_create(dladm_handle_t handle, const char *simnetname,
181 uint_t media, uint32_t flags)
183 datalink_id_t simnet_id;
184 dladm_status_t status;
185 dladm_simnet_attr_t attr;
187 if (!(flags & DLADM_OPT_ACTIVE))
188 return (DLADM_STATUS_NOTSUP);
190 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
191 if ((status = dladm_create_datalink_id(handle, simnetname,
192 DATALINK_CLASS_SIMNET, media, flags,
193 &simnet_id)) != DLADM_STATUS_OK)
194 return (status);
196 bzero(&attr, sizeof (attr));
197 attr.sna_link_id = simnet_id;
198 attr.sna_type = media;
199 status = i_dladm_create_simnet(handle, &attr);
200 if (status != DLADM_STATUS_OK)
201 goto done;
203 if (!(flags & DLADM_OPT_PERSIST))
204 goto done;
206 status = dladm_simnet_persist_conf(handle, simnetname, &attr);
207 if (status != DLADM_STATUS_OK) {
208 (void) i_dladm_delete_simnet(handle, &attr);
209 goto done;
212 (void) dladm_set_linkprop(handle, simnet_id, NULL, NULL, 0, flags);
214 done:
215 if (status != DLADM_STATUS_OK) {
216 (void) dladm_destroy_datalink_id(handle, simnet_id, flags);
218 return (status);
221 /* Update existing simnet configuration */
222 static dladm_status_t
223 i_dladm_simnet_update_conf(dladm_handle_t handle, datalink_id_t simnet_id,
224 datalink_id_t peer_simnet_id)
226 dladm_status_t status;
227 dladm_conf_t conf;
228 char simnetpeer[MAXLINKNAMELEN];
230 status = dladm_open_conf(handle, simnet_id, &conf);
231 if (status != DLADM_STATUS_OK)
232 return (status);
234 /* First clear previous peer if any in configuration */
235 (void) dladm_unset_conf_field(handle, conf, FSIMNETPEER);
236 if (peer_simnet_id != DATALINK_INVALID_LINKID) {
237 if ((status = dladm_datalink_id2info(handle,
238 peer_simnet_id, NULL, NULL, NULL, simnetpeer,
239 sizeof (simnetpeer))) == DLADM_STATUS_OK) {
240 status = dladm_set_conf_field(handle, conf,
241 FSIMNETPEER, DLADM_TYPE_STR, simnetpeer);
243 if (status != DLADM_STATUS_OK)
244 goto fail;
247 status = dladm_write_conf(handle, conf);
248 fail:
249 dladm_destroy_conf(handle, conf);
250 return (status);
253 /* Modify attached simnet peer */
254 dladm_status_t
255 dladm_simnet_modify(dladm_handle_t handle, datalink_id_t simnet_id,
256 datalink_id_t peer_simnet_id, uint32_t flags)
258 dladm_simnet_attr_t attr;
259 dladm_simnet_attr_t prevattr;
260 dladm_status_t status;
261 datalink_class_t class;
262 uint32_t linkflags;
263 uint32_t peerlinkflags;
265 if (!(flags & DLADM_OPT_ACTIVE))
266 return (DLADM_STATUS_NOTSUP);
268 if ((dladm_datalink_id2info(handle, simnet_id, &linkflags, &class,
269 NULL, NULL, 0) != DLADM_STATUS_OK))
270 return (DLADM_STATUS_BADARG);
271 if (class != DATALINK_CLASS_SIMNET)
272 return (DLADM_STATUS_BADARG);
274 if (peer_simnet_id != DATALINK_INVALID_LINKID) {
275 if (dladm_datalink_id2info(handle, peer_simnet_id,
276 &peerlinkflags, &class, NULL, NULL, 0) != DLADM_STATUS_OK)
277 return (DLADM_STATUS_BADARG);
278 if (class != DATALINK_CLASS_SIMNET)
279 return (DLADM_STATUS_BADARG);
280 /* Check to ensure the peer link has identical flags */
281 if (peerlinkflags != linkflags)
282 return (DLADM_STATUS_BADARG);
285 /* Retrieve previous attrs before modification */
286 bzero(&prevattr, sizeof (prevattr));
287 if ((status = dladm_simnet_info(handle, simnet_id, &prevattr,
288 flags)) != DLADM_STATUS_OK)
289 return (status);
291 bzero(&attr, sizeof (attr));
292 attr.sna_link_id = simnet_id;
293 attr.sna_peer_link_id = peer_simnet_id;
294 status = i_dladm_modify_simnet(handle, &attr);
295 if ((status != DLADM_STATUS_OK) || !(flags & DLADM_OPT_PERSIST))
296 return (status);
298 /* First we clear link's existing peer field in config */
299 status = i_dladm_simnet_update_conf(handle, simnet_id,
300 DATALINK_INVALID_LINKID);
301 if (status != DLADM_STATUS_OK)
302 return (status);
304 /* Clear the previous peer link's existing peer field in config */
305 if (prevattr.sna_peer_link_id != DATALINK_INVALID_LINKID) {
306 status = i_dladm_simnet_update_conf(handle,
307 prevattr.sna_peer_link_id, DATALINK_INVALID_LINKID);
308 if (status != DLADM_STATUS_OK)
309 return (status);
312 /* Update the configuration in both simnets with any new peer link */
313 if (peer_simnet_id != DATALINK_INVALID_LINKID) {
314 status = i_dladm_simnet_update_conf(handle, simnet_id,
315 peer_simnet_id);
316 if (status == DLADM_STATUS_OK)
317 status = i_dladm_simnet_update_conf(handle,
318 peer_simnet_id, simnet_id);
321 return (status);
324 dladm_status_t
325 dladm_simnet_delete(dladm_handle_t handle, datalink_id_t simnet_id,
326 uint32_t flags)
328 dladm_simnet_attr_t attr;
329 dladm_simnet_attr_t prevattr;
330 dladm_status_t status;
331 datalink_class_t class;
333 if ((dladm_datalink_id2info(handle, simnet_id, NULL, &class,
334 NULL, NULL, 0) != DLADM_STATUS_OK))
335 return (DLADM_STATUS_BADARG);
337 if (class != DATALINK_CLASS_SIMNET)
338 return (DLADM_STATUS_BADARG);
340 /* Check current simnet attributes before deletion */
341 flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
342 bzero(&prevattr, sizeof (prevattr));
343 if ((status = dladm_simnet_info(handle, simnet_id, &prevattr,
344 flags)) != DLADM_STATUS_OK)
345 return (status);
347 bzero(&attr, sizeof (attr));
348 attr.sna_link_id = simnet_id;
349 if (flags & DLADM_OPT_ACTIVE) {
350 status = i_dladm_delete_simnet(handle, &attr);
351 if (status == DLADM_STATUS_OK) {
352 (void) dladm_set_linkprop(handle, simnet_id, NULL,
353 NULL, 0, DLADM_OPT_ACTIVE);
354 (void) dladm_destroy_datalink_id(handle, simnet_id,
355 DLADM_OPT_ACTIVE);
356 } else if (status != DLADM_STATUS_NOTFOUND) {
357 return (status);
361 if (flags & DLADM_OPT_PERSIST) {
362 (void) dladm_remove_conf(handle, simnet_id);
363 (void) dladm_destroy_datalink_id(handle, simnet_id,
364 DLADM_OPT_PERSIST);
366 /* Update any attached peer configuration */
367 if (prevattr.sna_peer_link_id != DATALINK_INVALID_LINKID)
368 status = i_dladm_simnet_update_conf(handle,
369 prevattr.sna_peer_link_id, DATALINK_INVALID_LINKID);
371 return (status);
374 /* Retrieve simnet information either active or from configuration */
375 dladm_status_t
376 dladm_simnet_info(dladm_handle_t handle, datalink_id_t simnet_id,
377 dladm_simnet_attr_t *attrp, uint32_t flags)
379 datalink_class_t class;
380 dladm_status_t status;
382 if ((dladm_datalink_id2info(handle, simnet_id, NULL, &class,
383 NULL, NULL, 0) != DLADM_STATUS_OK))
384 return (DLADM_STATUS_BADARG);
386 if (class != DATALINK_CLASS_SIMNET)
387 return (DLADM_STATUS_BADARG);
389 bzero(attrp, sizeof (attrp));
390 attrp->sna_link_id = simnet_id;
392 if (flags & DLADM_OPT_ACTIVE) {
393 status = i_dladm_get_simnet_info(handle, attrp);
395 * If no active simnet found then return any simnet
396 * from stored config if requested.
398 if (status == DLADM_STATUS_NOTFOUND &&
399 (flags & DLADM_OPT_PERSIST))
400 return (i_dladm_get_simnet_info_persist(handle, attrp));
401 return (status);
402 } else if (flags & DLADM_OPT_PERSIST) {
403 return (i_dladm_get_simnet_info_persist(handle, attrp));
404 } else {
405 return (DLADM_STATUS_BADARG);
409 /* Bring up simnet from stored configuration */
410 static int
411 i_dladm_simnet_up(dladm_handle_t handle, datalink_id_t simnet_id, void *arg)
413 dladm_status_t *statusp = arg;
414 dladm_status_t status;
415 dladm_simnet_attr_t attr;
416 dladm_simnet_attr_t peer_attr;
418 bzero(&attr, sizeof (attr));
419 attr.sna_link_id = simnet_id;
420 status = dladm_simnet_info(handle, simnet_id, &attr,
421 DLADM_OPT_PERSIST);
422 if (status != DLADM_STATUS_OK)
423 goto done;
425 status = i_dladm_create_simnet(handle, &attr);
426 if (status != DLADM_STATUS_OK)
427 goto done;
430 * When bringing up check if the peer link is available, if it
431 * is then modify the simnet and attach the peer link.
433 if ((attr.sna_peer_link_id != DATALINK_INVALID_LINKID) &&
434 (dladm_simnet_info(handle, attr.sna_peer_link_id, &peer_attr,
435 DLADM_OPT_ACTIVE) == DLADM_STATUS_OK)) {
436 status = i_dladm_modify_simnet(handle, &attr);
437 if (status != DLADM_STATUS_OK)
438 goto done;
441 if ((status = dladm_up_datalink_id(handle, simnet_id)) !=
442 DLADM_STATUS_OK) {
443 (void) dladm_simnet_delete(handle, simnet_id,
444 DLADM_OPT_PERSIST);
445 goto done;
447 done:
448 *statusp = status;
449 return (DLADM_WALK_CONTINUE);
452 /* Bring up simnet instance(s) from configuration */
453 /* ARGSUSED */
454 dladm_status_t
455 dladm_simnet_up(dladm_handle_t handle, datalink_id_t simnet_id,
456 uint32_t flags)
458 dladm_status_t status;
460 if (simnet_id == DATALINK_ALL_LINKID) {
461 (void) dladm_walk_datalink_id(i_dladm_simnet_up, handle,
462 &status, DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE,
463 DLADM_OPT_PERSIST);
464 return (DLADM_STATUS_OK);
465 } else {
466 (void) i_dladm_simnet_up(handle, simnet_id, &status);
467 return (status);
471 /* Store simnet configuration */
472 static dladm_status_t
473 dladm_simnet_persist_conf(dladm_handle_t handle, const char *name,
474 dladm_simnet_attr_t *attrp)
476 dladm_conf_t conf;
477 dladm_status_t status;
478 char mstr[ETHERADDRL * 3];
479 uint64_t u64;
481 if ((status = dladm_create_conf(handle, name, attrp->sna_link_id,
482 DATALINK_CLASS_SIMNET, attrp->sna_type, &conf)) != DLADM_STATUS_OK)
483 return (status);
485 status = dladm_set_conf_field(handle, conf, FMACADDR,
486 DLADM_TYPE_STR, dladm_aggr_macaddr2str(attrp->sna_mac_addr, mstr));
487 if (status != DLADM_STATUS_OK)
488 goto done;
490 u64 = attrp->sna_type;
491 status = dladm_set_conf_field(handle, conf, FSIMNETTYPE,
492 DLADM_TYPE_UINT64, &u64);
493 if (status != DLADM_STATUS_OK)
494 goto done;
496 u64 = attrp->sna_mac_len;
497 status = dladm_set_conf_field(handle, conf, FMADDRLEN,
498 DLADM_TYPE_UINT64, &u64);
499 if (status != DLADM_STATUS_OK)
500 goto done;
502 status = dladm_write_conf(handle, conf);
503 done:
504 dladm_destroy_conf(handle, conf);
505 return (status);