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