]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - tc/q_fq.c
Merge branch 'main' into next
[mirror_iproute2.git] / tc / q_fq.c
index 2a370b365df1ccae032989ea20ab29059365bbdd..98d1bf4014e3f9fbb8e804f92dcdc96e417b5c74 100644 (file)
--- a/tc/q_fq.c
+++ b/tc/q_fq.c
@@ -38,7 +38,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <syslog.h>
 #include <fcntl.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 
 static void explain(void)
 {
-       fprintf(stderr, "Usage: ... fq [ limit PACKETS ] [ flow_limit PACKETS ]\n");
-       fprintf(stderr, "              [ quantum BYTES ] [ initial_quantum BYTES ]\n");
-       fprintf(stderr, "              [ maxrate RATE  ] [ buckets NUMBER ]\n");
-       fprintf(stderr, "              [ [no]pacing ] [ refill_delay TIME ]\n");
-       fprintf(stderr, "              [ orphan_mask MASK]\n");
+       fprintf(stderr,
+               "Usage: ... fq  [ limit PACKETS ] [ flow_limit PACKETS ]\n"
+               "               [ quantum BYTES ] [ initial_quantum BYTES ]\n"
+               "               [ maxrate RATE  ] [ buckets NUMBER ]\n"
+               "               [ [no]pacing ] [ refill_delay TIME ]\n"
+               "               [ low_rate_threshold RATE ]\n"
+               "               [ orphan_mask MASK]\n"
+               "               [ timer_slack TIME]\n"
+               "               [ ce_threshold TIME ]\n");
 }
 
 static unsigned int ilog2(unsigned int val)
@@ -71,7 +74,7 @@ static unsigned int ilog2(unsigned int val)
 }
 
 static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
