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 <locale.h>
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <stropts.h>
33 #include <errno.h>
34 #include <strings.h>
35 #include <getopt.h>
36 #include <unistd.h>
37 #include <priv.h>
38 #include <netdb.h>
39 #include <libintl.h>
40 #include <libdlflow.h>
41 #include <libdllink.h>
42 #include <libdlstat.h>
43 #include <sys/types.h>
216 char *altroot = NULL;
217
218 /*
219 * Handle to libdladm. Opened in main() before the sub-command
220 * specific function is called.
221 */
222 static dladm_handle_t handle = NULL;
223
224 static const char *attr_table[] =
225 {"local_ip", "remote_ip", "transport", "local_port", "remote_port",
226 "dsfield"};
227
228 #define NATTR (sizeof (attr_table)/sizeof (char *))
229
230 static void
231 usage(void)
232 {
233 (void) fprintf(stderr, gettext("usage: flowadm <subcommand>"
234 " <args>...\n"
235 " add-flow [-t] -l <link> -a <attr>=<value>[,...]\n"
236 "\t\t [-p <prop>=<value>,...] <flow>\n"
237 " remove-flow [-t] {-l <link> | <flow>}\n"
238 " show-flow [-p] [-l <link>] "
239 "[<flow>]\n\n"
240 " set-flowprop [-t] -p <prop>=<value>[,...] <flow>\n"
241 " reset-flowprop [-t] [-p <prop>,...] <flow>\n"
242 " show-flowprop [-cP] [-l <link>] [-p <prop>,...] "
243 "[<flow>]\n"));
244
245 /* close dladm handle if it was opened */
246 if (handle != NULL)
247 dladm_close(handle);
248
249 exit(1);
250 }
251
252 int
253 main(int argc, char *argv[])
254 {
255 int i, arglen, cmdlen;
256 cmd_t *cmdp;
257 dladm_status_t status;
258
316 status = dladm_flow_init(handle);
317 if (status != DLADM_STATUS_OK)
318 die_dlerr(status, "flows initialization failed");
319 }
320
321 static void
322 do_add_flow(int argc, char *argv[])
323 {
324 char devname[MAXLINKNAMELEN];
325 char *name = NULL;
326 uint_t index;
327 datalink_id_t linkid;
328
329 char option;
330 boolean_t l_arg = B_FALSE;
331 char propstr[DLADM_STRSIZE];
332 char attrstr[DLADM_STRSIZE];
333 dladm_arg_list_t *proplist = NULL;
334 dladm_arg_list_t *attrlist = NULL;
335 dladm_status_t status;
336
337 bzero(propstr, DLADM_STRSIZE);
338 bzero(attrstr, DLADM_STRSIZE);
339
340 while ((option = getopt_long(argc, argv, "tR:l:a:p:",
341 prop_longopts, NULL)) != -1) {
342 switch (option) {
343 case 't':
344 t_arg = B_TRUE;
345 break;
346 case 'R':
347 altroot = optarg;
348 break;
349 case 'l':
350 if (strlcpy(devname, optarg,
351 MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
352 die("link name too long");
353 }
354 if (dladm_name2info(handle, devname, &linkid, NULL,
355 NULL, NULL) != DLADM_STATUS_OK)
356 die("invalid link '%s'", devname);
357 l_arg = B_TRUE;
358 break;
359 case 'a':
360 (void) strlcat(attrstr, optarg, DLADM_STRSIZE);
361 if (strlcat(attrstr, ",", DLADM_STRSIZE) >=
362 DLADM_STRSIZE)
363 die("attribute list too long '%s'", attrstr);
364 break;
365 case 'p':
366 (void) strlcat(propstr, optarg, DLADM_STRSIZE);
367 if (strlcat(propstr, ",", DLADM_STRSIZE) >=
368 DLADM_STRSIZE)
369 die("property list too long '%s'", propstr);
370 break;
371 default:
372 die_opterr(optopt, option);
373 }
374 }
375 if (!l_arg) {
376 die("link is required");
377 }
378
379 opterr = 0;
380 index = optind;
381
382 if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) {
383 die("flow name is required");
384 } else {
385 /* get flow name; required last argument */
386 if (strlen(argv[index]) >= MAXFLOWNAMELEN)
387 die("flow name too long");
388 name = argv[index];
389 }
390
391 if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE)
392 != DLADM_STATUS_OK)
393 die("invalid flow attribute specified");
394 if (dladm_parse_flow_props(propstr, &proplist, B_FALSE)
395 != DLADM_STATUS_OK)
396 die("invalid flow property specified");
397
398 status = dladm_flow_add(handle, linkid, attrlist, proplist, name,
399 t_arg, altroot);
400 if (status != DLADM_STATUS_OK)
401 die_dlerr(status, "add flow failed");
402
403 dladm_free_attrs(attrlist);
404 dladm_free_props(proplist);
405 }
406
407 static void
408 do_remove_flow(int argc, char *argv[])
409 {
410 char option;
411 char *flowname = NULL;
412 char linkname[MAXLINKNAMELEN];
413 datalink_id_t linkid = DATALINK_ALL_LINKID;
414 boolean_t l_arg = B_FALSE;
415 remove_flow_state_t state;
416 dladm_status_t status;
417
418 bzero(&state, sizeof (state));
419
420 opterr = 0;
421 while ((option = getopt_long(argc, argv, ":tR:l:",
422 longopts, NULL)) != -1) {
423 switch (option) {
424 case 't':
425 t_arg = B_TRUE;
426 break;
427 case 'R':
428 altroot = optarg;
429 break;
430 case 'l':
431 if (strlcpy(linkname, optarg,
432 MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
433 die("link name too long");
434 }
435 if (dladm_name2info(handle, linkname, &linkid, NULL,
436 NULL, NULL) != DLADM_STATUS_OK) {
437 die("invalid link '%s'", linkname);
438 }
439 l_arg = B_TRUE;
440 break;
441 default:
442 die_opterr(optopt, option);
443 break;
444 }
445 }
446
447 /* when link not specified get flow name */
448 if (!l_arg) {
449 if (optind != (argc-1)) {
450 usage();
451 } else {
452 if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
453 die("flow name too long");
454 flowname = argv[optind];
455 }
456 status = dladm_flow_remove(handle, flowname, t_arg, altroot);
457 } else {
458 /* if link is specified then flow name should not be there */
459 if (optind == argc-1)
460 usage();
461 /* walk the link to find flows and remove them */
462 state.fs_tempop = t_arg;
463 state.fs_altroot = altroot;
464 state.fs_status = DLADM_STATUS_OK;
465 status = dladm_walk_flow(remove_flow, handle, linkid, &state,
466 B_FALSE);
467 /*
468 * check if dladm_walk_flow terminated early and see if the
469 * walker function as any status for us
470 */
471 if (status == DLADM_STATUS_OK)
472 status = state.fs_status;
473 }
474
475 if (status != DLADM_STATUS_OK)
476 die_dlerr(status, "remove flow failed");
477 }
478
479 /*
480 * Walker function for removing a flow through dladm_walk_flow();
580
581 (void) dladm_walk_flow(show_flow, dh, linkid, arg, state->fs_persist);
582
583 return (DLADM_WALK_CONTINUE);
584 }
585
586 static void
587 do_show_flow(int argc, char *argv[])
588 {
589 char flowname[MAXFLOWNAMELEN];
590 char linkname[MAXLINKNAMELEN];
591 datalink_id_t linkid = DATALINK_ALL_LINKID;
592 int option;
593 boolean_t l_arg = B_FALSE;
594 boolean_t o_arg = B_FALSE;
595 show_flow_state_t state;
596 char *fields_str = NULL;
597 ofmt_handle_t ofmt;
598 ofmt_status_t oferr;
599 uint_t ofmtflags = 0;
600
601 bzero(&state, sizeof (state));
602
603 opterr = 0;
604 while ((option = getopt_long(argc, argv, ":pPl:o:",
605 longopts, NULL)) != -1) {
606 switch (option) {
607 case 'p':
608 state.fs_parsable = B_TRUE;
609 ofmtflags |= OFMT_PARSABLE;
610 break;
611 case 'P':
612 state.fs_persist = B_TRUE;
613 break;
614 case 'o':
615 if (o_arg)
616 die_optdup(option);
617
618 o_arg = B_TRUE;
619 fields_str = optarg;
620 break;
621 case 'l':
622 if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
623 >= MAXLINKNAMELEN)
624 die("link name too long\n");
625 if (dladm_name2info(handle, linkname, &linkid, NULL,
626 NULL, NULL) != DLADM_STATUS_OK)
627 die("invalid link '%s'", linkname);
628 l_arg = B_TRUE;
629 break;
630 default:
631 die_opterr(optopt, option);
632 break;
633 }
634 }
635
636 /* get flow name (optional last argument */
637 if (optind == (argc-1)) {
638 if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
639 >= MAXFLOWNAMELEN)
640 die("flow name too long");
641 state.fs_flow = flowname;
642 }
643
644 oferr = ofmt_open(fields_str, flow_fields, ofmtflags, 0, &ofmt);
645 flowadm_ofmt_check(oferr, state.fs_parsable, ofmt);
646 state.fs_ofmt = ofmt;
647
648 /* Show attributes of one flow */
649 if (state.fs_flow != NULL) {
650 show_one_flow(&state, state.fs_flow);
651
652 /* Show attributes of flows on one link */
653 } else if (l_arg) {
654 (void) show_flows_onelink(handle, linkid, &state);
655
|
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 * Copyright 2011 Joyent, Inc. All rights reserved.
25 */
26
27 #include <stdio.h>
28 #include <locale.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <stropts.h>
34 #include <errno.h>
35 #include <strings.h>
36 #include <getopt.h>
37 #include <unistd.h>
38 #include <priv.h>
39 #include <netdb.h>
40 #include <libintl.h>
41 #include <libdlflow.h>
42 #include <libdllink.h>
43 #include <libdlstat.h>
44 #include <sys/types.h>
217 char *altroot = NULL;
218
219 /*
220 * Handle to libdladm. Opened in main() before the sub-command
221 * specific function is called.
222 */
223 static dladm_handle_t handle = NULL;
224
225 static const char *attr_table[] =
226 {"local_ip", "remote_ip", "transport", "local_port", "remote_port",
227 "dsfield"};
228
229 #define NATTR (sizeof (attr_table)/sizeof (char *))
230
231 static void
232 usage(void)
233 {
234 (void) fprintf(stderr, gettext("usage: flowadm <subcommand>"
235 " <args>...\n"
236 " add-flow [-t] -l <link> -a <attr>=<value>[,...]\n"
237 "\t\t [-p <prop>=<value>,...] [-z zonename] <flow>\n"
238 " remove-flow [-t] [-z zonename] {-l <link> | <flow>}\n"
239 " show-flow [-p] [-l <link>] [-z zonename] "
240 "[<flow>]\n\n"
241 " set-flowprop [-t] -p <prop>=<value>[,...] <flow>\n"
242 " reset-flowprop [-t] [-p <prop>,...] <flow>\n"
243 " show-flowprop [-cP] [-l <link>] [-p <prop>,...] "
244 "[<flow>]\n"));
245
246 /* close dladm handle if it was opened */
247 if (handle != NULL)
248 dladm_close(handle);
249
250 exit(1);
251 }
252
253 int
254 main(int argc, char *argv[])
255 {
256 int i, arglen, cmdlen;
257 cmd_t *cmdp;
258 dladm_status_t status;
259
317 status = dladm_flow_init(handle);
318 if (status != DLADM_STATUS_OK)
319 die_dlerr(status, "flows initialization failed");
320 }
321
322 static void
323 do_add_flow(int argc, char *argv[])
324 {
325 char devname[MAXLINKNAMELEN];
326 char *name = NULL;
327 uint_t index;
328 datalink_id_t linkid;
329
330 char option;
331 boolean_t l_arg = B_FALSE;
332 char propstr[DLADM_STRSIZE];
333 char attrstr[DLADM_STRSIZE];
334 dladm_arg_list_t *proplist = NULL;
335 dladm_arg_list_t *attrlist = NULL;
336 dladm_status_t status;
337 char *zonename = NULL;
338
339 bzero(propstr, DLADM_STRSIZE);
340 bzero(attrstr, DLADM_STRSIZE);
341
342 while ((option = getopt_long(argc, argv, "tR:l:a:p:z:",
343 prop_longopts, NULL)) != -1) {
344 switch (option) {
345 case 't':
346 t_arg = B_TRUE;
347 break;
348 case 'R':
349 altroot = optarg;
350 break;
351 case 'l':
352 if (strlcpy(devname, optarg,
353 MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
354 die("link name too long");
355 }
356 l_arg = B_TRUE;
357 break;
358 case 'a':
359 (void) strlcat(attrstr, optarg, DLADM_STRSIZE);
360 if (strlcat(attrstr, ",", DLADM_STRSIZE) >=
361 DLADM_STRSIZE)
362 die("attribute list too long '%s'", attrstr);
363 break;
364 case 'p':
365 (void) strlcat(propstr, optarg, DLADM_STRSIZE);
366 if (strlcat(propstr, ",", DLADM_STRSIZE) >=
367 DLADM_STRSIZE)
368 die("property list too long '%s'", propstr);
369 break;
370 case 'z':
371 zonename = optarg;
372 break;
373 default:
374 die_opterr(optopt, option);
375 }
376 }
377 if (!l_arg) {
378 die("link is required");
379 }
380
381 if (dladm_zname2info(handle, zonename, devname, &linkid, NULL,
382 NULL, NULL) != DLADM_STATUS_OK)
383 die("invalid link '%s'", devname);
384
385 opterr = 0;
386 index = optind;
387
388 if ((index != (argc - 1)) || match_attr(argv[index]) != NULL) {
389 die("flow name is required");
390 } else {
391 /* get flow name; required last argument */
392 if (strlen(argv[index]) >= MAXFLOWNAMELEN)
393 die("flow name too long");
394 name = argv[index];
395 }
396
397 if (dladm_parse_flow_attrs(attrstr, &attrlist, B_FALSE)
398 != DLADM_STATUS_OK)
399 die("invalid flow attribute specified");
400 if (dladm_parse_flow_props(propstr, &proplist, B_FALSE)
401 != DLADM_STATUS_OK)
402 die("invalid flow property specified");
403
404 status = dladm_flow_add(handle, linkid, attrlist, proplist, name,
405 t_arg, altroot);
406 if (status != DLADM_STATUS_OK)
407 die_dlerr(status, "add flow failed");
408
409 dladm_free_attrs(attrlist);
410 dladm_free_props(proplist);
411 }
412
413 static void
414 do_remove_flow(int argc, char *argv[])
415 {
416 char option;
417 char *flowname = NULL;
418 char linkname[MAXLINKNAMELEN];
419 datalink_id_t linkid = DATALINK_ALL_LINKID;
420 boolean_t l_arg = B_FALSE;
421 remove_flow_state_t state;
422 dladm_status_t status;
423 char *zonename = NULL;
424
425 bzero(&state, sizeof (state));
426
427 opterr = 0;
428 while ((option = getopt_long(argc, argv, ":tR:l:z:",
429 longopts, NULL)) != -1) {
430 switch (option) {
431 case 't':
432 t_arg = B_TRUE;
433 break;
434 case 'R':
435 altroot = optarg;
436 break;
437 case 'l':
438 if (strlcpy(linkname, optarg,
439 MAXLINKNAMELEN) >= MAXLINKNAMELEN) {
440 die("link name too long");
441 }
442 l_arg = B_TRUE;
443 break;
444 case 'z':
445 zonename = optarg;
446 break;
447 default:
448 die_opterr(optopt, option);
449 break;
450 }
451 }
452
453 /* when link not specified get flow name */
454 if (!l_arg) {
455 if (optind != (argc-1)) {
456 usage();
457 } else {
458 if (strlen(argv[optind]) >= MAXFLOWNAMELEN)
459 die("flow name too long");
460 flowname = argv[optind];
461 }
462 status = dladm_flow_remove(handle, flowname, t_arg, altroot);
463 } else {
464 /* if link is specified then flow name should not be there */
465 if (optind == argc-1)
466 usage();
467
468 if (dladm_zname2info(handle, zonename, linkname, &linkid, NULL,
469 NULL, NULL) != DLADM_STATUS_OK) {
470 die("invalid link '%s'", linkname);
471 }
472
473 /* walk the link to find flows and remove them */
474 state.fs_tempop = t_arg;
475 state.fs_altroot = altroot;
476 state.fs_status = DLADM_STATUS_OK;
477 status = dladm_walk_flow(remove_flow, handle, linkid, &state,
478 B_FALSE);
479 /*
480 * check if dladm_walk_flow terminated early and see if the
481 * walker function as any status for us
482 */
483 if (status == DLADM_STATUS_OK)
484 status = state.fs_status;
485 }
486
487 if (status != DLADM_STATUS_OK)
488 die_dlerr(status, "remove flow failed");
489 }
490
491 /*
492 * Walker function for removing a flow through dladm_walk_flow();
592
593 (void) dladm_walk_flow(show_flow, dh, linkid, arg, state->fs_persist);
594
595 return (DLADM_WALK_CONTINUE);
596 }
597
598 static void
599 do_show_flow(int argc, char *argv[])
600 {
601 char flowname[MAXFLOWNAMELEN];
602 char linkname[MAXLINKNAMELEN];
603 datalink_id_t linkid = DATALINK_ALL_LINKID;
604 int option;
605 boolean_t l_arg = B_FALSE;
606 boolean_t o_arg = B_FALSE;
607 show_flow_state_t state;
608 char *fields_str = NULL;
609 ofmt_handle_t ofmt;
610 ofmt_status_t oferr;
611 uint_t ofmtflags = 0;
612 char *zonename = NULL;
613
614 bzero(&state, sizeof (state));
615
616 opterr = 0;
617 while ((option = getopt_long(argc, argv, ":pPl:o:z:",
618 longopts, NULL)) != -1) {
619 switch (option) {
620 case 'p':
621 state.fs_parsable = B_TRUE;
622 ofmtflags |= OFMT_PARSABLE;
623 break;
624 case 'P':
625 state.fs_persist = B_TRUE;
626 break;
627 case 'o':
628 if (o_arg)
629 die_optdup(option);
630
631 o_arg = B_TRUE;
632 fields_str = optarg;
633 break;
634 case 'l':
635 if (strlcpy(linkname, optarg, MAXLINKNAMELEN)
636 >= MAXLINKNAMELEN)
637 die("link name too long\n");
638 l_arg = B_TRUE;
639 break;
640 case 'z':
641 zonename = optarg;
642 break;
643 default:
644 die_opterr(optopt, option);
645 break;
646 }
647 }
648
649 if (l_arg) {
650 if (dladm_zname2info(handle, zonename, linkname, &linkid, NULL,
651 NULL, NULL) != DLADM_STATUS_OK)
652 die("invalid link '%s'", linkname);
653 }
654
655 /* get flow name (optional last argument */
656 if (optind == (argc-1)) {
657 if (strlcpy(flowname, argv[optind], MAXFLOWNAMELEN)
658 >= MAXFLOWNAMELEN)
659 die("flow name too long");
660 state.fs_flow = flowname;
661 }
662
663 oferr = ofmt_open(fields_str, flow_fields, ofmtflags, 0, &ofmt);
664 flowadm_ofmt_check(oferr, state.fs_parsable, ofmt);
665 state.fs_ofmt = ofmt;
666
667 /* Show attributes of one flow */
668 if (state.fs_flow != NULL) {
669 show_one_flow(&state, state.fs_flow);
670
671 /* Show attributes of flows on one link */
672 } else if (l_arg) {
673 (void) show_flows_onelink(handle, linkid, &state);
674
|