/* * lib/cli/qdisc/hfsc.c HFSC module for CLI lib * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * * Copyright (c) 2014 Cong Wang */ #include #include #include #include static void print_qdisc_usage(void) { printf( "Usage: nl-qdisc-add [...] hfsc [OPTIONS]...\n" "\n" "OPTIONS\n" " --help Show this help text.\n" " --default=ID Default class for unclassified traffic.\n" "\n" "EXAMPLE" " # Create hfsc root qdisc 1: and direct unclassified traffic to class 1:10\n" " nl-qdisc-add --dev=eth1 --parent=root --handle=1: hfsc --default=10\n"); } static void hfsc_parse_qdisc_argv(struct rtnl_tc *tc, int argc, char **argv) { struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc; for (;;) { int c, optidx = 0; enum { ARG_DEFAULT = 257, }; static struct option long_opts[] = { { "help", 0, 0, 'h' }, { "default", 1, 0, ARG_DEFAULT }, { 0, 0, 0, 0 } }; c = getopt_long(argc, argv, "hv", long_opts, &optidx); if (c == -1) break; switch (c) { case 'h': print_qdisc_usage(); return; case ARG_DEFAULT: rtnl_qdisc_hfsc_set_defcls(qdisc, nl_cli_parse_u32(optarg)); break; } } } static void print_class_usage(void) { printf( "Usage: nl-class-add [...] hfsc [OPTIONS]...\n" "\n" "OPTIONS\n" " --help Show this help text.\n" " --ls=SC Link-sharing service curve\n" " --rt=SC Real-time service curve\n" " --sc=SC Specifiy both of the above\n" " --ul=SC Upper limit\n" " where SC := [ [ m1 bits ] d usec ] m2 bits\n" "\n" "EXAMPLE" " # Attach class 1:1 to hfsc qdisc 1: and use rt and ls curve\n" " nl-class-add --dev=eth1 --parent=1: --classid=1:1 hfsc --sc=m1:250,d:8,m2:100\n"); } static int hfsc_get_sc(char *optarg, struct tc_service_curve *sc) { unsigned int m1 = 0, d = 0, m2 = 0; char *tmp = strdup(optarg); char *p, *endptr; char *pp = tmp; if (!tmp) return -ENOMEM; p = strstr(pp, "m1:"); if (p) { char *q; p += 3; if (*p == 0) goto err; q = strchr(p, ','); if (!q) goto err; *q = 0; m1 = strtoul(p, &endptr, 10); if (endptr == p) goto err; pp = q + 1; } p = strstr(pp, "d:"); if (p) { char *q; p += 2; if (*p == 0) goto err; q = strchr(p, ','); if (!q) goto err; *q = 0; d = strtoul(p, &endptr, 10); if (endptr == p) goto err; pp = q + 1; } p = strstr(pp, "m2:"); if (p) { p += 3; if (*p == 0) goto err; m2 = strtoul(p, &endptr, 10); if (endptr == p) goto err; } else goto err; free(tmp); sc->m1 = m1; sc->d = d; sc->m2 = m2; return 0; err: free(tmp); return -EINVAL; } static void hfsc_parse_class_argv(struct rtnl_tc *tc, int argc, char **argv) { struct rtnl_class *class = (struct rtnl_class *) tc; int arg_ok = 0, ret = -EINVAL; for (;;) { int c, optidx = 0; enum { ARG_RT = 257, ARG_LS = 258, ARG_SC, ARG_UL, }; static struct option long_opts[] = { { "help", 0, 0, 'h' }, { "rt", 1, 0, ARG_RT }, { "ls", 1, 0, ARG_LS }, { "sc", 1, 0, ARG_SC }, { "ul", 1, 0, ARG_UL }, { 0, 0, 0, 0 } }; struct tc_service_curve tsc; c = getopt_long(argc, argv, "h", long_opts, &optidx); if (c == -1) break; switch (c) { case 'h': print_class_usage(); return; case ARG_RT: ret = hfsc_get_sc(optarg, &tsc); if (ret < 0) { nl_cli_fatal(ret, "Unable to parse sc " "\"%s\": Invalid format.", optarg); } rtnl_class_hfsc_set_rsc(class, &tsc); arg_ok++; break; case ARG_LS: ret = hfsc_get_sc(optarg, &tsc); if (ret < 0) { nl_cli_fatal(ret, "Unable to parse sc " "\"%s\": Invalid format.", optarg); } rtnl_class_hfsc_set_fsc(class, &tsc); arg_ok++; break; case ARG_SC: ret = hfsc_get_sc(optarg, &tsc); if (ret < 0) { nl_cli_fatal(ret, "Unable to parse sc " "\"%s\": Invalid format.", optarg); } rtnl_class_hfsc_set_rsc(class, &tsc); rtnl_class_hfsc_set_fsc(class, &tsc); arg_ok++; break; case ARG_UL: ret = hfsc_get_sc(optarg, &tsc); if (ret < 0) { nl_cli_fatal(ret, "Unable to parse sc " "\"%s\": Invalid format.", optarg); } rtnl_class_hfsc_set_usc(class, &tsc); arg_ok++; break; } } if (!arg_ok) nl_cli_fatal(ret, "Invalid arguments"); } static struct nl_cli_tc_module hfsc_qdisc_module = { .tm_name = "hfsc", .tm_type = RTNL_TC_TYPE_QDISC, .tm_parse_argv = hfsc_parse_qdisc_argv, }; static struct nl_cli_tc_module hfsc_class_module = { .tm_name = "hfsc", .tm_type = RTNL_TC_TYPE_CLASS, .tm_parse_argv = hfsc_parse_class_argv, }; static void __init hfsc_init(void) { nl_cli_tc_register(&hfsc_qdisc_module); nl_cli_tc_register(&hfsc_class_module); } static void __exit hfsc_exit(void) { nl_cli_tc_unregister(&hfsc_class_module); nl_cli_tc_unregister(&hfsc_qdisc_module); }