-                       struct nlmsghdr *n)
+                       struct nlmsghdr *n, const char *dev)
 {
        unsigned int plimit;
        unsigned int flow_plimit;
@@ -79,9 +82,12 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        unsigned int initial_quantum;
        unsigned int buckets = 0;
        unsigned int maxrate;
+       unsigned int low_rate_threshold;
        unsigned int defrate;
        unsigned int refill_delay;
        unsigned int orphan_mask;
+       unsigned int ce_threshold;
+       unsigned int timer_slack;
        bool set_plimit = false;
        bool set_flow_plimit = false;
        bool set_quantum = false;
@@ -90,6 +96,9 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        bool set_defrate = false;
        bool set_refill_delay = false;
        bool set_orphan_mask = false;
+       bool set_low_rate_threshold = false;
+       bool set_ce_threshold = false;
+       bool set_timer_slack = false;
        int pacing = -1;
        struct rtattr *tail;
 
@@ -116,14 +125,52 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                        }
                } else if (strcmp(*argv, "maxrate") == 0) {
                        NEXT_ARG();
-                       if (get_rate(&maxrate, *argv)) {
+                       if (strchr(*argv, '%')) {
+                               if (get_percent_rate(&maxrate, *argv, dev)) {
+                                       fprintf(stderr, "Illegal \"maxrate\"\n");
+                                       return -1;
+                               }
+                       } else if (get_rate(&maxrate, *argv)) {
                                fprintf(stderr, "Illegal \"maxrate\"\n");
                                return -1;
                        }
                        set_maxrate = true;
+               } else if (strcmp(*argv, "low_rate_threshold") == 0) {
+                       NEXT_ARG();
+                       if (get_rate(&low_rate_threshold, *argv)) {
+                               fprintf(stderr, "Illegal \"low_rate_threshold\"\n");
+                               return -1;
+                       }
+                       set_low_rate_threshold = true;
+               } else if (strcmp(*argv, "ce_threshold") == 0) {
+                       NEXT_ARG();
+                       if (get_time(&ce_threshold, *argv)) {
+                               fprintf(stderr, "Illegal \"ce_threshold\"\n");
+                               return -1;
+                       }
+                       set_ce_threshold = true;
+               } else if (strcmp(*argv, "timer_slack") == 0) {
+                       __s64 t64;
+
+                       NEXT_ARG();
+                       if (get_time64(&t64, *argv)) {
+                               fprintf(stderr, "Illegal \"timer_slack\"\n");
+                               return -1;
+                       }
+                       timer_slack = t64;
+                       if (timer_slack != t64) {
+                               fprintf(stderr, "Illegal (out of range) \"timer_slack\"\n");
+                               return -1;
+                       }
+                       set_timer_slack = true;
                } else if (strcmp(*argv, "defrate") == 0) {
                        NEXT_ARG();
-                       if (get_rate(&defrate, *argv)) {
+                       if (strchr(*argv, '%')) {
+                               if (get_percent_rate(&defrate, *argv, dev)) {
+                                       fprintf(stderr, "Illegal \"defrate\"\n");
+                                       return -1;
+                               }
+                       } else if (get_rate(&defrate, *argv)) {
                                fprintf(stderr, "Illegal \"defrate\"\n");
                                return -1;
                        }
@@ -171,8 +218,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                argc--; argv++;
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        if (buckets) {
                unsigned int log = ilog2(buckets);
 
@@ -196,6 +242,9 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        if (set_maxrate)
                addattr_l(n, 1024, TCA_FQ_FLOW_MAX_RATE,
                          &maxrate, sizeof(maxrate));
+       if (set_low_rate_threshold)
+               addattr_l(n, 1024, TCA_FQ_LOW_RATE_THRESHOLD,
+                         &low_rate_threshold, sizeof(low_rate_threshold));
        if (set_defrate)
                addattr_l(n, 1024, TCA_FQ_FLOW_DEFAULT_RATE,
                          &defrate, sizeof(defrate));
@@ -205,7 +254,13 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        if (set_orphan_mask)
                addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
                          &orphan_mask, sizeof(refill_delay));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       if (set_ce_threshold)
+               addattr_l(n, 1024, TCA_FQ_CE_THRESHOLD,
+                         &ce_threshold, sizeof(ce_threshold));
+    if (set_timer_slack)
+               addattr_l(n, 1024, TCA_FQ_TIMER_SLACK,
+                         &timer_slack, sizeof(timer_slack));
+       addattr_nest_end(n, tail);
        return 0;
 }
 
@@ -218,6 +273,9 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        unsigned int rate, quantum;
        unsigned int refill_delay;
        unsigned int orphan_mask;
+       unsigned int ce_threshold;
+       unsigned int timer_slack;
+
        SPRINT_BUF(b1);
 
        if (opt == NULL)
@@ -228,57 +286,102 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
        if (tb[TCA_FQ_PLIMIT] &&
            RTA_PAYLOAD(tb[TCA_FQ_PLIMIT]) >= sizeof(__u32)) {
                plimit = rta_getattr_u32(tb[TCA_FQ_PLIMIT]);
-               fprintf(f, "limit %up ", plimit);
+               print_uint(PRINT_ANY, "limit", "limit %up ", plimit);
        }
        if (tb[TCA_FQ_FLOW_PLIMIT] &&
            RTA_PAYLOAD(tb[TCA_FQ_FLOW_PLIMIT]) >= sizeof(__u32)) {
                flow_plimit = rta_getattr_u32(tb[TCA_FQ_FLOW_PLIMIT]);
-               fprintf(f, "flow_limit %up ", flow_plimit);
+               print_uint(PRINT_ANY, "flow_limit", "flow_limit %up ",
+                          flow_plimit);
        }
        if (tb[TCA_FQ_BUCKETS_LOG] &&
            RTA_PAYLOAD(tb[TCA_FQ_BUCKETS_LOG]) >= sizeof(__u32)) {
                buckets_log = rta_getattr_u32(tb[TCA_FQ_BUCKETS_LOG]);
-               fprintf(f, "buckets %u ", 1U << buckets_log);
+               print_uint(PRINT_ANY, "buckets", "buckets %u ",
+                          1U << buckets_log);
        }
        if (tb[TCA_FQ_ORPHAN_MASK] &&
            RTA_PAYLOAD(tb[TCA_FQ_ORPHAN_MASK]) >= sizeof(__u32)) {
                orphan_mask = rta_getattr_u32(tb[TCA_FQ_ORPHAN_MASK]);
-               fprintf(f, "orphan_mask %u ", orphan_mask);
+               print_uint(PRINT_ANY, "orphan_mask", "orphan_mask %u ",
+                          orphan_mask);
        }
        if (tb[TCA_FQ_RATE_ENABLE] &&
            RTA_PAYLOAD(tb[TCA_FQ_RATE_ENABLE]) >= sizeof(int)) {
                pacing = rta_getattr_u32(tb[TCA_FQ_RATE_ENABLE]);
                if (pacing == 0)
-                       fprintf(f, "nopacing ");
+                       print_bool(PRINT_ANY, "pacing", "nopacing ", false);
        }
        if (tb[TCA_FQ_QUANTUM] &&
            RTA_PAYLOAD(tb[TCA_FQ_QUANTUM]) >= sizeof(__u32)) {
                quantum = rta_getattr_u32(tb[TCA_FQ_QUANTUM]);
-               fprintf(f, "quantum %u ", quantum);
+               print_uint(PRINT_JSON, "quantum", NULL, quantum);
+               print_string(PRINT_FP, NULL, "quantum %s ",
+                            sprint_size(quantum, b1));
        }
        if (tb[TCA_FQ_INITIAL_QUANTUM] &&
            RTA_PAYLOAD(tb[TCA_FQ_INITIAL_QUANTUM]) >= sizeof(__u32)) {
                quantum = rta_getattr_u32(tb[TCA_FQ_INITIAL_QUANTUM]);
-               fprintf(f, "initial_quantum %u ", quantum);
+               print_uint(PRINT_JSON, "initial_quantum", NULL, quantum);
+               print_string(PRINT_FP, NULL, "initial_quantum %s ",
+                            sprint_size(quantum, b1));
        }
        if (tb[TCA_FQ_FLOW_MAX_RATE] &&
            RTA_PAYLOAD(tb[TCA_FQ_FLOW_MAX_RATE]) >= sizeof(__u32)) {
                rate = rta_getattr_u32(tb[TCA_FQ_FLOW_MAX_RATE]);
 
-               if (rate != ~0U)
-                       fprintf(f, "maxrate %s ", sprint_rate(rate, b1));
+               if (rate != ~0U) {
+                       print_uint(PRINT_JSON, "maxrate", NULL, rate);
+                       print_string(PRINT_FP, NULL, "maxrate %s ",
+                                    sprint_rate(rate, b1));
+               }
        }
        if (tb[TCA_FQ_FLOW_DEFAULT_RATE] &&
            RTA_PAYLOAD(tb[TCA_FQ_FLOW_DEFAULT_RATE]) >= sizeof(__u32)) {
                rate = rta_getattr_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]);
 
-               if (rate != 0)
-                       fprintf(f, "defrate %s ", sprint_rate(rate, b1));
+               if (rate != 0) {
+                       print_uint(PRINT_JSON, "defrate", NULL, rate);
+                       print_string(PRINT_FP, NULL, "defrate %s ",
+                                    sprint_rate(rate, b1));
+               }
+       }
+       if (tb[TCA_FQ_LOW_RATE_THRESHOLD] &&
+           RTA_PAYLOAD(tb[TCA_FQ_LOW_RATE_THRESHOLD]) >= sizeof(__u32)) {
+               rate = rta_getattr_u32(tb[TCA_FQ_LOW_RATE_THRESHOLD]);
+
+               if (rate != 0) {
+                       print_uint(PRINT_JSON, "low_rate_threshold", NULL,
+                                  rate);
+                       print_string(PRINT_FP, NULL, "low_rate_threshold %s ",
+                                    sprint_rate(rate, b1));
+               }
        }
        if (tb[TCA_FQ_FLOW_REFILL_DELAY] &&
            RTA_PAYLOAD(tb[TCA_FQ_FLOW_REFILL_DELAY]) >= sizeof(__u32)) {
                refill_delay = rta_getattr_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]);
