1da14cebeSEric Cheng /*
2da14cebeSEric Cheng  * CDDL HEADER START
3da14cebeSEric Cheng  *
4da14cebeSEric Cheng  * The contents of this file are subject to the terms of the
5da14cebeSEric Cheng  * Common Development and Distribution License (the "License").
6da14cebeSEric Cheng  * You may not use this file except in compliance with the License.
7da14cebeSEric Cheng  *
8da14cebeSEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da14cebeSEric Cheng  * or http://www.opensolaris.org/os/licensing.
10da14cebeSEric Cheng  * See the License for the specific language governing permissions
11da14cebeSEric Cheng  * and limitations under the License.
12da14cebeSEric Cheng  *
13da14cebeSEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
14da14cebeSEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da14cebeSEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
16da14cebeSEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
17da14cebeSEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
18da14cebeSEric Cheng  *
19da14cebeSEric Cheng  * CDDL HEADER END
20da14cebeSEric Cheng  */
21da14cebeSEric Cheng /*
226ba597c5SAnurag S. Maskey  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23da14cebeSEric Cheng  * Use is subject to license terms.
24da14cebeSEric Cheng  */
25da14cebeSEric Cheng 
26da14cebeSEric Cheng #include <stdio.h>
27da14cebeSEric Cheng #include <sys/types.h>
28da14cebeSEric Cheng #include <sys/socket.h>
29da14cebeSEric Cheng #include <sys/ethernet.h>
30da14cebeSEric Cheng #include <netinet/in.h>
31da14cebeSEric Cheng #include <arpa/inet.h>
32da14cebeSEric Cheng #include <sys/stat.h>
3382a2fc47SJames Carlson #include <sys/dld_ioc.h>
34da14cebeSEric Cheng #include <string.h>
35da14cebeSEric Cheng #include <fcntl.h>
36da14cebeSEric Cheng #include <unistd.h>
37da14cebeSEric Cheng #include <stropts.h>
38da14cebeSEric Cheng #include <stdlib.h>
39da14cebeSEric Cheng #include <errno.h>
40da14cebeSEric Cheng #include <strings.h>
41da14cebeSEric Cheng #include <libintl.h>
42da14cebeSEric Cheng #include <netdb.h>
43da14cebeSEric Cheng #include <net/if_types.h>
44da14cebeSEric Cheng #include <net/if_dl.h>
45da14cebeSEric Cheng #include <inet/ip.h>
46da14cebeSEric Cheng #include <inet/ip6.h>
47da14cebeSEric Cheng #include <libdlflow.h>
48da14cebeSEric Cheng #include <libdlflow_impl.h>
49da14cebeSEric Cheng #include <libdladm_impl.h>
50da14cebeSEric Cheng 
51da14cebeSEric Cheng /* minimum buffer size for DLDIOCWALKFLOW */
52da14cebeSEric Cheng #define	MIN_INFO_SIZE	(4 * 1024)
53da14cebeSEric Cheng 
54da14cebeSEric Cheng #define	DLADM_FLOW_DB		"/etc/dladm/flowadm.conf"
55da14cebeSEric Cheng #define	DLADM_FLOW_DB_TMP	"/etc/dladm/flowadm.conf.new"
56da14cebeSEric Cheng #define	DLADM_FLOW_DB_LOCK	"/tmp/flowadm.conf.lock"
57da14cebeSEric Cheng 
58da14cebeSEric Cheng #define	DLADM_FLOW_DB_PERMS	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
59da14cebeSEric Cheng #define	DLADM_FLOW_DB_OWNER	UID_DLADM
606ba597c5SAnurag S. Maskey #define	DLADM_FLOW_DB_GROUP	GID_NETADM
61da14cebeSEric Cheng 
62da14cebeSEric Cheng #define	BLANK_LINE(s)	((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n'))
63da14cebeSEric Cheng #define	MAXLINELEN	1024
64da14cebeSEric Cheng #define	MAXPATHLEN	1024
65da14cebeSEric Cheng 
66da14cebeSEric Cheng /* database file parameters */
67da14cebeSEric Cheng static const char *BW_LIMIT = "bw_limit";
68da14cebeSEric Cheng static const char *PRIORITY = "priority";
69da14cebeSEric Cheng static const char *LOCAL_IP_ADDR = "local_ip";
70da14cebeSEric Cheng static const char *REMOTE_IP_ADDR = "remote_ip";
71da14cebeSEric Cheng static const char *TRANSPORT = "transport";
72da14cebeSEric Cheng static const char *LOCAL_PORT = "local_port";
7325ec3e3dSEric Cheng static const char *REMOTE_PORT = "remote_port";
74da14cebeSEric Cheng static const char *DSFIELD = "dsfield";
75da14cebeSEric Cheng 
76da14cebeSEric Cheng /*
77da14cebeSEric Cheng  * Open and lock the flowadm configuration file lock. The lock is
78da14cebeSEric Cheng  * acquired as a reader (F_RDLCK) or writer (F_WRLCK).
79da14cebeSEric Cheng  */
80da14cebeSEric Cheng static int
i_dladm_flow_lock_db(short type)81da14cebeSEric Cheng i_dladm_flow_lock_db(short type)
82da14cebeSEric Cheng {
83da14cebeSEric Cheng 	int lock_fd;
84da14cebeSEric Cheng 	struct flock lock;
85da14cebeSEric Cheng 
86da14cebeSEric Cheng 	if ((lock_fd = open(DLADM_FLOW_DB_LOCK, O_RDWR | O_CREAT | O_TRUNC,
87da14cebeSEric Cheng 	    DLADM_FLOW_DB_PERMS)) < 0)
88da14cebeSEric Cheng 		return (-1);
89da14cebeSEric Cheng 
90da14cebeSEric Cheng 	lock.l_type = type;
91da14cebeSEric Cheng 	lock.l_whence = SEEK_SET;
92da14cebeSEric Cheng 	lock.l_start = 0;
93da14cebeSEric Cheng 	lock.l_len = 0;
94da14cebeSEric Cheng 
95da14cebeSEric Cheng 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
96da14cebeSEric Cheng 		(void) close(lock_fd);
97da14cebeSEric Cheng 		(void) unlink(DLADM_FLOW_DB_LOCK);
98da14cebeSEric Cheng 		return (-1);
99da14cebeSEric Cheng 	}
100da14cebeSEric Cheng 	return (lock_fd);
101da14cebeSEric Cheng }
102da14cebeSEric Cheng 
103da14cebeSEric Cheng /*
104da14cebeSEric Cheng  * Unlock and close the specified file.
105da14cebeSEric Cheng  */
106da14cebeSEric Cheng static void
i_dladm_flow_unlock_db(int fd)107da14cebeSEric Cheng i_dladm_flow_unlock_db(int fd)
108da14cebeSEric Cheng {
109da14cebeSEric Cheng 	struct flock lock;
110da14cebeSEric Cheng 
111da14cebeSEric Cheng 	if (fd < 0)
112da14cebeSEric Cheng 		return;
113da14cebeSEric Cheng 
114da14cebeSEric Cheng 	lock.l_type = F_UNLCK;
115da14cebeSEric Cheng 	lock.l_whence = SEEK_SET;
116da14cebeSEric Cheng 	lock.l_start = 0;
117da14cebeSEric Cheng 	lock.l_len = 0;
118da14cebeSEric Cheng 
119da14cebeSEric Cheng 	(void) fcntl(fd, F_SETLKW, &lock);
120da14cebeSEric Cheng 	(void) close(fd);
121da14cebeSEric Cheng 	(void) unlink(DLADM_FLOW_DB_LOCK);
122da14cebeSEric Cheng }
123da14cebeSEric Cheng 
124da14cebeSEric Cheng /*
125da14cebeSEric Cheng  * Parse one line of the link flowadm DB
126da14cebeSEric Cheng  * Returns -1 on failure, 0 on success.
127da14cebeSEric Cheng  */
128da14cebeSEric Cheng dladm_status_t
dladm_flow_parse_db(char * line,dld_flowinfo_t * attr)129da14cebeSEric Cheng dladm_flow_parse_db(char *line, dld_flowinfo_t *attr)
130da14cebeSEric Cheng {
131da14cebeSEric Cheng 	char		*token;
132da14cebeSEric Cheng 	char		*value, *name = NULL;
133da14cebeSEric Cheng 	char		*lasts = NULL;
134da14cebeSEric Cheng 	dladm_status_t	status = DLADM_STATUS_FLOW_DB_PARSE_ERR;
135da14cebeSEric Cheng 
136da14cebeSEric Cheng 	bzero(attr, sizeof (*attr));
137da14cebeSEric Cheng 
138da14cebeSEric Cheng 	/* flow name */
139da14cebeSEric Cheng 	if ((token = strtok_r(line, " \t", &lasts)) == NULL)
140da14cebeSEric Cheng 		goto done;
141da14cebeSEric Cheng 
142da000602SGirish Moodalbail 	if (strlcpy(attr->fi_flowname, token, MAXFLOWNAMELEN) >= MAXFLOWNAMELEN)
143da14cebeSEric Cheng 		goto done;
144da14cebeSEric Cheng 
145da14cebeSEric Cheng 	/* resource control and flow descriptor parameters */
146da14cebeSEric Cheng 	while ((token = strtok_r(NULL, " \t", &lasts)) != NULL) {
147da14cebeSEric Cheng 		if ((name = strdup(token)) == NULL)
148da14cebeSEric Cheng 			goto done;
149da14cebeSEric Cheng 
150da14cebeSEric Cheng 		(void) strtok(name, "=");
151da14cebeSEric Cheng 		value = strtok(NULL, "=");
152da14cebeSEric Cheng 		if (value == NULL)
153da14cebeSEric Cheng 			goto done;
154da14cebeSEric Cheng 
155da14cebeSEric Cheng 		if (strcmp(name, "linkid") == 0) {
156da14cebeSEric Cheng 			if ((attr->fi_linkid =
15725ec3e3dSEric Cheng 			    (uint32_t)strtol(value, NULL, 10)) ==
158da14cebeSEric Cheng 			    DATALINK_INVALID_LINKID)
159da14cebeSEric Cheng 				goto done;
160da14cebeSEric Cheng 
161da14cebeSEric Cheng 		} else if (strcmp(name, BW_LIMIT) == 0) {
162da14cebeSEric Cheng 			attr->fi_resource_props.mrp_mask |=
163da14cebeSEric Cheng 			    MRP_MAXBW;
164da14cebeSEric Cheng 			attr->fi_resource_props.mrp_maxbw =
16525ec3e3dSEric Cheng 			    (uint64_t)strtol(value, NULL, 0);
166da14cebeSEric Cheng 
167da14cebeSEric Cheng 		} else if (strcmp(name, PRIORITY) == 0) {
168da14cebeSEric Cheng 			attr->fi_resource_props.mrp_mask |= MRP_PRIORITY;
169da14cebeSEric Cheng 			status = dladm_str2pri(value,
170da14cebeSEric Cheng 			    &attr->fi_resource_props.mrp_priority);
171da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
172da14cebeSEric Cheng 				goto done;
173da14cebeSEric Cheng 
174da14cebeSEric Cheng 		} else if (strcmp(name, DSFIELD) == 0) {
175da14cebeSEric Cheng 			status = do_check_dsfield(value,
176da14cebeSEric Cheng 			    &attr->fi_flow_desc);
177da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
178da14cebeSEric Cheng 				goto done;
179da14cebeSEric Cheng 
180da14cebeSEric Cheng 		} else if (strcmp(name, LOCAL_IP_ADDR) == 0) {
181da14cebeSEric Cheng 			status = do_check_ip_addr(value, B_TRUE,
182da14cebeSEric Cheng 			    &attr->fi_flow_desc);
183da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
184da14cebeSEric Cheng 				goto done;
185da14cebeSEric Cheng 
186da14cebeSEric Cheng 		} else if (strcmp(name, REMOTE_IP_ADDR) == 0) {
187da14cebeSEric Cheng 			status = do_check_ip_addr(value, B_FALSE,
188da14cebeSEric Cheng 			    &attr->fi_flow_desc);
189da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK)
190da14cebeSEric Cheng 				goto done;
191da14cebeSEric Cheng 
192da14cebeSEric Cheng 		} else if (strcmp(name, TRANSPORT) == 0) {
193da14cebeSEric Cheng 			attr->fi_flow_desc.fd_mask |= FLOW_IP_PROTOCOL;
194da14cebeSEric Cheng 			attr->fi_flow_desc.fd_protocol =
19525ec3e3dSEric Cheng 			    (uint8_t)strtol(value, NULL, 0);
196da14cebeSEric Cheng 
197da14cebeSEric Cheng 		} else if (strcmp(name, LOCAL_PORT) == 0) {
198da14cebeSEric Cheng 			attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_LOCAL;
199da14cebeSEric Cheng 			attr->fi_flow_desc.fd_local_port =
20025ec3e3dSEric Cheng 			    (uint16_t)strtol(value, NULL, 10);
201da14cebeSEric Cheng 			attr->fi_flow_desc.fd_local_port =
202da14cebeSEric Cheng 			    htons(attr->fi_flow_desc.fd_local_port);
20325ec3e3dSEric Cheng 		} else if (strcmp(name, REMOTE_PORT) == 0) {
20425ec3e3dSEric Cheng 			attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_REMOTE;
20525ec3e3dSEric Cheng 			attr->fi_flow_desc.fd_remote_port =
20625ec3e3dSEric Cheng 			    (uint16_t)strtol(value, NULL, 10);
20725ec3e3dSEric Cheng 			attr->fi_flow_desc.fd_remote_port =
20825ec3e3dSEric Cheng 			    htons(attr->fi_flow_desc.fd_remote_port);
209da14cebeSEric Cheng 		}
210da14cebeSEric Cheng 		free(name);
211da14cebeSEric Cheng 		name = NULL;
212da14cebeSEric Cheng 	}
213da14cebeSEric Cheng 	if (attr->fi_linkid != DATALINK_INVALID_LINKID)
214da14cebeSEric Cheng 		status = DLADM_STATUS_OK;
215da14cebeSEric Cheng done:
216da14cebeSEric Cheng 	free(name);
217da14cebeSEric Cheng 	return (status);
218da14cebeSEric Cheng }
219da14cebeSEric Cheng 
220da14cebeSEric Cheng #define	FPRINTF_ERR(fcall) if ((fcall) < 0) return (-1);
221da14cebeSEric Cheng 
222da14cebeSEric Cheng /*
223da14cebeSEric Cheng  * Write the attribute of a group to the specified file. Returns 0 on
224da14cebeSEric Cheng  * success, -1 on failure.
225da14cebeSEric Cheng  */
226da14cebeSEric Cheng static int
i_dladm_flow_fput_grp(FILE * fp,dld_flowinfo_t * attr)227da14cebeSEric Cheng i_dladm_flow_fput_grp(FILE *fp, dld_flowinfo_t *attr)
228da14cebeSEric Cheng {
229da14cebeSEric Cheng 
230da14cebeSEric Cheng 	FPRINTF_ERR(fprintf(fp, "%s\tlinkid=%d\t",
231da14cebeSEric Cheng 	    attr->fi_flowname, attr->fi_linkid));
232da14cebeSEric Cheng 
233da14cebeSEric Cheng 	/* flow policy */
234da14cebeSEric Cheng 	if (attr->fi_resource_props.mrp_mask & MRP_MAXBW)
235da14cebeSEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%" PRIu64 "\t", BW_LIMIT,
236da14cebeSEric Cheng 		    attr->fi_resource_props.mrp_maxbw));
237da14cebeSEric Cheng 
238da14cebeSEric Cheng 	if (attr->fi_resource_props.mrp_mask & MRP_PRIORITY)
239da14cebeSEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%d\t", PRIORITY,
240da14cebeSEric Cheng 		    attr->fi_resource_props.mrp_priority));
241da14cebeSEric Cheng 
242da14cebeSEric Cheng 	/* flow descriptor */
243da14cebeSEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_IP_DSFIELD)
244da14cebeSEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%x:%x\t", DSFIELD,
245da14cebeSEric Cheng 		    attr->fi_flow_desc.fd_dsfield,
246da14cebeSEric Cheng 		    attr->fi_flow_desc.fd_dsfield_mask));
247da14cebeSEric Cheng 
248da14cebeSEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_IP_LOCAL) {
249da14cebeSEric Cheng 		char abuf[INET6_ADDRSTRLEN], *ap;
250da14cebeSEric Cheng 		struct in_addr ipaddr;
251da14cebeSEric Cheng 		int prefix_len, prefix_max;
252da14cebeSEric Cheng 
253da14cebeSEric Cheng 		if (attr->fi_flow_desc.fd_ipversion != 6) {
254da14cebeSEric Cheng 			ipaddr.s_addr =
255da14cebeSEric Cheng 			    attr->fi_flow_desc.
256da14cebeSEric Cheng 			    fd_local_addr._S6_un._S6_u32[3];
257da14cebeSEric Cheng 
258da14cebeSEric Cheng 			ap = inet_ntoa(ipaddr);
259da14cebeSEric Cheng 			prefix_max = IP_ABITS;
260da14cebeSEric Cheng 		} else {
261da14cebeSEric Cheng 			(void) inet_ntop(AF_INET6,
262da14cebeSEric Cheng 			    &attr->fi_flow_desc.fd_local_addr,
263da14cebeSEric Cheng 			    abuf, INET6_ADDRSTRLEN);
264da14cebeSEric Cheng 
265da14cebeSEric Cheng 			ap = abuf;
266da14cebeSEric Cheng 			prefix_max = IPV6_ABITS;
267da14cebeSEric Cheng 		}
268da14cebeSEric Cheng 		(void) dladm_mask2prefixlen(
269da14cebeSEric Cheng 		    &attr->fi_flow_desc.fd_local_netmask, prefix_max,
270da14cebeSEric Cheng 		    &prefix_len);
271da14cebeSEric Cheng 
272da14cebeSEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%s/%d\t", LOCAL_IP_ADDR,
273da14cebeSEric Cheng 		    ap, prefix_len));
274da14cebeSEric Cheng 	}
275da14cebeSEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_IP_REMOTE) {
276da14cebeSEric Cheng 		char abuf[INET6_ADDRSTRLEN], *ap;
277da14cebeSEric Cheng 		struct in_addr ipaddr;
278da14cebeSEric Cheng 		int prefix_len, prefix_max;
279da14cebeSEric Cheng 
280da14cebeSEric Cheng 		if (attr->fi_flow_desc.fd_ipversion != 6) {
281da14cebeSEric Cheng 			ipaddr.s_addr =
282da14cebeSEric Cheng 			    attr->fi_flow_desc.
283da14cebeSEric Cheng 			    fd_remote_addr._S6_un._S6_u32[3];
284da14cebeSEric Cheng 
285da14cebeSEric Cheng 			ap = inet_ntoa(ipaddr);
286da14cebeSEric Cheng 			prefix_max = IP_ABITS;
287da14cebeSEric Cheng 		} else {
288da14cebeSEric Cheng 			(void) inet_ntop(AF_INET6,
289da14cebeSEric Cheng 			    &(attr->fi_flow_desc.fd_remote_addr),
290da14cebeSEric Cheng 			    abuf, INET6_ADDRSTRLEN);
291da14cebeSEric Cheng 
292da14cebeSEric Cheng 			ap = abuf;
293da14cebeSEric Cheng 			prefix_max = IPV6_ABITS;
294da14cebeSEric Cheng 		}
295da14cebeSEric Cheng 		(void) dladm_mask2prefixlen(
296da14cebeSEric Cheng 		    &attr->fi_flow_desc.fd_remote_netmask, prefix_max,
297da14cebeSEric Cheng 		    &prefix_len);
298da14cebeSEric Cheng 
299da14cebeSEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%s/%d\t", REMOTE_IP_ADDR,
300da14cebeSEric Cheng 		    ap, prefix_len));
301da14cebeSEric Cheng 	}
302da14cebeSEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_IP_PROTOCOL)
303da14cebeSEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%d\t", TRANSPORT,
304da14cebeSEric Cheng 		    attr->fi_flow_desc.fd_protocol));
305da14cebeSEric Cheng 
306da14cebeSEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL)
307da14cebeSEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%d\t", LOCAL_PORT,
308da14cebeSEric Cheng 		    ntohs(attr->fi_flow_desc.fd_local_port)));
309da14cebeSEric Cheng 
31025ec3e3dSEric Cheng 	if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE)
31125ec3e3dSEric Cheng 		FPRINTF_ERR(fprintf(fp, "%s=%d\t", REMOTE_PORT,
31225ec3e3dSEric Cheng 		    ntohs(attr->fi_flow_desc.fd_remote_port)));
31325ec3e3dSEric Cheng 
314da14cebeSEric Cheng 	FPRINTF_ERR(fprintf(fp, "\n"));
315da14cebeSEric Cheng 
316da14cebeSEric Cheng 	return (0);
317da14cebeSEric Cheng 
318da14cebeSEric Cheng }
319da14cebeSEric Cheng 
320da14cebeSEric Cheng static dladm_status_t
i_dladm_flow_walk_rw_db(int (* fn)(void *,dld_flowinfo_t *),void * arg,const char * root)321da14cebeSEric Cheng i_dladm_flow_walk_rw_db(int (*fn)(void *, dld_flowinfo_t *),
322da14cebeSEric Cheng     void *arg,
323da14cebeSEric Cheng     const char *root)
324da14cebeSEric Cheng {
325da14cebeSEric Cheng 	FILE *fp, *nfp;
326da14cebeSEric Cheng 	int nfd, fn_rc, lock_fd;
327da14cebeSEric Cheng 	char line[MAXLINELEN];
328da14cebeSEric Cheng 	dld_flowinfo_t attr;
329da14cebeSEric Cheng 	char *db_file, *tmp_db_file;
330da14cebeSEric Cheng 	char db_file_buf[MAXPATHLEN];
331da14cebeSEric Cheng 	char tmp_db_file_buf[MAXPATHLEN];
332da14cebeSEric Cheng 	dladm_status_t	status = DLADM_STATUS_FLOW_DB_ERR;
333da14cebeSEric Cheng 
334da14cebeSEric Cheng 	if (root == NULL) {
335da14cebeSEric Cheng 		db_file = DLADM_FLOW_DB;
336da14cebeSEric Cheng 		tmp_db_file = DLADM_FLOW_DB_TMP;
337da14cebeSEric Cheng 	} else {
338da14cebeSEric Cheng 		(void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
339da14cebeSEric Cheng 		    DLADM_FLOW_DB);
340da14cebeSEric Cheng 		(void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root,
341da14cebeSEric Cheng 		    DLADM_FLOW_DB_TMP);
342da14cebeSEric Cheng 		db_file = db_file_buf;
343da14cebeSEric Cheng 		tmp_db_file = tmp_db_file_buf;
344da14cebeSEric Cheng 	}
345da14cebeSEric Cheng 
346da14cebeSEric Cheng 	if ((lock_fd = i_dladm_flow_lock_db(F_WRLCK)) < 0)
347da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_DB_ERR);
348da14cebeSEric Cheng 
349da14cebeSEric Cheng 	if ((fp = fopen(db_file, "r")) == NULL) {
350da14cebeSEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
351da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
352da14cebeSEric Cheng 	}
353da14cebeSEric Cheng 
354da14cebeSEric Cheng 	if ((nfd = open(tmp_db_file, O_WRONLY|O_CREAT|O_TRUNC,
355da14cebeSEric Cheng 	    DLADM_FLOW_DB_PERMS)) == -1) {
356da14cebeSEric Cheng 		(void) fclose(fp);
357da14cebeSEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
358da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
359da14cebeSEric Cheng 	}
360da14cebeSEric Cheng 
361da14cebeSEric Cheng 	if ((nfp = fdopen(nfd, "w")) == NULL) {
362da14cebeSEric Cheng 		(void) close(nfd);
363da14cebeSEric Cheng 		(void) fclose(fp);
364da14cebeSEric Cheng 		(void) unlink(tmp_db_file);
365da14cebeSEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
366da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
367da14cebeSEric Cheng 	}
368da14cebeSEric Cheng 
369da14cebeSEric Cheng 	while (fgets(line, MAXLINELEN, fp) != NULL) {
370da14cebeSEric Cheng 
371da14cebeSEric Cheng 		/* skip comments */
372da14cebeSEric Cheng 		if (BLANK_LINE(line)) {
373da14cebeSEric Cheng 			if (fputs(line, nfp) == EOF)
374da14cebeSEric Cheng 				goto failed;
375da14cebeSEric Cheng 			continue;
376da14cebeSEric Cheng 		}
377da14cebeSEric Cheng 		(void) strtok(line, " \n");
378da14cebeSEric Cheng 
379da14cebeSEric Cheng 		if ((status = dladm_flow_parse_db(line, &attr)) !=
380da14cebeSEric Cheng 		    DLADM_STATUS_OK)
381da14cebeSEric Cheng 			goto failed;
382da14cebeSEric Cheng 
383da14cebeSEric Cheng 		fn_rc = fn(arg, &attr);
384da14cebeSEric Cheng 
385da14cebeSEric Cheng 		switch (fn_rc) {
386da14cebeSEric Cheng 		case -1:
387da14cebeSEric Cheng 			/* failure, stop walking */
388da14cebeSEric Cheng 			goto failed;
389da14cebeSEric Cheng 		case 0:
390da14cebeSEric Cheng 			/*
391da14cebeSEric Cheng 			 * Success, write group attributes, which could
392da14cebeSEric Cheng 			 * have been modified by fn().
393da14cebeSEric Cheng 			 */
394da14cebeSEric Cheng 			if (i_dladm_flow_fput_grp(nfp, &attr) != 0)
395da14cebeSEric Cheng 				goto failed;
396da14cebeSEric Cheng 			break;
397da14cebeSEric Cheng 		case 1:
398da14cebeSEric Cheng 			/* skip current group */
399da14cebeSEric Cheng 			break;
400da14cebeSEric Cheng 		}
401da14cebeSEric Cheng 	}
402da14cebeSEric Cheng 	if (fchmod(nfd, DLADM_FLOW_DB_PERMS) == -1)
403da14cebeSEric Cheng 		goto failed;
404da14cebeSEric Cheng 
405da14cebeSEric Cheng 	if (fchown(nfd, DLADM_FLOW_DB_OWNER, DLADM_FLOW_DB_GROUP) == -1)
406da14cebeSEric Cheng 		goto failed;
407da14cebeSEric Cheng 
408da14cebeSEric Cheng 	if (fflush(nfp) == EOF)
409da14cebeSEric Cheng 		goto failed;
410da14cebeSEric Cheng 
411da14cebeSEric Cheng 	(void) fclose(fp);
412da14cebeSEric Cheng 	(void) fclose(nfp);
413da14cebeSEric Cheng 
414da14cebeSEric Cheng 	if (rename(tmp_db_file, db_file) == -1) {
415da14cebeSEric Cheng 		(void) unlink(tmp_db_file);
416da14cebeSEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
417da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_DB_ERR);
418da14cebeSEric Cheng 	}
419da14cebeSEric Cheng 	i_dladm_flow_unlock_db(lock_fd);
420da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
421da14cebeSEric Cheng 
422da14cebeSEric Cheng failed:
423da14cebeSEric Cheng 	(void) fclose(fp);
424da14cebeSEric Cheng 	(void) fclose(nfp);
425da14cebeSEric Cheng 	(void) unlink(tmp_db_file);
426da14cebeSEric Cheng 	i_dladm_flow_unlock_db(lock_fd);
427da14cebeSEric Cheng 
428da14cebeSEric Cheng 	return (status);
429da14cebeSEric Cheng }
430da14cebeSEric Cheng 
431da14cebeSEric Cheng /*
432da14cebeSEric Cheng  * Remove existing flow from DB.
433da14cebeSEric Cheng  */
434da14cebeSEric Cheng 
435da14cebeSEric Cheng typedef struct remove_db_state {
436da14cebeSEric Cheng 	dld_flowinfo_t	rs_newattr;
437da14cebeSEric Cheng 	dld_flowinfo_t	rs_oldattr;
438da14cebeSEric Cheng 	boolean_t	rs_found;
439da14cebeSEric Cheng } remove_db_state_t;
440da14cebeSEric Cheng 
441da14cebeSEric Cheng static int
i_dladm_flow_remove_db_fn(void * arg,dld_flowinfo_t * grp)442da14cebeSEric Cheng i_dladm_flow_remove_db_fn(void *arg, dld_flowinfo_t *grp)
443da14cebeSEric Cheng {
444da14cebeSEric Cheng 	remove_db_state_t *state = (remove_db_state_t *)arg;
445da14cebeSEric Cheng 	dld_flowinfo_t *attr = &state->rs_newattr;
446da14cebeSEric Cheng 
447da14cebeSEric Cheng 	if ((strcmp(grp->fi_flowname, attr->fi_flowname)) != 0)
448da14cebeSEric Cheng 		return (0);
449da14cebeSEric Cheng 	else {
450da14cebeSEric Cheng 		bcopy(grp, &state->rs_oldattr,
451da14cebeSEric Cheng 		    sizeof (dld_flowinfo_t));
452da14cebeSEric Cheng 		state->rs_found = B_TRUE;
453da14cebeSEric Cheng 		return (1);
454da14cebeSEric Cheng 	}
455da14cebeSEric Cheng }
456da14cebeSEric Cheng 
457da14cebeSEric Cheng /* ARGSUSED */
458da14cebeSEric Cheng static int
i_dladm_flow_remove_db(remove_db_state_t * state,const char * root)459da14cebeSEric Cheng i_dladm_flow_remove_db(remove_db_state_t *state, const char *root)
460da14cebeSEric Cheng {
461da14cebeSEric Cheng 	if (i_dladm_flow_walk_rw_db(i_dladm_flow_remove_db_fn, state, root)
462da14cebeSEric Cheng 	    != 0)
463da14cebeSEric Cheng 		return (-1);
464da14cebeSEric Cheng 
465da14cebeSEric Cheng 	if (!state->rs_found) {
466da14cebeSEric Cheng 		errno = ENOENT;
467da14cebeSEric Cheng 		return (-1);
468da14cebeSEric Cheng 	}
469da14cebeSEric Cheng 
470da14cebeSEric Cheng 	return (0);
471da14cebeSEric Cheng }
472da14cebeSEric Cheng 
473da14cebeSEric Cheng /*
474da14cebeSEric Cheng  * Create a flow in the DB.
475da14cebeSEric Cheng  */
476da14cebeSEric Cheng 
477da14cebeSEric Cheng typedef struct modify_db_state {
478da14cebeSEric Cheng 	dld_flowinfo_t	ms_newattr;
479da14cebeSEric Cheng 	dld_flowinfo_t	ms_oldattr;
480da14cebeSEric Cheng 	boolean_t	ms_found;
481da14cebeSEric Cheng } modify_db_state_t;
482da14cebeSEric Cheng 
483da14cebeSEric Cheng static dladm_status_t
i_dladm_flow_create_db(dld_flowinfo_t * attr,const char * root)484da14cebeSEric Cheng i_dladm_flow_create_db(dld_flowinfo_t *attr, const char *root)
485da14cebeSEric Cheng {
486*4202e8bfSToomas Soome 	FILE	*fp;
487*4202e8bfSToomas Soome 	char	line[MAXLINELEN];
488da14cebeSEric Cheng 	char	*db_file;
489da14cebeSEric Cheng 	char	db_file_buf[MAXPATHLEN];
490da14cebeSEric Cheng 	int	lock_fd;
491da14cebeSEric Cheng 	dladm_status_t	status = DLADM_STATUS_OK;
492da14cebeSEric Cheng 
493da14cebeSEric Cheng 	if (root == NULL) {
494da14cebeSEric Cheng 		db_file = DLADM_FLOW_DB;
495da14cebeSEric Cheng 	} else {
496da14cebeSEric Cheng 		(void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
497da14cebeSEric Cheng 		    DLADM_FLOW_DB);
498da14cebeSEric Cheng 		db_file = db_file_buf;
499da14cebeSEric Cheng 	}
500da14cebeSEric Cheng 
501da14cebeSEric Cheng 	if ((lock_fd = i_dladm_flow_lock_db(F_WRLCK)) < 0)
502da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_DB_ERR);
503da14cebeSEric Cheng 
504da14cebeSEric Cheng 	if ((fp = fopen(db_file, "r+")) == NULL &&
505da14cebeSEric Cheng 	    (fp = fopen(db_file, "w")) == NULL) {
506da14cebeSEric Cheng 		i_dladm_flow_unlock_db(lock_fd);
507da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
508da14cebeSEric Cheng 	}
509da14cebeSEric Cheng 
510da14cebeSEric Cheng 	/* look for existing group with same flowname */
511da14cebeSEric Cheng 	while (fgets(line, MAXLINELEN, fp) != NULL) {
512da14cebeSEric Cheng 		char *holder, *lasts;
513da14cebeSEric Cheng 
514da14cebeSEric Cheng 		/* skip comments */
515da14cebeSEric Cheng 		if (BLANK_LINE(line))
516da14cebeSEric Cheng 			continue;
517da14cebeSEric Cheng 
518da14cebeSEric Cheng 		/* ignore corrupted lines */
519da14cebeSEric Cheng 		holder = strtok_r(line, " \t", &lasts);
520da14cebeSEric Cheng 		if (holder == NULL)
521da14cebeSEric Cheng 			continue;
522da14cebeSEric Cheng 
523da14cebeSEric Cheng 		/* flow id */
524da14cebeSEric Cheng 		if (strcmp(holder, attr->fi_flowname) == 0) {
525da14cebeSEric Cheng 			/* group with flow id already exists */
526da14cebeSEric Cheng 			status = DLADM_STATUS_PERSIST_FLOW_EXISTS;
527da14cebeSEric Cheng 			goto failed;
528da14cebeSEric Cheng 		}
529da14cebeSEric Cheng 	}
530da14cebeSEric Cheng 	/*
531da14cebeSEric Cheng 	 * If we get here, we've verified that no existing group with
532da14cebeSEric Cheng 	 * the same flow id already exists. Its now time to add the new
533da14cebeSEric Cheng 	 * group to the DB.
534da14cebeSEric Cheng 	 */
535da14cebeSEric Cheng 	if (i_dladm_flow_fput_grp(fp, attr) != 0)
536da14cebeSEric Cheng 		status = DLADM_STATUS_FLOW_DB_PARSE_ERR;
537da14cebeSEric Cheng 
538da14cebeSEric Cheng failed:
539da14cebeSEric Cheng 	(void) fclose(fp);
540da14cebeSEric Cheng 	i_dladm_flow_unlock_db(lock_fd);
541da14cebeSEric Cheng 	return (status);
542da14cebeSEric Cheng }
543da14cebeSEric Cheng 
544da14cebeSEric Cheng static dladm_status_t
i_dladm_flow_add(dladm_handle_t handle,char * flowname,datalink_id_t linkid,flow_desc_t * flowdesc,mac_resource_props_t * mrp)5454ac67f02SAnurag S. Maskey i_dladm_flow_add(dladm_handle_t handle, char *flowname, datalink_id_t linkid,
5464ac67f02SAnurag S. Maskey     flow_desc_t *flowdesc, mac_resource_props_t *mrp)
547da14cebeSEric Cheng {
548da14cebeSEric Cheng 	dld_ioc_addflow_t	attr;
549da14cebeSEric Cheng 
550da14cebeSEric Cheng 	/* create flow */
551da14cebeSEric Cheng 	bzero(&attr, sizeof (attr));
552da14cebeSEric Cheng 	bcopy(flowdesc, &attr.af_flow_desc, sizeof (flow_desc_t));
553da14cebeSEric Cheng 	if (mrp != NULL) {
554da14cebeSEric Cheng 		bcopy(mrp, &attr.af_resource_props,
555da14cebeSEric Cheng 		    sizeof (mac_resource_props_t));
556da14cebeSEric Cheng 	}
557da14cebeSEric Cheng 
558da14cebeSEric Cheng 	(void) strlcpy(attr.af_name, flowname, sizeof (attr.af_name));
559da14cebeSEric Cheng 	attr.af_linkid = linkid;
560da14cebeSEric Cheng 
5614ac67f02SAnurag S. Maskey 	if (ioctl(dladm_dld_fd(handle), DLDIOC_ADDFLOW, &attr) < 0)
562da14cebeSEric Cheng 		return (dladm_errno2status(errno));
563da14cebeSEric Cheng 
564da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
565da14cebeSEric Cheng }
566da14cebeSEric Cheng 
567da14cebeSEric Cheng static dladm_status_t
i_dladm_flow_remove(dladm_handle_t handle,char * flowname)5684ac67f02SAnurag S. Maskey i_dladm_flow_remove(dladm_handle_t handle, char *flowname)
569da14cebeSEric Cheng {
570da14cebeSEric Cheng 	dld_ioc_removeflow_t	attr;
571da14cebeSEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
572da14cebeSEric Cheng 
573da14cebeSEric Cheng 	(void) strlcpy(attr.rf_name, flowname,
574da14cebeSEric Cheng 	    sizeof (attr.rf_name));
575da14cebeSEric Cheng 
5764ac67f02SAnurag S. Maskey 	if (ioctl(dladm_dld_fd(handle), DLDIOC_REMOVEFLOW, &attr) < 0)
577da14cebeSEric Cheng 		status = dladm_errno2status(errno);
578da14cebeSEric Cheng 
579da14cebeSEric Cheng 	return (status);
580da14cebeSEric Cheng }
581da14cebeSEric Cheng 
582da14cebeSEric Cheng 
583da14cebeSEric Cheng /* ARGSUSED */
584da14cebeSEric Cheng dladm_status_t
dladm_flow_add(dladm_handle_t handle,datalink_id_t linkid,dladm_arg_list_t * attrlist,dladm_arg_list_t * proplist,char * flowname,boolean_t tempop,const char * root)5854ac67f02SAnurag S. Maskey dladm_flow_add(dladm_handle_t handle, datalink_id_t linkid,
5864ac67f02SAnurag S. Maskey     dladm_arg_list_t *attrlist, dladm_arg_list_t *proplist, char *flowname,
5874ac67f02SAnurag S. Maskey     boolean_t tempop, const char *root)
588da14cebeSEric Cheng {
589da14cebeSEric Cheng 	dld_flowinfo_t		db_attr;
590da14cebeSEric Cheng 	flow_desc_t		flowdesc;
591da14cebeSEric Cheng 	mac_resource_props_t	mrp;
592da14cebeSEric Cheng 	dladm_status_t		status;
593da14cebeSEric Cheng 
594da14cebeSEric Cheng 	/* Extract flow attributes from attrlist */
595da14cebeSEric Cheng 	bzero(&flowdesc, sizeof (flow_desc_t));
596da14cebeSEric Cheng 	if (attrlist != NULL && (status = dladm_flow_attrlist_extract(attrlist,
597da14cebeSEric Cheng 	    &flowdesc)) != DLADM_STATUS_OK) {
598da14cebeSEric Cheng 		return (status);
599da14cebeSEric Cheng 	}
600da14cebeSEric Cheng 
601da14cebeSEric Cheng 	/* Extract resource_ctl and cpu_list from proplist */
602da14cebeSEric Cheng 	bzero(&mrp, sizeof (mac_resource_props_t));
603da14cebeSEric Cheng 	if (proplist != NULL && (status = dladm_flow_proplist_extract(proplist,
604da14cebeSEric Cheng 	    &mrp)) != DLADM_STATUS_OK) {
605da14cebeSEric Cheng 		return (status);
606da14cebeSEric Cheng 	}
607da14cebeSEric Cheng 
608da14cebeSEric Cheng 	/* Add flow in kernel */
6094ac67f02SAnurag S. Maskey 	status = i_dladm_flow_add(handle, flowname, linkid, &flowdesc, &mrp);
610da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
611da14cebeSEric Cheng 		return (status);
612da14cebeSEric Cheng 
613da14cebeSEric Cheng 	/* Add flow to DB */
614da14cebeSEric Cheng 	if (!tempop) {
615da14cebeSEric Cheng 		bzero(&db_attr, sizeof (db_attr));
616da14cebeSEric Cheng 		bcopy(&flowdesc, &db_attr.fi_flow_desc, sizeof (flow_desc_t));
617da14cebeSEric Cheng 		(void) strlcpy(db_attr.fi_flowname, flowname,
618da14cebeSEric Cheng 		    sizeof (db_attr.fi_flowname));
619da14cebeSEric Cheng 		db_attr.fi_linkid = linkid;
620da14cebeSEric Cheng 
621da14cebeSEric Cheng 		if ((status = i_dladm_flow_create_db(&db_attr, root)) !=
622da14cebeSEric Cheng 		    DLADM_STATUS_OK) {
6234ac67f02SAnurag S. Maskey 			(void) i_dladm_flow_remove(handle, flowname);
624da14cebeSEric Cheng 			return (status);
625da14cebeSEric Cheng 		}
626da14cebeSEric Cheng 		/* set flow properties */
627da14cebeSEric Cheng 		if (proplist != NULL) {
6284ac67f02SAnurag S. Maskey 			status = i_dladm_set_flow_proplist_db(handle, flowname,
629da14cebeSEric Cheng 			    proplist);
630da14cebeSEric Cheng 			if (status != DLADM_STATUS_OK) {
6314ac67f02SAnurag S. Maskey 				(void) i_dladm_flow_remove(handle, flowname);
632da14cebeSEric Cheng 				return (status);
633da14cebeSEric Cheng 			}
634da14cebeSEric Cheng 		}
635da14cebeSEric Cheng 	}
636da14cebeSEric Cheng 	return (status);
637da14cebeSEric Cheng }
638da14cebeSEric Cheng 
639da14cebeSEric Cheng /*
640da14cebeSEric Cheng  * Remove a flow.
641da14cebeSEric Cheng  */
642da14cebeSEric Cheng /* ARGSUSED */
643da14cebeSEric Cheng dladm_status_t
dladm_flow_remove(dladm_handle_t handle,char * flowname,boolean_t tempop,const char * root)6444ac67f02SAnurag S. Maskey dladm_flow_remove(dladm_handle_t handle, char *flowname, boolean_t tempop,
645da14cebeSEric Cheng     const char *root)
646da14cebeSEric Cheng {
647da14cebeSEric Cheng 	remove_db_state_t		state;
648da14cebeSEric Cheng 	dladm_status_t			status = DLADM_STATUS_OK;
649da14cebeSEric Cheng 	dladm_status_t			s = DLADM_STATUS_OK;
650da14cebeSEric Cheng 
651da14cebeSEric Cheng 	/* remove flow */
6524ac67f02SAnurag S. Maskey 	status = i_dladm_flow_remove(handle, flowname);
653da14cebeSEric Cheng 	if ((status != DLADM_STATUS_OK) &&
654da14cebeSEric Cheng 	    (tempop || status != DLADM_STATUS_NOTFOUND))
655da14cebeSEric Cheng 		goto done;
656da14cebeSEric Cheng 
657da14cebeSEric Cheng 	/* remove flow from DB */
658da14cebeSEric Cheng 	if (!tempop) {
659da14cebeSEric Cheng 		bzero(&state, sizeof (state));
660da14cebeSEric Cheng 		(void) strlcpy(state.rs_newattr.fi_flowname, flowname,
661da14cebeSEric Cheng 		    sizeof (state.rs_newattr.fi_flowname));
662da14cebeSEric Cheng 		state.rs_found = B_FALSE;
663da14cebeSEric Cheng 
664da14cebeSEric Cheng 		/* flow DB */
665da14cebeSEric Cheng 		if (i_dladm_flow_remove_db(&state, root) < 0) {
666da14cebeSEric Cheng 			s = dladm_errno2status(errno);
667da14cebeSEric Cheng 			goto done;
668da14cebeSEric Cheng 		}
669da14cebeSEric Cheng 
670da14cebeSEric Cheng 		/* flow prop DB */
6714ac67f02SAnurag S. Maskey 		s = dladm_set_flowprop(handle, flowname, NULL, NULL, 0,
672da14cebeSEric Cheng 		    DLADM_OPT_PERSIST, NULL);
673da14cebeSEric Cheng 	}
674da14cebeSEric Cheng 
675da14cebeSEric Cheng done:
676da14cebeSEric Cheng 	if (!tempop) {
677da14cebeSEric Cheng 		if (s == DLADM_STATUS_OK) {
678da14cebeSEric Cheng 			if (status == DLADM_STATUS_NOTFOUND)
679da14cebeSEric Cheng 				status = s;
680da14cebeSEric Cheng 		} else {
681da14cebeSEric Cheng 			if (s != DLADM_STATUS_NOTFOUND)
682da14cebeSEric Cheng 				status = s;
683da14cebeSEric Cheng 		}
684da14cebeSEric Cheng 	}
685da14cebeSEric Cheng 	return (status);
686da14cebeSEric Cheng }
687da14cebeSEric Cheng 
688da14cebeSEric Cheng /*
689da14cebeSEric Cheng  * Get an existing flow in the DB.
690da14cebeSEric Cheng  */
691da14cebeSEric Cheng 
692da14cebeSEric Cheng typedef struct get_db_state {
693c3affd82SMichael Lim 	int		(*gs_fn)(dladm_handle_t, dladm_flow_attr_t *, void *);
694da14cebeSEric Cheng 	void		*gs_arg;
695da14cebeSEric Cheng 	datalink_id_t	gs_linkid;
696da14cebeSEric Cheng } get_db_state_t;
697da14cebeSEric Cheng 
698da14cebeSEric Cheng /*
699da14cebeSEric Cheng  * For each flow which matches the linkid, copy all flow information
700da14cebeSEric Cheng  * to a new dladm_flow_attr_t structure and call the provided
701da14cebeSEric Cheng  * function.  This is used to display perisistent flows from
702da14cebeSEric Cheng  * the database.
703da14cebeSEric Cheng  */
704da14cebeSEric Cheng 
705da14cebeSEric Cheng static int
i_dladm_flow_get_db_fn(void * arg,dld_flowinfo_t * grp)706da14cebeSEric Cheng i_dladm_flow_get_db_fn(void *arg, dld_flowinfo_t *grp)
707da14cebeSEric Cheng {
708da14cebeSEric Cheng 	get_db_state_t		*state = (get_db_state_t *)arg;
709da14cebeSEric Cheng 	dladm_flow_attr_t	attr;
710c3affd82SMichael Lim 	dladm_handle_t		handle = NULL;
711da14cebeSEric Cheng 
712da14cebeSEric Cheng 	if (grp->fi_linkid == state->gs_linkid) {
713da14cebeSEric Cheng 		attr.fa_linkid = state->gs_linkid;
714da14cebeSEric Cheng 		bcopy(grp->fi_flowname, &attr.fa_flowname,
715da14cebeSEric Cheng 		    sizeof (attr.fa_flowname));
716da14cebeSEric Cheng 		bcopy(&grp->fi_flow_desc, &attr.fa_flow_desc,
717da14cebeSEric Cheng 		    sizeof (attr.fa_flow_desc));
718da14cebeSEric Cheng 		bcopy(&grp->fi_resource_props, &attr.fa_resource_props,
719da14cebeSEric Cheng 		    sizeof (attr.fa_resource_props));
720c3affd82SMichael Lim 		(void) state->gs_fn(handle, &attr, state->gs_arg);
721da14cebeSEric Cheng 	}
722da14cebeSEric Cheng 	return (0);
723da14cebeSEric Cheng }
724da14cebeSEric Cheng 
725da14cebeSEric Cheng /*
726da14cebeSEric Cheng  * Walk through the flows defined on the system and for each flow
727da14cebeSEric Cheng  * invoke <fn>(<arg>, <flow>);
728da14cebeSEric Cheng  * Currently used for show-flow.
729da14cebeSEric Cheng  */
730da14cebeSEric Cheng /* ARGSUSED */
731da14cebeSEric Cheng dladm_status_t
dladm_walk_flow(int (* fn)(dladm_handle_t,dladm_flow_attr_t *,void *),dladm_handle_t handle,datalink_id_t linkid,void * arg,boolean_t persist)732c3affd82SMichael Lim dladm_walk_flow(int (*fn)(dladm_handle_t, dladm_flow_attr_t *, void *),
733c3affd82SMichael Lim     dladm_handle_t handle, datalink_id_t linkid, void *arg, boolean_t persist)
734da14cebeSEric Cheng {
735da14cebeSEric Cheng 	dld_flowinfo_t		*flow;
736*4202e8bfSToomas Soome 	uint_t			i, bufsize;
737da14cebeSEric Cheng 	dld_ioc_walkflow_t	*ioc = NULL;
738*4202e8bfSToomas Soome 	dladm_flow_attr_t	attr;
739da14cebeSEric Cheng 	dladm_status_t		status = DLADM_STATUS_OK;
740da14cebeSEric Cheng 
741da14cebeSEric Cheng 	if (fn == NULL)
742da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
743da14cebeSEric Cheng 
744da14cebeSEric Cheng 	if (persist) {
745da14cebeSEric Cheng 		get_db_state_t state;
746da14cebeSEric Cheng 
747da14cebeSEric Cheng 		bzero(&state, sizeof (state));
748da14cebeSEric Cheng 
749da14cebeSEric Cheng 		state.gs_linkid = linkid;
750da14cebeSEric Cheng 		state.gs_fn = fn;
751da14cebeSEric Cheng 		state.gs_arg = arg;
752da14cebeSEric Cheng 		status = i_dladm_flow_walk_rw_db(i_dladm_flow_get_db_fn,
753da14cebeSEric Cheng 		    &state, NULL);
754da14cebeSEric Cheng 		if (status != DLADM_STATUS_OK)
755da14cebeSEric Cheng 			return (status);
756da14cebeSEric Cheng 	} else {
757da14cebeSEric Cheng 		bufsize = MIN_INFO_SIZE;
758da14cebeSEric Cheng 		if ((ioc = calloc(1, bufsize)) == NULL) {
759da14cebeSEric Cheng 			status = dladm_errno2status(errno);
760da14cebeSEric Cheng 			return (status);
761da14cebeSEric Cheng 		}
762da14cebeSEric Cheng 
763da14cebeSEric Cheng 		ioc->wf_linkid = linkid;
764da14cebeSEric Cheng 		ioc->wf_len = bufsize - sizeof (*ioc);
765da14cebeSEric Cheng 
7664ac67f02SAnurag S. Maskey 		while (ioctl(dladm_dld_fd(handle), DLDIOC_WALKFLOW, ioc) < 0) {
767da14cebeSEric Cheng 			if (errno == ENOSPC) {
768da14cebeSEric Cheng 				bufsize *= 2;
769da14cebeSEric Cheng 				ioc = realloc(ioc, bufsize);
770da14cebeSEric Cheng 				if (ioc != NULL) {
771da14cebeSEric Cheng 					ioc->wf_linkid = linkid;
772da14cebeSEric Cheng 					ioc->wf_len = bufsize - sizeof (*ioc);
773da14cebeSEric Cheng 					continue;
774da14cebeSEric Cheng 				}
775da14cebeSEric Cheng 			}
776da14cebeSEric Cheng 			goto bail;
777da14cebeSEric Cheng 		}
778da14cebeSEric Cheng 
779da14cebeSEric Cheng 		flow = (dld_flowinfo_t *)(void *)(ioc + 1);
780da14cebeSEric Cheng 		for (i = 0; i < ioc->wf_nflows; i++, flow++) {
781da14cebeSEric Cheng 			bzero(&attr, sizeof (attr));
782da14cebeSEric Cheng 
783da14cebeSEric Cheng 			attr.fa_linkid = flow->fi_linkid;
784da14cebeSEric Cheng 			bcopy(&flow->fi_flowname, &attr.fa_flowname,
785da14cebeSEric Cheng 			    sizeof (attr.fa_flowname));
786da14cebeSEric Cheng 			bcopy(&flow->fi_flow_desc, &attr.fa_flow_desc,
787da14cebeSEric Cheng 			    sizeof (attr.fa_flow_desc));
788da14cebeSEric Cheng 			bcopy(&flow->fi_resource_props, &attr.fa_resource_props,
789da14cebeSEric Cheng 			    sizeof (attr.fa_resource_props));
790da14cebeSEric Cheng 
791c3affd82SMichael Lim 			if (fn(handle, &attr, arg) == DLADM_WALK_TERMINATE)
792da14cebeSEric Cheng 				break;
793da14cebeSEric Cheng 		}
794da14cebeSEric Cheng 	}
795da14cebeSEric Cheng 
796da14cebeSEric Cheng bail:
797da14cebeSEric Cheng 	free(ioc);
798da14cebeSEric Cheng 	return (status);
799da14cebeSEric Cheng }
800da14cebeSEric Cheng 
801da14cebeSEric Cheng dladm_status_t
dladm_flow_init(dladm_handle_t handle)8024ac67f02SAnurag S. Maskey dladm_flow_init(dladm_handle_t handle)
803da14cebeSEric Cheng {
804da14cebeSEric Cheng 	flow_desc_t		flowdesc;
805da14cebeSEric Cheng 	datalink_id_t		linkid;
806da14cebeSEric Cheng 	dladm_status_t		s, status = DLADM_STATUS_OK;
807da000602SGirish Moodalbail 	char			name[MAXFLOWNAMELEN];
808da14cebeSEric Cheng 	char			line[MAXLINELEN];
809da14cebeSEric Cheng 	dld_flowinfo_t		attr;
810da14cebeSEric Cheng 	FILE			*fp;
811da14cebeSEric Cheng 
812da14cebeSEric Cheng 	if ((fp = fopen(DLADM_FLOW_DB, "r")) == NULL)
813da14cebeSEric Cheng 		return (DLADM_STATUS_DB_NOTFOUND);
814da14cebeSEric Cheng 
815da14cebeSEric Cheng 	while (fgets(line, MAXLINELEN, fp) != NULL) {
816da14cebeSEric Cheng 		/* skip comments */
817da14cebeSEric Cheng 		if (BLANK_LINE(line))
818da14cebeSEric Cheng 			continue;
819da14cebeSEric Cheng 
820da14cebeSEric Cheng 		(void) strtok(line, " \n");
821da14cebeSEric Cheng 
822da14cebeSEric Cheng 		s = dladm_flow_parse_db(line, &attr);
823da14cebeSEric Cheng 		if (s != DLADM_STATUS_OK) {
824da14cebeSEric Cheng 			status = s;
825da14cebeSEric Cheng 			continue;
826da14cebeSEric Cheng 		}
827da14cebeSEric Cheng 		bzero(&flowdesc, sizeof (flowdesc));
828da14cebeSEric Cheng 		bcopy(&attr.fi_flow_desc, &flowdesc, sizeof (flow_desc_t));
829da14cebeSEric Cheng 		(void) strlcpy(name, attr.fi_flowname,
830da14cebeSEric Cheng 		    sizeof (attr.fi_flowname));
831da14cebeSEric Cheng 		linkid = attr.fi_linkid;
832da14cebeSEric Cheng 
8334ac67f02SAnurag S. Maskey 		s = i_dladm_flow_add(handle, name, linkid, &flowdesc, NULL);
834da14cebeSEric Cheng 		if (s != DLADM_STATUS_OK)
835da14cebeSEric Cheng 			status = s;
836da14cebeSEric Cheng 	}
8374ac67f02SAnurag S. Maskey 	s = i_dladm_init_flowprop_db(handle);
838da14cebeSEric Cheng 	if (s != DLADM_STATUS_OK)
839da14cebeSEric Cheng 		status = s;
840da14cebeSEric Cheng 
841da14cebeSEric Cheng 	(void) fclose(fp);
842da14cebeSEric Cheng 	return (status);
843da14cebeSEric Cheng }
844da14cebeSEric Cheng 
845da14cebeSEric Cheng dladm_status_t
dladm_prefixlen2mask(int prefixlen,int maxlen,uchar_t * mask)846da14cebeSEric Cheng dladm_prefixlen2mask(int prefixlen, int maxlen, uchar_t *mask)
847da14cebeSEric Cheng {
848da14cebeSEric Cheng 	if (prefixlen < 0 || prefixlen > maxlen)
849da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
850da14cebeSEric Cheng 
851da14cebeSEric Cheng 	while (prefixlen > 0) {
852da14cebeSEric Cheng 		if (prefixlen >= 8) {
853da14cebeSEric Cheng 			*mask++ = 0xFF;
854da14cebeSEric Cheng 			prefixlen -= 8;
855da14cebeSEric Cheng 			continue;
856da14cebeSEric Cheng 		}
857da14cebeSEric Cheng 		*mask |= 1 << (8 - prefixlen);
858da14cebeSEric Cheng 		prefixlen--;
859da14cebeSEric Cheng 	}
860da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
861da14cebeSEric Cheng }
862da14cebeSEric Cheng 
863da14cebeSEric Cheng dladm_status_t
dladm_mask2prefixlen(in6_addr_t * mask,int plen,int * prefixlen)864da14cebeSEric Cheng dladm_mask2prefixlen(in6_addr_t *mask, int plen, int *prefixlen)
865da14cebeSEric Cheng {
866da14cebeSEric Cheng 	int		bits;
867da14cebeSEric Cheng 	int		i, end;
868da14cebeSEric Cheng 
869da14cebeSEric Cheng 	switch (plen) {
870da14cebeSEric Cheng 	case IP_ABITS:
871da14cebeSEric Cheng 		end = 3;
872da14cebeSEric Cheng 		break;
873da14cebeSEric Cheng 	case IPV6_ABITS:
874da14cebeSEric Cheng 		end = 0;
875da14cebeSEric Cheng 		break;
876da14cebeSEric Cheng 	default:
877da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
878da14cebeSEric Cheng 	}
879da14cebeSEric Cheng 
880da14cebeSEric Cheng 	for (i = 3; i >= end; i--) {
881da14cebeSEric Cheng 		if (mask->_S6_un._S6_u32[i] == 0) {
882da14cebeSEric Cheng 			plen -= 32;
883da14cebeSEric Cheng 			continue;
884da14cebeSEric Cheng 		}
885da14cebeSEric Cheng 		bits = ffs(ntohl(mask->_S6_un._S6_u32[i])) - 1;
886da14cebeSEric Cheng 		if (bits == 0)
887da14cebeSEric Cheng 			break;
888da14cebeSEric Cheng 		plen -= bits;
889da14cebeSEric Cheng 	}
890da14cebeSEric Cheng 	*prefixlen = plen;
891da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
892da14cebeSEric Cheng }
893