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