-               fprintf(f, "refill_delay %s ", sprint_time(refill_delay, b1));
+               print_uint(PRINT_JSON, "refill_delay", NULL, refill_delay);
+               print_string(PRINT_FP, NULL, "refill_delay %s ",
+                            sprint_time(refill_delay, b1));
+       }
+
+       if (tb[TCA_FQ_CE_THRESHOLD] &&
+           RTA_PAYLOAD(tb[TCA_FQ_CE_THRESHOLD]) >= sizeof(__u32)) {
+               ce_threshold = rta_getattr_u32(tb[TCA_FQ_CE_THRESHOLD]);
+               if (ce_threshold != ~0U) {
+                       print_uint(PRINT_JSON, "ce_threshold", NULL,
+                                  ce_threshold);
+                       print_string(PRINT_FP, NULL, "ce_threshold %s ",
+                                    sprint_time(ce_threshold, b1));
+               }
+       }
+
+       if (tb[TCA_FQ_TIMER_SLACK] &&
+           RTA_PAYLOAD(tb[TCA_FQ_TIMER_SLACK]) >= sizeof(__u32)) {
+               timer_slack = rta_getattr_u32(tb[TCA_FQ_TIMER_SLACK]);
+               print_uint(PRINT_JSON, "timer_slack", NULL, timer_slack);
+               print_string(PRINT_FP, NULL, "timer_slack %s ",
+                            sprint_time64(timer_slack, b1));
        }
 
        return 0;
