18275SEric Cheng /*
28275SEric Cheng * CDDL HEADER START
38275SEric Cheng *
48275SEric Cheng * The contents of this file are subject to the terms of the
58275SEric Cheng * Common Development and Distribution License (the "License").
68275SEric Cheng * You may not use this file except in compliance with the License.
78275SEric Cheng *
88275SEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98275SEric Cheng * or http://www.opensolaris.org/os/licensing.
108275SEric Cheng * See the License for the specific language governing permissions
118275SEric Cheng * and limitations under the License.
128275SEric Cheng *
138275SEric Cheng * When distributing Covered Code, include this CDDL HEADER in each
148275SEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158275SEric Cheng * If applicable, add the following below this CDDL HEADER, with the
168275SEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying
178275SEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner]
188275SEric Cheng *
198275SEric Cheng * CDDL HEADER END
208275SEric Cheng */
218275SEric Cheng /*
22*11767SAnurag.Maskey@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
238275SEric Cheng * Use is subject to license terms.
248275SEric Cheng */
258275SEric Cheng
268275SEric Cheng #include <stdio.h>
278275SEric Cheng #include <sys/types.h>
288275SEric Cheng #include <sys/socket.h>
298275SEric Cheng #include <sys/ethernet.h>
308275SEric Cheng #include <netinet/in.h>
318275SEric Cheng #include <arpa/inet.h>
328275SEric Cheng #include <sys/stat.h>
339107Sjames.d.carlson@sun.com #include <sys/dld_ioc.h>
348275SEric Cheng #include <string.h>
358275SEric Cheng #include <fcntl.h>
368275SEric Cheng #include <unistd.h>
378275SEric Cheng #include <stropts.h>
388275SEric Cheng #include <stdlib.h>
398275SEric Cheng #include <errno.h>
408275SEric Cheng #include <strings.h>
418275SEric Cheng #include <libintl.h>
428275SEric Cheng #include <netdb.h>
438275SEric Cheng #include <net/if_types.h>
448275SEric Cheng #include <net/if_dl.h>
458275SEric Cheng #include <inet/ip.h>
468275SEric Cheng #include <inet/ip6.h>
478275SEric Cheng #include <libdlflow.h>
488275SEric Cheng #include <libdlflow_impl.h>
498275SEric Cheng #include <libdladm_impl.h>
508275SEric Cheng
518275SEric Cheng /* minimum buffer size for DLDIOCWALKFLOW */
528275SEric Cheng #define MIN_INFO_SIZE (4 * 1024)
538275SEric Cheng
548275SEric Cheng #define DLADM_FLOW_DB "/etc/dladm/flowadm.conf"
558275SEric Cheng #define DLADM_FLOW_DB_TMP "/etc/dladm/flowadm.conf.new"
568275SEric Cheng #define DLADM_FLOW_DB_LOCK "/tmp/flowadm.conf.lock"
578275SEric Cheng
588275SEric Cheng #define DLADM_FLOW_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
598275SEric Cheng #define DLADM_FLOW_DB_OWNER UID_DLADM
60*11767SAnurag.Maskey@Sun.COM #define DLADM_FLOW_DB_GROUP GID_NETADM
618275SEric Cheng
628275SEric Cheng #define BLANK_LINE(s) ((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n'))
638275SEric Cheng #define MAXLINELEN 1024
648275SEric Cheng #define MAXPATHLEN 1024
658275SEric Cheng
668275SEric Cheng /* database file parameters */
678275SEric Cheng static const char *BW_LIMIT = "bw_limit";
688275SEric Cheng static const char *PRIORITY = "priority";
698275SEric Cheng static const char *LOCAL_IP_ADDR = "local_ip";
708275SEric Cheng static const char *REMOTE_IP_ADDR = "remote_ip";
718275SEric Cheng static const char *TRANSPORT = "transport";
728275SEric Cheng static const char *LOCAL_PORT = "local_port";
7310734SEric Cheng static const char *REMOTE_PORT = "remote_port";
748275SEric Cheng static const char *DSFIELD = "dsfield";
758275SEric Cheng
768275SEric Cheng /*
778275SEric Cheng * Open and lock the flowadm configuration file lock. The lock is
788275SEric Cheng * acquired as a reader (F_RDLCK) or writer (F_WRLCK).
798275SEric Cheng */
808275SEric Cheng static int
i_dladm_flow_lock_db(short type)818275SEric Cheng i_dladm_flow_lock_db(short type)
828275SEric Cheng {
838275SEric Cheng int lock_fd;
848275SEric Cheng struct flock lock;
858275SEric Cheng
868275SEric Cheng if ((lock_fd = open(DLADM_FLOW_DB_LOCK, O_RDWR | O_CREAT | O_TRUNC,
878275SEric Cheng DLADM_FLOW_DB_PERMS)) < 0)
888275SEric Cheng return (-1);
898275SEric Cheng
908275SEric Cheng lock.l_type = type;
918275SEric Cheng lock.l_whence = SEEK_SET;
928275SEric Cheng lock.l_start = 0;
938275SEric Cheng lock.l_len = 0;
948275SEric Cheng
958275SEric Cheng if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
968275SEric Cheng (void) close(lock_fd);
978275SEric Cheng (void) unlink(DLADM_FLOW_DB_LOCK);
988275SEric Cheng return (-1);
998275SEric Cheng }
1008275SEric Cheng return (lock_fd);
1018275SEric Cheng }
1028275SEric Cheng
1038275SEric Cheng /*
1048275SEric Cheng * Unlock and close the specified file.
1058275SEric Cheng */
1068275SEric Cheng static void
i_dladm_flow_unlock_db(int fd)1078275SEric Cheng i_dladm_flow_unlock_db(int fd)
1088275SEric Cheng {
1098275SEric Cheng struct flock lock;
1108275SEric Cheng
1118275SEric Cheng if (fd < 0)
1128275SEric Cheng return;
1138275SEric Cheng
1148275SEric Cheng lock.l_type = F_UNLCK;
1158275SEric Cheng lock.l_whence = SEEK_SET;
1168275SEric Cheng lock.l_start = 0;
1178275SEric Cheng lock.l_len = 0;
1188275SEric Cheng
1198275SEric Cheng (void) fcntl(fd, F_SETLKW, &lock);
1208275SEric Cheng (void) close(fd);
1218275SEric Cheng (void) unlink(DLADM_FLOW_DB_LOCK);
1228275SEric Cheng }
1238275SEric Cheng
1248275SEric Cheng /*
1258275SEric Cheng * Parse one line of the link flowadm DB
1268275SEric Cheng * Returns -1 on failure, 0 on success.
1278275SEric Cheng */
1288275SEric Cheng dladm_status_t
dladm_flow_parse_db(char * line,dld_flowinfo_t * attr)1298275SEric Cheng dladm_flow_parse_db(char *line, dld_flowinfo_t *attr)
1308275SEric Cheng {
1318275SEric Cheng char *token;
1328275SEric Cheng char *value, *name = NULL;
1338275SEric Cheng char *lasts = NULL;
1348275SEric Cheng dladm_status_t status = DLADM_STATUS_FLOW_DB_PARSE_ERR;
1358275SEric Cheng
1368275SEric Cheng bzero(attr, sizeof (*attr));
1378275SEric Cheng
1388275SEric Cheng /* flow name */
1398275SEric Cheng if ((token = strtok_r(line, " \t", &lasts)) == NULL)
1408275SEric Cheng goto done;
1418275SEric Cheng
1428558SGirish.Moodalbail@Sun.COM if (strlcpy(attr->fi_flowname, token, MAXFLOWNAMELEN) >= MAXFLOWNAMELEN)
1438275SEric Cheng goto done;
1448275SEric Cheng
1458275SEric Cheng /* resource control and flow descriptor parameters */
1468275SEric Cheng while ((token = strtok_r(NULL, " \t", &lasts)) != NULL) {
1478275SEric Cheng if ((name = strdup(token)) == NULL)
1488275SEric Cheng goto done;
1498275SEric Cheng
1508275SEric Cheng (void) strtok(name, "=");
1518275SEric Cheng value = strtok(NULL, "=");
1528275SEric Cheng if (value == NULL)
1538275SEric Cheng goto done;
1548275SEric Cheng
1558275SEric Cheng if (strcmp(name, "linkid") == 0) {
1568275SEric Cheng if ((attr->fi_linkid =
15710734SEric Cheng (uint32_t)strtol(value, NULL, 10)) ==
1588275SEric Cheng DATALINK_INVALID_LINKID)
1598275SEric Cheng goto done;
1608275SEric Cheng
1618275SEric Cheng } else if (strcmp(name, BW_LIMIT) == 0) {
1628275SEric Cheng attr->fi_resource_props.mrp_mask |=
1638275SEric Cheng MRP_MAXBW;
1648275SEric Cheng attr->fi_resource_props.mrp_maxbw =
16510734SEric Cheng (uint64_t)strtol(value, NULL, 0);
1668275SEric Cheng
1678275SEric Cheng } else if (strcmp(name, PRIORITY) == 0) {
1688275SEric Cheng attr->fi_resource_props.mrp_mask |= MRP_PRIORITY;
1698275SEric Cheng status = dladm_str2pri(value,
1708275SEric Cheng &attr->fi_resource_props.mrp_priority);
1718275SEric Cheng if (status != DLADM_STATUS_OK)
1728275SEric Cheng goto done;
1738275SEric Cheng
1748275SEric Cheng } else if (strcmp(name, DSFIELD) == 0) {
1758275SEric Cheng status = do_check_dsfield(value,
1768275SEric Cheng &attr->fi_flow_desc);
1778275SEric Cheng if (status != DLADM_STATUS_OK)
1788275SEric Cheng goto done;
1798275SEric Cheng
1808275SEric Cheng } else if (strcmp(name, LOCAL_IP_ADDR) == 0) {
1818275SEric Cheng status = do_check_ip_addr(value, B_TRUE,
1828275SEric Cheng &attr->fi_flow_desc);
1838275SEric Cheng if (status != DLADM_STATUS_OK)
1848275SEric Cheng goto done;
1858275SEric Cheng
1868275SEric Cheng } else if (strcmp(name, REMOTE_IP_ADDR) == 0) {
1878275SEric Cheng status = do_check_ip_addr(value, B_FALSE,
1888275SEric Cheng &attr->fi_flow_desc);
1898275SEric Cheng if (status != DLADM_STATUS_OK)
1908275SEric Cheng goto done;
1918275SEric Cheng
1928275SEric Cheng } else if (strcmp(name, TRANSPORT) == 0) {
1938275SEric Cheng attr->fi_flow_desc.fd_mask |= FLOW_IP_PROTOCOL;
1948275SEric Cheng attr->fi_flow_desc.fd_protocol =
19510734SEric Cheng (uint8_t)strtol(value, NULL, 0);
1968275SEric Cheng
1978275SEric Cheng } else if (strcmp(name, LOCAL_PORT) == 0) {
1988275SEric Cheng attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_LOCAL;
1998275SEric Cheng attr->fi_flow_desc.fd_local_port =
20010734SEric Cheng (uint16_t)strtol(value, NULL, 10);
2018275SEric Cheng attr->fi_flow_desc.fd_local_port =
2028275SEric Cheng htons(attr->fi_flow_desc.fd_local_port);
20310734SEric Cheng } else if (strcmp(name, REMOTE_PORT) == 0) {
20410734SEric Cheng attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_REMOTE;
20510734SEric Cheng attr->fi_flow_desc.fd_remote_port =
20610734SEric Cheng (uint16_t)strtol(value, NULL, 10);
20710734SEric Cheng attr->fi_flow_desc.fd_remote_port =
20810734SEric Cheng htons(attr->fi_flow_desc.fd_remote_port);
2098275SEric Cheng }
2108275SEric Cheng free(name);
2118275SEric Cheng name = NULL;
2128275SEric Cheng }
2138275SEric Cheng if (attr->fi_linkid != DATALINK_INVALID_LINKID)
2148275SEric Cheng status = DLADM_STATUS_OK;
2158275SEric Cheng done:
2168275SEric Cheng free(name);
2178275SEric Cheng return (status);
2188275SEric Cheng }
2198275SEric Cheng
2208275SEric Cheng #define FPRINTF_ERR(fcall) if ((fcall) < 0) return (-1);
2218275SEric Cheng
2228275SEric Cheng /*
2238275SEric Cheng * Write the attribute of a group to the specified file. Returns 0 on
2248275SEric Cheng * success, -1 on failure.
2258275SEric Cheng */
2268275SEric Cheng static int
i_dladm_flow_fput_grp(FILE * fp,dld_flowinfo_t * attr)2278275SEric Cheng i_dladm_flow_fput_grp(FILE *fp, dld_flowinfo_t *attr)
2288275SEric Cheng {
2298275SEric Cheng
2308275SEric Cheng FPRINTF_ERR(fprintf(fp, "%s\tlinkid=%d\t",
2318275SEric Cheng attr->fi_flowname, attr->fi_linkid));
2328275SEric Cheng
2338275SEric Cheng /* flow policy */
2348275SEric Cheng if (attr->fi_resource_props.mrp_mask & MRP_MAXBW)
2358275SEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%" PRIu64 "\t", BW_LIMIT,
2368275SEric Cheng attr->fi_resource_props.mrp_maxbw));
2378275SEric Cheng
2388275SEric Cheng if (attr->fi_resource_props.mrp_mask & MRP_PRIORITY)
2398275SEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%d\t", PRIORITY,
2408275SEric Cheng attr->fi_resource_props.mrp_priority));
2418275SEric Cheng
2428275SEric Cheng /* flow descriptor */
2438275SEric Cheng if (attr->fi_flow_desc.fd_mask & FLOW_IP_DSFIELD)
2448275SEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%x:%x\t", DSFIELD,
2458275SEric Cheng attr->fi_flow_desc.fd_dsfield,
2468275SEric Cheng attr->fi_flow_desc.fd_dsfield_mask));
2478275SEric Cheng
2488275SEric Cheng if (attr->fi_flow_desc.fd_mask & FLOW_IP_LOCAL) {
2498275SEric Cheng char abuf[INET6_ADDRSTRLEN], *ap;
2508275SEric Cheng struct in_addr ipaddr;
2518275SEric Cheng int prefix_len, prefix_max;
2528275SEric Cheng
2538275SEric Cheng if (attr->fi_flow_desc.fd_ipversion != 6) {
2548275SEric Cheng ipaddr.s_addr =
2558275SEric Cheng attr->fi_flow_desc.
2568275SEric Cheng fd_local_addr._S6_un._S6_u32[3];
2578275SEric Cheng
2588275SEric Cheng ap = inet_ntoa(ipaddr);
2598275SEric Cheng prefix_max = IP_ABITS;
2608275SEric Cheng } else {
2618275SEric Cheng (void) inet_ntop(AF_INET6,
2628275SEric Cheng &attr->fi_flow_desc.fd_local_addr,
2638275SEric Cheng abuf, INET6_ADDRSTRLEN);
2648275SEric Cheng
2658275SEric Cheng ap = abuf;
2668275SEric Cheng prefix_max = IPV6_ABITS;
2678275SEric Cheng }
2688275SEric Cheng (void) dladm_mask2prefixlen(
2698275SEric Cheng &attr->fi_flow_desc.fd_local_netmask, prefix_max,
2708275SEric Cheng &prefix_len);
2718275SEric Cheng
2728275SEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%s/%d\t", LOCAL_IP_ADDR,
2738275SEric Cheng ap, prefix_len));
2748275SEric Cheng }
2758275SEric Cheng if (attr->fi_flow_desc.fd_mask & FLOW_IP_REMOTE) {
2768275SEric Cheng char abuf[INET6_ADDRSTRLEN], *ap;
2778275SEric Cheng struct in_addr ipaddr;
2788275SEric Cheng int prefix_len, prefix_max;
2798275SEric Cheng
2808275SEric Cheng if (attr->fi_flow_desc.fd_ipversion != 6) {
2818275SEric Cheng ipaddr.s_addr =
2828275SEric Cheng attr->fi_flow_desc.
2838275SEric Cheng fd_remote_addr._S6_un._S6_u32[3];
2848275SEric Cheng
2858275SEric Cheng ap = inet_ntoa(ipaddr);
2868275SEric Cheng prefix_max = IP_ABITS;
2878275SEric Cheng } else {
2888275SEric Cheng (void) inet_ntop(AF_INET6,
2898275SEric Cheng &(attr->fi_flow_desc.fd_remote_addr),
2908275SEric Cheng abuf, INET6_ADDRSTRLEN);
2918275SEric Cheng
2928275SEric Cheng ap = abuf;
2938275SEric Cheng prefix_max = IPV6_ABITS;
2948275SEric Cheng }
2958275SEric Cheng (void) dladm_mask2prefixlen(
2968275SEric Cheng &attr->fi_flow_desc.fd_remote_netmask, prefix_max,
2978275SEric Cheng &prefix_len);
2988275SEric Cheng
2998275SEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%s/%d\t", REMOTE_IP_ADDR,
3008275SEric Cheng ap, prefix_len));
3018275SEric Cheng }
3028275SEric Cheng if (attr->fi_flow_desc.fd_mask & FLOW_IP_PROTOCOL)
3038275SEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%d\t", TRANSPORT,
3048275SEric Cheng attr->fi_flow_desc.fd_protocol));
3058275SEric Cheng
3068275SEric Cheng if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL)
3078275SEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%d\t", LOCAL_PORT,
3088275SEric Cheng ntohs(attr->fi_flow_desc.fd_local_port)));
3098275SEric Cheng
31010734SEric Cheng if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE)
31110734SEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%d\t", REMOTE_PORT,
31210734SEric Cheng ntohs(attr->fi_flow_desc.fd_remote_port)));
31310734SEric Cheng
3148275SEric Cheng FPRINTF_ERR(fprintf(fp, "\n"));
3158275SEric Cheng
3168275SEric Cheng return (0);
3178275SEric Cheng
3188275SEric Cheng }
3198275SEric Cheng
3208275SEric Cheng static dladm_status_t
i_dladm_flow_walk_rw_db(int (* fn)(void *,dld_flowinfo_t *),void * arg,const char * root)3218275SEric Cheng i_dladm_flow_walk_rw_db(int (*fn)(void *, dld_flowinfo_t *),
3228275SEric Cheng void *arg,
3238275SEric Cheng const char *root)
3248275SEric Cheng {
3258275SEric Cheng FILE *fp, *nfp;
3268275SEric Cheng int nfd, fn_rc, lock_fd;
3278275SEric Cheng char line[MAXLINELEN];
3288275SEric Cheng dld_flowinfo_t attr;
3298275SEric Cheng char *db_file, *tmp_db_file;
3308275SEric Cheng char db_file_buf[MAXPATHLEN];
3318275SEric Cheng char tmp_db_file_buf[MAXPATHLEN];
3328275SEric Cheng dladm_status_t status = DLADM_STATUS_FLOW_DB_ERR;
3338275SEric Cheng
3348275SEric Cheng if (root == NULL) {
3358275SEric Cheng db_file = DLADM_FLOW_DB;
3368275SEric Cheng tmp_db_file = DLADM_FLOW_DB_TMP;
3378275SEric Cheng } else {
3388275SEric Cheng (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
3398275SEric Cheng DLADM_FLOW_DB);
3408275SEric Cheng (void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root,
3418275SEric Cheng DLADM_FLOW_DB_TMP);
3428275SEric Cheng db_file = db_file_buf;
3438275SEric Cheng tmp_db_file = tmp_db_file_buf;
3448275SEric Cheng }
3458275SEric Cheng
3468275SEric Cheng if ((lock_fd = i_dladm_flow_lock_db(F_WRLCK)) < 0)
3478275SEric Cheng return (DLADM_STATUS_FLOW_DB_ERR);
3488275SEric Cheng
3498275SEric Cheng if ((fp = fopen(db_file, "r")) == NULL) {
3508275SEric Cheng i_dladm_flow_unlock_db(lock_fd);
3518275SEric Cheng return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
3528275SEric Cheng }
3538275SEric Cheng
3548275SEric Cheng if ((nfd = open(tmp_db_file, O_WRONLY|O_CREAT|O_TRUNC,
3558275SEric Cheng DLADM_FLOW_DB_PERMS)) == -1) {
3568275SEric Cheng (void) fclose(fp);
3578275SEric Cheng i_dladm_flow_unlock_db(lock_fd);
3588275SEric Cheng return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
3598275SEric Cheng }
3608275SEric Cheng
3618275SEric Cheng if ((nfp = fdopen(nfd, "w")) == NULL) {
3628275SEric Cheng (void) close(nfd);
3638275SEric Cheng (void) fclose(fp);
3648275SEric Cheng (void) unlink(tmp_db_file);
3658275SEric Cheng i_dladm_flow_unlock_db(lock_fd);
3668275SEric Cheng return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
3678275SEric Cheng }
3688275SEric Cheng
3698275SEric Cheng while (fgets(line, MAXLINELEN, fp) != NULL) {
3708275SEric Cheng
3718275SEric Cheng /* skip comments */
3728275SEric Cheng if (BLANK_LINE(line)) {
3738275SEric Cheng if (fputs(line, nfp) == EOF)
3748275SEric Cheng goto failed;
3758275SEric Cheng continue;
3768275SEric Cheng }
3778275SEric Cheng (void) strtok(line, " \n");
3788275SEric Cheng
3798275SEric Cheng if ((status = dladm_flow_parse_db(line, &attr)) !=
3808275SEric Cheng DLADM_STATUS_OK)
3818275SEric Cheng goto failed;
3828275SEric Cheng
3838275SEric Cheng fn_rc = fn(arg, &attr);
3848275SEric Cheng
3858275SEric Cheng switch (fn_rc) {
3868275SEric Cheng case -1:
3878275SEric Cheng /* failure, stop walking */
3888275SEric Cheng goto failed;
3898275SEric Cheng case 0:
3908275SEric Cheng /*
3918275SEric Cheng * Success, write group attributes, which could
3928275SEric Cheng * have been modified by fn().
3938275SEric Cheng */
3948275SEric Cheng if (i_dladm_flow_fput_grp(nfp, &attr) != 0)
3958275SEric Cheng goto failed;
3968275SEric Cheng break;
3978275SEric Cheng case 1:
3988275SEric Cheng /* skip current group */
3998275SEric Cheng break;
4008275SEric Cheng }
4018275SEric Cheng }
4028275SEric Cheng if (fchmod(nfd, DLADM_FLOW_DB_PERMS) == -1)
4038275SEric Cheng goto failed;
4048275SEric Cheng
4058275SEric Cheng if (fchown(nfd, DLADM_FLOW_DB_OWNER, DLADM_FLOW_DB_GROUP) == -1)
4068275SEric Cheng goto failed;
4078275SEric Cheng
4088275SEric Cheng if (fflush(nfp) == EOF)
4098275SEric Cheng goto failed;
4108275SEric Cheng
4118275SEric Cheng (void) fclose(fp);
4128275SEric Cheng (void) fclose(nfp);
4138275SEric Cheng
4148275SEric Cheng if (rename(tmp_db_file, db_file) == -1) {
4158275SEric Cheng (void) unlink(tmp_db_file);
4168275SEric Cheng i_dladm_flow_unlock_db(lock_fd);
4178275SEric Cheng return (DLADM_STATUS_FLOW_DB_ERR);
4188275SEric Cheng }
4198275SEric Cheng i_dladm_flow_unlock_db(lock_fd);
4208275SEric Cheng return (DLADM_STATUS_OK);
4218275SEric Cheng
4228275SEric Cheng failed:
4238275SEric Cheng (void) fclose(fp);
4248275SEric Cheng (void) fclose(nfp);
4258275SEric Cheng (void) unlink(tmp_db_file);
4268275SEric Cheng i_dladm_flow_unlock_db(lock_fd);
4278275SEric Cheng
4288275SEric Cheng return (status);
4298275SEric Cheng }
4308275SEric Cheng
4318275SEric Cheng /*
4328275SEric Cheng * Remove existing flow from DB.
4338275SEric Cheng */
4348275SEric Cheng
4358275SEric Cheng typedef struct remove_db_state {
4368275SEric Cheng dld_flowinfo_t rs_newattr;
4378275SEric Cheng dld_flowinfo_t rs_oldattr;
4388275SEric Cheng boolean_t rs_found;
4398275SEric Cheng } remove_db_state_t;
4408275SEric Cheng
4418275SEric Cheng static int
i_dladm_flow_remove_db_fn(void * arg,dld_flowinfo_t * grp)4428275SEric Cheng i_dladm_flow_remove_db_fn(void *arg, dld_flowinfo_t *grp)
4438275SEric Cheng {
4448275SEric Cheng remove_db_state_t *state = (remove_db_state_t *)arg;
4458275SEric Cheng dld_flowinfo_t *attr = &state->rs_newattr;
4468275SEric Cheng
4478275SEric Cheng if ((strcmp(grp->fi_flowname, attr->fi_flowname)) != 0)
4488275SEric Cheng return (0);
4498275SEric Cheng else {
4508275SEric Cheng bcopy(grp, &state->rs_oldattr,
4518275SEric Cheng sizeof (dld_flowinfo_t));
4528275SEric Cheng state->rs_found = B_TRUE;
4538275SEric Cheng return (1);
4548275SEric Cheng }
4558275SEric Cheng }
4568275SEric Cheng
4578275SEric Cheng /* ARGSUSED */
4588275SEric Cheng static int
i_dladm_flow_remove_db(remove_db_state_t * state,const char * root)4598275SEric Cheng i_dladm_flow_remove_db(remove_db_state_t *state, const char *root)
4608275SEric Cheng {
4618275SEric Cheng if (i_dladm_flow_walk_rw_db(i_dladm_flow_remove_db_fn, state, root)
4628275SEric Cheng != 0)
4638275SEric Cheng return (-1);
4648275SEric Cheng
4658275SEric Cheng if (!state->rs_found) {
4668275SEric Cheng errno = ENOENT;
4678275SEric Cheng return (-1);
4688275SEric Cheng }
4698275SEric Cheng
4708275SEric Cheng return (0);
4718275SEric Cheng }
4728275SEric Cheng
4738275SEric Cheng /*
4748275SEric Cheng * Create a flow in the DB.
4758275SEric Cheng */
4768275SEric Cheng
4778275SEric Cheng typedef struct modify_db_state {
4788275SEric Cheng dld_flowinfo_t ms_newattr;
4798275SEric Cheng dld_flowinfo_t ms_oldattr;
4808275SEric Cheng boolean_t ms_found;
4818275SEric Cheng } modify_db_state_t;
4828275SEric Cheng
4838275SEric Cheng static dladm_status_t
i_dladm_flow_create_db(dld_flowinfo_t * attr,const char * root)4848275SEric Cheng i_dladm_flow_create_db(dld_flowinfo_t *attr, const char *root)
4858275SEric Cheng {
4868275SEric Cheng FILE *fp;
4878275SEric Cheng char line[MAXLINELEN];
4888275SEric Cheng char *db_file;
4898275SEric Cheng char db_file_buf[MAXPATHLEN];
4908275SEric Cheng int lock_fd;
4918275SEric Cheng dladm_status_t status = DLADM_STATUS_OK;
4928275SEric Cheng
4938275SEric Cheng if (root == NULL) {
4948275SEric Cheng db_file = DLADM_FLOW_DB;
4958275SEric Cheng } else {
4968275SEric Cheng (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root,
4978275SEric Cheng DLADM_FLOW_DB);
4988275SEric Cheng db_file = db_file_buf;
4998275SEric Cheng }
5008275SEric Cheng
5018275SEric Cheng if ((lock_fd = i_dladm_flow_lock_db(F_WRLCK)) < 0)
5028275SEric Cheng return (DLADM_STATUS_FLOW_DB_ERR);
5038275SEric Cheng
5048275SEric Cheng if ((fp = fopen(db_file, "r+")) == NULL &&
5058275SEric Cheng (fp = fopen(db_file, "w")) == NULL) {
5068275SEric Cheng i_dladm_flow_unlock_db(lock_fd);
5078275SEric Cheng return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
5088275SEric Cheng }
5098275SEric Cheng
5108275SEric Cheng /* look for existing group with same flowname */
5118275SEric Cheng while (fgets(line, MAXLINELEN, fp) != NULL) {
5128275SEric Cheng char *holder, *lasts;
5138275SEric Cheng
5148275SEric Cheng /* skip comments */
5158275SEric Cheng if (BLANK_LINE(line))
5168275SEric Cheng continue;
5178275SEric Cheng
5188275SEric Cheng /* ignore corrupted lines */
5198275SEric Cheng holder = strtok_r(line, " \t", &lasts);
5208275SEric Cheng if (holder == NULL)
5218275SEric Cheng continue;
5228275SEric Cheng
5238275SEric Cheng /* flow id */
5248275SEric Cheng if (strcmp(holder, attr->fi_flowname) == 0) {
5258275SEric Cheng /* group with flow id already exists */
5268275SEric Cheng status = DLADM_STATUS_PERSIST_FLOW_EXISTS;
5278275SEric Cheng goto failed;
5288275SEric Cheng }
5298275SEric Cheng }
5308275SEric Cheng /*
5318275SEric Cheng * If we get here, we've verified that no existing group with
5328275SEric Cheng * the same flow id already exists. Its now time to add the new
5338275SEric Cheng * group to the DB.
5348275SEric Cheng */
5358275SEric Cheng if (i_dladm_flow_fput_grp(fp, attr) != 0)
5368275SEric Cheng status = DLADM_STATUS_FLOW_DB_PARSE_ERR;
5378275SEric Cheng
5388275SEric Cheng failed:
5398275SEric Cheng (void) fclose(fp);
5408275SEric Cheng i_dladm_flow_unlock_db(lock_fd);
5418275SEric Cheng return (status);
5428275SEric Cheng }
5438275SEric Cheng
5448275SEric Cheng static dladm_status_t
i_dladm_flow_add(dladm_handle_t handle,char * flowname,datalink_id_t linkid,flow_desc_t * flowdesc,mac_resource_props_t * mrp)5458453SAnurag.Maskey@Sun.COM i_dladm_flow_add(dladm_handle_t handle, char *flowname, datalink_id_t linkid,
5468453SAnurag.Maskey@Sun.COM flow_desc_t *flowdesc, mac_resource_props_t *mrp)
5478275SEric Cheng {
5488275SEric Cheng dld_ioc_addflow_t attr;
5498275SEric Cheng
5508275SEric Cheng /* create flow */
5518275SEric Cheng bzero(&attr, sizeof (attr));
5528275SEric Cheng bcopy(flowdesc, &attr.af_flow_desc, sizeof (flow_desc_t));
5538275SEric Cheng if (mrp != NULL) {
5548275SEric Cheng bcopy(mrp, &attr.af_resource_props,
5558275SEric Cheng sizeof (mac_resource_props_t));
5568275SEric Cheng }
5578275SEric Cheng
5588275SEric Cheng (void) strlcpy(attr.af_name, flowname, sizeof (attr.af_name));
5598275SEric Cheng attr.af_linkid = linkid;
5608275SEric Cheng
5618453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_ADDFLOW, &attr) < 0)
5628275SEric Cheng return (dladm_errno2status(errno));
5638275SEric Cheng
5648275SEric Cheng return (DLADM_STATUS_OK);
5658275SEric Cheng }
5668275SEric Cheng
5678275SEric Cheng static dladm_status_t
i_dladm_flow_remove(dladm_handle_t handle,char * flowname)5688453SAnurag.Maskey@Sun.COM i_dladm_flow_remove(dladm_handle_t handle, char *flowname)
5698275SEric Cheng {
5708275SEric Cheng dld_ioc_removeflow_t attr;
5718275SEric Cheng dladm_status_t status = DLADM_STATUS_OK;
5728275SEric Cheng
5738275SEric Cheng (void) strlcpy(attr.rf_name, flowname,
5748275SEric Cheng sizeof (attr.rf_name));
5758275SEric Cheng
5768453SAnurag.Maskey@Sun.COM if (ioctl(dladm_dld_fd(handle), DLDIOC_REMOVEFLOW, &attr) < 0)
5778275SEric Cheng status = dladm_errno2status(errno);
5788275SEric Cheng
5798275SEric Cheng return (status);
5808275SEric Cheng }
5818275SEric Cheng
5828275SEric Cheng
5838275SEric Cheng /* ARGSUSED */
5848275SEric Cheng dladm_status_t
dladm_flow_add(dladm_handle_t handle,datalink_id_t linkid,dladm_arg_list_t * attrlist,dladm_arg_list_t * proplist,char * flowname,boolean_t tempop,const char * root)5858453SAnurag.Maskey@Sun.COM dladm_flow_add(dladm_handle_t handle, datalink_id_t linkid,
5868453SAnurag.Maskey@Sun.COM dladm_arg_list_t *attrlist, dladm_arg_list_t *proplist, char *flowname,
5878453SAnurag.Maskey@Sun.COM boolean_t tempop, const char *root)
5888275SEric Cheng {
5898275SEric Cheng dld_flowinfo_t db_attr;
5908275SEric Cheng flow_desc_t flowdesc;
5918275SEric Cheng mac_resource_props_t mrp;
5928275SEric Cheng dladm_status_t status;
5938275SEric Cheng
5948275SEric Cheng /* Extract flow attributes from attrlist */
5958275SEric Cheng bzero(&flowdesc, sizeof (flow_desc_t));
5968275SEric Cheng if (attrlist != NULL && (status = dladm_flow_attrlist_extract(attrlist,
5978275SEric Cheng &flowdesc)) != DLADM_STATUS_OK) {
5988275SEric Cheng return (status);
5998275SEric Cheng }
6008275SEric Cheng
6018275SEric Cheng /* Extract resource_ctl and cpu_list from proplist */
6028275SEric Cheng bzero(&mrp, sizeof (mac_resource_props_t));
6038275SEric Cheng if (proplist != NULL && (status = dladm_flow_proplist_extract(proplist,
6048275SEric Cheng &mrp)) != DLADM_STATUS_OK) {
6058275SEric Cheng return (status);
6068275SEric Cheng }
6078275SEric Cheng
6088275SEric Cheng /* Add flow in kernel */
6098453SAnurag.Maskey@Sun.COM status = i_dladm_flow_add(handle, flowname, linkid, &flowdesc, &mrp);
6108275SEric Cheng if (status != DLADM_STATUS_OK)
6118275SEric Cheng return (status);
6128275SEric Cheng
6138275SEric Cheng /* Add flow to DB */
6148275SEric Cheng if (!tempop) {
6158275SEric Cheng bzero(&db_attr, sizeof (db_attr));
6168275SEric Cheng bcopy(&flowdesc, &db_attr.fi_flow_desc, sizeof (flow_desc_t));
6178275SEric Cheng (void) strlcpy(db_attr.fi_flowname, flowname,
6188275SEric Cheng sizeof (db_attr.fi_flowname));
6198275SEric Cheng db_attr.fi_linkid = linkid;
6208275SEric Cheng
6218275SEric Cheng if ((status = i_dladm_flow_create_db(&db_attr, root)) !=
6228275SEric Cheng DLADM_STATUS_OK) {
6238453SAnurag.Maskey@Sun.COM (void) i_dladm_flow_remove(handle, flowname);
6248275SEric Cheng return (status);
6258275SEric Cheng }
6268275SEric Cheng /* set flow properties */
6278275SEric Cheng if (proplist != NULL) {
6288453SAnurag.Maskey@Sun.COM status = i_dladm_set_flow_proplist_db(handle, flowname,
6298275SEric Cheng proplist);
6308275SEric Cheng if (status != DLADM_STATUS_OK) {
6318453SAnurag.Maskey@Sun.COM (void) i_dladm_flow_remove(handle, flowname);
6328275SEric Cheng return (status);
6338275SEric Cheng }
6348275SEric Cheng }
6358275SEric Cheng }
6368275SEric Cheng return (status);
6378275SEric Cheng }
6388275SEric Cheng
6398275SEric Cheng /*
6408275SEric Cheng * Remove a flow.
6418275SEric Cheng */
6428275SEric Cheng /* ARGSUSED */
6438275SEric Cheng dladm_status_t
dladm_flow_remove(dladm_handle_t handle,char * flowname,boolean_t tempop,const char * root)6448453SAnurag.Maskey@Sun.COM dladm_flow_remove(dladm_handle_t handle, char *flowname, boolean_t tempop,
6458275SEric Cheng const char *root)
6468275SEric Cheng {
6478275SEric Cheng remove_db_state_t state;
6488275SEric Cheng dladm_status_t status = DLADM_STATUS_OK;
6498275SEric Cheng dladm_status_t s = DLADM_STATUS_OK;
6508275SEric Cheng
6518275SEric Cheng /* remove flow */
6528453SAnurag.Maskey@Sun.COM status = i_dladm_flow_remove(handle, flowname);
6538275SEric Cheng if ((status != DLADM_STATUS_OK) &&
6548275SEric Cheng (tempop || status != DLADM_STATUS_NOTFOUND))
6558275SEric Cheng goto done;
6568275SEric Cheng
6578275SEric Cheng /* remove flow from DB */
6588275SEric Cheng if (!tempop) {
6598275SEric Cheng bzero(&state, sizeof (state));
6608275SEric Cheng (void) strlcpy(state.rs_newattr.fi_flowname, flowname,
6618275SEric Cheng sizeof (state.rs_newattr.fi_flowname));
6628275SEric Cheng state.rs_found = B_FALSE;
6638275SEric Cheng
6648275SEric Cheng /* flow DB */
6658275SEric Cheng if (i_dladm_flow_remove_db(&state, root) < 0) {
6668275SEric Cheng s = dladm_errno2status(errno);
6678275SEric Cheng goto done;
6688275SEric Cheng }
6698275SEric Cheng
6708275SEric Cheng /* flow prop DB */
6718453SAnurag.Maskey@Sun.COM s = dladm_set_flowprop(handle, flowname, NULL, NULL, 0,
6728275SEric Cheng DLADM_OPT_PERSIST, NULL);
6738275SEric Cheng }
6748275SEric Cheng
6758275SEric Cheng done:
6768275SEric Cheng if (!tempop) {
6778275SEric Cheng if (s == DLADM_STATUS_OK) {
6788275SEric Cheng if (status == DLADM_STATUS_NOTFOUND)
6798275SEric Cheng status = s;
6808275SEric Cheng } else {
6818275SEric Cheng if (s != DLADM_STATUS_NOTFOUND)
6828275SEric Cheng status = s;
6838275SEric Cheng }
6848275SEric Cheng }
6858275SEric Cheng return (status);
6868275SEric Cheng }
6878275SEric Cheng
6888275SEric Cheng /*
6898275SEric Cheng * Get an existing flow in the DB.
6908275SEric Cheng */
6918275SEric Cheng
6928275SEric Cheng typedef struct get_db_state {
6939421SMichael.Lim@Sun.COM int (*gs_fn)(dladm_handle_t, dladm_flow_attr_t *, void *);
6948275SEric Cheng void *gs_arg;
6958275SEric Cheng datalink_id_t gs_linkid;
6968275SEric Cheng } get_db_state_t;
6978275SEric Cheng
6988275SEric Cheng /*
6998275SEric Cheng * For each flow which matches the linkid, copy all flow information
7008275SEric Cheng * to a new dladm_flow_attr_t structure and call the provided
7018275SEric Cheng * function. This is used to display perisistent flows from
7028275SEric Cheng * the database.
7038275SEric Cheng */
7048275SEric Cheng
7058275SEric Cheng static int
i_dladm_flow_get_db_fn(void * arg,dld_flowinfo_t * grp)7068275SEric Cheng i_dladm_flow_get_db_fn(void *arg, dld_flowinfo_t *grp)
7078275SEric Cheng {
7088275SEric Cheng get_db_state_t *state = (get_db_state_t *)arg;
7098275SEric Cheng dladm_flow_attr_t attr;
7109421SMichael.Lim@Sun.COM dladm_handle_t handle = NULL;
7118275SEric Cheng
7128275SEric Cheng if (grp->fi_linkid == state->gs_linkid) {
7138275SEric Cheng attr.fa_linkid = state->gs_linkid;
7148275SEric Cheng bcopy(grp->fi_flowname, &attr.fa_flowname,
7158275SEric Cheng sizeof (attr.fa_flowname));
7168275SEric Cheng bcopy(&grp->fi_flow_desc, &attr.fa_flow_desc,
7178275SEric Cheng sizeof (attr.fa_flow_desc));
7188275SEric Cheng bcopy(&grp->fi_resource_props, &attr.fa_resource_props,
7198275SEric Cheng sizeof (attr.fa_resource_props));
7209421SMichael.Lim@Sun.COM (void) state->gs_fn(handle, &attr, state->gs_arg);
7218275SEric Cheng }
7228275SEric Cheng return (0);
7238275SEric Cheng }
7248275SEric Cheng
7258275SEric Cheng /*
7268275SEric Cheng * Walk through the flows defined on the system and for each flow
7278275SEric Cheng * invoke <fn>(<arg>, <flow>);
7288275SEric Cheng * Currently used for show-flow.
7298275SEric Cheng */
7308275SEric Cheng /* ARGSUSED */
7318275SEric Cheng dladm_status_t
dladm_walk_flow(int (* fn)(dladm_handle_t,dladm_flow_attr_t *,void *),dladm_handle_t handle,datalink_id_t linkid,void * arg,boolean_t persist)7329421SMichael.Lim@Sun.COM dladm_walk_flow(int (*fn)(dladm_handle_t, dladm_flow_attr_t *, void *),
7339421SMichael.Lim@Sun.COM dladm_handle_t handle, datalink_id_t linkid, void *arg, boolean_t persist)
7348275SEric Cheng {
7358275SEric Cheng dld_flowinfo_t *flow;
7368453SAnurag.Maskey@Sun.COM int i, bufsize;
7378275SEric Cheng dld_ioc_walkflow_t *ioc = NULL;
7388275SEric Cheng dladm_flow_attr_t attr;
7398275SEric Cheng dladm_status_t status = DLADM_STATUS_OK;
7408275SEric Cheng
7418275SEric Cheng if (fn == NULL)
7428275SEric Cheng return (DLADM_STATUS_BADARG);
7438275SEric Cheng
7448275SEric Cheng if (persist) {
7458275SEric Cheng get_db_state_t state;
7468275SEric Cheng
7478275SEric Cheng bzero(&state, sizeof (state));
7488275SEric Cheng
7498275SEric Cheng state.gs_linkid = linkid;
7508275SEric Cheng state.gs_fn = fn;
7518275SEric Cheng state.gs_arg = arg;
7528275SEric Cheng status = i_dladm_flow_walk_rw_db(i_dladm_flow_get_db_fn,
7538275SEric Cheng &state, NULL);
7548275SEric Cheng if (status != DLADM_STATUS_OK)
7558275SEric Cheng return (status);
7568275SEric Cheng } else {
7578275SEric Cheng bufsize = MIN_INFO_SIZE;
7588275SEric Cheng if ((ioc = calloc(1, bufsize)) == NULL) {
7598275SEric Cheng status = dladm_errno2status(errno);
7608275SEric Cheng return (status);
7618275SEric Cheng }
7628275SEric Cheng
7638275SEric Cheng ioc->wf_linkid = linkid;
7648275SEric Cheng ioc->wf_len = bufsize - sizeof (*ioc);
7658275SEric Cheng
7668453SAnurag.Maskey@Sun.COM while (ioctl(dladm_dld_fd(handle), DLDIOC_WALKFLOW, ioc) < 0) {
7678275SEric Cheng if (errno == ENOSPC) {
7688275SEric Cheng bufsize *= 2;
7698275SEric Cheng ioc = realloc(ioc, bufsize);
7708275SEric Cheng if (ioc != NULL) {
7718275SEric Cheng ioc->wf_linkid = linkid;
7728275SEric Cheng ioc->wf_len = bufsize - sizeof (*ioc);
7738275SEric Cheng continue;
7748275SEric Cheng }
7758275SEric Cheng }
7768275SEric Cheng goto bail;
7778275SEric Cheng }
7788275SEric Cheng
7798275SEric Cheng flow = (dld_flowinfo_t *)(void *)(ioc + 1);
7808275SEric Cheng for (i = 0; i < ioc->wf_nflows; i++, flow++) {
7818275SEric Cheng bzero(&attr, sizeof (attr));
7828275SEric Cheng
7838275SEric Cheng attr.fa_linkid = flow->fi_linkid;
7848275SEric Cheng bcopy(&flow->fi_flowname, &attr.fa_flowname,
7858275SEric Cheng sizeof (attr.fa_flowname));
7868275SEric Cheng bcopy(&flow->fi_flow_desc, &attr.fa_flow_desc,
7878275SEric Cheng sizeof (attr.fa_flow_desc));
7888275SEric Cheng bcopy(&flow->fi_resource_props, &attr.fa_resource_props,
7898275SEric Cheng sizeof (attr.fa_resource_props));
7908275SEric Cheng
7919421SMichael.Lim@Sun.COM if (fn(handle, &attr, arg) == DLADM_WALK_TERMINATE)
7928275SEric Cheng break;
7938275SEric Cheng }
7948275SEric Cheng }
7958275SEric Cheng
7968275SEric Cheng bail:
7978275SEric Cheng free(ioc);
7988275SEric Cheng return (status);
7998275SEric Cheng }
8008275SEric Cheng
8018275SEric Cheng dladm_status_t
dladm_flow_init(dladm_handle_t handle)8028453SAnurag.Maskey@Sun.COM dladm_flow_init(dladm_handle_t handle)
8038275SEric Cheng {
8048275SEric Cheng flow_desc_t flowdesc;
8058275SEric Cheng datalink_id_t linkid;
8068275SEric Cheng dladm_status_t s, status = DLADM_STATUS_OK;
8078558SGirish.Moodalbail@Sun.COM char name[MAXFLOWNAMELEN];
8088275SEric Cheng char line[MAXLINELEN];
8098275SEric Cheng dld_flowinfo_t attr;
8108275SEric Cheng FILE *fp;
8118275SEric Cheng
8128275SEric Cheng if ((fp = fopen(DLADM_FLOW_DB, "r")) == NULL)
8138275SEric Cheng return (DLADM_STATUS_DB_NOTFOUND);
8148275SEric Cheng
8158275SEric Cheng while (fgets(line, MAXLINELEN, fp) != NULL) {
8168275SEric Cheng /* skip comments */
8178275SEric Cheng if (BLANK_LINE(line))
8188275SEric Cheng continue;
8198275SEric Cheng
8208275SEric Cheng (void) strtok(line, " \n");
8218275SEric Cheng
8228275SEric Cheng s = dladm_flow_parse_db(line, &attr);
8238275SEric Cheng if (s != DLADM_STATUS_OK) {
8248275SEric Cheng status = s;
8258275SEric Cheng continue;
8268275SEric Cheng }
8278275SEric Cheng bzero(&flowdesc, sizeof (flowdesc));
8288275SEric Cheng bcopy(&attr.fi_flow_desc, &flowdesc, sizeof (flow_desc_t));
8298275SEric Cheng (void) strlcpy(name, attr.fi_flowname,
8308275SEric Cheng sizeof (attr.fi_flowname));
8318275SEric Cheng linkid = attr.fi_linkid;
8328275SEric Cheng
8338453SAnurag.Maskey@Sun.COM s = i_dladm_flow_add(handle, name, linkid, &flowdesc, NULL);
8348275SEric Cheng if (s != DLADM_STATUS_OK)
8358275SEric Cheng status = s;
8368275SEric Cheng }
8378453SAnurag.Maskey@Sun.COM s = i_dladm_init_flowprop_db(handle);
8388275SEric Cheng if (s != DLADM_STATUS_OK)
8398275SEric Cheng status = s;
8408275SEric Cheng
8418275SEric Cheng (void) fclose(fp);
8428275SEric Cheng return (status);
8438275SEric Cheng }
8448275SEric Cheng
8458275SEric Cheng dladm_status_t
dladm_prefixlen2mask(int prefixlen,int maxlen,uchar_t * mask)8468275SEric Cheng dladm_prefixlen2mask(int prefixlen, int maxlen, uchar_t *mask)
8478275SEric Cheng {
8488275SEric Cheng if (prefixlen < 0 || prefixlen > maxlen)
8498275SEric Cheng return (DLADM_STATUS_BADARG);
8508275SEric Cheng
8518275SEric Cheng while (prefixlen > 0) {
8528275SEric Cheng if (prefixlen >= 8) {
8538275SEric Cheng *mask++ = 0xFF;
8548275SEric Cheng prefixlen -= 8;
8558275SEric Cheng continue;
8568275SEric Cheng }
8578275SEric Cheng *mask |= 1 << (8 - prefixlen);
8588275SEric Cheng prefixlen--;
8598275SEric Cheng }
8608275SEric Cheng return (DLADM_STATUS_OK);
8618275SEric Cheng }
8628275SEric Cheng
8638275SEric Cheng dladm_status_t
dladm_mask2prefixlen(in6_addr_t * mask,int plen,int * prefixlen)8648275SEric Cheng dladm_mask2prefixlen(in6_addr_t *mask, int plen, int *prefixlen)
8658275SEric Cheng {
8668275SEric Cheng int bits;
8678275SEric Cheng int i, end;
8688275SEric Cheng
8698275SEric Cheng switch (plen) {
8708275SEric Cheng case IP_ABITS:
8718275SEric Cheng end = 3;
8728275SEric Cheng break;
8738275SEric Cheng case IPV6_ABITS:
8748275SEric Cheng end = 0;
8758275SEric Cheng break;
8768275SEric Cheng default:
8778275SEric Cheng return (DLADM_STATUS_BADARG);
8788275SEric Cheng }
8798275SEric Cheng
8808275SEric Cheng for (i = 3; i >= end; i--) {
8818275SEric Cheng if (mask->_S6_un._S6_u32[i] == 0) {
8828275SEric Cheng plen -= 32;
8838275SEric Cheng continue;
8848275SEric Cheng }
8858275SEric Cheng bits = ffs(ntohl(mask->_S6_un._S6_u32[i])) - 1;
8868275SEric Cheng if (bits == 0)
8878275SEric Cheng break;
8888275SEric Cheng plen -= bits;
8898275SEric Cheng }
8908275SEric Cheng *prefixlen = plen;
8918275SEric Cheng return (DLADM_STATUS_OK);
8928275SEric Cheng }
893