aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@kernel.org>2023-12-06 16:52:47 +0000
committerDavid Ahern <dsahern@kernel.org>2023-12-06 16:52:47 +0000
commit89b99cd67fa8e93d2d917d4972781702af775c20 (patch)
tree4f0010a7f92ba321e72b487f474eec7c24377020
parentf441c022218f6a3526e0bd5140229ea2919ee35c (diff)
parent3086a339f681a1abd4f6717e3d7f348515c74761 (diff)
downloadiproute2-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.c7
-rw-r--r--misc/ss.c4
-rw-r--r--tc/q_fq.c127
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;
diff --git a/misc/ss.c b/misc/ss.c
index 9438382b8..3dacee48d 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -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);
diff --git a/tc/q_fq.c b/tc/q_fq.c
index 3277ebc7c..7f8a2b80d 100644
--- a/tc/q_fq.c
+++ b/tc/q_fq.c
@@ -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;