@@ -287,36 +390,63 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
 static int fq_print_xstats(struct qdisc_util *qu, FILE *f,
                           struct rtattr *xstats)
 {
-       struct tc_fq_qd_stats *st;
+       struct tc_fq_qd_stats *st, _st;
+
+       SPRINT_BUF(b1);
 
        if (xstats == NULL)
                return 0;
 
-       if (RTA_PAYLOAD(xstats) < sizeof(*st))
-               return -1;
+       memset(&_st, 0, sizeof(_st));
+       memcpy(&_st, RTA_DATA(xstats), min(RTA_PAYLOAD(xstats), sizeof(*st)));
 
-       st = RTA_DATA(xstats);
+       st = &_st;
 
-       fprintf(f, "  %u flows (%u inactive, %u throttled)",
-               st->flows, st->inactive_flows, st->throttled_flows);
+       print_uint(PRINT_ANY, "flows", "  flows %u", st->flows);
+       print_uint(PRINT_ANY, "inactive", " (inactive %u", st->inactive_flows);
+       print_uint(PRINT_ANY, "throttled", " throttled %u)",
+                  st->throttled_flows);
 
-       if (st->time_next_delayed_flow > 0)
-               fprintf(f, ", next packet delay %llu ns", st->time_next_delayed_flow);
+       if (st->time_next_delayed_flow > 0) {
+               print_lluint(PRINT_JSON, "next_packet_delay", NULL,
+                            st->time_next_delayed_flow);
+               print_string(PRINT_FP, NULL, " next_packet_delay %s",
+                            sprint_time64(st->time_next_delayed_flow, b1));
+       }
 
-       fprintf(f, "\n  %llu gc, %llu highprio",
-               st->gc_flows, st->highprio_packets);
+       print_nl();
+       print_lluint(PRINT_ANY, "gc", "  gc %llu", st->gc_flows);
+       print_lluint(PRINT_ANY, "highprio", " highprio %llu",
+                    st->highprio_packets);
 
        if (st->tcp_retrans)
-               fprintf(f, ", %llu retrans", st->tcp_retrans);
+               print_lluint(PRINT_ANY, "retrans", " retrans %llu",
+                            st->tcp_retrans);
 
-       fprintf(f, ", %llu throttled", st->throttled);
+       print_lluint(PRINT_ANY, "throttled", " throttled %llu", st->throttled);
+
+       if (st->unthrottle_latency_ns) {
+               print_uint(PRINT_JSON, "latency", NULL,
+                          st->unthrottle_latency_ns);
+               print_string(PRINT_FP, NULL, " latency %s",
+                            sprint_time64(st->unthrottle_latency_ns, b1));
+       }
+
+       if (st->ce_mark)
+               print_lluint(PRINT_ANY, "ce_mark", " ce_mark %llu",
+                            st->ce_mark);
 
        if (st->flows_plimit)
-               fprintf(f, ", %llu flows_plimit", st->flows_plimit);
+               print_lluint(PRINT_ANY, "flows_plimit", " flows_plimit %llu",
+                            st->flows_plimit);
 
-       if (st->pkts_too_long || st->allocation_errors)
-               fprintf(f, "\n  %llu too long pkts, %llu alloc errors\n",
-                       st->pkts_too_long, st->allocation_errors);
+       if (st->pkts_too_long || st->allocation_errors) {
+               print_nl();
+               print_lluint(PRINT_ANY, "pkts_too_long",
+                            "  pkts_too_long %llu", st->pkts_too_long);
+               print_lluint(PRINT_ANY, "alloc_errors", " alloc_errors %llu",
+                            st->allocation_errors);
+       }
 
        return 0;
 }