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