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