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