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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
33 #include <sys/dld_ioc.h>
43 #include <net/if_types.h>
44 #include <net/if_dl.h>
47 #include <libdlflow.h>
48 #include <libdlflow_impl.h>
49 #include <libdladm_impl.h>
51 /* minimum buffer size for DLDIOCWALKFLOW */
52 #define MIN_INFO_SIZE (4 * 1024)
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"
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
62 #define BLANK_LINE(s) ((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n'))
63 #define MAXLINELEN 1024
64 #define MAXPATHLEN 1024
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";
77 * Open and lock the flowadm configuration file lock. The lock is
78 * acquired as a reader (F_RDLCK) or writer (F_WRLCK).
81 i_dladm_flow_lock_db(short type
)
86 if ((lock_fd
= open(DLADM_FLOW_DB_LOCK
, O_RDWR
| O_CREAT
| O_TRUNC
,
87 DLADM_FLOW_DB_PERMS
)) < 0)
91 lock
.l_whence
= SEEK_SET
;
95 if (fcntl(lock_fd
, F_SETLKW
, &lock
) < 0) {
96 (void) close(lock_fd
);
97 (void) unlink(DLADM_FLOW_DB_LOCK
);
104 * Unlock and close the specified file.
107 i_dladm_flow_unlock_db(int fd
)
114 lock
.l_type
= F_UNLCK
;
115 lock
.l_whence
= SEEK_SET
;
119 (void) fcntl(fd
, F_SETLKW
, &lock
);
121 (void) unlink(DLADM_FLOW_DB_LOCK
);
125 * Parse one line of the link flowadm DB
126 * Returns -1 on failure, 0 on success.
129 dladm_flow_parse_db(char *line
, dld_flowinfo_t
*attr
)
132 char *value
, *name
= NULL
;
134 dladm_status_t status
= DLADM_STATUS_FLOW_DB_PARSE_ERR
;
136 bzero(attr
, sizeof (*attr
));
139 if ((token
= strtok_r(line
, " \t", &lasts
)) == NULL
)
142 if (strlcpy(attr
->fi_flowname
, token
, MAXFLOWNAMELEN
) >= MAXFLOWNAMELEN
)
145 /* resource control and flow descriptor parameters */
146 while ((token
= strtok_r(NULL
, " \t", &lasts
)) != NULL
) {
147 if ((name
= strdup(token
)) == NULL
)
150 (void) strtok(name
, "=");
151 value
= strtok(NULL
, "=");
155 if (strcmp(name
, "linkid") == 0) {
156 if ((attr
->fi_linkid
=
157 (uint32_t)strtol(value
, NULL
, 10)) ==
158 DATALINK_INVALID_LINKID
)
161 } else if (strcmp(name
, BW_LIMIT
) == 0) {
162 attr
->fi_resource_props
.mrp_mask
|=
164 attr
->fi_resource_props
.mrp_maxbw
=
165 (uint64_t)strtol(value
, NULL
, 0);
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
)
174 } else if (strcmp(name
, DSFIELD
) == 0) {
175 status
= do_check_dsfield(value
,
176 &attr
->fi_flow_desc
);
177 if (status
!= DLADM_STATUS_OK
)
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
)
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
)
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);
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
);
213 if (attr
->fi_linkid
!= DATALINK_INVALID_LINKID
)
214 status
= DLADM_STATUS_OK
;
220 #define FPRINTF_ERR(fcall) if ((fcall) < 0) return (-1);
223 * Write the attribute of a group to the specified file. Returns 0 on
224 * success, -1 on failure.
227 i_dladm_flow_fput_grp(FILE *fp
, dld_flowinfo_t
*attr
)
230 FPRINTF_ERR(fprintf(fp
, "%s\tlinkid=%d\t",
231 attr
->fi_flowname
, attr
->fi_linkid
));
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
));
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
));
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
));
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
;
253 if (attr
->fi_flow_desc
.fd_ipversion
!= 6) {
256 fd_local_addr
._S6_un
._S6_u32
[3];
258 ap
= inet_ntoa(ipaddr
);
259 prefix_max
= IP_ABITS
;
261 (void) inet_ntop(AF_INET6
,
262 &attr
->fi_flow_desc
.fd_local_addr
,
263 abuf
, INET6_ADDRSTRLEN
);
266 prefix_max
= IPV6_ABITS
;
268 (void) dladm_mask2prefixlen(
269 &attr
->fi_flow_desc
.fd_local_netmask
, prefix_max
,
272 FPRINTF_ERR(fprintf(fp
, "%s=%s/%d\t", LOCAL_IP_ADDR
,
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
;
280 if (attr
->fi_flow_desc
.fd_ipversion
!= 6) {
283 fd_remote_addr
._S6_un
._S6_u32
[3];
285 ap
= inet_ntoa(ipaddr
);
286 prefix_max
= IP_ABITS
;
288 (void) inet_ntop(AF_INET6
,
289 &(attr
->fi_flow_desc
.fd_remote_addr
),
290 abuf
, INET6_ADDRSTRLEN
);
293 prefix_max
= IPV6_ABITS
;
295 (void) dladm_mask2prefixlen(
296 &attr
->fi_flow_desc
.fd_remote_netmask
, prefix_max
,
299 FPRINTF_ERR(fprintf(fp
, "%s=%s/%d\t", REMOTE_IP_ADDR
,
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
));
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
)));
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
)));
314 FPRINTF_ERR(fprintf(fp
, "\n"));
320 static dladm_status_t
321 i_dladm_flow_walk_rw_db(int (*fn
)(void *, dld_flowinfo_t
*),
326 int nfd
, fn_rc
, lock_fd
;
327 char line
[MAXLINELEN
];
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
;
335 db_file
= DLADM_FLOW_DB
;
336 tmp_db_file
= DLADM_FLOW_DB_TMP
;
338 (void) snprintf(db_file_buf
, MAXPATHLEN
, "%s%s", root
,
340 (void) snprintf(tmp_db_file_buf
, MAXPATHLEN
, "%s%s", root
,
342 db_file
= db_file_buf
;
343 tmp_db_file
= tmp_db_file_buf
;
346 if ((lock_fd
= i_dladm_flow_lock_db(F_WRLCK
)) < 0)
347 return (DLADM_STATUS_FLOW_DB_ERR
);
349 if ((fp
= fopen(db_file
, "r")) == NULL
) {
350 i_dladm_flow_unlock_db(lock_fd
);
351 return (DLADM_STATUS_FLOW_DB_OPEN_ERR
);
354 if ((nfd
= open(tmp_db_file
, O_WRONLY
|O_CREAT
|O_TRUNC
,
355 DLADM_FLOW_DB_PERMS
)) == -1) {
357 i_dladm_flow_unlock_db(lock_fd
);
358 return (DLADM_STATUS_FLOW_DB_OPEN_ERR
);
361 if ((nfp
= fdopen(nfd
, "w")) == NULL
) {
364 (void) unlink(tmp_db_file
);
365 i_dladm_flow_unlock_db(lock_fd
);
366 return (DLADM_STATUS_FLOW_DB_OPEN_ERR
);
369 while (fgets(line
, MAXLINELEN
, fp
) != NULL
) {
372 if (BLANK_LINE(line
)) {
373 if (fputs(line
, nfp
) == EOF
)
377 (void) strtok(line
, " \n");
379 if ((status
= dladm_flow_parse_db(line
, &attr
)) !=
383 fn_rc
= fn(arg
, &attr
);
387 /* failure, stop walking */
391 * Success, write group attributes, which could
392 * have been modified by fn().
394 if (i_dladm_flow_fput_grp(nfp
, &attr
) != 0)
398 /* skip current group */
402 if (fchmod(nfd
, DLADM_FLOW_DB_PERMS
) == -1)
405 if (fchown(nfd
, DLADM_FLOW_DB_OWNER
, DLADM_FLOW_DB_GROUP
) == -1)
408 if (fflush(nfp
) == EOF
)
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
);
419 i_dladm_flow_unlock_db(lock_fd
);
420 return (DLADM_STATUS_OK
);
425 (void) unlink(tmp_db_file
);
426 i_dladm_flow_unlock_db(lock_fd
);
432 * Remove existing flow from DB.
435 typedef struct remove_db_state
{
436 dld_flowinfo_t rs_newattr
;
437 dld_flowinfo_t rs_oldattr
;
442 i_dladm_flow_remove_db_fn(void *arg
, dld_flowinfo_t
*grp
)
444 remove_db_state_t
*state
= (remove_db_state_t
*)arg
;
445 dld_flowinfo_t
*attr
= &state
->rs_newattr
;
447 if ((strcmp(grp
->fi_flowname
, attr
->fi_flowname
)) != 0)
450 bcopy(grp
, &state
->rs_oldattr
,
451 sizeof (dld_flowinfo_t
));
452 state
->rs_found
= B_TRUE
;
459 i_dladm_flow_remove_db(remove_db_state_t
*state
, const char *root
)
461 if (i_dladm_flow_walk_rw_db(i_dladm_flow_remove_db_fn
, state
, root
)
465 if (!state
->rs_found
) {
474 * Create a flow in the DB.
477 typedef struct modify_db_state
{
478 dld_flowinfo_t ms_newattr
;
479 dld_flowinfo_t ms_oldattr
;
483 static dladm_status_t
484 i_dladm_flow_create_db(dld_flowinfo_t
*attr
, const char *root
)
487 char line
[MAXLINELEN
];
489 char db_file_buf
[MAXPATHLEN
];
491 dladm_status_t status
= DLADM_STATUS_OK
;
494 db_file
= DLADM_FLOW_DB
;
496 (void) snprintf(db_file_buf
, MAXPATHLEN
, "%s%s", root
,
498 db_file
= db_file_buf
;
501 if ((lock_fd
= i_dladm_flow_lock_db(F_WRLCK
)) < 0)
502 return (DLADM_STATUS_FLOW_DB_ERR
);
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
);
510 /* look for existing group with same flowname */
511 while (fgets(line
, MAXLINELEN
, fp
) != NULL
) {
512 char *holder
, *lasts
;
515 if (BLANK_LINE(line
))
518 /* ignore corrupted lines */
519 holder
= strtok_r(line
, " \t", &lasts
);
524 if (strcmp(holder
, attr
->fi_flowname
) == 0) {
525 /* group with flow id already exists */
526 status
= DLADM_STATUS_PERSIST_FLOW_EXISTS
;
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
535 if (i_dladm_flow_fput_grp(fp
, attr
) != 0)
536 status
= DLADM_STATUS_FLOW_DB_PARSE_ERR
;
540 i_dladm_flow_unlock_db(lock_fd
);
544 static dladm_status_t
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
)
548 dld_ioc_addflow_t attr
;
551 bzero(&attr
, sizeof (attr
));
552 bcopy(flowdesc
, &attr
.af_flow_desc
, sizeof (flow_desc_t
));
554 bcopy(mrp
, &attr
.af_resource_props
,
555 sizeof (mac_resource_props_t
));
558 (void) strlcpy(attr
.af_name
, flowname
, sizeof (attr
.af_name
));
559 attr
.af_linkid
= linkid
;
561 if (ioctl(dladm_dld_fd(handle
), DLDIOC_ADDFLOW
, &attr
) < 0)
562 return (dladm_errno2status(errno
));
564 return (DLADM_STATUS_OK
);
567 static dladm_status_t
568 i_dladm_flow_remove(dladm_handle_t handle
, char *flowname
)
570 dld_ioc_removeflow_t attr
;
571 dladm_status_t status
= DLADM_STATUS_OK
;
573 (void) strlcpy(attr
.rf_name
, flowname
,
574 sizeof (attr
.rf_name
));
576 if (ioctl(dladm_dld_fd(handle
), DLDIOC_REMOVEFLOW
, &attr
) < 0)
577 status
= dladm_errno2status(errno
);
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
)
589 dld_flowinfo_t db_attr
;
590 flow_desc_t flowdesc
;
591 mac_resource_props_t mrp
;
592 dladm_status_t status
;
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
) {
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
) {
608 /* Add flow in kernel */
609 status
= i_dladm_flow_add(handle
, flowname
, linkid
, &flowdesc
, &mrp
);
610 if (status
!= DLADM_STATUS_OK
)
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
;
621 if ((status
= i_dladm_flow_create_db(&db_attr
, root
)) !=
623 (void) i_dladm_flow_remove(handle
, flowname
);
626 /* set flow properties */
627 if (proplist
!= NULL
) {
628 status
= i_dladm_set_flow_proplist_db(handle
, flowname
,
630 if (status
!= DLADM_STATUS_OK
) {
631 (void) i_dladm_flow_remove(handle
, flowname
);
644 dladm_flow_remove(dladm_handle_t handle
, char *flowname
, boolean_t tempop
,
647 remove_db_state_t state
;
648 dladm_status_t status
= DLADM_STATUS_OK
;
649 dladm_status_t s
= DLADM_STATUS_OK
;
652 status
= i_dladm_flow_remove(handle
, flowname
);
653 if ((status
!= DLADM_STATUS_OK
) &&
654 (tempop
|| status
!= DLADM_STATUS_NOTFOUND
))
657 /* remove flow from DB */
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
;
665 if (i_dladm_flow_remove_db(&state
, root
) < 0) {
666 s
= dladm_errno2status(errno
);
671 s
= dladm_set_flowprop(handle
, flowname
, NULL
, NULL
, 0,
672 DLADM_OPT_PERSIST
, NULL
);
677 if (s
== DLADM_STATUS_OK
) {
678 if (status
== DLADM_STATUS_NOTFOUND
)
681 if (s
!= DLADM_STATUS_NOTFOUND
)
689 * Get an existing flow in the DB.
692 typedef struct get_db_state
{
693 int (*gs_fn
)(dladm_handle_t
, dladm_flow_attr_t
*, void *);
695 datalink_id_t gs_linkid
;
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
706 i_dladm_flow_get_db_fn(void *arg
, dld_flowinfo_t
*grp
)
708 get_db_state_t
*state
= (get_db_state_t
*)arg
;
709 dladm_flow_attr_t attr
;
710 dladm_handle_t handle
= NULL
;
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
);
726 * Walk through the flows defined on the system and for each flow
727 * invoke <fn>(<arg>, <flow>);
728 * Currently used for show-flow.
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
)
735 dld_flowinfo_t
*flow
;
737 dld_ioc_walkflow_t
*ioc
= NULL
;
738 dladm_flow_attr_t attr
;
739 dladm_status_t status
= DLADM_STATUS_OK
;
742 return (DLADM_STATUS_BADARG
);
745 get_db_state_t state
;
747 bzero(&state
, sizeof (state
));
749 state
.gs_linkid
= linkid
;
752 status
= i_dladm_flow_walk_rw_db(i_dladm_flow_get_db_fn
,
754 if (status
!= DLADM_STATUS_OK
)
757 bufsize
= MIN_INFO_SIZE
;
758 if ((ioc
= calloc(1, bufsize
)) == NULL
) {
759 status
= dladm_errno2status(errno
);
763 ioc
->wf_linkid
= linkid
;
764 ioc
->wf_len
= bufsize
- sizeof (*ioc
);
766 while (ioctl(dladm_dld_fd(handle
), DLDIOC_WALKFLOW
, ioc
) < 0) {
767 if (errno
== ENOSPC
) {
769 ioc
= realloc(ioc
, bufsize
);
771 ioc
->wf_linkid
= linkid
;
772 ioc
->wf_len
= bufsize
- sizeof (*ioc
);
779 flow
= (dld_flowinfo_t
*)(void *)(ioc
+ 1);
780 for (i
= 0; i
< ioc
->wf_nflows
; i
++, flow
++) {
781 bzero(&attr
, sizeof (attr
));
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
));
791 if (fn(handle
, &attr
, arg
) == DLADM_WALK_TERMINATE
)
802 dladm_flow_init(dladm_handle_t handle
)
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
];
812 if ((fp
= fopen(DLADM_FLOW_DB
, "r")) == NULL
)
813 return (DLADM_STATUS_DB_NOTFOUND
);
815 while (fgets(line
, MAXLINELEN
, fp
) != NULL
) {
817 if (BLANK_LINE(line
))
820 (void) strtok(line
, " \n");
822 s
= dladm_flow_parse_db(line
, &attr
);
823 if (s
!= DLADM_STATUS_OK
) {
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
;
833 s
= i_dladm_flow_add(handle
, name
, linkid
, &flowdesc
, NULL
);
834 if (s
!= DLADM_STATUS_OK
)
837 s
= i_dladm_init_flowprop_db(handle
);
838 if (s
!= DLADM_STATUS_OK
)
846 dladm_prefixlen2mask(int prefixlen
, int maxlen
, uchar_t
*mask
)
848 if (prefixlen
< 0 || prefixlen
> maxlen
)
849 return (DLADM_STATUS_BADARG
);
851 while (prefixlen
> 0) {
852 if (prefixlen
>= 8) {
857 *mask
|= 1 << (8 - prefixlen
);
860 return (DLADM_STATUS_OK
);
864 dladm_mask2prefixlen(in6_addr_t
*mask
, int plen
, int *prefixlen
)
877 return (DLADM_STATUS_BADARG
);
880 for (i
= 3; i
>= end
; i
--) {
881 if (mask
->_S6_un
._S6_u32
[i
] == 0) {
885 bits
= ffs(ntohl(mask
->_S6_un
._S6_u32
[i
])) - 1;
891 return (DLADM_STATUS_OK
);