18275SEric Cheng /*
28275SEric Cheng  * CDDL HEADER START
38275SEric Cheng  *
48275SEric Cheng  * The contents of this file are subject to the terms of the
58275SEric Cheng  * Common Development and Distribution License (the "License").
68275SEric Cheng  * You may not use this file except in compliance with the License.
78275SEric Cheng  *
88275SEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98275SEric Cheng  * or http://www.opensolaris.org/os/licensing.
108275SEric Cheng  * See the License for the specific language governing permissions
118275SEric Cheng  * and limitations under the License.
128275SEric Cheng  *
138275SEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
148275SEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158275SEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
168275SEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
178275SEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
188275SEric Cheng  *
198275SEric Cheng  * CDDL HEADER END
208275SEric Cheng  */
218275SEric Cheng /*
228558SGirish.Moodalbail@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
238275SEric Cheng  * Use is subject to license terms.
248275SEric Cheng  */
258275SEric Cheng 
268275SEric Cheng #include <stdio.h>
278275SEric Cheng #include <sys/types.h>
288275SEric Cheng #include <sys/socket.h>
298275SEric Cheng #include <sys/ethernet.h>
308275SEric Cheng #include <netinet/in.h>
318275SEric Cheng #include <arpa/inet.h>
328275SEric Cheng #include <sys/stat.h>
339107Sjames.d.carlson@sun.com #include <sys/dld_ioc.h>
348275SEric Cheng #include <string.h>
358275SEric Cheng #include <fcntl.h>
368275SEric Cheng #include <unistd.h>
378275SEric Cheng #include <stropts.h>
388275SEric Cheng #include <stdlib.h>
398275SEric Cheng #include <errno.h>
408275SEric Cheng #include <strings.h>
418275SEric Cheng #include <libintl.h>
428275SEric Cheng #include <netdb.h>
438275SEric Cheng #include <net/if_types.h>
448275SEric Cheng #include <net/if_dl.h>
458275SEric Cheng #include <inet/ip.h>
468275SEric Cheng #include <inet/ip6.h>
478275SEric Cheng #include <libdlflow.h>
488275SEric Cheng #include <libdlflow_impl.h>
498275SEric Cheng #include <libdladm_impl.h>
508275SEric Cheng 
518275SEric Cheng /* minimum buffer size for DLDIOCWALKFLOW */
528275SEric Cheng #define	MIN_INFO_SIZE	(4 * 1024)
538275SEric Cheng 
548275SEric Cheng #define	DLADM_FLOW_DB		"/etc/dladm/flowadm.conf"
558275SEric Cheng #define	DLADM_FLOW_DB_TMP	"/etc/dladm/flowadm.conf.new"
568275SEric Cheng #define	DLADM_FLOW_DB_LOCK	"/tmp/flowadm.conf.lock"
578275SEric Cheng 
588275SEric Cheng #define	DLADM_FLOW_DB_PERMS	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
598275SEric Cheng #define	DLADM_FLOW_DB_OWNER	UID_DLADM
608275SEric Cheng #define	DLADM_FLOW_DB_GROUP	GID_SYS
618275SEric Cheng 
628275SEric Cheng #define	BLANK_LINE(s)	((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n'))
638275SEric Cheng #define	MAXLINELEN	1024
648275SEric Cheng #define	MAXPATHLEN	1024
658275SEric Cheng 
668275SEric Cheng #define	V4_PART_OF_V6(v6)	((v6)._S6_un._S6_u32[3])
678275SEric Cheng 
688275SEric Cheng /* database file parameters */
698275SEric Cheng static const char *BW_LIMIT = "bw_limit";
708275SEric Cheng static const char *PRIORITY = "priority";
718275SEric Cheng static const char *LOCAL_IP_ADDR = "local_ip";
728275SEric Cheng static const char *REMOTE_IP_ADDR = "remote_ip";
738275SEric Cheng static const char *TRANSPORT = "transport";
748275SEric Cheng static const char *LOCAL_PORT = "local_port";
75*10734SEric Cheng static const char *REMOTE_PORT = "remote_port";
768275SEric Cheng static const char *DSFIELD = "dsfield";
778275SEric Cheng 
788275SEric Cheng /*
798275SEric Cheng  * Open and lock the flowadm configuration file lock. The lock is
808275SEric Cheng  * acquired as a reader (F_RDLCK) or writer (F_WRLCK).
818275SEric Cheng  */
828275SEric Cheng static int
838275SEric Cheng i_dladm_flow_lock_db(short type)
848275SEric Cheng {
858275SEric Cheng 	int lock_fd;
868275SEric Cheng 	struct flock lock;
878275SEric Cheng 
888275SEric Cheng 	if ((lock_fd = open(DLADM_FLOW_DB_LOCK, O_RDWR | O_CREAT | O_TRUNC,
898275SEric Cheng 	    DLADM_FLOW_DB_PERMS)) < 0)
908275SEric Cheng 		return (-1);
918275SEric Cheng 
928275SEric Cheng 	lock.l_type = type;
938275SEric Cheng 	lock.l_whence = SEEK_SET;
948275SEric Cheng 	lock.l_start = 0;
958275SEric Cheng 	lock.l_len = 0;
968275SEric Cheng 
978275SEric Cheng 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
988275SEric Cheng 		(void) close(lock_fd);
998275SEric Cheng 		(void) unlink(DLADM_FLOW_DB_LOCK);
1008275SEric Cheng 		return (-1);
1018275SEric Cheng 	}
1028275SEric Cheng 	return (lock_fd);
1038275SEric Cheng }
1048275SEric Cheng 
1058275SEric Cheng /*
1068275SEric Cheng  * Unlock and close the specified file.
1078275SEric Cheng  */
1088275SEric Cheng static void
1098275SEric Cheng i_dladm_flow_unlock_db(int fd)
1108275SEric Cheng {
1118275SEric Cheng 	struct flock lock;
1128275SEric Cheng 
1138275SEric Cheng 	if (fd < 0)
1148275SEric Cheng 		return;
1158275SEric Cheng 
1168275SEric Cheng 	lock.l_type = F_UNLCK;
1178275SEric Cheng 	lock.l_whence = SEEK_SET;
1188275SEric Cheng 	lock.l_start = 0;
1198275SEric Cheng 	lock.l_len = 0;
1208275SEric Cheng 
1218275SEric Cheng 	(void) fcntl(fd, F_SETLKW, &lock);
1228275SEric Cheng 	(void) close(fd);
1238275SEric Cheng 	(void) unlink(DLADM_FLOW_DB_LOCK);
1248275SEric Cheng }
1258275SEric Cheng 
1268275SEric Cheng /*
1278275SEric Cheng  * Parse one line of the link flowadm DB
1288275SEric Cheng  * Returns -1 on failure, 0 on success.
1298275SEric Cheng  */
1308275SEric Cheng dladm_status_t
1318275SEric Cheng dladm_flow_parse_db(char *line, dld_flowinfo_t *attr)
1328275SEric Cheng {
1338275SEric Cheng 	char		*token;
1348275SEric Cheng 	char		*value, *name = NULL;
1358275SEric Cheng 	char		*lasts = NULL;
1368275SEric Cheng 	dladm_status_t	status = DLADM_STATUS_FLOW_DB_PARSE_ERR;
1378275SEric Cheng 
1388275SEric Cheng 	bzero(attr, sizeof (*attr));
1398275SEric Cheng 
1408275SEric Cheng 	/* flow name */
1418275SEric Cheng 	if ((token = strtok_r(line, " \t", &lasts)) == NULL)
1428275SEric Cheng 		goto done;
1438275SEric Cheng 
1448558SGirish.Moodalbail@Sun.COM 	if (strlcpy(attr->fi_flowname, token, MAXFLOWNAMELEN) >= MAXFLOWNAMELEN)
1458275SEric Cheng 		goto done;
1468275SEric Cheng 
1478275SEric Cheng 	/* resource control and flow descriptor parameters */
1488275SEric Cheng 	while ((token = strtok_r(NULL, " \t", &lasts)) != NULL) {
1498275SEric Cheng 		if ((name = strdup(token)) == NULL)
1508275SEric Cheng 			goto done;
1518275SEric Cheng 
1528275SEric Cheng 		(void) strtok(name, "=");
1538275SEric Cheng 		value = strtok(NULL, "=");
1548275SEric Cheng 		if (value == NULL)
1558275SEric Cheng 			goto done;
1568275SEric Cheng 
1578275SEric Cheng 		if (strcmp(name, "linkid") == 0) {
1588275SEric Cheng 			if ((attr->fi_linkid =
159*10734SEric Cheng 			    (uint32_t)strtol(value, NULL, 10)) ==
1608275SEric Cheng 			    DATALINK_INVALID_LINKID)
1618275SEric Cheng 				goto done;
1628275SEric Cheng 
1638275SEric Cheng 		} else if (strcmp(name, BW_LIMIT) == 0) {
1648275SEric Cheng 			attr->fi_resource_props.mrp_mask |=
1658275SEric Cheng 			    MRP_MAXBW;
1668275SEric Cheng 			attr->fi_resource_props.mrp_maxbw =
167*10734SEric Cheng 			    (uint64_t)strtol(value, NULL, 0);
1688275SEric Cheng 
1698275SEric Cheng 		} else if (strcmp(name, PRIORITY) == 0) {
1708275SEric Cheng 			attr->fi_resource_props.mrp_mask |= MRP_PRIORITY;
1718275SEric Cheng 			status = dladm_str2pri(value,
1728275SEric Cheng 			    &attr->fi_resource_props.mrp_priority);
1738275SEric Cheng 			if (status != DLADM_STATUS_OK)
1748275SEric Cheng 				goto done;
1758275SEric Cheng 
1768275SEric Cheng 		} else if (strcmp(name, DSFIELD) == 0) {
1778275SEric Cheng 			status = do_check_dsfield(value,
1788275SEric Cheng 			    &attr->fi_flow_desc);
1798275SEric Cheng 			if (status != DLADM_STATUS_OK)
1808275SEric Cheng 				goto done;
1818275SEric Cheng 
1828275SEric Cheng 		} else if (strcmp(name, LOCAL_IP_ADDR) == 0) {
1838275SEric Cheng 			status = do_check_ip_addr(value, B_TRUE,
1848275SEric Cheng 			    &attr->fi_flow_desc);
1858275SEric Cheng 			if (status != DLADM_STATUS_OK)
1868275SEric Cheng 				goto done;
1878275SEric Cheng 
1888275SEric Cheng 		} else if (strcmp(name, REMOTE_IP_ADDR) == 0) {
1898275SEric Cheng 			status = do_check_ip_addr(value, B_FALSE,
1908275SEric Cheng 			    &attr->fi_flow_desc);
1918275SEric Cheng 			if (status != DLADM_STATUS_OK)
1928275SEric Cheng 				goto done;
1938275SEric Cheng 
1948275SEric Cheng 		} else if (strcmp(name, TRANSPORT) == 0) {
1958275SEric Cheng 			attr->fi_flow_desc.fd_mask |= FLOW_IP_PROTOCOL;
1968275SEric Cheng 			attr->fi_flow_desc.fd_protocol =
197*10734SEric Cheng 			    (uint8_t)strtol(value, NULL, 0);
1988275SEric Cheng 
1998275SEric Cheng 		} else if (strcmp(name, LOCAL_PORT) == 0) {
2008275SEric Cheng 			attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_LOCAL;
2018275SEric Cheng 			attr->fi_flow_desc.fd_local_port =
202*10734SEric Cheng 			    (uint16_t)strtol(value, NULL, 10);
2038275SEric Cheng 			attr->fi_flow_desc.fd_local_port =
2048275SEric Cheng 			    htons(attr->fi_flow_desc.fd_local_port);
205*10734SEric Cheng 		} else if (strcmp(name, REMOTE_PORT) == 0) {
206*10734SEric Cheng 			attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_REMOTE;
207*10734SEric Cheng 			attr->fi_flow_desc.fd_remote_port =
208*10734SEric Cheng 			    (uint16_t)strtol(value, NULL, 10);
209*10734SEric Cheng 			attr->fi_flow_desc.fd_remote_port =
210*10734SEric Cheng 			    htons(attr->fi_flow_desc.fd_remote_port);
2118275SEric Cheng 		}
2128275SEric Cheng 		free(name);
2138275SEric Cheng 		name = NULL;
2148275SEric Cheng 	}
2158275SEric Cheng 	if (attr->fi_linkid != DATALINK_INVALID_LINKID)
2168275SEric Cheng 		status = DLADM_STATUS_OK;
2178275SEric Cheng done:
2188275SEric Cheng 	free(name);
2198275SEric Cheng 	return (status);
2208275SEric Cheng }
2218275SEric Cheng 
2228275SEric Cheng #define	FPRINTF_ERR(fcall) if ((fcall) < 0) return (-1);
2238275SEric Cheng 
2248275SEric Cheng /*
2258275SEric Cheng  * Write the attribute of a group to the specified file. Returns 0 on
2268275SEric Cheng  * success, -1 on failure.
2278275SEric Cheng  */
2288275SEric Cheng static int
2298275SEric Cheng i_dladm_flow_fput_grp(FILE *fp, dld_flowinfo_t *attr)
2308275SEric Cheng {
2318275SEric Cheng 
2328275SEric Cheng 	FPRINTF_ERR(fprintf(fp, "%s\tlinkid=%d\t",
2338275SEric Cheng 	    attr->fi_flowname, attr->fi_linkid));
2348275SEric Cheng 
2358275SEric Cheng 	/* flow policy */
2368275SEric Cheng 	if (attr->fi_resource_props.mrp_mask & MRP_MAXBW)
2378275SEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%" PRIu64 "\t", BW_LIMIT,
2388275SEric Cheng 		    attr->fi_resource_props.mrp_maxbw));
2398275SEric Cheng 
2408275SEric Cheng 	if (attr->fi_resource_props.mrp_mask & MRP_PRIORITY)
2418275SEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%d\t", PRIORITY,
2428275SEric Cheng 		    attr->fi_resource_props.mrp_priority));
2438275SEric Cheng 
2448275SEric Cheng 	/* flow descriptor */
2458275SEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_IP_DSFIELD)
2468275SEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%x:%x\t", DSFIELD,
2478275SEric Cheng 		    attr->fi_flow_desc.fd_dsfield,
2488275SEric Cheng 		    attr->fi_flow_desc.fd_dsfield_mask));
2498275SEric Cheng 
2508275SEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_IP_LOCAL) {
2518275SEric Cheng 		char abuf[INET6_ADDRSTRLEN], *ap;
2528275SEric Cheng 		struct in_addr ipaddr;
2538275SEric Cheng 		int prefix_len, prefix_max;
2548275SEric Cheng 
2558275SEric Cheng 		if (attr->fi_flow_desc.fd_ipversion != 6) {
2568275SEric Cheng 			ipaddr.s_addr =
2578275SEric Cheng 			    attr->fi_flow_desc.
2588275SEric Cheng 			    fd_local_addr._S6_un._S6_u32[3];
2598275SEric Cheng 
2608275SEric Cheng 			ap = inet_ntoa(ipaddr);
2618275SEric Cheng 			prefix_max = IP_ABITS;
2628275SEric Cheng 		} else {
2638275SEric Cheng 			(void) inet_ntop(AF_INET6,
2648275SEric Cheng 			    &attr->fi_flow_desc.fd_local_addr,
2658275SEric Cheng 			    abuf, INET6_ADDRSTRLEN);
2668275SEric Cheng 
2678275SEric Cheng 			ap = abuf;
2688275SEric Cheng 			prefix_max = IPV6_ABITS;
2698275SEric Cheng 		}
2708275SEric Cheng 		(void) dladm_mask2prefixlen(
2718275SEric Cheng 		    &attr->fi_flow_desc.fd_local_netmask, prefix_max,
2728275SEric Cheng 		    &prefix_len);
2738275SEric Cheng 
2748275SEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%s/%d\t", LOCAL_IP_ADDR,
2758275SEric Cheng 		    ap, prefix_len));
2768275SEric Cheng 	}
2778275SEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_IP_REMOTE) {
2788275SEric Cheng 		char abuf[INET6_ADDRSTRLEN], *ap;
2798275SEric Cheng 		struct in_addr ipaddr;
2808275SEric Cheng 		int prefix_len, prefix_max;
2818275SEric Cheng 
2828275SEric Cheng 		if (attr->fi_flow_desc.fd_ipversion != 6) {
2838275SEric Cheng 			ipaddr.s_addr =
2848275SEric Cheng 			    attr->fi_flow_desc.
2858275SEric Cheng 			    fd_remote_addr._S6_un._S6_u32[3];
2868275SEric Cheng 
2878275SEric Cheng 			ap = inet_ntoa(ipaddr);
2888275SEric Cheng 			prefix_max = IP_ABITS;
2898275SEric Cheng 		} else {
2908275SEric Cheng 			(void) inet_ntop(AF_INET6,
2918275SEric Cheng 			    &(attr->fi_flow_desc.fd_remote_addr),
2928275SEric Cheng 			    abuf, INET6_ADDRSTRLEN);
2938275SEric Cheng 
2948275SEric Cheng 			ap = abuf;
2958275SEric Cheng 			prefix_max = IPV6_ABITS;
2968275SEric Cheng 		}
2978275SEric Cheng 		(void) dladm_mask2prefixlen(
2988275SEric Cheng 		    &attr->fi_flow_desc.fd_remote_netmask, prefix_max,
2998275SEric Cheng 		    &prefix_len);
3008275SEric Cheng 
3018275SEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%s/%d\t", REMOTE_IP_ADDR,
3028275SEric Cheng 		    ap, prefix_len));
3038275SEric Cheng 	}
3048275SEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_IP_PROTOCOL)
3058275SEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%d\t", TRANSPORT,
3068275SEric Cheng 		    attr->fi_flow_desc.fd_protocol));
3078275SEric Cheng 
3088275SEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL)
3098275SEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%d\t", LOCAL_PORT,
3108275SEric Cheng 		    ntohs(attr->fi_flow_desc.fd_local_port)));
3118275SEric Cheng 
312*10734SEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE)
313*10734SEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%d\t", REMOTE_PORT,
314*10734SEric Cheng 		    ntohs(attr->fi_flow_desc.fd_remote_port)));
315*10734SEric Cheng 
3168275SEric Cheng 	FPRINTF_ERR(fprintf(fp, "\n"));
3178275SEric Cheng 
3188275SEric Cheng 	return (0);
3198275SEric Cheng 
3208275SEric Cheng }
3218275SEric Cheng 
3228275SEric Cheng static dladm_status_t
3238275SEric Cheng i_dladm_flow_walk_rw_db(int (*fn)(void *, dld_flowinfo_t *),
3248275SEric Cheng     void *arg,
3258275SEric Cheng     const char *root)
3268275SEric Cheng {
3278275SEric Cheng 	FILE *fp, *nfp;
3288275SEric Cheng 	int nfd, fn_rc, lock_fd;
3298275SEric Cheng 	char line[MAXLINELEN];
3308275SEric Cheng 	dld_flowinfo_t attr;
3318275SEric Cheng 	char *db_file, *tmp_db_file;
3328275SEric Cheng 	char db_file_buf[MAXPATHLEN];
3338275SEric Cheng 	char tmp_db_file_buf[MAXPATHLEN];
3348275SEric Cheng 	dladm_status_t	status = DLADM_STATUS_FLOW_DB_ERR;
3358275SEric Cheng 
3368275SEric Cheng 	if (root == NULL) {
3378275SEric Cheng 		db_file = DLADM_FLOW_DB;
3388275SEric Cheng 		tmp_db_file = DLADM_FLOW_DB_TMP;
3398275SEric Cheng 	} else {
3408275SEric Cheng 		(void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
3418275SEric Cheng 		    DLADM_FLOW_DB);
3428275SEric Cheng 		(void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root,
3438275SEric Cheng 		    DLADM_FLOW_DB_TMP);
3448275SEric Cheng 		db_file = db_file_buf;
3458275SEric Cheng 		tmp_db_file = tmp_db_file_buf;
3468275SEric Cheng 	}
3478275SEric Cheng 
3488275SEric Cheng 	if ((lock_fd = i_dladm_flow_lock_db(F_WRLCK)) < 0)
3498275SEric Cheng 		return (DLADM_STATUS_FLOW_DB_ERR);
3508275SEric Cheng 
3518275SEric Cheng 	if ((fp = fopen(db_file, "r")) == NULL) {
3528275SEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
3538275SEric Cheng 		return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
3548275SEric Cheng 	}
3558275SEric Cheng 
3568275SEric Cheng 	if ((nfd = open(tmp_db_file, O_WRONLY|O_CREAT|O_TRUNC,
3578275SEric Cheng 	    DLADM_FLOW_DB_PERMS)) == -1) {
3588275SEric Cheng 		(void) fclose(fp);
3598275SEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
3608275SEric Cheng 		return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
3618275SEric Cheng 	}
3628275SEric Cheng 
3638275SEric Cheng 	if ((nfp = fdopen(nfd, "w")) == NULL) {
3648275SEric Cheng 		(void) close(nfd);
3658275SEric Cheng 		(void) fclose(fp);
3668275SEric Cheng 		(void) unlink(tmp_db_file);
3678275SEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
3688275SEric Cheng 		return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
3698275SEric Cheng 	}
3708275SEric Cheng 
3718275SEric Cheng 	while (fgets(line, MAXLINELEN, fp) != NULL) {
3728275SEric Cheng 
3738275SEric Cheng 		/* skip comments */
3748275SEric Cheng 		if (BLANK_LINE(line)) {
3758275SEric Cheng 			if (fputs(line, nfp) == EOF)
3768275SEric Cheng 				goto failed;
3778275SEric Cheng 			continue;
3788275SEric Cheng 		}
3798275SEric Cheng 		(void) strtok(line, " \n");
3808275SEric Cheng 
3818275SEric Cheng 		if ((status = dladm_flow_parse_db(line, &attr)) !=
3828275SEric Cheng 		    DLADM_STATUS_OK)
3838275SEric Cheng 			goto failed;
3848275SEric Cheng 
3858275SEric Cheng 		fn_rc = fn(arg, &attr);
3868275SEric Cheng 
3878275SEric Cheng 		switch (fn_rc) {
3888275SEric Cheng 		case -1:
3898275SEric Cheng 			/* failure, stop walking */
3908275SEric Cheng 			goto failed;
3918275SEric Cheng 		case 0:
3928275SEric Cheng 			/*
3938275SEric Cheng 			 * Success, write group attributes, which could
3948275SEric Cheng 			 * have been modified by fn().
3958275SEric Cheng 			 */
3968275SEric Cheng 			if (i_dladm_flow_fput_grp(nfp, &attr) != 0)
3978275SEric Cheng 				goto failed;
3988275SEric Cheng 			break;
3998275SEric Cheng 		case 1:
4008275SEric Cheng 			/* skip current group */
4018275SEric Cheng 			break;
4028275SEric Cheng 		}
4038275SEric Cheng 	}
4048275SEric Cheng 	if (fchmod(nfd, DLADM_FLOW_DB_PERMS) == -1)
4058275SEric Cheng 		goto failed;
4068275SEric Cheng 
4078275SEric Cheng 	if (fchown(nfd, DLADM_FLOW_DB_OWNER, DLADM_FLOW_DB_GROUP) == -1)
4088275SEric Cheng 		goto failed;
4098275SEric Cheng 
4108275SEric Cheng 	if (fflush(nfp) == EOF)
4118275SEric Cheng 		goto failed;
4128275SEric Cheng 
4138275SEric Cheng 	(void) fclose(fp);
4148275SEric Cheng 	(void) fclose(nfp);
4158275SEric Cheng 
4168275SEric Cheng 	if (rename(tmp_db_file, db_file) == -1) {
4178275SEric Cheng 		(void) unlink(tmp_db_file);
4188275SEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
4198275SEric Cheng 		return (DLADM_STATUS_FLOW_DB_ERR);
4208275SEric Cheng 	}
4218275SEric Cheng 	i_dladm_flow_unlock_db(lock_fd);
4228275SEric Cheng 	return (DLADM_STATUS_OK);
4238275SEric Cheng 
4248275SEric Cheng failed:
4258275SEric Cheng 	(void) fclose(fp);
4268275SEric Cheng 	(void) fclose(nfp);
4278275SEric Cheng 	(void) unlink(tmp_db_file);
4288275SEric Cheng 	i_dladm_flow_unlock_db(lock_fd);
4298275SEric Cheng 
4308275SEric Cheng 	return (status);
4318275SEric Cheng }
4328275SEric Cheng 
4338275SEric Cheng /*
4348275SEric Cheng  * Remove existing flow from DB.
4358275SEric Cheng  */
4368275SEric Cheng 
4378275SEric Cheng typedef struct remove_db_state {
4388275SEric Cheng 	dld_flowinfo_t	rs_newattr;
4398275SEric Cheng 	dld_flowinfo_t	rs_oldattr;
4408275SEric Cheng 	boolean_t	rs_found;
4418275SEric Cheng } remove_db_state_t;
4428275SEric Cheng 
4438275SEric Cheng static int
4448275SEric Cheng i_dladm_flow_remove_db_fn(void *arg, dld_flowinfo_t *grp)
4458275SEric Cheng {
4468275SEric Cheng 	remove_db_state_t *state = (remove_db_state_t *)arg;
4478275SEric Cheng 	dld_flowinfo_t *attr = &state->rs_newattr;
4488275SEric Cheng 
4498275SEric Cheng 	if ((strcmp(grp->fi_flowname, attr->fi_flowname)) != 0)
4508275SEric Cheng 		return (0);
4518275SEric Cheng 	else {
4528275SEric Cheng 		bcopy(grp, &state->rs_oldattr,
4538275SEric Cheng 		    sizeof (dld_flowinfo_t));
4548275SEric Cheng 		state->rs_found = B_TRUE;
4558275SEric Cheng 		return (1);
4568275SEric Cheng 	}
4578275SEric Cheng }
4588275SEric Cheng 
4598275SEric Cheng /* ARGSUSED */
4608275SEric Cheng static int
4618275SEric Cheng i_dladm_flow_remove_db(remove_db_state_t *state, const char *root)
4628275SEric Cheng {
4638275SEric Cheng 	if (i_dladm_flow_walk_rw_db(i_dladm_flow_remove_db_fn, state, root)
4648275SEric Cheng 	    != 0)
4658275SEric Cheng 		return (-1);
4668275SEric Cheng 
4678275SEric Cheng 	if (!state->rs_found) {
4688275SEric Cheng 		errno = ENOENT;
4698275SEric Cheng 		return (-1);
4708275SEric Cheng 	}
4718275SEric Cheng 
4728275SEric Cheng 	return (0);
4738275SEric Cheng }
4748275SEric Cheng 
4758275SEric Cheng /*
4768275SEric Cheng  * Create a flow in the DB.
4778275SEric Cheng  */
4788275SEric Cheng 
4798275SEric Cheng typedef struct modify_db_state {
4808275SEric Cheng 	dld_flowinfo_t	ms_newattr;
4818275SEric Cheng 	dld_flowinfo_t	ms_oldattr;
4828275SEric Cheng 	boolean_t	ms_found;
4838275SEric Cheng } modify_db_state_t;
4848275SEric Cheng 
4858275SEric Cheng static dladm_status_t
4868275SEric Cheng i_dladm_flow_create_db(dld_flowinfo_t *attr, const char *root)
4878275SEric Cheng {
4888275SEric Cheng 	FILE 	*fp;
4898275SEric Cheng 	char 	line[MAXLINELEN];
4908275SEric Cheng 	char	*db_file;
4918275SEric Cheng 	char	db_file_buf[MAXPATHLEN];
4928275SEric Cheng 	int	lock_fd;
4938275SEric Cheng 	dladm_status_t	status = DLADM_STATUS_OK;
4948275SEric Cheng 
4958275SEric Cheng 	if (root == NULL) {
4968275SEric Cheng 		db_file = DLADM_FLOW_DB;
4978275SEric Cheng 	} else {
4988275SEric Cheng 		(void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
4998275SEric Cheng 		    DLADM_FLOW_DB);
5008275SEric Cheng 		db_file = db_file_buf;
5018275SEric Cheng 	}
5028275SEric Cheng 
5038275SEric Cheng 	if ((lock_fd = i_dladm_flow_lock_db(F_WRLCK)) < 0)
5048275SEric Cheng 		return (DLADM_STATUS_FLOW_DB_ERR);
5058275SEric Cheng 
5068275SEric Cheng 	if ((fp = fopen(db_file, "r+")) == NULL &&
5078275SEric Cheng 	    (fp = fopen(db_file, "w")) == NULL) {
5088275SEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
5098275SEric Cheng 		return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
5108275SEric Cheng 	}
5118275SEric Cheng 
5128275SEric Cheng 	/* look for existing group with same flowname */
5138275SEric Cheng 	while (fgets(line, MAXLINELEN, fp) != NULL) {
5148275SEric Cheng 		char *holder, *lasts;
5158275SEric Cheng 
5168275SEric Cheng 		/* skip comments */
5178275SEric Cheng 		if (BLANK_LINE(line))
5188275SEric Cheng 			continue;
5198275SEric Cheng 
5208275SEric Cheng 		/* ignore corrupted lines */
5218275SEric Cheng 		holder = strtok_r(line, " \t", &lasts);
5228275SEric Cheng 		if (holder == NULL)
5238275SEric Cheng 			continue;
5248275SEric Cheng 
5258275SEric Cheng 		/* flow id */
5268275SEric Cheng 		if (strcmp(holder, attr->fi_flowname) == 0) {
5278275SEric Cheng 			/* group with flow id already exists */
5288275SEric Cheng 			status = DLADM_STATUS_PERSIST_FLOW_EXISTS;
5298275SEric Cheng 			goto failed;
5308275SEric Cheng 		}
5318275SEric Cheng 	}
5328275SEric Cheng 	/*
5338275SEric Cheng 	 * If we get here, we've verified that no existing group with
5348275SEric Cheng 	 * the same flow id already exists. Its now time to add the new
5358275SEric Cheng 	 * group to the DB.
5368275SEric Cheng 	 */
5378275SEric Cheng 	if (i_dladm_flow_fput_grp(fp, attr) != 0)
5388275SEric Cheng 		status = DLADM_STATUS_FLOW_DB_PARSE_ERR;
5398275SEric Cheng 
5408275SEric Cheng failed:
5418275SEric Cheng 	(void) fclose(fp);
5428275SEric Cheng 	i_dladm_flow_unlock_db(lock_fd);
5438275SEric Cheng 	return (status);
5448275SEric Cheng }
5458275SEric Cheng 
5468275SEric Cheng static dladm_status_t
5478453SAnurag.Maskey@Sun.COM i_dladm_flow_add(dladm_handle_t handle, char *flowname, datalink_id_t linkid,
5488453SAnurag.Maskey@Sun.COM     flow_desc_t *flowdesc, mac_resource_props_t *mrp)
5498275SEric Cheng {
5508275SEric Cheng 	dld_ioc_addflow_t	attr;
5518275SEric Cheng 
5528275SEric Cheng 	/* create flow */
5538275SEric Cheng 	bzero(&attr, sizeof (attr));
5548275SEric Cheng 	bcopy(flowdesc, &attr.af_flow_desc, sizeof (flow_desc_t));
5558275SEric Cheng 	if (mrp != NULL) {
5568275SEric Cheng 		bcopy(mrp, &attr.af_resource_props,
5578275SEric Cheng 		    sizeof (mac_resource_props_t));
5588275SEric Cheng 	}
5598275SEric Cheng 
5608275SEric Cheng 	(void) strlcpy(attr.af_name, flowname, sizeof (attr.af_name));
5618275SEric Cheng 	attr.af_linkid = linkid;
5628275SEric Cheng 
5638453SAnurag.Maskey@Sun.COM 	if (ioctl(dladm_dld_fd(handle), DLDIOC_ADDFLOW, &attr) < 0)
5648275SEric Cheng 		return (dladm_errno2status(errno));
5658275SEric Cheng 
5668275SEric Cheng 	return (DLADM_STATUS_OK);
5678275SEric Cheng }
5688275SEric Cheng 
5698275SEric Cheng static dladm_status_t
5708453SAnurag.Maskey@Sun.COM i_dladm_flow_remove(dladm_handle_t handle, char *flowname)
5718275SEric Cheng {
5728275SEric Cheng 	dld_ioc_removeflow_t	attr;
5738275SEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
5748275SEric Cheng 
5758275SEric Cheng 	(void) strlcpy(attr.rf_name, flowname,
5768275SEric Cheng 	    sizeof (attr.rf_name));
5778275SEric Cheng 
5788453SAnurag.Maskey@Sun.COM 	if (ioctl(dladm_dld_fd(handle), DLDIOC_REMOVEFLOW, &attr) < 0)
5798275SEric Cheng 		status = dladm_errno2status(errno);
5808275SEric Cheng 
5818275SEric Cheng 	return (status);
5828275SEric Cheng }
5838275SEric Cheng 
5848275SEric Cheng 
5858275SEric Cheng /* ARGSUSED */
5868275SEric Cheng dladm_status_t
5878453SAnurag.Maskey@Sun.COM dladm_flow_add(dladm_handle_t handle, datalink_id_t linkid,
5888453SAnurag.Maskey@Sun.COM     dladm_arg_list_t *attrlist, dladm_arg_list_t *proplist, char *flowname,
5898453SAnurag.Maskey@Sun.COM     boolean_t tempop, const char *root)
5908275SEric Cheng {
5918275SEric Cheng 	dld_flowinfo_t		db_attr;
5928275SEric Cheng 	flow_desc_t		flowdesc;
5938275SEric Cheng 	mac_resource_props_t	mrp;
5948275SEric Cheng 	dladm_status_t		status;
5958275SEric Cheng 
5968275SEric Cheng 	/* Extract flow attributes from attrlist */
5978275SEric Cheng 	bzero(&flowdesc, sizeof (flow_desc_t));
5988275SEric Cheng 	if (attrlist != NULL && (status = dladm_flow_attrlist_extract(attrlist,
5998275SEric Cheng 	    &flowdesc)) != DLADM_STATUS_OK) {
6008275SEric Cheng 		return (status);
6018275SEric Cheng 	}
6028275SEric Cheng 
6038275SEric Cheng 	/* Extract resource_ctl and cpu_list from proplist */
6048275SEric Cheng 	bzero(&mrp, sizeof (mac_resource_props_t));
6058275SEric Cheng 	if (proplist != NULL && (status = dladm_flow_proplist_extract(proplist,
6068275SEric Cheng 	    &mrp)) != DLADM_STATUS_OK) {
6078275SEric Cheng 		return (status);
6088275SEric Cheng 	}
6098275SEric Cheng 
6108275SEric Cheng 	/* Add flow in kernel */
6118453SAnurag.Maskey@Sun.COM 	status = i_dladm_flow_add(handle, flowname, linkid, &flowdesc, &mrp);
6128275SEric Cheng 	if (status != DLADM_STATUS_OK)
6138275SEric Cheng 		return (status);
6148275SEric Cheng 
6158275SEric Cheng 	/* Add flow to DB */
6168275SEric Cheng 	if (!tempop) {
6178275SEric Cheng 		bzero(&db_attr, sizeof (db_attr));
6188275SEric Cheng 		bcopy(&flowdesc, &db_attr.fi_flow_desc, sizeof (flow_desc_t));
6198275SEric Cheng 		(void) strlcpy(db_attr.fi_flowname, flowname,
6208275SEric Cheng 		    sizeof (db_attr.fi_flowname));
6218275SEric Cheng 		db_attr.fi_linkid = linkid;
6228275SEric Cheng 
6238275SEric Cheng 		if ((status = i_dladm_flow_create_db(&db_attr, root)) !=
6248275SEric Cheng 		    DLADM_STATUS_OK) {
6258453SAnurag.Maskey@Sun.COM 			(void) i_dladm_flow_remove(handle, flowname);
6268275SEric Cheng 			return (status);
6278275SEric Cheng 		}
6288275SEric Cheng 		/* set flow properties */
6298275SEric Cheng 		if (proplist != NULL) {
6308453SAnurag.Maskey@Sun.COM 			status = i_dladm_set_flow_proplist_db(handle, flowname,
6318275SEric Cheng 			    proplist);
6328275SEric Cheng 			if (status != DLADM_STATUS_OK) {
6338453SAnurag.Maskey@Sun.COM 				(void) i_dladm_flow_remove(handle, flowname);
6348275SEric Cheng 				return (status);
6358275SEric Cheng 			}
6368275SEric Cheng 		}
6378275SEric Cheng 	}
6388275SEric Cheng 	return (status);
6398275SEric Cheng }
6408275SEric Cheng 
6418275SEric Cheng /*
6428275SEric Cheng  * Remove a flow.
6438275SEric Cheng  */
6448275SEric Cheng /* ARGSUSED */
6458275SEric Cheng dladm_status_t
6468453SAnurag.Maskey@Sun.COM dladm_flow_remove(dladm_handle_t handle, char *flowname, boolean_t tempop,
6478275SEric Cheng     const char *root)
6488275SEric Cheng {
6498275SEric Cheng 	remove_db_state_t		state;
6508275SEric Cheng 	dladm_status_t			status = DLADM_STATUS_OK;
6518275SEric Cheng 	dladm_status_t			s = DLADM_STATUS_OK;
6528275SEric Cheng 
6538275SEric Cheng 	/* remove flow */
6548453SAnurag.Maskey@Sun.COM 	status = i_dladm_flow_remove(handle, flowname);
6558275SEric Cheng 	if ((status != DLADM_STATUS_OK) &&
6568275SEric Cheng 	    (tempop || status != DLADM_STATUS_NOTFOUND))
6578275SEric Cheng 		goto done;
6588275SEric Cheng 
6598275SEric Cheng 	/* remove flow from DB */
6608275SEric Cheng 	if (!tempop) {
6618275SEric Cheng 		bzero(&state, sizeof (state));
6628275SEric Cheng 		(void) strlcpy(state.rs_newattr.fi_flowname, flowname,
6638275SEric Cheng 		    sizeof (state.rs_newattr.fi_flowname));
6648275SEric Cheng 		state.rs_found = B_FALSE;
6658275SEric Cheng 
6668275SEric Cheng 		/* flow DB */
6678275SEric Cheng 		if (i_dladm_flow_remove_db(&state, root) < 0) {
6688275SEric Cheng 			s = dladm_errno2status(errno);
6698275SEric Cheng 			goto done;
6708275SEric Cheng 		}
6718275SEric Cheng 
6728275SEric Cheng 		/* flow prop DB */
6738453SAnurag.Maskey@Sun.COM 		s = dladm_set_flowprop(handle, flowname, NULL, NULL, 0,
6748275SEric Cheng 		    DLADM_OPT_PERSIST, NULL);
6758275SEric Cheng 	}
6768275SEric Cheng 
6778275SEric Cheng done:
6788275SEric Cheng 	if (!tempop) {
6798275SEric Cheng 		if (s == DLADM_STATUS_OK) {
6808275SEric Cheng 			if (status == DLADM_STATUS_NOTFOUND)
6818275SEric Cheng 				status = s;
6828275SEric Cheng 		} else {
6838275SEric Cheng 			if (s != DLADM_STATUS_NOTFOUND)
6848275SEric Cheng 				status = s;
6858275SEric Cheng 		}
6868275SEric Cheng 	}
6878275SEric Cheng 	return (status);
6888275SEric Cheng }
6898275SEric Cheng 
6908275SEric Cheng /*
6918275SEric Cheng  * Get an existing flow in the DB.
6928275SEric Cheng  */
6938275SEric Cheng 
6948275SEric Cheng typedef struct get_db_state {
6959421SMichael.Lim@Sun.COM 	int		(*gs_fn)(dladm_handle_t, dladm_flow_attr_t *, void *);
6968275SEric Cheng 	void		*gs_arg;
6978275SEric Cheng 	datalink_id_t	gs_linkid;
6988275SEric Cheng } get_db_state_t;
6998275SEric Cheng 
7008275SEric Cheng /*
7018275SEric Cheng  * For each flow which matches the linkid, copy all flow information
7028275SEric Cheng  * to a new dladm_flow_attr_t structure and call the provided
7038275SEric Cheng  * function.  This is used to display perisistent flows from
7048275SEric Cheng  * the database.
7058275SEric Cheng  */
7068275SEric Cheng 
7078275SEric Cheng static int
7088275SEric Cheng i_dladm_flow_get_db_fn(void *arg, dld_flowinfo_t *grp)
7098275SEric Cheng {
7108275SEric Cheng 	get_db_state_t		*state = (get_db_state_t *)arg;
7118275SEric Cheng 	dladm_flow_attr_t	attr;
7129421SMichael.Lim@Sun.COM 	dladm_handle_t		handle = NULL;
7138275SEric Cheng 
7148275SEric Cheng 	if (grp->fi_linkid == state->gs_linkid) {
7158275SEric Cheng 		attr.fa_linkid = state->gs_linkid;
7168275SEric Cheng 		bcopy(grp->fi_flowname, &attr.fa_flowname,
7178275SEric Cheng 		    sizeof (attr.fa_flowname));
7188275SEric Cheng 		bcopy(&grp->fi_flow_desc, &attr.fa_flow_desc,
7198275SEric Cheng 		    sizeof (attr.fa_flow_desc));
7208275SEric Cheng 		bcopy(&grp->fi_resource_props, &attr.fa_resource_props,
7218275SEric Cheng 		    sizeof (attr.fa_resource_props));
7229421SMichael.Lim@Sun.COM 		(void) state->gs_fn(handle, &attr, state->gs_arg);
7238275SEric Cheng 	}
7248275SEric Cheng 	return (0);
7258275SEric Cheng }
7268275SEric Cheng 
7278275SEric Cheng /*
7288275SEric Cheng  * Walk through the flows defined on the system and for each flow
7298275SEric Cheng  * invoke <fn>(<arg>, <flow>);
7308275SEric Cheng  * Currently used for show-flow.
7318275SEric Cheng  */
7328275SEric Cheng /* ARGSUSED */
7338275SEric Cheng dladm_status_t
7349421SMichael.Lim@Sun.COM dladm_walk_flow(int (*fn)(dladm_handle_t, dladm_flow_attr_t *, void *),
7359421SMichael.Lim@Sun.COM     dladm_handle_t handle, datalink_id_t linkid, void *arg, boolean_t persist)
7368275SEric Cheng {
7378275SEric Cheng 	dld_flowinfo_t		*flow;
7388453SAnurag.Maskey@Sun.COM 	int			i, bufsize;
7398275SEric Cheng 	dld_ioc_walkflow_t	*ioc = NULL;
7408275SEric Cheng 	dladm_flow_attr_t 	attr;
7418275SEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
7428275SEric Cheng 
7438275SEric Cheng 	if (fn == NULL)
7448275SEric Cheng 		return (DLADM_STATUS_BADARG);
7458275SEric Cheng 
7468275SEric Cheng 	if (persist) {
7478275SEric Cheng 		get_db_state_t state;
7488275SEric Cheng 
7498275SEric Cheng 		bzero(&state, sizeof (state));
7508275SEric Cheng 
7518275SEric Cheng 		state.gs_linkid = linkid;
7528275SEric Cheng 		state.gs_fn = fn;
7538275SEric Cheng 		state.gs_arg = arg;
7548275SEric Cheng 		status = i_dladm_flow_walk_rw_db(i_dladm_flow_get_db_fn,
7558275SEric Cheng 		    &state, NULL);
7568275SEric Cheng 		if (status != DLADM_STATUS_OK)
7578275SEric Cheng 			return (status);
7588275SEric Cheng 	} else {
7598275SEric Cheng 		bufsize = MIN_INFO_SIZE;
7608275SEric Cheng 		if ((ioc = calloc(1, bufsize)) == NULL) {
7618275SEric Cheng 			status = dladm_errno2status(errno);
7628275SEric Cheng 			return (status);
7638275SEric Cheng 		}
7648275SEric Cheng 
7658275SEric Cheng 		ioc->wf_linkid = linkid;
7668275SEric Cheng 		ioc->wf_len = bufsize - sizeof (*ioc);
7678275SEric Cheng 
7688453SAnurag.Maskey@Sun.COM 		while (ioctl(dladm_dld_fd(handle), DLDIOC_WALKFLOW, ioc) < 0) {
7698275SEric Cheng 			if (errno == ENOSPC) {
7708275SEric Cheng 				bufsize *= 2;
7718275SEric Cheng 				ioc = realloc(ioc, bufsize);
7728275SEric Cheng 				if (ioc != NULL) {
7738275SEric Cheng 					ioc->wf_linkid = linkid;
7748275SEric Cheng 					ioc->wf_len = bufsize - sizeof (*ioc);
7758275SEric Cheng 					continue;
7768275SEric Cheng 				}
7778275SEric Cheng 			}
7788275SEric Cheng 			goto bail;
7798275SEric Cheng 		}
7808275SEric Cheng 
7818275SEric Cheng 		flow = (dld_flowinfo_t *)(void *)(ioc + 1);
7828275SEric Cheng 		for (i = 0; i < ioc->wf_nflows; i++, flow++) {
7838275SEric Cheng 			bzero(&attr, sizeof (attr));
7848275SEric Cheng 
7858275SEric Cheng 			attr.fa_linkid = flow->fi_linkid;
7868275SEric Cheng 			bcopy(&flow->fi_flowname, &attr.fa_flowname,
7878275SEric Cheng 			    sizeof (attr.fa_flowname));
7888275SEric Cheng 			bcopy(&flow->fi_flow_desc, &attr.fa_flow_desc,
7898275SEric Cheng 			    sizeof (attr.fa_flow_desc));
7908275SEric Cheng 			bcopy(&flow->fi_resource_props, &attr.fa_resource_props,
7918275SEric Cheng 			    sizeof (attr.fa_resource_props));
7928275SEric Cheng 
7939421SMichael.Lim@Sun.COM 			if (fn(handle, &attr, arg) == DLADM_WALK_TERMINATE)
7948275SEric Cheng 				break;
7958275SEric Cheng 		}
7968275SEric Cheng 	}
7978275SEric Cheng 
7988275SEric Cheng bail:
7998275SEric Cheng 	free(ioc);
8008275SEric Cheng 	return (status);
8018275SEric Cheng }
8028275SEric Cheng 
8038275SEric Cheng dladm_status_t
8048453SAnurag.Maskey@Sun.COM dladm_flow_init(dladm_handle_t handle)
8058275SEric Cheng {
8068275SEric Cheng 	flow_desc_t		flowdesc;
8078275SEric Cheng 	datalink_id_t		linkid;
8088275SEric Cheng 	dladm_status_t		s, status = DLADM_STATUS_OK;
8098558SGirish.Moodalbail@Sun.COM 	char			name[MAXFLOWNAMELEN];
8108275SEric Cheng 	char			line[MAXLINELEN];
8118275SEric Cheng 	dld_flowinfo_t		attr;
8128275SEric Cheng 	FILE			*fp;
8138275SEric Cheng 
8148275SEric Cheng 	if ((fp = fopen(DLADM_FLOW_DB, "r")) == NULL)
8158275SEric Cheng 		return (DLADM_STATUS_DB_NOTFOUND);
8168275SEric Cheng 
8178275SEric Cheng 	while (fgets(line, MAXLINELEN, fp) != NULL) {
8188275SEric Cheng 		/* skip comments */
8198275SEric Cheng 		if (BLANK_LINE(line))
8208275SEric Cheng 			continue;
8218275SEric Cheng 
8228275SEric Cheng 		(void) strtok(line, " \n");
8238275SEric Cheng 
8248275SEric Cheng 		s = dladm_flow_parse_db(line, &attr);
8258275SEric Cheng 		if (s != DLADM_STATUS_OK) {
8268275SEric Cheng 			status = s;
8278275SEric Cheng 			continue;
8288275SEric Cheng 		}
8298275SEric Cheng 		bzero(&flowdesc, sizeof (flowdesc));
8308275SEric Cheng 		bcopy(&attr.fi_flow_desc, &flowdesc, sizeof (flow_desc_t));
8318275SEric Cheng 		(void) strlcpy(name, attr.fi_flowname,
8328275SEric Cheng 		    sizeof (attr.fi_flowname));
8338275SEric Cheng 		linkid = attr.fi_linkid;
8348275SEric Cheng 
8358453SAnurag.Maskey@Sun.COM 		s = i_dladm_flow_add(handle, name, linkid, &flowdesc, NULL);
8368275SEric Cheng 		if (s != DLADM_STATUS_OK)
8378275SEric Cheng 			status = s;
8388275SEric Cheng 	}
8398453SAnurag.Maskey@Sun.COM 	s = i_dladm_init_flowprop_db(handle);
8408275SEric Cheng 	if (s != DLADM_STATUS_OK)
8418275SEric Cheng 		status = s;
8428275SEric Cheng 
8438275SEric Cheng 	(void) fclose(fp);
8448275SEric Cheng 	return (status);
8458275SEric Cheng }
8468275SEric Cheng 
8478275SEric Cheng dladm_status_t
8488275SEric Cheng dladm_prefixlen2mask(int prefixlen, int maxlen, uchar_t *mask)
8498275SEric Cheng {
8508275SEric Cheng 	if (prefixlen < 0 || prefixlen > maxlen)
8518275SEric Cheng 		return (DLADM_STATUS_BADARG);
8528275SEric Cheng 
8538275SEric Cheng 	while (prefixlen > 0) {
8548275SEric Cheng 		if (prefixlen >= 8) {
8558275SEric Cheng 			*mask++ = 0xFF;
8568275SEric Cheng 			prefixlen -= 8;
8578275SEric Cheng 			continue;
8588275SEric Cheng 		}
8598275SEric Cheng 		*mask |= 1 << (8 - prefixlen);
8608275SEric Cheng 		prefixlen--;
8618275SEric Cheng 	}
8628275SEric Cheng 	return (DLADM_STATUS_OK);
8638275SEric Cheng }
8648275SEric Cheng 
8658275SEric Cheng dladm_status_t
8668275SEric Cheng dladm_mask2prefixlen(in6_addr_t *mask, int plen, int *prefixlen)
8678275SEric Cheng {
8688275SEric Cheng 	int		bits;
8698275SEric Cheng 	int		i, end;
8708275SEric Cheng 
8718275SEric Cheng 	switch (plen) {
8728275SEric Cheng 	case IP_ABITS:
8738275SEric Cheng 		end = 3;
8748275SEric Cheng 		break;
8758275SEric Cheng 	case IPV6_ABITS:
8768275SEric Cheng 		end = 0;
8778275SEric Cheng 		break;
8788275SEric Cheng 	default:
8798275SEric Cheng 		return (DLADM_STATUS_BADARG);
8808275SEric Cheng 	}
8818275SEric Cheng 
8828275SEric Cheng 	for (i = 3; i >= end; i--) {
8838275SEric Cheng 		if (mask->_S6_un._S6_u32[i] == 0) {
8848275SEric Cheng 			plen -= 32;
8858275SEric Cheng 			continue;
8868275SEric Cheng 		}
8878275SEric Cheng 		bits = ffs(ntohl(mask->_S6_un._S6_u32[i])) - 1;
8888275SEric Cheng 		if (bits == 0)
8898275SEric Cheng 			break;
8908275SEric Cheng 		plen -= bits;
8918275SEric Cheng 	}
8928275SEric Cheng 	*prefixlen = plen;
8938275SEric Cheng 	return (DLADM_STATUS_OK);
8948275SEric Cheng }
895