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