Skip to content

Commit 4620940

Browse files
jpirkodavem330
authored andcommitted
net: core: introduce mini_Qdisc and eliminate usage of tp->q for clsact fastpath
In sch_handle_egress and sch_handle_ingress tp->q is used only in order to update stats. So stats and filter list are the only things that are needed in clsact qdisc fastpath processing. Introduce new mini_Qdisc struct to hold those items. Also, introduce a helper to swap the mini_Qdisc structures in case filter list head changes. This removes need for tp->q usage without added overhead. Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c7eb7d7 commit 4620940

File tree

5 files changed

+109
-18
lines changed

5 files changed

+109
-18
lines changed

include/linux/netdevice.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,8 @@ enum netdev_priv_flags {
15591559
*
15601560
* @rx_handler: handler for received packets
15611561
* @rx_handler_data: XXX: need comments on this one
1562+
* @miniq_ingress: ingress/clsact qdisc specific data for
1563+
* ingress processing
15621564
* @ingress_queue: XXX: need comments on this one
15631565
* @broadcast: hw bcast address
15641566
*
@@ -1576,7 +1578,8 @@ enum netdev_priv_flags {
15761578
* @tx_global_lock: XXX: need comments on this one
15771579
*
15781580
* @xps_maps: XXX: need comments on this one
1579-
*
1581+
* @miniq_egress: clsact qdisc specific data for
1582+
* egress processing
15801583
* @watchdog_timeo: Represents the timeout that is used by
15811584
* the watchdog (see dev_watchdog())
15821585
* @watchdog_timer: List of timers
@@ -1795,7 +1798,7 @@ struct net_device {
17951798
void __rcu *rx_handler_data;
17961799

17971800
#ifdef CONFIG_NET_CLS_ACT
1798-
struct tcf_proto __rcu *ingress_cl_list;
1801+
struct mini_Qdisc __rcu *miniq_ingress;
17991802
#endif
18001803
struct netdev_queue __rcu *ingress_queue;
18011804
#ifdef CONFIG_NETFILTER_INGRESS
@@ -1826,7 +1829,7 @@ struct net_device {
18261829
struct xps_dev_maps __rcu *xps_maps;
18271830
#endif
18281831
#ifdef CONFIG_NET_CLS_ACT
1829-
struct tcf_proto __rcu *egress_cl_list;
1832+
struct mini_Qdisc __rcu *miniq_egress;
18301833
#endif
18311834

18321835
/* These may be needed for future network-power-down code. */

include/net/sch_generic.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,4 +904,36 @@ static inline void psched_ratecfg_getrate(struct tc_ratespec *res,
904904
res->linklayer = (r->linklayer & TC_LINKLAYER_MASK);
905905
}
906906

907+
/* Mini Qdisc serves for specific needs of ingress/clsact Qdisc.
908+
* The fast path only needs to access filter list and to update stats
909+
*/
910+
struct mini_Qdisc {
911+
struct tcf_proto *filter_list;
912+
struct gnet_stats_basic_cpu __percpu *cpu_bstats;
913+
struct gnet_stats_queue __percpu *cpu_qstats;
914+
struct rcu_head rcu;
915+
};
916+
917+
static inline void mini_qdisc_bstats_cpu_update(struct mini_Qdisc *miniq,
918+
const struct sk_buff *skb)
919+
{
920+
bstats_cpu_update(this_cpu_ptr(miniq->cpu_bstats), skb);
921+
}
922+
923+
static inline void mini_qdisc_qstats_cpu_drop(struct mini_Qdisc *miniq)
924+
{
925+
this_cpu_inc(miniq->cpu_qstats->drops);
926+
}
927+
928+
struct mini_Qdisc_pair {
929+
struct mini_Qdisc miniq1;
930+
struct mini_Qdisc miniq2;
931+
struct mini_Qdisc __rcu **p_miniq;
932+
};
933+
934+
void mini_qdisc_pair_swap(struct mini_Qdisc_pair *miniqp,
935+
struct tcf_proto *tp_head);
936+
void mini_qdisc_pair_init(struct mini_Qdisc_pair *miniqp, struct Qdisc *qdisc,
937+
struct mini_Qdisc __rcu **p_miniq);
938+
907939
#endif

net/core/dev.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3274,22 +3274,22 @@ EXPORT_SYMBOL(dev_loopback_xmit);
32743274
static struct sk_buff *
32753275
sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
32763276
{
3277-
struct tcf_proto *cl = rcu_dereference_bh(dev->egress_cl_list);
3277+
struct mini_Qdisc *miniq = rcu_dereference_bh(dev->miniq_egress);
32783278
struct tcf_result cl_res;
32793279

3280-
if (!cl)
3280+
if (!miniq)
32813281
return skb;
32823282

32833283
/* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */
3284-
qdisc_bstats_cpu_update(cl->q, skb);
3284+
mini_qdisc_bstats_cpu_update(miniq, skb);
32853285

3286-
switch (tcf_classify(skb, cl, &cl_res, false)) {
3286+
switch (tcf_classify(skb, miniq->filter_list, &cl_res, false)) {
32873287
case TC_ACT_OK:
32883288
case TC_ACT_RECLASSIFY:
32893289
skb->tc_index = TC_H_MIN(cl_res.classid);
32903290
break;
32913291
case TC_ACT_SHOT:
3292-
qdisc_qstats_cpu_drop(cl->q);
3292+
mini_qdisc_qstats_cpu_drop(miniq);
32933293
*ret = NET_XMIT_DROP;
32943294
kfree_skb(skb);
32953295
return NULL;
@@ -4189,32 +4189,33 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
41894189
struct net_device *orig_dev)
41904190
{
41914191
#ifdef CONFIG_NET_CLS_ACT
4192-
struct tcf_proto *cl = rcu_dereference_bh(skb->dev->ingress_cl_list);
4192+
struct mini_Qdisc *miniq = rcu_dereference_bh(skb->dev->miniq_ingress);
41934193
struct tcf_result cl_res;
41944194

41954195
/* If there's at least one ingress present somewhere (so
41964196
* we get here via enabled static key), remaining devices
41974197
* that are not configured with an ingress qdisc will bail
41984198
* out here.
41994199
*/
4200-
if (!cl)
4200+
if (!miniq)
42014201
return skb;
4202+
42024203
if (*pt_prev) {
42034204
*ret = deliver_skb(skb, *pt_prev, orig_dev);
42044205
*pt_prev = NULL;
42054206
}
42064207

42074208
qdisc_skb_cb(skb)->pkt_len = skb->len;
42084209
skb->tc_at_ingress = 1;
4209-
qdisc_bstats_cpu_update(cl->q, skb);
4210+
mini_qdisc_bstats_cpu_update(miniq, skb);
42104211

4211-
switch (tcf_classify(skb, cl, &cl_res, false)) {
4212+
switch (tcf_classify(skb, miniq->filter_list, &cl_res, false)) {
42124213
case TC_ACT_OK:
42134214
case TC_ACT_RECLASSIFY:
42144215
skb->tc_index = TC_H_MIN(cl_res.classid);
42154216
break;
42164217
case TC_ACT_SHOT:
4217-
qdisc_qstats_cpu_drop(cl->q);
4218+
mini_qdisc_qstats_cpu_drop(miniq);
42184219
kfree_skb(skb);
42194220
return NULL;
42204221
case TC_ACT_STOLEN:

net/sched/sch_generic.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,3 +1024,49 @@ void psched_ratecfg_precompute(struct psched_ratecfg *r,
10241024
}
10251025
}
10261026
EXPORT_SYMBOL(psched_ratecfg_precompute);
1027+
1028+
static void mini_qdisc_rcu_func(struct rcu_head *head)
1029+
{
1030+
}
1031+
1032+
void mini_qdisc_pair_swap(struct mini_Qdisc_pair *miniqp,
1033+
struct tcf_proto *tp_head)
1034+
{
1035+
struct mini_Qdisc *miniq_old = rtnl_dereference(*miniqp->p_miniq);
1036+
struct mini_Qdisc *miniq;
1037+
1038+
if (!tp_head) {
1039+
RCU_INIT_POINTER(*miniqp->p_miniq, NULL);
1040+
return;
1041+
}
1042+
1043+
miniq = !miniq_old || miniq_old == &miniqp->miniq2 ?
1044+
&miniqp->miniq1 : &miniqp->miniq2;
1045+
1046+
/* We need to make sure that readers won't see the miniq
1047+
* we are about to modify. So wait until previous call_rcu_bh callback
1048+
* is done.
1049+
*/
1050+
rcu_barrier_bh();
1051+
miniq->filter_list = tp_head;
1052+
rcu_assign_pointer(*miniqp->p_miniq, miniq);
1053+
1054+
if (miniq_old)
1055+
/* This is counterpart of the rcu barrier above. We need to
1056+
* block potential new user of miniq_old until all readers
1057+
* are not seeing it.
1058+
*/
1059+
call_rcu_bh(&miniq_old->rcu, mini_qdisc_rcu_func);
1060+
}
1061+
EXPORT_SYMBOL(mini_qdisc_pair_swap);
1062+
1063+
void mini_qdisc_pair_init(struct mini_Qdisc_pair *miniqp, struct Qdisc *qdisc,
1064+
struct mini_Qdisc __rcu **p_miniq)
1065+
{
1066+
miniqp->miniq1.cpu_bstats = qdisc->cpu_bstats;
1067+
miniqp->miniq1.cpu_qstats = qdisc->cpu_qstats;
1068+
miniqp->miniq2.cpu_bstats = qdisc->cpu_bstats;
1069+
miniqp->miniq2.cpu_qstats = qdisc->cpu_qstats;
1070+
miniqp->p_miniq = p_miniq;
1071+
}
1072+
EXPORT_SYMBOL(mini_qdisc_pair_init);

net/sched/sch_ingress.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
struct ingress_sched_data {
2222
struct tcf_block *block;
2323
struct tcf_block_ext_info block_info;
24+
struct mini_Qdisc_pair miniqp;
2425
};
2526

2627
static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
@@ -56,9 +57,9 @@ static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl)
5657

5758
static void clsact_chain_head_change(struct tcf_proto *tp_head, void *priv)
5859
{
59-
struct tcf_proto __rcu **p_filter_chain = priv;
60+
struct mini_Qdisc_pair *miniqp = priv;
6061

61-
rcu_assign_pointer(*p_filter_chain, tp_head);
62+
mini_qdisc_pair_swap(miniqp, tp_head);
6263
}
6364

6465
static int ingress_init(struct Qdisc *sch, struct nlattr *opt)
@@ -67,9 +68,11 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt)
6768
struct net_device *dev = qdisc_dev(sch);
6869
int err;
6970

71+
mini_qdisc_pair_init(&q->miniqp, sch, &dev->miniq_ingress);
72+
7073
q->block_info.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
7174
q->block_info.chain_head_change = clsact_chain_head_change;
72-
q->block_info.chain_head_change_priv = &dev->ingress_cl_list;
75+
q->block_info.chain_head_change_priv = &q->miniqp;
7376

7477
err = tcf_block_get_ext(&q->block, sch, &q->block_info);
7578
if (err)
@@ -128,6 +131,8 @@ struct clsact_sched_data {
128131
struct tcf_block *egress_block;
129132
struct tcf_block_ext_info ingress_block_info;
130133
struct tcf_block_ext_info egress_block_info;
134+
struct mini_Qdisc_pair miniqp_ingress;
135+
struct mini_Qdisc_pair miniqp_egress;
131136
};
132137

133138
static unsigned long clsact_find(struct Qdisc *sch, u32 classid)
@@ -167,17 +172,21 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt)
167172
struct net_device *dev = qdisc_dev(sch);
168173
int err;
169174

175+
mini_qdisc_pair_init(&q->miniqp_ingress, sch, &dev->miniq_ingress);
176+
170177
q->ingress_block_info.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
171178
q->ingress_block_info.chain_head_change = clsact_chain_head_change;
172-
q->ingress_block_info.chain_head_change_priv = &dev->ingress_cl_list;
179+
q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
173180

174181
err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info);
175182
if (err)
176183
return err;
177184

185+
mini_qdisc_pair_init(&q->miniqp_egress, sch, &dev->miniq_egress);
186+
178187
q->egress_block_info.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
179188
q->egress_block_info.chain_head_change = clsact_chain_head_change;
180-
q->egress_block_info.chain_head_change_priv = &dev->egress_cl_list;
189+
q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
181190

182191
err = tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info);
183192
if (err)

0 commit comments

Comments
 (0)