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 /*
22*6ba597c5SAnurag 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
60*6ba597c5SAnurag 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
306