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