]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - tc/q_hfsc.c
tc: implement support for terse dump
[mirror_iproute2.git] / tc / q_hfsc.c
index 021fbb5bad4c0c9d12307a6f4de73976b4cb9112..f34b1b2fe2a98f10c5f65ac4f20b26686fcbae4f 100644 (file)
@@ -13,7 +13,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <syslog.h>
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -24,8 +23,8 @@
 #include "utils.h"
 #include "tc_util.h"
 
-static int hfsc_get_sc(int *, char ***, struct tc_service_curve *);
-
+static int hfsc_get_sc(int *, char ***,
+                      struct tc_service_curve *, const char *);
 
 static void
 explain_qdisc(void)
@@ -43,7 +42,7 @@ explain_class(void)
        fprintf(stderr,
                "Usage: ... hfsc [ [ rt SC ] [ ls SC ] | [ sc SC ] ] [ ul SC ]\n"
                "\n"
-               "SC := [ [ m1 BPS ] d SEC ] m2 BPS\n"
+               "SC := [ [ m1 BPS ] d SEC ] m2 BPS\n"
                "\n"
                " m1 : slope of first segment\n"
                " d  : x-coordinate of intersection\n"
@@ -57,6 +56,10 @@ explain_class(void)
                " dmax : maximum delay\n"
                " rate : rate\n"
                "\n"
+               "Remarks:\n"
+               " - at least one of 'rt', 'ls' or 'sc' must be specified\n"
+               " - 'ul' can only be specified with 'ls' or 'sc'\n"
+               "\n"
        );
 }
 
@@ -67,11 +70,10 @@ explain1(char *arg)
 }
 
 static int
