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