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 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 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 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 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 306da14cebeSEric Cheng if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL) 307da14cebeSEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%d\t", LOCAL_PORT, 308da14cebeSEric Cheng ntohs(attr->fi_flow_desc.fd_local_port))); 309da14cebeSEric Cheng 31025ec3e3dSEric Cheng if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE) 31125ec3e3dSEric Cheng FPRINTF_ERR(fprintf(fp, "%s=%d\t", REMOTE_PORT, 31225ec3e3dSEric Cheng ntohs(attr->fi_flow_desc.fd_remote_port))); 31325ec3e3dSEric Cheng 314da14cebeSEric Cheng FPRINTF_ERR(fprintf(fp, "\n")); 315da14cebeSEric Cheng 316da14cebeSEric Cheng return (0); 317da14cebeSEric Cheng 318da14cebeSEric Cheng } 319da14cebeSEric Cheng 320da14cebeSEric Cheng static dladm_status_t 321da14cebeSEric Cheng i_dladm_flow_walk_rw_db(int (*fn)(void *, dld_flowinfo_t *), 322da14cebeSEric Cheng void *arg, 323da14cebeSEric Cheng const char *root) 324da14cebeSEric Cheng { 325da14cebeSEric Cheng FILE *fp, *nfp; 326da14cebeSEric Cheng int nfd, fn_rc, lock_fd; 327da14cebeSEric Cheng char line[MAXLINELEN]; 328da14cebeSEric Cheng dld_flowinfo_t attr; 329da14cebeSEric Cheng char *db_file, *tmp_db_file; 330da14cebeSEric Cheng char db_file_buf[MAXPATHLEN]; 331da14cebeSEric Cheng char tmp_db_file_buf[MAXPATHLEN]; 332da14cebeSEric Cheng dladm_status_t status = DLADM_STATUS_FLOW_DB_ERR; 333da14cebeSEric Cheng 334da14cebeSEric Cheng if (root == NULL) { 335da14cebeSEric Cheng db_file = DLADM_FLOW_DB; 336da14cebeSEric Cheng tmp_db_file = DLADM_FLOW_DB_TMP; 337da14cebeSEric Cheng } else { 338da14cebeSEric Cheng (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, 339da14cebeSEric Cheng DLADM_FLOW_DB); 340da14cebeSEric Cheng (void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root, 341da14cebeSEric Cheng DLADM_FLOW_DB_TMP); 342da14cebeSEric Cheng db_file = db_file_buf; 343da14cebeSEric Cheng tmp_db_file = tmp_db_file_buf; 344da14cebeSEric Cheng } 345da14cebeSEric Cheng 346da14cebeSEric Cheng if ((lock_fd = i_dladm_flow_lock_db(F_WRLCK)) < 0) 347da14cebeSEric Cheng return (DLADM_STATUS_FLOW_DB_ERR); 348da14cebeSEric Cheng 349da14cebeSEric Cheng if ((fp = fopen(db_file, "r")) == NULL) { 350da14cebeSEric Cheng i_dladm_flow_unlock_db(lock_fd); 351da14cebeSEric Cheng return (DLADM_STATUS_FLOW_DB_OPEN_ERR); 352da14cebeSEric Cheng } 353da14cebeSEric Cheng 354da14cebeSEric Cheng if ((nfd = open(tmp_db_file, O_WRONLY|O_CREAT|O_TRUNC, 355da14cebeSEric Cheng DLADM_FLOW_DB_PERMS)) == -1) { 356da14cebeSEric Cheng (void) fclose(fp); 357da14cebeSEric Cheng i_dladm_flow_unlock_db(lock_fd); 358da14cebeSEric Cheng return (DLADM_STATUS_FLOW_DB_OPEN_ERR); 359da14cebeSEric Cheng } 360da14cebeSEric Cheng 361da14cebeSEric Cheng if ((nfp = fdopen(nfd, "w")) == NULL) { 362da14cebeSEric Cheng (void) close(nfd); 363da14cebeSEric Cheng (void) fclose(fp); 364da14cebeSEric Cheng (void) unlink(tmp_db_file); 365da14cebeSEric Cheng i_dladm_flow_unlock_db(lock_fd); 366da14cebeSEric Cheng return (DLADM_STATUS_FLOW_DB_OPEN_ERR); 367da14cebeSEric Cheng } 368da14cebeSEric Cheng 369da14cebeSEric Cheng while (fgets(line, MAXLINELEN, fp) != NULL) { 370da14cebeSEric Cheng 371da14cebeSEric Cheng /* skip comments */ 372da14cebeSEric Cheng if (BLANK_LINE(line)) { 373da14cebeSEric Cheng if (fputs(line, nfp) == EOF) 374da14cebeSEric Cheng goto failed; 375da14cebeSEric Cheng continue; 376da14cebeSEric Cheng } 377da14cebeSEric Cheng (void) strtok(line, " \n"); 378da14cebeSEric Cheng 379da14cebeSEric Cheng if ((status = dladm_flow_parse_db(line, &attr)) != 380da14cebeSEric Cheng DLADM_STATUS_OK) 381da14cebeSEric Cheng goto failed; 382da14cebeSEric Cheng 383da14cebeSEric Cheng fn_rc = fn(arg, &attr); 384da14cebeSEric Cheng 385da14cebeSEric Cheng switch (fn_rc) { 386da14cebeSEric Cheng case -1: 387da14cebeSEric Cheng /* failure, stop walking */ 388da14cebeSEric Cheng goto failed; 389da14cebeSEric Cheng case 0: 390da14cebeSEric Cheng /* 391da14cebeSEric Cheng * Success, write group attributes, which could 392da14cebeSEric Cheng * have been modified by fn(). 393da14cebeSEric Cheng */ 394da14cebeSEric Cheng if (i_dladm_flow_fput_grp(nfp, &attr) != 0) 395da14cebeSEric Cheng goto failed; 396da14cebeSEric Cheng break; 397da14cebeSEric Cheng case 1: 398da14cebeSEric Cheng /* skip current group */ 399da14cebeSEric Cheng break; 400da14cebeSEric Cheng } 401da14cebeSEric Cheng } 402da14cebeSEric Cheng if (fchmod(nfd, DLADM_FLOW_DB_PERMS) == -1) 403da14cebeSEric Cheng goto failed; 404da14cebeSEric Cheng 405da14cebeSEric Cheng if (fchown(nfd, DLADM_FLOW_DB_OWNER, DLADM_FLOW_DB_GROUP) == -1) 406da14cebeSEric Cheng goto failed; 407da14cebeSEric Cheng 408da14cebeSEric Cheng if (fflush(nfp) == EOF) 409da14cebeSEric Cheng goto failed; 410da14cebeSEric Cheng 411da14cebeSEric Cheng (void) fclose(fp); 412da14cebeSEric Cheng (void) fclose(nfp); 413da14cebeSEric Cheng 414da14cebeSEric Cheng if (rename(tmp_db_file, db_file) == -1) { 415da14cebeSEric Cheng (void) unlink(tmp_db_file); 416da14cebeSEric Cheng i_dladm_flow_unlock_db(lock_fd); 417da14cebeSEric Cheng return (DLADM_STATUS_FLOW_DB_ERR); 418da14cebeSEric Cheng } 419da14cebeSEric Cheng i_dladm_flow_unlock_db(lock_fd); 420da14cebeSEric Cheng return (DLADM_STATUS_OK); 421da14cebeSEric Cheng 422da14cebeSEric Cheng failed: 423da14cebeSEric Cheng (void) fclose(fp); 424da14cebeSEric Cheng (void) fclose(nfp); 425da14cebeSEric Cheng (void) unlink(tmp_db_file); 426da14cebeSEric Cheng i_dladm_flow_unlock_db(lock_fd); 427da14cebeSEric Cheng 428da14cebeSEric Cheng return (status); 429da14cebeSEric Cheng } 430da14cebeSEric Cheng 431da14cebeSEric Cheng /* 432da14cebeSEric Cheng * Remove existing flow from DB. 433da14cebeSEric Cheng */ 434da14cebeSEric Cheng 435da14cebeSEric Cheng typedef struct remove_db_state { 436da14cebeSEric Cheng dld_flowinfo_t rs_newattr; 437da14cebeSEric Cheng dld_flowinfo_t rs_oldattr; 438da14cebeSEric Cheng boolean_t rs_found; 439da14cebeSEric Cheng } remove_db_state_t; 440da14cebeSEric Cheng 441da14cebeSEric Cheng static int 442da14cebeSEric Cheng i_dladm_flow_remove_db_fn(void *arg, dld_flowinfo_t *grp) 443da14cebeSEric Cheng { 444da14cebeSEric Cheng remove_db_state_t *state = (remove_db_state_t *)arg; 445da14cebeSEric Cheng dld_flowinfo_t *attr = &state->rs_newattr; 446da14cebeSEric Cheng 447da14cebeSEric Cheng if ((strcmp(grp->fi_flowname, attr->fi_flowname)) != 0) 448da14cebeSEric Cheng return (0); 449da14cebeSEric Cheng else { 450da14cebeSEric Cheng bcopy(grp, &state->rs_oldattr, 451da14cebeSEric Cheng sizeof (dld_flowinfo_t)); 452da14cebeSEric Cheng state->rs_found = B_TRUE; 453da14cebeSEric Cheng return (1); 454da14cebeSEric Cheng } 455da14cebeSEric Cheng } 456da14cebeSEric Cheng 457da14cebeSEric Cheng /* ARGSUSED */ 458da14cebeSEric Cheng static int 459da14cebeSEric Cheng i_dladm_flow_remove_db(remove_db_state_t *state, const char *root) 460da14cebeSEric Cheng { 461da14cebeSEric Cheng if (i_dladm_flow_walk_rw_db(i_dladm_flow_remove_db_fn, state, root) 462da14cebeSEric Cheng != 0) 463da14cebeSEric Cheng return (-1); 464da14cebeSEric Cheng 465da14cebeSEric Cheng if (!state->rs_found) { 466da14cebeSEric Cheng errno = ENOENT; 467da14cebeSEric Cheng return (-1); 468da14cebeSEric Cheng } 469da14cebeSEric Cheng 470da14cebeSEric Cheng return (0); 471da14cebeSEric Cheng } 472da14cebeSEric Cheng 473da14cebeSEric Cheng /* 474da14cebeSEric Cheng * Create a flow in the DB. 475da14cebeSEric Cheng */ 476da14cebeSEric Cheng 477da14cebeSEric Cheng typedef struct modify_db_state { 478da14cebeSEric Cheng dld_flowinfo_t ms_newattr; 479da14cebeSEric Cheng dld_flowinfo_t ms_oldattr; 480da14cebeSEric Cheng boolean_t ms_found; 481da14cebeSEric Cheng } modify_db_state_t; 482da14cebeSEric Cheng 483da14cebeSEric Cheng static dladm_status_t 484da14cebeSEric Cheng i_dladm_flow_create_db(dld_flowinfo_t *attr, const char *root) 485da14cebeSEric Cheng { 486da14cebeSEric Cheng FILE *fp; 487da14cebeSEric Cheng char line[MAXLINELEN]; 488da14cebeSEric Cheng char *db_file; 489da14cebeSEric Cheng char db_file_buf[MAXPATHLEN]; 490da14cebeSEric Cheng int lock_fd; 491da14cebeSEric Cheng dladm_status_t status = DLADM_STATUS_OK; 492da14cebeSEric Cheng 493da14cebeSEric Cheng if (root == NULL) { 494da14cebeSEric Cheng db_file = DLADM_FLOW_DB; 495da14cebeSEric Cheng } else { 496da14cebeSEric Cheng (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, 497da14cebeSEric Cheng DLADM_FLOW_DB); 498da14cebeSEric Cheng db_file = db_file_buf; 499da14cebeSEric Cheng } 500da14cebeSEric Cheng 501da14cebeSEric Cheng if ((lock_fd = i_dladm_flow_lock_db(F_WRLCK)) < 0) 502da14cebeSEric Cheng return (DLADM_STATUS_FLOW_DB_ERR); 503da14cebeSEric Cheng 504da14cebeSEric Cheng if ((fp = fopen(db_file, "r+")) == NULL && 505da14cebeSEric Cheng (fp = fopen(db_file, "w")) == NULL) { 506da14cebeSEric Cheng i_dladm_flow_unlock_db(lock_fd); 507da14cebeSEric Cheng return (DLADM_STATUS_FLOW_DB_OPEN_ERR); 508da14cebeSEric Cheng } 509da14cebeSEric Cheng 510da14cebeSEric Cheng /* look for existing group with same flowname */ 511da14cebeSEric Cheng while (fgets(line, MAXLINELEN, fp) != NULL) { 512da14cebeSEric Cheng char *holder, *lasts; 513da14cebeSEric Cheng 514da14cebeSEric Cheng /* skip comments */ 515da14cebeSEric Cheng if (BLANK_LINE(line)) 516da14cebeSEric Cheng continue; 517da14cebeSEric Cheng 518da14cebeSEric Cheng /* ignore corrupted lines */ 519da14cebeSEric Cheng holder = strtok_r(line, " \t", &lasts); 520da14cebeSEric Cheng if (holder == NULL) 521da14cebeSEric Cheng continue; 522da14cebeSEric Cheng 523da14cebeSEric Cheng /* flow id */ 524da14cebeSEric Cheng if (strcmp(holder, attr->fi_flowname) == 0) { 525da14cebeSEric Cheng /* group with flow id already exists */ 526da14cebeSEric Cheng status = DLADM_STATUS_PERSIST_FLOW_EXISTS; 527da14cebeSEric Cheng goto failed; 528da14cebeSEric Cheng } 529da14cebeSEric Cheng } 530da14cebeSEric Cheng /* 531da14cebeSEric Cheng * If we get here, we've verified that no existing group with 532da14cebeSEric Cheng * the same flow id already exists. Its now time to add the new 533da14cebeSEric Cheng * group to the DB. 534da14cebeSEric Cheng */ 535da14cebeSEric Cheng if (i_dladm_flow_fput_grp(fp, attr) != 0) 536da14cebeSEric Cheng status = DLADM_STATUS_FLOW_DB_PARSE_ERR; 537da14cebeSEric Cheng 538da14cebeSEric Cheng failed: 539da14cebeSEric Cheng (void) fclose(fp); 540da14cebeSEric Cheng i_dladm_flow_unlock_db(lock_fd); 541da14cebeSEric Cheng return (status); 542da14cebeSEric Cheng } 543da14cebeSEric Cheng 544da14cebeSEric Cheng static dladm_status_t 5454ac67f02SAnurag S. Maskey i_dladm_flow_add(dladm_handle_t handle, char *flowname, datalink_id_t linkid, 5464ac67f02SAnurag S. Maskey flow_desc_t *flowdesc, mac_resource_props_t *mrp) 547da14cebeSEric Cheng { 548da14cebeSEric Cheng dld_ioc_addflow_t attr; 549da14cebeSEric Cheng 550da14cebeSEric Cheng /* create flow */ 551da14cebeSEric Cheng bzero(&attr, sizeof (attr)); 552da14cebeSEric Cheng bcopy(flowdesc, &attr.af_flow_desc, sizeof (flow_desc_t)); 553da14cebeSEric Cheng if (mrp != NULL) { 554da14cebeSEric Cheng bcopy(mrp, &attr.af_resource_props, 555da14cebeSEric Cheng sizeof (mac_resource_props_t)); 556da14cebeSEric Cheng } 557da14cebeSEric Cheng 558da14cebeSEric Cheng (void) strlcpy(attr.af_name, flowname, sizeof (attr.af_name)); 559da14cebeSEric Cheng attr.af_linkid = linkid; 560da14cebeSEric Cheng 5614ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_ADDFLOW, &attr) < 0) 562da14cebeSEric Cheng return (dladm_errno2status(errno)); 563da14cebeSEric Cheng 564da14cebeSEric Cheng return (DLADM_STATUS_OK); 565da14cebeSEric Cheng } 566da14cebeSEric Cheng 567da14cebeSEric Cheng static dladm_status_t 5684ac67f02SAnurag S. Maskey i_dladm_flow_remove(dladm_handle_t handle, char *flowname) 569da14cebeSEric Cheng { 570da14cebeSEric Cheng dld_ioc_removeflow_t attr; 571da14cebeSEric Cheng dladm_status_t status = DLADM_STATUS_OK; 572da14cebeSEric Cheng 573da14cebeSEric Cheng (void) strlcpy(attr.rf_name, flowname, 574da14cebeSEric Cheng sizeof (attr.rf_name)); 575da14cebeSEric Cheng 5764ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(handle), DLDIOC_REMOVEFLOW, &attr) < 0) 577da14cebeSEric Cheng status = dladm_errno2status(errno); 578da14cebeSEric Cheng 579da14cebeSEric Cheng return (status); 580da14cebeSEric Cheng } 581da14cebeSEric Cheng 582da14cebeSEric Cheng 583da14cebeSEric Cheng /* ARGSUSED */ 584da14cebeSEric Cheng dladm_status_t 5854ac67f02SAnurag S. Maskey dladm_flow_add(dladm_handle_t handle, datalink_id_t linkid, 5864ac67f02SAnurag S. Maskey dladm_arg_list_t *attrlist, dladm_arg_list_t *proplist, char *flowname, 5874ac67f02SAnurag S. Maskey boolean_t tempop, const char *root) 588da14cebeSEric Cheng { 589da14cebeSEric Cheng dld_flowinfo_t db_attr; 590da14cebeSEric Cheng flow_desc_t flowdesc; 591da14cebeSEric Cheng mac_resource_props_t mrp; 592da14cebeSEric Cheng dladm_status_t status; 593da14cebeSEric Cheng 594da14cebeSEric Cheng /* Extract flow attributes from attrlist */ 595da14cebeSEric Cheng bzero(&flowdesc, sizeof (flow_desc_t)); 596da14cebeSEric Cheng if (attrlist != NULL && (status = dladm_flow_attrlist_extract(attrlist, 597da14cebeSEric Cheng &flowdesc)) != DLADM_STATUS_OK) { 598da14cebeSEric Cheng return (status); 599da14cebeSEric Cheng } 600da14cebeSEric Cheng 601da14cebeSEric Cheng /* Extract resource_ctl and cpu_list from proplist */ 602da14cebeSEric Cheng bzero(&mrp, sizeof (mac_resource_props_t)); 603da14cebeSEric Cheng if (proplist != NULL && (status = dladm_flow_proplist_extract(proplist, 604da14cebeSEric Cheng &mrp)) != DLADM_STATUS_OK) { 605da14cebeSEric Cheng return (status); 606da14cebeSEric Cheng } 607da14cebeSEric Cheng 608da14cebeSEric Cheng /* Add flow in kernel */ 6094ac67f02SAnurag S. Maskey status = i_dladm_flow_add(handle, flowname, linkid, &flowdesc, &mrp); 610da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 611da14cebeSEric Cheng return (status); 612da14cebeSEric Cheng 613da14cebeSEric Cheng /* Add flow to DB */ 614da14cebeSEric Cheng if (!tempop) { 615da14cebeSEric Cheng bzero(&db_attr, sizeof (db_attr)); 616da14cebeSEric Cheng bcopy(&flowdesc, &db_attr.fi_flow_desc, sizeof (flow_desc_t)); 617da14cebeSEric Cheng (void) strlcpy(db_attr.fi_flowname, flowname, 618da14cebeSEric Cheng sizeof (db_attr.fi_flowname)); 619da14cebeSEric Cheng db_attr.fi_linkid = linkid; 620da14cebeSEric Cheng 621da14cebeSEric Cheng if ((status = i_dladm_flow_create_db(&db_attr, root)) != 622da14cebeSEric Cheng DLADM_STATUS_OK) { 6234ac67f02SAnurag S. Maskey (void) i_dladm_flow_remove(handle, flowname); 624da14cebeSEric Cheng return (status); 625da14cebeSEric Cheng } 626da14cebeSEric Cheng /* set flow properties */ 627da14cebeSEric Cheng if (proplist != NULL) { 6284ac67f02SAnurag S. Maskey status = i_dladm_set_flow_proplist_db(handle, flowname, 629da14cebeSEric Cheng proplist); 630da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 6314ac67f02SAnurag S. Maskey (void) i_dladm_flow_remove(handle, flowname); 632da14cebeSEric Cheng return (status); 633da14cebeSEric Cheng } 634da14cebeSEric Cheng } 635da14cebeSEric Cheng } 636da14cebeSEric Cheng return (status); 637da14cebeSEric Cheng } 638da14cebeSEric Cheng 639da14cebeSEric Cheng /* 640da14cebeSEric Cheng * Remove a flow. 641da14cebeSEric Cheng */ 642da14cebeSEric Cheng /* ARGSUSED */ 643da14cebeSEric Cheng dladm_status_t 6444ac67f02SAnurag S. Maskey dladm_flow_remove(dladm_handle_t handle, char *flowname, boolean_t tempop, 645da14cebeSEric Cheng const char *root) 646da14cebeSEric Cheng { 647da14cebeSEric Cheng remove_db_state_t state; 648da14cebeSEric Cheng dladm_status_t status = DLADM_STATUS_OK; 649da14cebeSEric Cheng dladm_status_t s = DLADM_STATUS_OK; 650da14cebeSEric Cheng 651da14cebeSEric Cheng /* remove flow */ 6524ac67f02SAnurag S. Maskey status = i_dladm_flow_remove(handle, flowname); 653da14cebeSEric Cheng if ((status != DLADM_STATUS_OK) && 654da14cebeSEric Cheng (tempop || status != DLADM_STATUS_NOTFOUND)) 655da14cebeSEric Cheng goto done; 656da14cebeSEric Cheng 657da14cebeSEric Cheng /* remove flow from DB */ 658da14cebeSEric Cheng if (!tempop) { 659da14cebeSEric Cheng bzero(&state, sizeof (state)); 660da14cebeSEric Cheng (void) strlcpy(state.rs_newattr.fi_flowname, flowname, 661da14cebeSEric Cheng sizeof (state.rs_newattr.fi_flowname)); 662da14cebeSEric Cheng state.rs_found = B_FALSE; 663da14cebeSEric Cheng 664da14cebeSEric Cheng /* flow DB */ 665da14cebeSEric Cheng if (i_dladm_flow_remove_db(&state, root) < 0) { 666da14cebeSEric Cheng s = dladm_errno2status(errno); 667da14cebeSEric Cheng goto done; 668da14cebeSEric Cheng } 669da14cebeSEric Cheng 670da14cebeSEric Cheng /* flow prop DB */ 6714ac67f02SAnurag S. Maskey s = dladm_set_flowprop(handle, flowname, NULL, NULL, 0, 672da14cebeSEric Cheng DLADM_OPT_PERSIST, NULL); 673da14cebeSEric Cheng } 674da14cebeSEric Cheng 675da14cebeSEric Cheng done: 676da14cebeSEric Cheng if (!tempop) { 677da14cebeSEric Cheng if (s == DLADM_STATUS_OK) { 678da14cebeSEric Cheng if (status == DLADM_STATUS_NOTFOUND) 679da14cebeSEric Cheng status = s; 680da14cebeSEric Cheng } else { 681da14cebeSEric Cheng if (s != DLADM_STATUS_NOTFOUND) 682da14cebeSEric Cheng status = s; 683da14cebeSEric Cheng } 684da14cebeSEric Cheng } 685da14cebeSEric Cheng return (status); 686da14cebeSEric Cheng } 687da14cebeSEric Cheng 688da14cebeSEric Cheng /* 689da14cebeSEric Cheng * Get an existing flow in the DB. 690da14cebeSEric Cheng */ 691da14cebeSEric Cheng 692da14cebeSEric Cheng typedef struct get_db_state { 693c3affd82SMichael Lim int (*gs_fn)(dladm_handle_t, dladm_flow_attr_t *, void *); 694da14cebeSEric Cheng void *gs_arg; 695da14cebeSEric Cheng datalink_id_t gs_linkid; 696da14cebeSEric Cheng } get_db_state_t; 697da14cebeSEric Cheng 698da14cebeSEric Cheng /* 699da14cebeSEric Cheng * For each flow which matches the linkid, copy all flow information 700da14cebeSEric Cheng * to a new dladm_flow_attr_t structure and call the provided 701da14cebeSEric Cheng * function. This is used to display perisistent flows from 702da14cebeSEric Cheng * the database. 703da14cebeSEric Cheng */ 704da14cebeSEric Cheng 705da14cebeSEric Cheng static int 706da14cebeSEric Cheng i_dladm_flow_get_db_fn(void *arg, dld_flowinfo_t *grp) 707da14cebeSEric Cheng { 708da14cebeSEric Cheng get_db_state_t *state = (get_db_state_t *)arg; 709da14cebeSEric Cheng dladm_flow_attr_t attr; 710c3affd82SMichael Lim dladm_handle_t handle = NULL; 711da14cebeSEric Cheng 712da14cebeSEric Cheng if (grp->fi_linkid == state->gs_linkid) { 713da14cebeSEric Cheng attr.fa_linkid = state->gs_linkid; 714da14cebeSEric Cheng bcopy(grp->fi_flowname, &attr.fa_flowname, 715da14cebeSEric Cheng sizeof (attr.fa_flowname)); 716da14cebeSEric Cheng bcopy(&grp->fi_flow_desc, &attr.fa_flow_desc, 717da14cebeSEric Cheng sizeof (attr.fa_flow_desc)); 718da14cebeSEric Cheng bcopy(&grp->fi_resource_props, &attr.fa_resource_props, 719da14cebeSEric Cheng sizeof (attr.fa_resource_props)); 720c3affd82SMichael Lim (void) state->gs_fn(handle, &attr, state->gs_arg); 721da14cebeSEric Cheng } 722da14cebeSEric Cheng return (0); 723da14cebeSEric Cheng } 724da14cebeSEric Cheng 725da14cebeSEric Cheng /* 726da14cebeSEric Cheng * Walk through the flows defined on the system and for each flow 727da14cebeSEric Cheng * invoke <fn>(<arg>, <flow>); 728da14cebeSEric Cheng * Currently used for show-flow. 729da14cebeSEric Cheng */ 730da14cebeSEric Cheng /* ARGSUSED */ 731da14cebeSEric Cheng dladm_status_t 732c3affd82SMichael Lim dladm_walk_flow(int (*fn)(dladm_handle_t, dladm_flow_attr_t *, void *), 733c3affd82SMichael Lim dladm_handle_t handle, datalink_id_t linkid, void *arg, boolean_t persist) 734da14cebeSEric Cheng { 735da14cebeSEric Cheng dld_flowinfo_t *flow; 7364ac67f02SAnurag S. Maskey int i, bufsize; 737da14cebeSEric Cheng dld_ioc_walkflow_t *ioc = NULL; 738da14cebeSEric Cheng dladm_flow_attr_t attr; 739da14cebeSEric Cheng dladm_status_t status = DLADM_STATUS_OK; 740da14cebeSEric Cheng 741da14cebeSEric Cheng if (fn == NULL) 742da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 743da14cebeSEric Cheng 744da14cebeSEric Cheng if (persist) { 745da14cebeSEric Cheng get_db_state_t state; 746da14cebeSEric Cheng 747da14cebeSEric Cheng bzero(&state, sizeof (state)); 748da14cebeSEric Cheng 749da14cebeSEric Cheng state.gs_linkid = linkid; 750da14cebeSEric Cheng state.gs_fn = fn; 751da14cebeSEric Cheng state.gs_arg = arg; 752da14cebeSEric Cheng status = i_dladm_flow_walk_rw_db(i_dladm_flow_get_db_fn, 753da14cebeSEric Cheng &state, NULL); 754da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 755da14cebeSEric Cheng return (status); 756da14cebeSEric Cheng } else { 757da14cebeSEric Cheng bufsize = MIN_INFO_SIZE; 758da14cebeSEric Cheng if ((ioc = calloc(1, bufsize)) == NULL) { 759da14cebeSEric Cheng status = dladm_errno2status(errno); 760da14cebeSEric Cheng return (status); 761da14cebeSEric Cheng } 762da14cebeSEric Cheng 763da14cebeSEric Cheng ioc->wf_linkid = linkid; 764da14cebeSEric Cheng ioc->wf_len = bufsize - sizeof (*ioc); 765da14cebeSEric Cheng 7664ac67f02SAnurag S. Maskey while (ioctl(dladm_dld_fd(handle), DLDIOC_WALKFLOW, ioc) < 0) { 767da14cebeSEric Cheng if (errno == ENOSPC) { 768da14cebeSEric Cheng bufsize *= 2; 769da14cebeSEric Cheng ioc = realloc(ioc, bufsize); 770da14cebeSEric Cheng if (ioc != NULL) { 771da14cebeSEric Cheng ioc->wf_linkid = linkid; 772da14cebeSEric Cheng ioc->wf_len = bufsize - sizeof (*ioc); 773da14cebeSEric Cheng continue; 774da14cebeSEric Cheng } 775da14cebeSEric Cheng } 776da14cebeSEric Cheng goto bail; 777da14cebeSEric Cheng } 778da14cebeSEric Cheng 779da14cebeSEric Cheng flow = (dld_flowinfo_t *)(void *)(ioc + 1); 780da14cebeSEric Cheng for (i = 0; i < ioc->wf_nflows; i++, flow++) { 781da14cebeSEric Cheng bzero(&attr, sizeof (attr)); 782da14cebeSEric Cheng 783da14cebeSEric Cheng attr.fa_linkid = flow->fi_linkid; 784da14cebeSEric Cheng bcopy(&flow->fi_flowname, &attr.fa_flowname, 785da14cebeSEric Cheng sizeof (attr.fa_flowname)); 786da14cebeSEric Cheng bcopy(&flow->fi_flow_desc, &attr.fa_flow_desc, 787da14cebeSEric Cheng sizeof (attr.fa_flow_desc)); 788da14cebeSEric Cheng bcopy(&flow->fi_resource_props, &attr.fa_resource_props, 789da14cebeSEric Cheng sizeof (attr.fa_resource_props)); 790da14cebeSEric Cheng 791c3affd82SMichael Lim if (fn(handle, &attr, arg) == DLADM_WALK_TERMINATE) 792da14cebeSEric Cheng break; 793da14cebeSEric Cheng } 794da14cebeSEric Cheng } 795da14cebeSEric Cheng 796da14cebeSEric Cheng bail: 797da14cebeSEric Cheng free(ioc); 798da14cebeSEric Cheng return (status); 799da14cebeSEric Cheng } 800da14cebeSEric Cheng 801da14cebeSEric Cheng dladm_status_t 8024ac67f02SAnurag S. Maskey dladm_flow_init(dladm_handle_t handle) 803da14cebeSEric Cheng { 804da14cebeSEric Cheng flow_desc_t flowdesc; 805da14cebeSEric Cheng datalink_id_t linkid; 806da14cebeSEric Cheng dladm_status_t s, status = DLADM_STATUS_OK; 807da000602SGirish Moodalbail char name[MAXFLOWNAMELEN]; 808da14cebeSEric Cheng char line[MAXLINELEN]; 809da14cebeSEric Cheng dld_flowinfo_t attr; 810da14cebeSEric Cheng FILE *fp; 811da14cebeSEric Cheng 812da14cebeSEric Cheng if ((fp = fopen(DLADM_FLOW_DB, "r")) == NULL) 813da14cebeSEric Cheng return (DLADM_STATUS_DB_NOTFOUND); 814da14cebeSEric Cheng 815da14cebeSEric Cheng while (fgets(line, MAXLINELEN, fp) != NULL) { 816da14cebeSEric Cheng /* skip comments */ 817da14cebeSEric Cheng if (BLANK_LINE(line)) 818da14cebeSEric Cheng continue; 819da14cebeSEric Cheng 820da14cebeSEric Cheng (void) strtok(line, " \n"); 821da14cebeSEric Cheng 822da14cebeSEric Cheng s = dladm_flow_parse_db(line, &attr); 823da14cebeSEric Cheng if (s != DLADM_STATUS_OK) { 824da14cebeSEric Cheng status = s; 825da14cebeSEric Cheng continue; 826da14cebeSEric Cheng } 827da14cebeSEric Cheng bzero(&flowdesc, sizeof (flowdesc)); 828da14cebeSEric Cheng bcopy(&attr.fi_flow_desc, &flowdesc, sizeof (flow_desc_t)); 829da14cebeSEric Cheng (void) strlcpy(name, attr.fi_flowname, 830da14cebeSEric Cheng sizeof (attr.fi_flowname)); 831da14cebeSEric Cheng linkid = attr.fi_linkid; 832da14cebeSEric Cheng 8334ac67f02SAnurag S. Maskey s = i_dladm_flow_add(handle, name, linkid, &flowdesc, NULL); 834da14cebeSEric Cheng if (s != DLADM_STATUS_OK) 835da14cebeSEric Cheng status = s; 836da14cebeSEric Cheng } 8374ac67f02SAnurag S. Maskey s = i_dladm_init_flowprop_db(handle); 838da14cebeSEric Cheng if (s != DLADM_STATUS_OK) 839da14cebeSEric Cheng status = s; 840da14cebeSEric Cheng 841da14cebeSEric Cheng (void) fclose(fp); 842da14cebeSEric Cheng return (status); 843da14cebeSEric Cheng } 844da14cebeSEric Cheng 845da14cebeSEric Cheng dladm_status_t 846da14cebeSEric Cheng dladm_prefixlen2mask(int prefixlen, int maxlen, uchar_t *mask) 847da14cebeSEric Cheng { 848da14cebeSEric Cheng if (prefixlen < 0 || prefixlen > maxlen) 849da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 850da14cebeSEric Cheng 851da14cebeSEric Cheng while (prefixlen > 0) { 852da14cebeSEric Cheng if (prefixlen >= 8) { 853da14cebeSEric Cheng *mask++ = 0xFF; 854da14cebeSEric Cheng prefixlen -= 8; 855da14cebeSEric Cheng continue; 856da14cebeSEric Cheng } 857da14cebeSEric Cheng *mask |= 1 << (8 - prefixlen); 858da14cebeSEric Cheng prefixlen--; 859da14cebeSEric Cheng } 860da14cebeSEric Cheng return (DLADM_STATUS_OK); 861da14cebeSEric Cheng } 862da14cebeSEric Cheng 863da14cebeSEric Cheng dladm_status_t 864da14cebeSEric Cheng dladm_mask2prefixlen(in6_addr_t *mask, int plen, int *prefixlen) 865da14cebeSEric Cheng { 866da14cebeSEric Cheng int bits; 867da14cebeSEric Cheng int i, end; 868da14cebeSEric Cheng 869da14cebeSEric Cheng switch (plen) { 870da14cebeSEric Cheng case IP_ABITS: 871da14cebeSEric Cheng end = 3; 872da14cebeSEric Cheng break; 873da14cebeSEric Cheng case IPV6_ABITS: 874da14cebeSEric Cheng end = 0; 875da14cebeSEric Cheng break; 876da14cebeSEric Cheng default: 877da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 878da14cebeSEric Cheng } 879da14cebeSEric Cheng 880da14cebeSEric Cheng for (i = 3; i >= end; i--) { 881da14cebeSEric Cheng if (mask->_S6_un._S6_u32[i] == 0) { 882da14cebeSEric Cheng plen -= 32; 883da14cebeSEric Cheng continue; 884da14cebeSEric Cheng } 885da14cebeSEric Cheng bits = ffs(ntohl(mask->_S6_un._S6_u32[i])) - 1; 886da14cebeSEric Cheng if (bits == 0) 887da14cebeSEric Cheng break; 888da14cebeSEric Cheng plen -= bits; 889da14cebeSEric Cheng } 890da14cebeSEric Cheng *prefixlen = plen; 891da14cebeSEric Cheng return (DLADM_STATUS_OK); 892da14cebeSEric Cheng } 893