-hfsc_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
+hfsc_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+              struct nlmsghdr *n, const char *dev)
 {
-       struct tc_hfsc_qopt qopt;
-
-       memset(&qopt, 0, sizeof(qopt));
+       struct tc_hfsc_qopt qopt = {};
 
        while (argc > 0) {
                if (matches(*argv, "default") == 0) {
@@ -140,35 +142,30 @@ hfsc_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
 
 static int
 hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
-                     struct nlmsghdr *n)
+                    struct nlmsghdr *n, const char *dev)
 {
-       struct tc_service_curve rsc, fsc, usc;
-       int rsc_ok, fsc_ok, usc_ok;
+       struct tc_service_curve rsc = {}, fsc = {}, usc = {};
+       int rsc_ok = 0, fsc_ok = 0, usc_ok = 0;
        struct rtattr *tail;
 
-       memset(&rsc, 0, sizeof(rsc));
-       memset(&fsc, 0, sizeof(fsc));
-       memset(&usc, 0, sizeof(usc));
-       rsc_ok = fsc_ok = usc_ok = 0;
-
        while (argc > 0) {
                if (matches(*argv, "rt") == 0) {
                        NEXT_ARG();
-                       if (hfsc_get_sc(&argc, &argv, &rsc) < 0) {
+                       if (hfsc_get_sc(&argc, &argv, &rsc, dev) < 0) {
                                explain1("rt");
                                return -1;
                        }
                        rsc_ok = 1;
                } else if (matches(*argv, "ls") == 0) {
                        NEXT_ARG();
-                       if (hfsc_get_sc(&argc, &argv, &fsc) < 0) {
+                       if (hfsc_get_sc(&argc, &argv, &fsc, dev) < 0) {
                                explain1("ls");
                                return -1;
                        }
                        fsc_ok = 1;
                } else if (matches(*argv, "sc") == 0) {
                        NEXT_ARG();
-                       if (hfsc_get_sc(&argc, &argv, &rsc) < 0) {
+                       if (hfsc_get_sc(&argc, &argv, &rsc, dev) < 0) {
                                explain1("sc");
                                return -1;
                        }
@@ -177,7 +174,7 @@ hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
                        fsc_ok = 1;
                } else if (matches(*argv, "ul") == 0) {
                        NEXT_ARG();
-                       if (hfsc_get_sc(&argc, &argv, &usc) < 0) {
+                       if (hfsc_get_sc(&argc, &argv, &usc, dev) < 0) {
                                explain1("ul");
                                return -1;
                        }
@@ -199,15 +196,12 @@ hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
                return -1;
        }
        if (usc_ok && !fsc_ok) {
-               fprintf(stderr, "HFSC: Upper-limit Service Curve without "
-                               "Link-Share Service Curve\n");
+               fprintf(stderr, "HFSC: Upper-limit Service Curve without Link-Share Service Curve\n");
                explain_class();
                return -1;
        }
 
-       tail = (struct rtattr*)(((void*)n) + NLMSG_ALIGN(n->nlmsg_len));
-
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        if (rsc_ok)
                addattr_l(n, 1024, TCA_HFSC_RSC, &rsc, sizeof(rsc));
        if (fsc_ok)
@@ -215,7 +209,7 @@ hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
        if (usc_ok)
                addattr_l(n, 1024, TCA_HFSC_USC, &usc, sizeof(usc));
 
-       tail->rta_len = (((void*)n) + NLMSG_ALIGN(n->nlmsg_len)) - (void*)tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
@@ -226,7 +220,7 @@ hfsc_print_sc(FILE *f, char *name, struct tc_service_curve *sc)
 
        fprintf(f, "%s ", name);
        fprintf(f, "m1 %s ", sprint_rate(sc->m1, b1));
-       fprintf(f, "d %s ", sprint_usecs(sc->d, b1));
+       fprintf(f, "d %s ", sprint_time(tc_core_ktime2time(sc->d), b1));
        fprintf(f, "m2 %s ", sprint_rate(sc->m2, b1));
 }
 
@@ -239,8 +233,7 @@ hfsc_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        if (opt == NULL)
                return 0;
 
-       memset(tb, 0, sizeof(tb));
-       parse_rtattr(tb, TCA_HFSC_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt));
+       parse_rtattr_nested(tb, TCA_HFSC_MAX, opt);
 
        if (tb[TCA_HFSC_RSC]) {
                if (RTA_PAYLOAD(tb[TCA_HFSC_RSC]) < sizeof(*rsc))
@@ -261,7 +254,7 @@ hfsc_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
                        usc = RTA_DATA(tb[TCA_HFSC_USC]);
        }
 
-       
+
        if (rsc != NULL && fsc != NULL &&
            memcmp(rsc, fsc, sizeof(*rsc)) == 0)
                hfsc_print_sc(f, "sc", rsc);
@@ -276,7 +269,7 @@ hfsc_print_class_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 
        return 0;
 }
+
 struct qdisc_util hfsc_qdisc_util = {
        .id             = "hfsc",
        .parse_qopt     = hfsc_parse_opt,
@@ -287,7 +280,8 @@ struct qdisc_util hfsc_qdisc_util = {
 };
 
 static int
-hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
+hfsc_get_sc1(int *argcp, char ***argvp,
+            struct tc_service_curve *sc, const char *dev)
 {
        char **argv = *argvp;
        int argc = *argcp;
@@ -295,7 +289,12 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
 
        if (matches(*argv, "m1") == 0) {
                NEXT_ARG();
-               if (get_rate(&m1, *argv) < 0) {
+               if (strchr(*argv, '%')) {
+                       if (get_percent_rate(&m1, *argv, dev)) {
+                               explain1("m1");
+                               return -1;
+                       }
+               } else if (get_rate(&m1, *argv) < 0) {
                        explain1("m1");
                        return -1;
                }
@@ -304,7 +303,7 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
 
        if (matches(*argv, "d") == 0) {
                NEXT_ARG();
-               if (get_usecs(&d, *argv) < 0) {
+               if (get_time(&d, *argv) < 0) {
                        explain1("d");
                        return -1;
                }
@@ -313,7 +312,12 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
 
        if (matches(*argv, "m2") == 0) {
                NEXT_ARG();
-               if (get_rate(&m2, *argv) < 0) {
+               if (strchr(*argv, '%')) {
+                       if (get_percent_rate(&m2, *argv, dev)) {
+                               explain1("m2");
+                               return -1;
+                       }
+               } else if (get_rate(&m2, *argv) < 0) {
                        explain1("m2");
                        return -1;
                }
@@ -321,7 +325,7 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
                return -1;
 
        sc->m1 = m1;
-       sc->d  = d;
+       sc->d  = tc_core_time2ktime(d);
        sc->m2 = m2;
 
        *argvp = argv;
@@ -330,7 +334,7 @@ hfsc_get_sc1(int *argcp, char ***argvp, struct tc_service_curve *sc)
 }
 
 static int
-hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
+hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc, const char *dev)
 {
        char **argv = *argvp;
        int argc = *argcp;
@@ -347,7 +351,7 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
 
        if (matches(*argv, "dmax") == 0) {
                NEXT_ARG();
-               if (get_usecs(&dmax, *argv) < 0) {
+               if (get_time(&dmax, *argv) < 0) {
                        explain1("dmax");
                        return -1;
                }
@@ -356,7 +360,12 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
 
        if (matches(*argv, "rate") == 0) {
                NEXT_ARG();
-               if (get_rate(&rate, *argv) < 0) {
+               if (strchr(*argv, '%')) {
+                       if (get_percent_rate(&rate, *argv, dev)) {
+                               explain1("rate");
+                               return -1;
+                       }
+               } else if (get_rate(&rate, *argv) < 0) {
                        explain1("rate");
                        return -1;
                }
@@ -368,13 +377,13 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
                return -1;
        }
 
-       if (dmax != 0 && ceil(umax * 1000000.0 / dmax) > rate) {
+       if (dmax != 0 && ceil(1.0 * umax * TIME_UNITS_PER_SEC / dmax) > rate) {
                /*
                 * concave curve, slope of first segment is umax/dmax,
                 * intersection is at dmax
                 */
-               sc->m1 = ceil(umax * 1000000.0 / dmax); /* in bps */
-               sc->d  = dmax;
+               sc->m1 = ceil(1.0 * umax * TIME_UNITS_PER_SEC / dmax); /* in bps */
+               sc->d  = tc_core_time2ktime(dmax);
                sc->m2 = rate;
        } else {
                /*
@@ -382,7 +391,7 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
                 * is at dmax - umax / rate
                 */
                sc->m1 = 0;
-               sc->d  = ceil(dmax - umax * 1000000.0 / rate); /* in usec */
+               sc->d  = tc_core_time2ktime(ceil(dmax - umax * TIME_UNITS_PER_SEC / rate));
                sc->m2 = rate;
        }
 
@@ -392,10 +401,10 @@ hfsc_get_sc2(int *argcp, char ***argvp, struct tc_service_curve *sc)
 }
 
 static int
-hfsc_get_sc(int *argcp, char ***argvp, struct tc_service_curve *sc)
+hfsc_get_sc(int *argcp, char ***argvp, struct tc_service_curve *sc, const char *dev)
 {
-       if (hfsc_get_sc1(argcp, argvp, sc) < 0 &&
-           hfsc_get_sc2(argcp, argvp, sc) < 0)
+       if (hfsc_get_sc1(argcp, argvp, sc, dev) < 0 &&
+           hfsc_get_sc2(argcp, argvp, sc, dev) < 0)
                return -1;
 
        if (sc->m1 == 0 && sc->m2 == 0) {