diff options
author | David Ahern <dsahern@kernel.org> | 2023-12-06 16:52:47 +0000 |
---|---|---|
committer | David Ahern <dsahern@kernel.org> | 2023-12-06 16:52:47 +0000 |
commit | 89b99cd67fa8e93d2d917d4972781702af775c20 (patch) | |
tree | 4f0010a7f92ba321e72b487f474eec7c24377020 | |
parent | f441c022218f6a3526e0bd5140229ea2919ee35c (diff) | |
parent | 3086a339f681a1abd4f6717e3d7f348515c74761 (diff) | |
download | iproute2-89b99cd67fa8e93d2d917d4972781702af775c20.tar.gz |
Merge branch 'tcp-usec-fq' into next
Eric Dumazet says:
====================
Add iproute2 patches to support recent TCP usec timestamps,
and FQ changes landed in linux-6.7
====================
Signed-off-by: David Ahern <dsahern@kernel.org>
-rw-r--r-- | ip/iproute.c | 7 | ||||
-rw-r--r-- | misc/ss.c | 4 | ||||
-rw-r--r-- | tc/q_fq.c | 127 |
3 files changed, 137 insertions, 1 deletions
diff --git a/ip/iproute.c b/ip/iproute.c index fdf1f9a9d..73dbab48a 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -351,6 +351,11 @@ static void print_rtax_features(FILE *fp, unsigned int features) features &= ~RTAX_FEATURE_ECN; } + if (features & RTAX_FEATURE_TCP_USEC_TS) { + print_null(PRINT_ANY, "tcp_usec_ts", "tcp_usec_ts ", NULL); + features &= ~RTAX_FEATURE_TCP_USEC_TS; + } + if (features) print_0xhex(PRINT_ANY, "features", "%#llx ", of); @@ -1349,6 +1354,8 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv) if (strcmp(*argv, "ecn") == 0) features |= RTAX_FEATURE_ECN; + else if (strcmp(*argv, "tcp_usec_ts") == 0) + features |= RTAX_FEATURE_TCP_USEC_TS; else invarg("\"features\" value not valid\n", *argv); break; @@ -875,6 +875,7 @@ struct tcpstat { unsigned long long bytes_sent; unsigned long long bytes_retrans; bool has_ts_opt; + bool has_usec_ts_opt; bool has_sack_opt; bool has_ecn_opt; bool has_ecnseen_opt; @@ -2562,6 +2563,8 @@ static void tcp_stats_print(struct tcpstat *s) if (s->has_ts_opt) out(" ts"); + if (s->has_usec_ts_opt) + out(" usec_ts"); if (s->has_sack_opt) out(" sack"); if (s->has_ecn_opt) @@ -3037,6 +3040,7 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, if (show_options) { s.has_ts_opt = TCPI_HAS_OPT(info, TCPI_OPT_TIMESTAMPS); + s.has_usec_ts_opt = TCPI_HAS_OPT(info, TCPI_OPT_USEC_TS); s.has_sack_opt = TCPI_HAS_OPT(info, TCPI_OPT_SACK); s.has_ecn_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN); s.has_ecnseen_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN_SEEN); @@ -25,6 +25,8 @@ static void explain(void) " [ quantum BYTES ] [ initial_quantum BYTES ]\n" " [ maxrate RATE ] [ buckets NUMBER ]\n" " [ [no]pacing ] [ refill_delay TIME ]\n" + " [ bands 3 priomap P0 P1 ... P14 P15 ]\n" + " [ weights W1 W2 W3 ]\n" " [ low_rate_threshold RATE ]\n" " [ orphan_mask MASK]\n" " [ timer_slack TIME]\n" @@ -48,6 +50,7 @@ static unsigned int ilog2(unsigned int val) static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n, const char *dev) { + struct tc_prio_qopt prio2band; unsigned int plimit; unsigned int flow_plimit; unsigned int quantum; @@ -74,6 +77,9 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv, bool set_ce_threshold = false; bool set_timer_slack = false; bool set_horizon = false; + bool set_priomap = false; + bool set_weights = false; + int weights[FQ_BANDS]; int pacing = -1; struct rtattr *tail; @@ -193,6 +199,75 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv, pacing = 1; } else if (strcmp(*argv, "nopacing") == 0) { pacing = 0; + } else if (strcmp(*argv, "bands") == 0) { + int idx; + + if (set_priomap) { + fprintf(stderr, "Duplicate \"bands\"\n"); + return -1; + } + memset(&prio2band, 0, sizeof(prio2band)); + NEXT_ARG(); + if (get_integer(&prio2band.bands, *argv, 10)) { + fprintf(stderr, "Illegal \"bands\"\n"); + return -1; + } + if (prio2band.bands != 3) { + fprintf(stderr, "\"bands\" must be 3\n"); + return -1; + } + NEXT_ARG(); + if (strcmp(*argv, "priomap") != 0) { + fprintf(stderr, "\"priomap\" expected\n"); + return -1; + } + for (idx = 0; idx <= TC_PRIO_MAX; ++idx) { + unsigned band; + + if (!NEXT_ARG_OK()) { + fprintf(stderr, "Not enough elements in priomap\n"); + return -1; + } + NEXT_ARG(); + if (get_unsigned(&band, *argv, 10)) { + fprintf(stderr, "Illegal \"priomap\" element, number in [0..%u] expected\n", + prio2band.bands - 1); + return -1; + } + if (band >= prio2band.bands) { + fprintf(stderr, "\"priomap\" element %u too big\n", band); + return -1; + } + prio2band.priomap[idx] = band; + } + set_priomap = true; + } else if (strcmp(*argv, "weights") == 0) { + int idx; + + if (set_weights) { + fprintf(stderr, "Duplicate \"weights\"\n"); + return -1; + } + NEXT_ARG(); + for (idx = 0; idx < FQ_BANDS; ++idx) { + int val; + + if (!NEXT_ARG_OK()) { + fprintf(stderr, "Not enough elements in weights\n"); + return -1; + } + NEXT_ARG(); + if (get_integer(&val, *argv, 10)) { + fprintf(stderr, "Illegal \"weights\" element, positive number expected\n"); + return -1; + } + if (val < FQ_MIN_WEIGHT) { + fprintf(stderr, "\"weight\" element %d too small\n", val); + return -1; + } + weights[idx] = val; + } + set_weights = true; } else if (strcmp(*argv, "help") == 0) { explain(); return -1; @@ -252,6 +327,12 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv, if (horizon_drop != 255) addattr_l(n, 1024, TCA_FQ_HORIZON_DROP, &horizon_drop, sizeof(horizon_drop)); + if (set_priomap) + addattr_l(n, 1024, TCA_FQ_PRIOMAP, + &prio2band, sizeof(prio2band)); + if (set_weights) + addattr_l(n, 1024, TCA_FQ_WEIGHTS, + weights, sizeof(weights)); addattr_nest_end(n, tail); return 0; } @@ -306,6 +387,27 @@ static int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (pacing == 0) print_bool(PRINT_ANY, "pacing", "nopacing ", false); } + if (tb[TCA_FQ_PRIOMAP] && + RTA_PAYLOAD(tb[TCA_FQ_PRIOMAP]) >= sizeof(struct tc_prio_qopt)) { + struct tc_prio_qopt *prio2band = RTA_DATA(tb[TCA_FQ_PRIOMAP]); + int i; + + print_uint(PRINT_ANY, "bands", "bands %u ", prio2band->bands); + open_json_array(PRINT_ANY, "priomap "); + for (i = 0; i <= TC_PRIO_MAX; i++) + print_uint(PRINT_ANY, NULL, "%d ", prio2band->priomap[i]); + close_json_array(PRINT_ANY, ""); + } + if (tb[TCA_FQ_WEIGHTS] && + RTA_PAYLOAD(tb[TCA_FQ_WEIGHTS]) >= FQ_BANDS * sizeof(int)) { + const int *weights = RTA_DATA(tb[TCA_FQ_WEIGHTS]); + int i; + + open_json_array(PRINT_ANY, "weights "); + for (i = 0; i < FQ_BANDS; ++i) + print_uint(PRINT_ANY, NULL, "%d ", weights[i]); + close_json_array(PRINT_ANY, ""); + } if (tb[TCA_FQ_QUANTUM] && RTA_PAYLOAD(tb[TCA_FQ_QUANTUM]) >= sizeof(__u32)) { quantum = rta_getattr_u32(tb[TCA_FQ_QUANTUM]); @@ -408,6 +510,10 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f, print_uint(PRINT_ANY, "throttled", " throttled %u)", st->throttled_flows); + print_uint(PRINT_ANY, "band0_pkts", " band0_pkts %u", st->band_pkt_count[0]); + print_uint(PRINT_ANY, "band1_pkts", " band1_pkts %u", st->band_pkt_count[1]); + print_uint(PRINT_ANY, "band2_pkts", " band2_pkts %u", st->band_pkt_count[2]); + if (st->time_next_delayed_flow > 0) { print_lluint(PRINT_JSON, "next_packet_delay", NULL, st->time_next_delayed_flow); @@ -420,6 +526,10 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f, print_lluint(PRINT_ANY, "highprio", " highprio %llu", st->highprio_packets); + if (st->fastpath_packets) + print_lluint(PRINT_ANY, "fastpath", " fastpath %llu", + st->fastpath_packets); + if (st->tcp_retrans) print_lluint(PRINT_ANY, "retrans", " retrans %llu", st->tcp_retrans); @@ -442,7 +552,10 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f, st->flows_plimit); if (st->pkts_too_long || st->allocation_errors || - st->horizon_drops || st->horizon_caps) { + st->horizon_drops || st->horizon_caps || + st->band_drops[0] || + st->band_drops[1] || + st->band_drops[2]) { print_nl(); if (st->pkts_too_long) print_lluint(PRINT_ANY, "pkts_too_long", @@ -460,6 +573,18 @@ static int fq_print_xstats(struct qdisc_util *qu, FILE *f, print_lluint(PRINT_ANY, "horizon_caps", " horizon_caps %llu", st->horizon_caps); + if (st->band_drops[0]) + print_lluint(PRINT_ANY, "band0_drops", + " band0_drops %llu", + st->band_drops[0]); + if (st->band_drops[1]) + print_lluint(PRINT_ANY, "band1_drops", + " band1_drops %llu", + st->band_drops[1]); + if (st->band_drops[2]) + print_lluint(PRINT_ANY, "band2_drops", + " band2_drops %llu", + st->band_drops[2]); } return 0; |