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