Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: sched: sch_red: Add qevents "early_drop" and "mark"

In order to allow acting on dropped and/or ECN-marked packets, add two new
qevents to the RED qdisc: "early_drop" and "mark". Filters attached at
"early_drop" block are executed as packets are early-dropped, those
attached at the "mark" block are executed as packets are ECN-marked.

Two new attributes are introduced: TCA_RED_EARLY_DROP_BLOCK with the block
index for the "early_drop" qevent, and TCA_RED_MARK_BLOCK for the "mark"
qevent. Absence of these attributes signifies "don't care": no block is
allocated in that case, or the existing blocks are left intact in case of
the change callback.

For purposes of offloading, blocks attached to these qevents appear with
newly-introduced binder types, FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP and
FLOW_BLOCK_BINDER_TYPE_RED_MARK.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Petr Machata and committed by
David S. Miller
aee9caa0 65545ea2

+60 -2
+2
include/net/flow_offload.h
··· 424 424 FLOW_BLOCK_BINDER_TYPE_UNSPEC, 425 425 FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS, 426 426 FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS, 427 + FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP, 428 + FLOW_BLOCK_BINDER_TYPE_RED_MARK, 427 429 }; 428 430 429 431 struct flow_block {
+2
include/uapi/linux/pkt_sched.h
··· 257 257 TCA_RED_STAB, 258 258 TCA_RED_MAX_P, 259 259 TCA_RED_FLAGS, /* bitfield32 */ 260 + TCA_RED_EARLY_DROP_BLOCK, /* u32 */ 261 + TCA_RED_MARK_BLOCK, /* u32 */ 260 262 __TCA_RED_MAX, 261 263 }; 262 264
+56 -2
net/sched/sch_red.c
··· 46 46 struct red_vars vars; 47 47 struct red_stats stats; 48 48 struct Qdisc *qdisc; 49 + struct tcf_qevent qe_early_drop; 50 + struct tcf_qevent qe_mark; 49 51 }; 50 52 51 53 #define TC_RED_SUPPORTED_FLAGS (TC_RED_HISTORIC_FLAGS | TC_RED_NODROP) ··· 94 92 95 93 if (INET_ECN_set_ce(skb)) { 96 94 q->stats.prob_mark++; 95 + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, root_lock, to_free, &ret); 96 + if (!skb) 97 + return NET_XMIT_CN | ret; 97 98 } else if (!red_use_nodrop(q)) { 98 99 q->stats.prob_drop++; 99 100 goto congestion_drop; ··· 114 109 115 110 if (INET_ECN_set_ce(skb)) { 116 111 q->stats.forced_mark++; 112 + skb = tcf_qevent_handle(&q->qe_mark, sch, skb, root_lock, to_free, &ret); 113 + if (!skb) 114 + return NET_XMIT_CN | ret; 117 115 } else if (!red_use_nodrop(q)) { 118 116 q->stats.forced_drop++; 119 117 goto congestion_drop; ··· 137 129 return ret; 138 130 139 131 congestion_drop: 132 + skb = tcf_qevent_handle(&q->qe_early_drop, sch, skb, root_lock, to_free, &ret); 133 + if (!skb) 134 + return NET_XMIT_CN | ret; 135 + 140 136 qdisc_drop(skb, sch, to_free); 141 137 return NET_XMIT_CN; 142 138 } ··· 214 202 { 215 203 struct red_sched_data *q = qdisc_priv(sch); 216 204 205 + tcf_qevent_destroy(&q->qe_mark, sch); 206 + tcf_qevent_destroy(&q->qe_early_drop, sch); 217 207 del_timer_sync(&q->adapt_timer); 218 208 red_offload(sch, false); 219 209 qdisc_put(q->qdisc); ··· 227 213 [TCA_RED_STAB] = { .len = RED_STAB_SIZE }, 228 214 [TCA_RED_MAX_P] = { .type = NLA_U32 }, 229 215 [TCA_RED_FLAGS] = NLA_POLICY_BITFIELD32(TC_RED_SUPPORTED_FLAGS), 216 + [TCA_RED_EARLY_DROP_BLOCK] = { .type = NLA_U32 }, 217 + [TCA_RED_MARK_BLOCK] = { .type = NLA_U32 }, 230 218 }; 231 219 232 220 static int __red_change(struct Qdisc *sch, struct nlattr **tb, ··· 344 328 q->qdisc = &noop_qdisc; 345 329 q->sch = sch; 346 330 timer_setup(&q->adapt_timer, red_adaptative_timer, 0); 347 - return __red_change(sch, tb, extack); 331 + 332 + err = __red_change(sch, tb, extack); 333 + if (err) 334 + return err; 335 + 336 + err = tcf_qevent_init(&q->qe_early_drop, sch, 337 + FLOW_BLOCK_BINDER_TYPE_RED_EARLY_DROP, 338 + tb[TCA_RED_EARLY_DROP_BLOCK], extack); 339 + if (err) 340 + goto err_early_drop_init; 341 + 342 + err = tcf_qevent_init(&q->qe_mark, sch, 343 + FLOW_BLOCK_BINDER_TYPE_RED_MARK, 344 + tb[TCA_RED_MARK_BLOCK], extack); 345 + if (err) 346 + goto err_mark_init; 347 + 348 + return 0; 349 + 350 + err_mark_init: 351 + tcf_qevent_destroy(&q->qe_early_drop, sch); 352 + err_early_drop_init: 353 + del_timer_sync(&q->adapt_timer); 354 + red_offload(sch, false); 355 + qdisc_put(q->qdisc); 356 + return err; 348 357 } 349 358 350 359 static int red_change(struct Qdisc *sch, struct nlattr *opt, 351 360 struct netlink_ext_ack *extack) 352 361 { 362 + struct red_sched_data *q = qdisc_priv(sch); 353 363 struct nlattr *tb[TCA_RED_MAX + 1]; 354 364 int err; 355 365 ··· 385 343 err = nla_parse_nested_deprecated(tb, TCA_RED_MAX, opt, red_policy, 386 344 extack); 387 345 if (err < 0) 346 + return err; 347 + 348 + err = tcf_qevent_validate_change(&q->qe_early_drop, 349 + tb[TCA_RED_EARLY_DROP_BLOCK], extack); 350 + if (err) 351 + return err; 352 + 353 + err = tcf_qevent_validate_change(&q->qe_mark, 354 + tb[TCA_RED_MARK_BLOCK], extack); 355 + if (err) 388 356 return err; 389 357 390 358 return __red_change(sch, tb, extack); ··· 441 389 if (nla_put(skb, TCA_RED_PARMS, sizeof(opt), &opt) || 442 390 nla_put_u32(skb, TCA_RED_MAX_P, q->parms.max_P) || 443 391 nla_put_bitfield32(skb, TCA_RED_FLAGS, 444 - q->flags, TC_RED_SUPPORTED_FLAGS)) 392 + q->flags, TC_RED_SUPPORTED_FLAGS) || 393 + tcf_qevent_dump(skb, TCA_RED_MARK_BLOCK, &q->qe_mark) || 394 + tcf_qevent_dump(skb, TCA_RED_EARLY_DROP_BLOCK, &q->qe_early_drop)) 445 395 goto nla_put_failure; 446 396 return nla_nest_end(skb, opts); 447 397