summaryrefslogtreecommitdiffstats
path: root/lib/cli/qdisc/hfsc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cli/qdisc/hfsc.c')
-rw-r--r--lib/cli/qdisc/hfsc.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/lib/cli/qdisc/hfsc.c b/lib/cli/qdisc/hfsc.c
new file mode 100644
index 0000000..1e6878a
--- /dev/null
+++ b/lib/cli/qdisc/hfsc.c
@@ -0,0 +1,250 @@
+/*
+ * 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 <xiyou.wangcong@gmail.com>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/hfsc.h>
+
+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 = tmp, *endptr;
+
+ if (!tmp)
+ return -ENOMEM;
+
+ p = strstr(p, "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;
+ p = q + 1;
+ }
+
+ p = strstr(p, "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;
+ p = q + 1;
+ }
+
+ p = strstr(p, "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);
+}