19815SRishi.Srivatsavai@Sun.COM /*
29815SRishi.Srivatsavai@Sun.COM  * CDDL HEADER START
39815SRishi.Srivatsavai@Sun.COM  *
49815SRishi.Srivatsavai@Sun.COM  * The contents of this file are subject to the terms of the
59815SRishi.Srivatsavai@Sun.COM  * Common Development and Distribution License (the "License").
69815SRishi.Srivatsavai@Sun.COM  * You may not use this file except in compliance with the License.
79815SRishi.Srivatsavai@Sun.COM  *
89815SRishi.Srivatsavai@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99815SRishi.Srivatsavai@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109815SRishi.Srivatsavai@Sun.COM  * See the License for the specific language governing permissions
119815SRishi.Srivatsavai@Sun.COM  * and limitations under the License.
129815SRishi.Srivatsavai@Sun.COM  *
139815SRishi.Srivatsavai@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149815SRishi.Srivatsavai@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159815SRishi.Srivatsavai@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169815SRishi.Srivatsavai@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179815SRishi.Srivatsavai@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189815SRishi.Srivatsavai@Sun.COM  *
199815SRishi.Srivatsavai@Sun.COM  * CDDL HEADER END
209815SRishi.Srivatsavai@Sun.COM  */
219815SRishi.Srivatsavai@Sun.COM /*
229815SRishi.Srivatsavai@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
239815SRishi.Srivatsavai@Sun.COM  * Use is subject to license terms.
249815SRishi.Srivatsavai@Sun.COM  */
259815SRishi.Srivatsavai@Sun.COM 
269815SRishi.Srivatsavai@Sun.COM #include <sys/types.h>
279815SRishi.Srivatsavai@Sun.COM #include <string.h>
289815SRishi.Srivatsavai@Sun.COM #include <strings.h>
299815SRishi.Srivatsavai@Sun.COM #include <sys/mac.h>
309815SRishi.Srivatsavai@Sun.COM #include <sys/dls_mgmt.h>
319815SRishi.Srivatsavai@Sun.COM #include <sys/dlpi.h>
329815SRishi.Srivatsavai@Sun.COM #include <net/simnet.h>
339815SRishi.Srivatsavai@Sun.COM #include <errno.h>
349815SRishi.Srivatsavai@Sun.COM #include <unistd.h>
359815SRishi.Srivatsavai@Sun.COM 
369815SRishi.Srivatsavai@Sun.COM #include <libdladm_impl.h>
379815SRishi.Srivatsavai@Sun.COM #include <libdllink.h>
389815SRishi.Srivatsavai@Sun.COM #include <libdlaggr.h>
399815SRishi.Srivatsavai@Sun.COM #include <libdlsim.h>
409815SRishi.Srivatsavai@Sun.COM 
419815SRishi.Srivatsavai@Sun.COM static dladm_status_t dladm_simnet_persist_conf(dladm_handle_t, const char *,
429815SRishi.Srivatsavai@Sun.COM     dladm_simnet_attr_t *);
439815SRishi.Srivatsavai@Sun.COM 
449815SRishi.Srivatsavai@Sun.COM /* New simnet instance creation */
459815SRishi.Srivatsavai@Sun.COM static dladm_status_t
469815SRishi.Srivatsavai@Sun.COM i_dladm_create_simnet(dladm_handle_t handle, dladm_simnet_attr_t *attrp)
479815SRishi.Srivatsavai@Sun.COM {
489815SRishi.Srivatsavai@Sun.COM 	int rc;
499815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
509815SRishi.Srivatsavai@Sun.COM 	simnet_ioc_create_t ioc;
519815SRishi.Srivatsavai@Sun.COM 
529815SRishi.Srivatsavai@Sun.COM 	bzero(&ioc, sizeof (ioc));
539815SRishi.Srivatsavai@Sun.COM 	ioc.sic_link_id = attrp->sna_link_id;
549815SRishi.Srivatsavai@Sun.COM 	ioc.sic_type = attrp->sna_type;
559815SRishi.Srivatsavai@Sun.COM 	if (attrp->sna_mac_len > 0 && attrp->sna_mac_len <= MAXMACADDRLEN) {
569815SRishi.Srivatsavai@Sun.COM 		ioc.sic_mac_len = attrp->sna_mac_len;
579815SRishi.Srivatsavai@Sun.COM 		bcopy(attrp->sna_mac_addr, ioc.sic_mac_addr, ioc.sic_mac_len);
589815SRishi.Srivatsavai@Sun.COM 	}
599815SRishi.Srivatsavai@Sun.COM 
609815SRishi.Srivatsavai@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_CREATE, &ioc);
619815SRishi.Srivatsavai@Sun.COM 	if (rc < 0)
629815SRishi.Srivatsavai@Sun.COM 		status = dladm_errno2status(errno);
639815SRishi.Srivatsavai@Sun.COM 
649815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
659815SRishi.Srivatsavai@Sun.COM 		return (status);
669815SRishi.Srivatsavai@Sun.COM 
679815SRishi.Srivatsavai@Sun.COM 	bcopy(ioc.sic_mac_addr, attrp->sna_mac_addr, MAXMACADDRLEN);
689815SRishi.Srivatsavai@Sun.COM 	attrp->sna_mac_len = ioc.sic_mac_len;
699815SRishi.Srivatsavai@Sun.COM 	return (status);
709815SRishi.Srivatsavai@Sun.COM }
719815SRishi.Srivatsavai@Sun.COM 
729815SRishi.Srivatsavai@Sun.COM /* Modify existing simnet instance */
739815SRishi.Srivatsavai@Sun.COM static dladm_status_t
749815SRishi.Srivatsavai@Sun.COM i_dladm_modify_simnet(dladm_handle_t handle, dladm_simnet_attr_t *attrp)
759815SRishi.Srivatsavai@Sun.COM {
769815SRishi.Srivatsavai@Sun.COM 	int rc;
779815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
789815SRishi.Srivatsavai@Sun.COM 	simnet_ioc_modify_t ioc;
799815SRishi.Srivatsavai@Sun.COM 
809815SRishi.Srivatsavai@Sun.COM 	bzero(&ioc, sizeof (ioc));
819815SRishi.Srivatsavai@Sun.COM 	ioc.sim_link_id = attrp->sna_link_id;
829815SRishi.Srivatsavai@Sun.COM 	ioc.sim_peer_link_id = attrp->sna_peer_link_id;
839815SRishi.Srivatsavai@Sun.COM 
849815SRishi.Srivatsavai@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_MODIFY, &ioc);
859815SRishi.Srivatsavai@Sun.COM 	if (rc < 0)
869815SRishi.Srivatsavai@Sun.COM 		status = dladm_errno2status(errno);
879815SRishi.Srivatsavai@Sun.COM 
889815SRishi.Srivatsavai@Sun.COM 	return (status);
899815SRishi.Srivatsavai@Sun.COM }
909815SRishi.Srivatsavai@Sun.COM 
919815SRishi.Srivatsavai@Sun.COM /* Delete simnet instance */
929815SRishi.Srivatsavai@Sun.COM static dladm_status_t
939815SRishi.Srivatsavai@Sun.COM i_dladm_delete_simnet(dladm_handle_t handle, dladm_simnet_attr_t *attrp)
949815SRishi.Srivatsavai@Sun.COM {
959815SRishi.Srivatsavai@Sun.COM 	int rc;
969815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
979815SRishi.Srivatsavai@Sun.COM 	simnet_ioc_delete_t ioc;
989815SRishi.Srivatsavai@Sun.COM 
999815SRishi.Srivatsavai@Sun.COM 	bzero(&ioc, sizeof (ioc));
1009815SRishi.Srivatsavai@Sun.COM 	ioc.sid_link_id = attrp->sna_link_id;
1019815SRishi.Srivatsavai@Sun.COM 
1029815SRishi.Srivatsavai@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_DELETE, &ioc);
1039815SRishi.Srivatsavai@Sun.COM 	if (rc < 0)
1049815SRishi.Srivatsavai@Sun.COM 		status = dladm_errno2status(errno);
1059815SRishi.Srivatsavai@Sun.COM 
1069815SRishi.Srivatsavai@Sun.COM 	return (status);
1079815SRishi.Srivatsavai@Sun.COM }
1089815SRishi.Srivatsavai@Sun.COM 
1099815SRishi.Srivatsavai@Sun.COM /* Retrieve simnet instance information */
1109815SRishi.Srivatsavai@Sun.COM static dladm_status_t
1119815SRishi.Srivatsavai@Sun.COM i_dladm_get_simnet_info(dladm_handle_t handle, dladm_simnet_attr_t *attrp)
1129815SRishi.Srivatsavai@Sun.COM {
1139815SRishi.Srivatsavai@Sun.COM 	int rc;
1149815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status = DLADM_STATUS_OK;
1159815SRishi.Srivatsavai@Sun.COM 	simnet_ioc_info_t ioc;
1169815SRishi.Srivatsavai@Sun.COM 
1179815SRishi.Srivatsavai@Sun.COM 	bzero(&ioc, sizeof (ioc));
1189815SRishi.Srivatsavai@Sun.COM 	ioc.sii_link_id = attrp->sna_link_id;
1199815SRishi.Srivatsavai@Sun.COM 
1209815SRishi.Srivatsavai@Sun.COM 	rc = ioctl(dladm_dld_fd(handle), SIMNET_IOC_INFO, &ioc);
1219815SRishi.Srivatsavai@Sun.COM 	if (rc < 0) {
1229815SRishi.Srivatsavai@Sun.COM 		status = dladm_errno2status(errno);
1239815SRishi.Srivatsavai@Sun.COM 		return (status);
1249815SRishi.Srivatsavai@Sun.COM 	}
1259815SRishi.Srivatsavai@Sun.COM 
1269815SRishi.Srivatsavai@Sun.COM 	bcopy(ioc.sii_mac_addr, attrp->sna_mac_addr, MAXMACADDRLEN);
1279815SRishi.Srivatsavai@Sun.COM 	attrp->sna_mac_len = ioc.sii_mac_len;
1289815SRishi.Srivatsavai@Sun.COM 	attrp->sna_peer_link_id = ioc.sii_peer_link_id;
1299815SRishi.Srivatsavai@Sun.COM 	attrp->sna_type = ioc.sii_type;
1309815SRishi.Srivatsavai@Sun.COM 	return (status);
1319815SRishi.Srivatsavai@Sun.COM }
1329815SRishi.Srivatsavai@Sun.COM 
1339815SRishi.Srivatsavai@Sun.COM /* Retrieve simnet configuratin */
1349815SRishi.Srivatsavai@Sun.COM static dladm_status_t
1359815SRishi.Srivatsavai@Sun.COM i_dladm_get_simnet_info_persist(dladm_handle_t handle,
1369815SRishi.Srivatsavai@Sun.COM     dladm_simnet_attr_t *attrp)
1379815SRishi.Srivatsavai@Sun.COM {
1389815SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf;
1399815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
1409815SRishi.Srivatsavai@Sun.COM 	char macstr[ETHERADDRL * 3];
141*10616SSebastien.Roy@Sun.COM 	char simnetpeer[MAXLINKNAMELEN];
1429815SRishi.Srivatsavai@Sun.COM 	uint64_t u64;
1439815SRishi.Srivatsavai@Sun.COM 	boolean_t mac_fixed;
1449815SRishi.Srivatsavai@Sun.COM 
1459815SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_read_conf(handle, attrp->sna_link_id, &conf)) !=
1469815SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK)
1479815SRishi.Srivatsavai@Sun.COM 		return (status);
1489815SRishi.Srivatsavai@Sun.COM 
1499815SRishi.Srivatsavai@Sun.COM 	status = dladm_get_conf_field(handle, conf, FSIMNETTYPE, &u64,
1509815SRishi.Srivatsavai@Sun.COM 	    sizeof (u64));
1519815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
1529815SRishi.Srivatsavai@Sun.COM 		goto done;
1539815SRishi.Srivatsavai@Sun.COM 	attrp->sna_type = (uint_t)u64;
1549815SRishi.Srivatsavai@Sun.COM 
1559815SRishi.Srivatsavai@Sun.COM 	status = dladm_get_conf_field(handle, conf, FMADDRLEN, &u64,
1569815SRishi.Srivatsavai@Sun.COM 	    sizeof (u64));
1579815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
1589815SRishi.Srivatsavai@Sun.COM 		goto done;
1599815SRishi.Srivatsavai@Sun.COM 	attrp->sna_mac_len = (uint_t)u64;
1609815SRishi.Srivatsavai@Sun.COM 
1619815SRishi.Srivatsavai@Sun.COM 	status = dladm_get_conf_field(handle, conf, FMACADDR, macstr,
1629815SRishi.Srivatsavai@Sun.COM 	    sizeof (macstr));
1639815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
1649815SRishi.Srivatsavai@Sun.COM 		goto done;
1659815SRishi.Srivatsavai@Sun.COM 	(void) dladm_aggr_str2macaddr(macstr, &mac_fixed, attrp->sna_mac_addr);
1669815SRishi.Srivatsavai@Sun.COM 
1679815SRishi.Srivatsavai@Sun.COM 	/* Peer field is optional and only set when peer is attached */
168*10616SSebastien.Roy@Sun.COM 	if (dladm_get_conf_field(handle, conf, FSIMNETPEER, simnetpeer,
169*10616SSebastien.Roy@Sun.COM 	    sizeof (simnetpeer)) == DLADM_STATUS_OK) {
170*10616SSebastien.Roy@Sun.COM 		status = dladm_name2info(handle, simnetpeer,
171*10616SSebastien.Roy@Sun.COM 		    &attrp->sna_peer_link_id, NULL, NULL, NULL);
172*10616SSebastien.Roy@Sun.COM 	} else {
1739815SRishi.Srivatsavai@Sun.COM 		attrp->sna_peer_link_id = DATALINK_INVALID_LINKID;
174*10616SSebastien.Roy@Sun.COM 	}
1759815SRishi.Srivatsavai@Sun.COM done:
1769815SRishi.Srivatsavai@Sun.COM 	dladm_destroy_conf(handle, conf);
1779815SRishi.Srivatsavai@Sun.COM 	return (status);
1789815SRishi.Srivatsavai@Sun.COM }
1799815SRishi.Srivatsavai@Sun.COM 
1809815SRishi.Srivatsavai@Sun.COM dladm_status_t
1819815SRishi.Srivatsavai@Sun.COM dladm_simnet_create(dladm_handle_t handle, const char *simnetname,
1829815SRishi.Srivatsavai@Sun.COM     uint_t media, uint32_t flags)
1839815SRishi.Srivatsavai@Sun.COM {
1849815SRishi.Srivatsavai@Sun.COM 	datalink_id_t simnet_id;
1859815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
1869815SRishi.Srivatsavai@Sun.COM 	dladm_simnet_attr_t attr;
1879815SRishi.Srivatsavai@Sun.COM 
1889815SRishi.Srivatsavai@Sun.COM 	if (!(flags & DLADM_OPT_ACTIVE))
1899815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOTSUP);
1909815SRishi.Srivatsavai@Sun.COM 
1919815SRishi.Srivatsavai@Sun.COM 	flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
1929815SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_create_datalink_id(handle, simnetname,
1939815SRishi.Srivatsavai@Sun.COM 	    DATALINK_CLASS_SIMNET, media, flags,
1949815SRishi.Srivatsavai@Sun.COM 	    &simnet_id)) != DLADM_STATUS_OK)
1959815SRishi.Srivatsavai@Sun.COM 		return (status);
1969815SRishi.Srivatsavai@Sun.COM 
1979815SRishi.Srivatsavai@Sun.COM 	bzero(&attr, sizeof (attr));
1989815SRishi.Srivatsavai@Sun.COM 	attr.sna_link_id = simnet_id;
1999815SRishi.Srivatsavai@Sun.COM 	attr.sna_type = media;
2009815SRishi.Srivatsavai@Sun.COM 	status = i_dladm_create_simnet(handle, &attr);
2019815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
2029815SRishi.Srivatsavai@Sun.COM 		goto done;
2039815SRishi.Srivatsavai@Sun.COM 
2049815SRishi.Srivatsavai@Sun.COM 	if (!(flags & DLADM_OPT_PERSIST))
2059815SRishi.Srivatsavai@Sun.COM 		goto done;
2069815SRishi.Srivatsavai@Sun.COM 
2079815SRishi.Srivatsavai@Sun.COM 	status = dladm_simnet_persist_conf(handle, simnetname, &attr);
2089815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK) {
2099815SRishi.Srivatsavai@Sun.COM 		(void) i_dladm_delete_simnet(handle, &attr);
2109815SRishi.Srivatsavai@Sun.COM 		goto done;
2119815SRishi.Srivatsavai@Sun.COM 	}
2129815SRishi.Srivatsavai@Sun.COM 
2139815SRishi.Srivatsavai@Sun.COM 	(void) dladm_set_linkprop(handle, simnet_id, NULL, NULL, 0, flags);
2149815SRishi.Srivatsavai@Sun.COM 
2159815SRishi.Srivatsavai@Sun.COM done:
2169815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK) {
2179815SRishi.Srivatsavai@Sun.COM 		(void) dladm_destroy_datalink_id(handle, simnet_id, flags);
2189815SRishi.Srivatsavai@Sun.COM 	}
2199815SRishi.Srivatsavai@Sun.COM 	return (status);
2209815SRishi.Srivatsavai@Sun.COM }
2219815SRishi.Srivatsavai@Sun.COM 
2229815SRishi.Srivatsavai@Sun.COM /* Update existing simnet configuration */
2239815SRishi.Srivatsavai@Sun.COM static dladm_status_t
2249815SRishi.Srivatsavai@Sun.COM i_dladm_simnet_update_conf(dladm_handle_t handle, datalink_id_t simnet_id,
2259815SRishi.Srivatsavai@Sun.COM     datalink_id_t peer_simnet_id)
2269815SRishi.Srivatsavai@Sun.COM {
2279815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
2289815SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf;
229*10616SSebastien.Roy@Sun.COM 	char simnetpeer[MAXLINKNAMELEN];
2309815SRishi.Srivatsavai@Sun.COM 
2319815SRishi.Srivatsavai@Sun.COM 	status = dladm_read_conf(handle, simnet_id, &conf);
2329815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
2339815SRishi.Srivatsavai@Sun.COM 		return (status);
2349815SRishi.Srivatsavai@Sun.COM 
2359815SRishi.Srivatsavai@Sun.COM 	/* First clear previous peer if any in configuration */
2369815SRishi.Srivatsavai@Sun.COM 	(void) dladm_unset_conf_field(handle, conf, FSIMNETPEER);
2379815SRishi.Srivatsavai@Sun.COM 	if (peer_simnet_id != DATALINK_INVALID_LINKID) {
2389815SRishi.Srivatsavai@Sun.COM 		if ((status = dladm_datalink_id2info(handle,
239*10616SSebastien.Roy@Sun.COM 		    peer_simnet_id, NULL, NULL, NULL, simnetpeer,
240*10616SSebastien.Roy@Sun.COM 		    sizeof (simnetpeer))) == DLADM_STATUS_OK) {
2419815SRishi.Srivatsavai@Sun.COM 			status = dladm_set_conf_field(handle, conf,
242*10616SSebastien.Roy@Sun.COM 			    FSIMNETPEER, DLADM_TYPE_STR, simnetpeer);
243*10616SSebastien.Roy@Sun.COM 		}
2449815SRishi.Srivatsavai@Sun.COM 		if (status != DLADM_STATUS_OK)
2459815SRishi.Srivatsavai@Sun.COM 			goto fail;
2469815SRishi.Srivatsavai@Sun.COM 	}
2479815SRishi.Srivatsavai@Sun.COM 
2489815SRishi.Srivatsavai@Sun.COM 	status = dladm_write_conf(handle, conf);
2499815SRishi.Srivatsavai@Sun.COM fail:
2509815SRishi.Srivatsavai@Sun.COM 	dladm_destroy_conf(handle, conf);
2519815SRishi.Srivatsavai@Sun.COM 	return (status);
2529815SRishi.Srivatsavai@Sun.COM }
2539815SRishi.Srivatsavai@Sun.COM 
2549815SRishi.Srivatsavai@Sun.COM /* Modify attached simnet peer */
2559815SRishi.Srivatsavai@Sun.COM dladm_status_t
2569815SRishi.Srivatsavai@Sun.COM dladm_simnet_modify(dladm_handle_t handle, datalink_id_t simnet_id,
2579815SRishi.Srivatsavai@Sun.COM     datalink_id_t peer_simnet_id, uint32_t flags)
2589815SRishi.Srivatsavai@Sun.COM {
2599815SRishi.Srivatsavai@Sun.COM 	dladm_simnet_attr_t attr;
2609815SRishi.Srivatsavai@Sun.COM 	dladm_simnet_attr_t prevattr;
2619815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
2629815SRishi.Srivatsavai@Sun.COM 	datalink_class_t class;
2639815SRishi.Srivatsavai@Sun.COM 	uint32_t linkflags;
2649815SRishi.Srivatsavai@Sun.COM 	uint32_t peerlinkflags;
2659815SRishi.Srivatsavai@Sun.COM 
2669815SRishi.Srivatsavai@Sun.COM 	if (!(flags & DLADM_OPT_ACTIVE))
2679815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_NOTSUP);
2689815SRishi.Srivatsavai@Sun.COM 
2699815SRishi.Srivatsavai@Sun.COM 	if ((dladm_datalink_id2info(handle, simnet_id, &linkflags, &class,
2709815SRishi.Srivatsavai@Sun.COM 	    NULL, NULL, 0) != DLADM_STATUS_OK))
2719815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
2729815SRishi.Srivatsavai@Sun.COM 	if (class != DATALINK_CLASS_SIMNET)
2739815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
2749815SRishi.Srivatsavai@Sun.COM 
2759815SRishi.Srivatsavai@Sun.COM 	if (peer_simnet_id != DATALINK_INVALID_LINKID) {
2769815SRishi.Srivatsavai@Sun.COM 		if (dladm_datalink_id2info(handle, peer_simnet_id,
2779815SRishi.Srivatsavai@Sun.COM 		    &peerlinkflags, &class, NULL, NULL, 0) != DLADM_STATUS_OK)
2789815SRishi.Srivatsavai@Sun.COM 			return (DLADM_STATUS_BADARG);
2799815SRishi.Srivatsavai@Sun.COM 		if (class != DATALINK_CLASS_SIMNET)
2809815SRishi.Srivatsavai@Sun.COM 			return (DLADM_STATUS_BADARG);
2819815SRishi.Srivatsavai@Sun.COM 		/* Check to ensure the peer link has identical flags */
2829815SRishi.Srivatsavai@Sun.COM 		if (peerlinkflags != linkflags)
2839815SRishi.Srivatsavai@Sun.COM 			return (DLADM_STATUS_BADARG);
2849815SRishi.Srivatsavai@Sun.COM 	}
2859815SRishi.Srivatsavai@Sun.COM 
2869815SRishi.Srivatsavai@Sun.COM 	/* Retrieve previous attrs before modification */
2879815SRishi.Srivatsavai@Sun.COM 	bzero(&prevattr, sizeof (prevattr));
2889815SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_simnet_info(handle, simnet_id, &prevattr,
2899815SRishi.Srivatsavai@Sun.COM 	    flags)) != DLADM_STATUS_OK)
2909815SRishi.Srivatsavai@Sun.COM 		return (status);
2919815SRishi.Srivatsavai@Sun.COM 
2929815SRishi.Srivatsavai@Sun.COM 	bzero(&attr, sizeof (attr));
2939815SRishi.Srivatsavai@Sun.COM 	attr.sna_link_id = simnet_id;
2949815SRishi.Srivatsavai@Sun.COM 	attr.sna_peer_link_id = peer_simnet_id;
2959815SRishi.Srivatsavai@Sun.COM 	status = i_dladm_modify_simnet(handle, &attr);
2969815SRishi.Srivatsavai@Sun.COM 	if ((status != DLADM_STATUS_OK) || !(flags & DLADM_OPT_PERSIST))
2979815SRishi.Srivatsavai@Sun.COM 		return (status);
2989815SRishi.Srivatsavai@Sun.COM 
2999815SRishi.Srivatsavai@Sun.COM 	/* First we clear link's existing peer field in config */
3009815SRishi.Srivatsavai@Sun.COM 	status = i_dladm_simnet_update_conf(handle, simnet_id,
3019815SRishi.Srivatsavai@Sun.COM 	    DATALINK_INVALID_LINKID);
3029815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
3039815SRishi.Srivatsavai@Sun.COM 		return (status);
3049815SRishi.Srivatsavai@Sun.COM 
3059815SRishi.Srivatsavai@Sun.COM 	/* Clear the previous peer link's existing peer field in config */
3069815SRishi.Srivatsavai@Sun.COM 	if (prevattr.sna_peer_link_id != DATALINK_INVALID_LINKID) {
3079815SRishi.Srivatsavai@Sun.COM 		status = i_dladm_simnet_update_conf(handle,
3089815SRishi.Srivatsavai@Sun.COM 		    prevattr.sna_peer_link_id, DATALINK_INVALID_LINKID);
3099815SRishi.Srivatsavai@Sun.COM 		if (status != DLADM_STATUS_OK)
3109815SRishi.Srivatsavai@Sun.COM 			return (status);
3119815SRishi.Srivatsavai@Sun.COM 	}
3129815SRishi.Srivatsavai@Sun.COM 
3139815SRishi.Srivatsavai@Sun.COM 	/* Update the configuration in both simnets with any new peer link */
3149815SRishi.Srivatsavai@Sun.COM 	if (peer_simnet_id != DATALINK_INVALID_LINKID) {
3159815SRishi.Srivatsavai@Sun.COM 		status = i_dladm_simnet_update_conf(handle, simnet_id,
3169815SRishi.Srivatsavai@Sun.COM 		    peer_simnet_id);
3179815SRishi.Srivatsavai@Sun.COM 		if (status == DLADM_STATUS_OK)
3189815SRishi.Srivatsavai@Sun.COM 			status = i_dladm_simnet_update_conf(handle,
3199815SRishi.Srivatsavai@Sun.COM 			    peer_simnet_id, simnet_id);
3209815SRishi.Srivatsavai@Sun.COM 	}
3219815SRishi.Srivatsavai@Sun.COM 
3229815SRishi.Srivatsavai@Sun.COM 	return (status);
3239815SRishi.Srivatsavai@Sun.COM }
3249815SRishi.Srivatsavai@Sun.COM 
3259815SRishi.Srivatsavai@Sun.COM dladm_status_t
3269815SRishi.Srivatsavai@Sun.COM dladm_simnet_delete(dladm_handle_t handle, datalink_id_t simnet_id,
3279815SRishi.Srivatsavai@Sun.COM     uint32_t flags)
3289815SRishi.Srivatsavai@Sun.COM {
3299815SRishi.Srivatsavai@Sun.COM 	dladm_simnet_attr_t attr;
3309815SRishi.Srivatsavai@Sun.COM 	dladm_simnet_attr_t prevattr;
3319815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
3329815SRishi.Srivatsavai@Sun.COM 	datalink_class_t class;
3339815SRishi.Srivatsavai@Sun.COM 
3349815SRishi.Srivatsavai@Sun.COM 	if ((dladm_datalink_id2info(handle, simnet_id, NULL, &class,
3359815SRishi.Srivatsavai@Sun.COM 	    NULL, NULL, 0) != DLADM_STATUS_OK))
3369815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
3379815SRishi.Srivatsavai@Sun.COM 
3389815SRishi.Srivatsavai@Sun.COM 	if (class != DATALINK_CLASS_SIMNET)
3399815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
3409815SRishi.Srivatsavai@Sun.COM 
3419815SRishi.Srivatsavai@Sun.COM 	/* Check current simnet attributes before deletion */
3429815SRishi.Srivatsavai@Sun.COM 	flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
3439815SRishi.Srivatsavai@Sun.COM 	bzero(&prevattr, sizeof (prevattr));
3449815SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_simnet_info(handle, simnet_id, &prevattr,
3459815SRishi.Srivatsavai@Sun.COM 	    flags)) != DLADM_STATUS_OK)
3469815SRishi.Srivatsavai@Sun.COM 		return (status);
3479815SRishi.Srivatsavai@Sun.COM 
3489815SRishi.Srivatsavai@Sun.COM 	bzero(&attr, sizeof (attr));
3499815SRishi.Srivatsavai@Sun.COM 	attr.sna_link_id = simnet_id;
3509815SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_ACTIVE) {
3519815SRishi.Srivatsavai@Sun.COM 		status = i_dladm_delete_simnet(handle, &attr);
3529815SRishi.Srivatsavai@Sun.COM 		if (status == DLADM_STATUS_OK) {
3539815SRishi.Srivatsavai@Sun.COM 			(void) dladm_set_linkprop(handle, simnet_id, NULL,
3549815SRishi.Srivatsavai@Sun.COM 			    NULL, 0, DLADM_OPT_ACTIVE);
3559815SRishi.Srivatsavai@Sun.COM 			(void) dladm_destroy_datalink_id(handle, simnet_id,
3569815SRishi.Srivatsavai@Sun.COM 			    DLADM_OPT_ACTIVE);
3579815SRishi.Srivatsavai@Sun.COM 		} else if (status != DLADM_STATUS_NOTFOUND) {
3589815SRishi.Srivatsavai@Sun.COM 			return (status);
3599815SRishi.Srivatsavai@Sun.COM 		}
3609815SRishi.Srivatsavai@Sun.COM 	}
3619815SRishi.Srivatsavai@Sun.COM 
3629815SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_PERSIST) {
363*10616SSebastien.Roy@Sun.COM 		(void) dladm_remove_conf(handle, simnet_id);
3649815SRishi.Srivatsavai@Sun.COM 		(void) dladm_destroy_datalink_id(handle, simnet_id,
3659815SRishi.Srivatsavai@Sun.COM 		    DLADM_OPT_PERSIST);
3669815SRishi.Srivatsavai@Sun.COM 
3679815SRishi.Srivatsavai@Sun.COM 		/* Update any attached peer configuration */
3689815SRishi.Srivatsavai@Sun.COM 		if (prevattr.sna_peer_link_id != DATALINK_INVALID_LINKID)
3699815SRishi.Srivatsavai@Sun.COM 			status = i_dladm_simnet_update_conf(handle,
3709815SRishi.Srivatsavai@Sun.COM 			    prevattr.sna_peer_link_id, DATALINK_INVALID_LINKID);
3719815SRishi.Srivatsavai@Sun.COM 	}
3729815SRishi.Srivatsavai@Sun.COM 	return (status);
3739815SRishi.Srivatsavai@Sun.COM }
3749815SRishi.Srivatsavai@Sun.COM 
3759815SRishi.Srivatsavai@Sun.COM /* Retrieve simnet information either active or from configuration */
3769815SRishi.Srivatsavai@Sun.COM dladm_status_t
3779815SRishi.Srivatsavai@Sun.COM dladm_simnet_info(dladm_handle_t handle, datalink_id_t simnet_id,
3789815SRishi.Srivatsavai@Sun.COM     dladm_simnet_attr_t *attrp, uint32_t flags)
3799815SRishi.Srivatsavai@Sun.COM {
3809815SRishi.Srivatsavai@Sun.COM 	datalink_class_t class;
3819815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
3829815SRishi.Srivatsavai@Sun.COM 
3839815SRishi.Srivatsavai@Sun.COM 	if ((dladm_datalink_id2info(handle, simnet_id, NULL, &class,
3849815SRishi.Srivatsavai@Sun.COM 	    NULL, NULL, 0) != DLADM_STATUS_OK))
3859815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
3869815SRishi.Srivatsavai@Sun.COM 
3879815SRishi.Srivatsavai@Sun.COM 	if (class != DATALINK_CLASS_SIMNET)
3889815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
3899815SRishi.Srivatsavai@Sun.COM 
3909815SRishi.Srivatsavai@Sun.COM 	bzero(attrp, sizeof (attrp));
3919815SRishi.Srivatsavai@Sun.COM 	attrp->sna_link_id = simnet_id;
3929815SRishi.Srivatsavai@Sun.COM 
3939815SRishi.Srivatsavai@Sun.COM 	if (flags & DLADM_OPT_ACTIVE) {
3949815SRishi.Srivatsavai@Sun.COM 		status = i_dladm_get_simnet_info(handle, attrp);
3959815SRishi.Srivatsavai@Sun.COM 		/*
3969815SRishi.Srivatsavai@Sun.COM 		 * If no active simnet found then return any simnet
3979815SRishi.Srivatsavai@Sun.COM 		 * from stored config if requested.
3989815SRishi.Srivatsavai@Sun.COM 		 */
3999815SRishi.Srivatsavai@Sun.COM 		if (status == DLADM_STATUS_NOTFOUND &&
4009815SRishi.Srivatsavai@Sun.COM 		    (flags & DLADM_OPT_PERSIST))
4019815SRishi.Srivatsavai@Sun.COM 			return (i_dladm_get_simnet_info_persist(handle, attrp));
4029815SRishi.Srivatsavai@Sun.COM 		return (status);
4039815SRishi.Srivatsavai@Sun.COM 	} else if (flags & DLADM_OPT_PERSIST) {
4049815SRishi.Srivatsavai@Sun.COM 		return (i_dladm_get_simnet_info_persist(handle, attrp));
4059815SRishi.Srivatsavai@Sun.COM 	} else {
4069815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_BADARG);
4079815SRishi.Srivatsavai@Sun.COM 	}
4089815SRishi.Srivatsavai@Sun.COM }
4099815SRishi.Srivatsavai@Sun.COM 
4109815SRishi.Srivatsavai@Sun.COM /* Bring up simnet from stored configuration */
4119815SRishi.Srivatsavai@Sun.COM static int
4129815SRishi.Srivatsavai@Sun.COM i_dladm_simnet_up(dladm_handle_t handle, datalink_id_t simnet_id, void *arg)
4139815SRishi.Srivatsavai@Sun.COM {
4149815SRishi.Srivatsavai@Sun.COM 	dladm_status_t *statusp = arg;
4159815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
4169815SRishi.Srivatsavai@Sun.COM 	dladm_simnet_attr_t attr;
4179815SRishi.Srivatsavai@Sun.COM 	dladm_simnet_attr_t peer_attr;
4189815SRishi.Srivatsavai@Sun.COM 
4199815SRishi.Srivatsavai@Sun.COM 	bzero(&attr, sizeof (attr));
4209815SRishi.Srivatsavai@Sun.COM 	attr.sna_link_id = simnet_id;
4219815SRishi.Srivatsavai@Sun.COM 	status = dladm_simnet_info(handle, simnet_id, &attr,
4229815SRishi.Srivatsavai@Sun.COM 	    DLADM_OPT_PERSIST);
4239815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
4249815SRishi.Srivatsavai@Sun.COM 		goto done;
4259815SRishi.Srivatsavai@Sun.COM 
4269815SRishi.Srivatsavai@Sun.COM 	status = i_dladm_create_simnet(handle, &attr);
4279815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
4289815SRishi.Srivatsavai@Sun.COM 		goto done;
4299815SRishi.Srivatsavai@Sun.COM 
4309815SRishi.Srivatsavai@Sun.COM 	/*
4319815SRishi.Srivatsavai@Sun.COM 	 * When bringing up check if the peer link is available, if it
4329815SRishi.Srivatsavai@Sun.COM 	 * is then modify the simnet and attach the peer link.
4339815SRishi.Srivatsavai@Sun.COM 	 */
4349815SRishi.Srivatsavai@Sun.COM 	if ((attr.sna_peer_link_id != DATALINK_INVALID_LINKID) &&
4359815SRishi.Srivatsavai@Sun.COM 	    (dladm_simnet_info(handle, attr.sna_peer_link_id, &peer_attr,
4369815SRishi.Srivatsavai@Sun.COM 	    DLADM_OPT_ACTIVE) == DLADM_STATUS_OK)) {
4379815SRishi.Srivatsavai@Sun.COM 		status = i_dladm_modify_simnet(handle, &attr);
4389815SRishi.Srivatsavai@Sun.COM 		if (status != DLADM_STATUS_OK)
4399815SRishi.Srivatsavai@Sun.COM 			goto done;
4409815SRishi.Srivatsavai@Sun.COM 	}
4419815SRishi.Srivatsavai@Sun.COM 
4429815SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_up_datalink_id(handle, simnet_id)) !=
4439815SRishi.Srivatsavai@Sun.COM 	    DLADM_STATUS_OK) {
4449815SRishi.Srivatsavai@Sun.COM 		(void) dladm_simnet_delete(handle, simnet_id,
4459815SRishi.Srivatsavai@Sun.COM 		    DLADM_OPT_PERSIST);
4469815SRishi.Srivatsavai@Sun.COM 		goto done;
4479815SRishi.Srivatsavai@Sun.COM 	}
4489815SRishi.Srivatsavai@Sun.COM done:
4499815SRishi.Srivatsavai@Sun.COM 	*statusp = status;
4509815SRishi.Srivatsavai@Sun.COM 	return (DLADM_WALK_CONTINUE);
4519815SRishi.Srivatsavai@Sun.COM }
4529815SRishi.Srivatsavai@Sun.COM 
4539815SRishi.Srivatsavai@Sun.COM /* Bring up simnet instance(s) from configuration */
4549815SRishi.Srivatsavai@Sun.COM /* ARGSUSED */
4559815SRishi.Srivatsavai@Sun.COM dladm_status_t
4569815SRishi.Srivatsavai@Sun.COM dladm_simnet_up(dladm_handle_t handle, datalink_id_t simnet_id,
4579815SRishi.Srivatsavai@Sun.COM     uint32_t flags)
4589815SRishi.Srivatsavai@Sun.COM {
4599815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
4609815SRishi.Srivatsavai@Sun.COM 
4619815SRishi.Srivatsavai@Sun.COM 	if (simnet_id == DATALINK_ALL_LINKID) {
4629815SRishi.Srivatsavai@Sun.COM 		(void) dladm_walk_datalink_id(i_dladm_simnet_up, handle,
4639815SRishi.Srivatsavai@Sun.COM 		    &status, DATALINK_CLASS_SIMNET, DATALINK_ANY_MEDIATYPE,
4649815SRishi.Srivatsavai@Sun.COM 		    DLADM_OPT_PERSIST);
4659815SRishi.Srivatsavai@Sun.COM 		return (DLADM_STATUS_OK);
4669815SRishi.Srivatsavai@Sun.COM 	} else {
4679815SRishi.Srivatsavai@Sun.COM 		(void) i_dladm_simnet_up(handle, simnet_id, &status);
4689815SRishi.Srivatsavai@Sun.COM 		return (status);
4699815SRishi.Srivatsavai@Sun.COM 	}
4709815SRishi.Srivatsavai@Sun.COM }
4719815SRishi.Srivatsavai@Sun.COM 
4729815SRishi.Srivatsavai@Sun.COM /* Store simnet configuration */
4739815SRishi.Srivatsavai@Sun.COM static dladm_status_t
4749815SRishi.Srivatsavai@Sun.COM dladm_simnet_persist_conf(dladm_handle_t handle, const char *name,
4759815SRishi.Srivatsavai@Sun.COM     dladm_simnet_attr_t *attrp)
4769815SRishi.Srivatsavai@Sun.COM {
4779815SRishi.Srivatsavai@Sun.COM 	dladm_conf_t conf = DLADM_INVALID_CONF;
4789815SRishi.Srivatsavai@Sun.COM 	dladm_status_t status;
4799815SRishi.Srivatsavai@Sun.COM 	char mstr[ETHERADDRL * 3];
4809815SRishi.Srivatsavai@Sun.COM 	uint64_t u64;
4819815SRishi.Srivatsavai@Sun.COM 
4829815SRishi.Srivatsavai@Sun.COM 	if ((status = dladm_create_conf(handle, name, attrp->sna_link_id,
4839815SRishi.Srivatsavai@Sun.COM 	    DATALINK_CLASS_SIMNET, attrp->sna_type, &conf)) != DLADM_STATUS_OK)
4849815SRishi.Srivatsavai@Sun.COM 		return (status);
4859815SRishi.Srivatsavai@Sun.COM 
4869815SRishi.Srivatsavai@Sun.COM 	status = dladm_set_conf_field(handle, conf, FMACADDR,
4879815SRishi.Srivatsavai@Sun.COM 	    DLADM_TYPE_STR, dladm_aggr_macaddr2str(attrp->sna_mac_addr, mstr));
4889815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
4899815SRishi.Srivatsavai@Sun.COM 		goto done;
4909815SRishi.Srivatsavai@Sun.COM 
4919815SRishi.Srivatsavai@Sun.COM 	u64 = attrp->sna_type;
4929815SRishi.Srivatsavai@Sun.COM 	status = dladm_set_conf_field(handle, conf, FSIMNETTYPE,
4939815SRishi.Srivatsavai@Sun.COM 	    DLADM_TYPE_UINT64, &u64);
4949815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
4959815SRishi.Srivatsavai@Sun.COM 		goto done;
4969815SRishi.Srivatsavai@Sun.COM 
4979815SRishi.Srivatsavai@Sun.COM 	u64 = attrp->sna_mac_len;
4989815SRishi.Srivatsavai@Sun.COM 	status = dladm_set_conf_field(handle, conf, FMADDRLEN,
4999815SRishi.Srivatsavai@Sun.COM 	    DLADM_TYPE_UINT64, &u64);
5009815SRishi.Srivatsavai@Sun.COM 	if (status != DLADM_STATUS_OK)
5019815SRishi.Srivatsavai@Sun.COM 		goto done;
5029815SRishi.Srivatsavai@Sun.COM 
5039815SRishi.Srivatsavai@Sun.COM 	status = dladm_write_conf(handle, conf);
5049815SRishi.Srivatsavai@Sun.COM done:
5059815SRishi.Srivatsavai@Sun.COM 	dladm_destroy_conf(handle, conf);
5069815SRishi.Srivatsavai@Sun.COM 	return (status);
5079815SRishi.Srivatsavai@Sun.COM }
508