The "early" qevent matches packets that have been early-dropped. The "mark" qevent matches packets that have been ECN-marked.
Signed-off-by: Petr Machata <pe...@mellanox.com> --- man/man8/tc-red.8 | 18 +++++++++++++++++- tc/q_red.c | 23 ++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/man/man8/tc-red.8 b/man/man8/tc-red.8 index b5aaa986..e74dd330 100644 --- a/man/man8/tc-red.8 +++ b/man/man8/tc-red.8 @@ -17,7 +17,11 @@ packets rate .B ] [ probability chance -.B ] [ adaptive ] +.B ] [ adaptive ] [ qevent early block +index +.B ] [ qevent mark block +index +.B ] .SH DESCRIPTION Random Early Detection is a classless qdisc which manages its queue size @@ -134,6 +138,18 @@ Goal of Adaptive RED is to make 'probability' dynamic value between 1% and 50% t .B (max - min) / 2 .fi +.SH QEVENTS +See tc (8) for some general notes about qevents. The RED qdisc supports the +following qevents: + +.TP +early +The associated block is executed when packets are early-dropped. This includes +non-ECT packets in ECN mode. +.TP +mark +The associated block is executed when packets are marked in ECN mode. + .SH EXAMPLE .P diff --git a/tc/q_red.c b/tc/q_red.c index 53181c82..7e7dfa05 100644 --- a/tc/q_red.c +++ b/tc/q_red.c @@ -22,6 +22,7 @@ #include "utils.h" #include "tc_util.h" +#include "tc_qevent.h" #include "tc_red.h" @@ -30,7 +31,8 @@ static void explain(void) fprintf(stderr, "Usage: ... red limit BYTES [min BYTES] [max BYTES] avpkt BYTES [burst PACKETS]\n" " [adaptive] [probability PROBABILITY] [bandwidth KBPS]\n" - " [ecn] [harddrop] [nodrop]\n"); + " [ecn] [harddrop] [nodrop]\n" + " [qevent early block IDX] [qevent mark block IDX]\n"); } #define RED_SUPPORTED_FLAGS (TC_RED_HISTORIC_FLAGS | TC_RED_NODROP) @@ -38,6 +40,14 @@ static void explain(void) static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) { + struct qevent_plain qe_early = {}; + struct qevent_plain qe_mark = {}; + struct qevent_util qevents[] = { + QEVENT("early", plain, &qe_early), + QEVENT("mark", plain, &qe_mark), + {}, + }; + struct nla_bitfield32 flags_bf = { .selector = RED_SUPPORTED_FLAGS, }; @@ -109,6 +119,11 @@ static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, flags_bf.value |= TC_RED_ADAPTATIVE; } else if (strcmp(*argv, "adaptive") == 0) { flags_bf.value |= TC_RED_ADAPTATIVE; + } else if (matches(*argv, "qevent") == 0) { + NEXT_ARG(); + if (qevent_parse(qevents, &argc, &argv)) + return -1; + continue; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; @@ -162,6 +177,12 @@ static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, max_P = probability * pow(2, 32); addattr_l(n, 1024, TCA_RED_MAX_P, &max_P, sizeof(max_P)); addattr_l(n, 1024, TCA_RED_FLAGS, &flags_bf, sizeof(flags_bf)); + if (qe_early.base.block_idx) + addattr32(n, 1024, TCA_RED_EARLY_BLOCK, + qe_early.base.block_idx); + if (qe_mark.base.block_idx) + addattr32(n, 1024, TCA_RED_MARK_BLOCK, + qe_mark.base.block_idx); addattr_nest_end(n, tail); return 0; } -- 2.20.1