blob: 625460ecfbbcde51de715850519480007f8ad496 [file] [log] [blame]
From cded87ae1e15aa95dba07f9be20868b5fef1368e Mon Sep 17 00:00:00 2001
From: Kan Yan <kyan@google.com>
Date: Thu, 23 Jan 2020 16:55:53 -0800
Subject: [PATCH] tc: add support for new qdisc "ARL"
Ingress mode is also supported in this patch.
BUG=b:124309202
TEST="tc qdisc add dev ifbwan0 root handle 1: arl minrate 4800kbit"
" buffer 5000 limit 500 latency 100ms latency_hysteresis 30ms"
" codel_target 10ms ingress"
Kill this once the 3.18 and 4.4 kernels are deprecated
Signed-off-by: Kan Yan <kyan@google.com>
---
include/uapi/linux/pkt_sched.h | 27 ++++
tc/Makefile | 1 +
tc/q_arl.c | 232 +++++++++++++++++++++++++++++++++
3 files changed, 260 insertions(+)
create mode 100644 tc/q_arl.c
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index d35dd7a2..12b51898 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -742,6 +742,33 @@ enum {
#define TCA_CBQ_MAX (__TCA_CBQ_MAX - 1)
+/* ARL section */
+
+struct tc_arl_xstats {
+ __u32 max_bw; /* The maximum bw measured */
+ __u32 min_rate; /* The lowest base rate */
+ __u32 current_rate; /* The current rate */
+ __u32 latency; /* The current latency */
+ __u32 base_rate; /* The base rate */
+ __u32 current_bw; /* The current bw measured */
+ __u32 state; /* The current state */
+};
+
+enum {
+ TCA_ARL_UNSPEC,
+ TCA_ARL_BUFFER,
+ TCA_ARL_MIN_RATE,
+ TCA_ARL_MAX_BW,
+ TCA_ARL_LIMIT,
+ TCA_ARL_MAX_LATENCY,
+ TCA_ARL_LATENCY_HYSTERESIS,
+ TCA_ARL_PAD,
+ TCA_ARL_MODE,
+ TCA_ARL_CODEL_TARGET,
+ __TCA_ARL_MAX,
+};
+#define TCA_ARL_MAX (__TCA_ARL_MAX - 1)
+
/* dsmark section */
enum {
diff --git a/tc/Makefile b/tc/Makefile
index 457a3ea1..d6e67940 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -80,6 +80,7 @@ TCMODULES += q_cbs.o
TCMODULES += q_etf.o
TCMODULES += q_taprio.o
TCMODULES += q_plug.o
+TCMODULES += q_arl.o
TCSO :=
ifeq ($(TC_CONFIG_ATM),y)
diff --git a/tc/q_arl.c b/tc/q_arl.c
new file mode 100644
index 00000000..4ba63a99
--- /dev/null
+++ b/tc/q_arl.c
@@ -0,0 +1,232 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Copyright 2018 Google LLC.
+ * Author: Kan Yan <kyan@google.com>
+ *
+ */
+
+#include <stdio.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+static const char * const arl_state_names[] = {
+ "STABLE",
+ "DRAIN",
+ "BW_PROBE",
+ "LATENCY_PROBE",
+ "UNTHROTTLED",
+ "UNDEFINED",
+};
+
+static void explain(void)
+{
+ fprintf(stderr, "Usage: ... arl [ limit PACKETS] [ buffer TIME ]");
+ fprintf(stderr, " [ minrate KBPS ] [ maxbw KBPS ]\n");
+ fprintf(stderr, " [ latency TIME ] ");
+ fprintf(stderr, "[ latency_hysteresis TIME ]\n");
+ fprintf(stderr, "[ codel_target TIME ]\n");
+ fprintf(stderr, "[ ingress ]\n");
+}
+
+static int arl_parse_opt(struct qdisc_util *qu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ unsigned int buffer = 0, limit = 0, latency = 0, latency_hysteresis = 0,
+ mode = 0, codel_target = 0;
+ __u64 min_rate = 0, max_bw = 0;
+ struct rtattr *tail;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "buffer") == 0) {
+ NEXT_ARG();
+ if (get_time(&buffer, *argv)) {
+ fprintf(stderr, "Illegal \"buffer\"\n");
+ return -1;
+ }
+ } else if (strcmp(*argv, "minrate") == 0) {
+ NEXT_ARG();
+ if (get_rate64(&min_rate, *argv)) {
+ fprintf(stderr, "Illegal \"minrate\"\n");
+ return -1;
+ }
+ } else if (strcmp(*argv, "maxbw") == 0) {
+ NEXT_ARG();
+ if (get_rate64(&max_bw, *argv)) {
+ fprintf(stderr, "Illegal \"max_bw\"\n");
+ return -1;
+ }
+ } else if (strcmp(*argv, "limit") == 0) {
+ NEXT_ARG();
+ if (get_unsigned(&limit, *argv, 0)) {
+ fprintf(stderr, "Illegal \"limit\"\n");
+ return -1;
+ }
+ } else if (strcmp(*argv, "latency") == 0) {
+ NEXT_ARG();
+ if (get_time(&latency, *argv)) {
+ fprintf(stderr, "Illegal \"latency\"\n");
+ return -1;
+ }
+ } else if (strcmp(*argv, "latency_hysteresis") == 0) {
+ NEXT_ARG();
+ if (get_time(&latency_hysteresis, *argv)) {
+ fprintf(stderr,
+ "Illegal \"latency hysteresis\"\n");
+ return -1;
+ }
+ } else if (strcmp(*argv, "codel_target") == 0) {
+ NEXT_ARG();
+ if (get_time(&codel_target, *argv)) {
+ fprintf(stderr, "Illegal \"codel_target\"\n");
+ return -1;
+ }
+ } else if (strcmp(*argv, "ingress") == 0) {
+ mode = 1;
+ } else if (strcmp(*argv, "help") == 0) {
+ explain();
+ return -1;
+ } else {
+ fprintf(stderr, "arl: unknown parameter \"%s\"\n",
+ *argv);
+ explain();
+ return -1;
+ }
+ argc--; argv++;
+ }
+
+ tail = NLMSG_TAIL(n);
+ addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+ if (buffer)
+ addattr_l(n, 1024, TCA_ARL_BUFFER, &buffer, sizeof(__u32));
+ if (min_rate)
+ addattr_l(n, 1024, TCA_ARL_MIN_RATE, &min_rate, sizeof(__u64));
+ if (max_bw)
+ addattr_l(n, 1024, TCA_ARL_MAX_BW, &max_bw, sizeof(__u64));
+ if (limit)
+ addattr_l(n, 1024, TCA_ARL_LIMIT, &limit, sizeof(__u32));
+ if (latency)
+ addattr_l(n, 1024, TCA_ARL_MAX_LATENCY, &latency,
+ sizeof(__u32));
+ if (latency_hysteresis)
+ addattr_l(n, 1024, TCA_ARL_LATENCY_HYSTERESIS,
+ &latency_hysteresis, sizeof(__u32));
+ if (codel_target)
+ addattr_l(n, 1024, TCA_ARL_CODEL_TARGET, &codel_target,
+ sizeof(__u32));
+ if (mode)
+ addattr_l(n, 1024, TCA_ARL_MODE, &mode, sizeof(__u32));
+
+ tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+ return 0;
+}
+
+static int arl_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
+{
+ unsigned int buffer, limit, latency, latency_hysteresis, mode,
+ codel_target;
+ __u64 min_rate = 0, max_bw;
+ struct rtattr *tb[TCA_ARL_MAX + 1];
+
+ SPRINT_BUF(b1);
+
+ if (opt == NULL)
+ return 0;
+
+ parse_rtattr_nested(tb, TCA_ARL_MAX, opt);
+ if (tb[TCA_ARL_MIN_RATE] &&
+ RTA_PAYLOAD(tb[TCA_ARL_MIN_RATE]) >= sizeof(__u64)) {
+ min_rate = rta_getattr_u64(tb[TCA_ARL_MIN_RATE]);
+ fprintf(f, "minrate %s ", sprint_rate(min_rate, b1));
+ }
+
+ if (tb[TCA_ARL_BUFFER] &&
+ RTA_PAYLOAD(tb[TCA_ARL_BUFFER]) >= sizeof(__u32)) {
+ buffer = rta_getattr_u32(tb[TCA_ARL_BUFFER]);
+ fprintf(f, "buffer %s ", sprint_time(buffer, b1));
+ }
+
+ if (tb[TCA_ARL_MAX_BW] &&
+ RTA_PAYLOAD(tb[TCA_ARL_MAX_BW]) >= sizeof(__u64)) {
+ max_bw = rta_getattr_u64(tb[TCA_ARL_MAX_BW]);
+ fprintf(f, "max_bw %s ", sprint_rate(max_bw, b1));
+ }
+
+ if (tb[TCA_ARL_LIMIT] &&
+ RTA_PAYLOAD(tb[TCA_ARL_LIMIT]) >= sizeof(__u32)) {
+ limit = rta_getattr_u32(tb[TCA_ARL_LIMIT]);
+ fprintf(f, "limit %u ", limit);
+ }
+
+ if (tb[TCA_ARL_MAX_LATENCY] &&
+ RTA_PAYLOAD(tb[TCA_ARL_MAX_LATENCY]) >= sizeof(__u32)) {
+ latency = rta_getattr_u32(tb[TCA_ARL_MAX_LATENCY]);
+ fprintf(f, "latency %s ", sprint_time(latency, b1));
+ }
+
+ if (tb[TCA_ARL_LATENCY_HYSTERESIS] &&
+ RTA_PAYLOAD(tb[TCA_ARL_LATENCY_HYSTERESIS]) >= sizeof(__u32)) {
+ latency_hysteresis =
+ rta_getattr_u32(tb[TCA_ARL_LATENCY_HYSTERESIS]);
+ fprintf(f, "latency_hysteresis %s ",
+ sprint_time(latency_hysteresis, b1));
+ }
+
+ if (tb[TCA_ARL_CODEL_TARGET] &&
+ RTA_PAYLOAD(tb[TCA_ARL_CODEL_TARGET]) >= sizeof(__u32)) {
+ codel_target = rta_getattr_u32(tb[TCA_ARL_CODEL_TARGET]);
+ fprintf(f, "codel_target %s ", sprint_time(codel_target, b1));
+ }
+
+ if (tb[TCA_ARL_MODE] &&
+ RTA_PAYLOAD(tb[TCA_ARL_MODE]) >= sizeof(__u32)) {
+ mode = rta_getattr_u32(tb[TCA_ARL_MODE]);
+ if (mode)
+ fprintf(f, "mode ingress");
+ else
+ fprintf(f, "mode egress");
+ }
+
+ return 0;
+}
+
+static int arl_print_xstats(struct qdisc_util *qu, FILE *f,
+ struct rtattr *xstats)
+{
+ struct tc_arl_xstats *st;
+
+ if (xstats == NULL)
+ return 0;
+
+ if (RTA_PAYLOAD(xstats) < sizeof(*st))
+ return -1;
+
+ st = RTA_DATA(xstats);
+
+ fprintf(f, "state %s base_rate %uKbit current_rate %uKbit latency %uus bw %uKbit",
+ arl_state_names[st->state], st->base_rate, st->current_rate,
+ st->latency, st->current_bw);
+ if (st->max_bw)
+ fprintf(f, " max_bw %uKbit", st->max_bw);
+
+ if (st->min_rate)
+ fprintf(f, " min_base_rate %uKbit", st->min_rate);
+
+ return 0;
+}
+
+struct qdisc_util arl_qdisc_util = {
+ .id = "arl",
+ .parse_qopt = arl_parse_opt,
+ .print_qopt = arl_print_opt,
+ .print_xstats = arl_print_xstats,
+};
--
2.21.0