Skip to content

Commit 3b4cf29

Browse files
committed
Merge branch 'net-rps-misc'
Eric Dumazet says: ==================== net: rps: misc changes Make RPS/RFS a bit more efficient with better cache locality and heuristics. Aso shrink include/linux/netdevice.h a bit. v2: fixed a build issue in patch 6/8 with CONFIG_RPS=n (Jakub and kernel build bots) ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents d823265 + d3ae5f4 commit 3b4cf29

File tree

5 files changed

+95
-70
lines changed

5 files changed

+95
-70
lines changed

include/linux/netdevice.h

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,6 +3204,7 @@ struct softnet_data {
32043204
struct softnet_data *rps_ipi_list;
32053205
#endif
32063206

3207+
unsigned int received_rps;
32073208
bool in_net_rx_action;
32083209
bool in_napi_threaded_poll;
32093210

@@ -3236,11 +3237,11 @@ struct softnet_data {
32363237
unsigned int cpu;
32373238
unsigned int input_queue_tail;
32383239
#endif
3239-
unsigned int received_rps;
3240-
unsigned int dropped;
32413240
struct sk_buff_head input_pkt_queue;
32423241
struct napi_struct backlog;
32433242

3243+
atomic_t dropped ____cacheline_aligned_in_smp;
3244+
32443245
/* Another possibly contended cache line */
32453246
spinlock_t defer_lock ____cacheline_aligned_in_smp;
32463247
int defer_count;
@@ -3249,46 +3250,13 @@ struct softnet_data {
32493250
call_single_data_t defer_csd;
32503251
};
32513252

3252-
static inline void input_queue_head_incr(struct softnet_data *sd)
3253-
{
3254-
#ifdef CONFIG_RPS
3255-
sd->input_queue_head++;
3256-
#endif
3257-
}
3258-
3259-
static inline void input_queue_tail_incr_save(struct softnet_data *sd,
3260-
unsigned int *qtail)
3261-
{
3262-
#ifdef CONFIG_RPS
3263-
*qtail = ++sd->input_queue_tail;
3264-
#endif
3265-
}
3266-
32673253
DECLARE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);
32683254

32693255
static inline int dev_recursion_level(void)
32703256
{
32713257
return this_cpu_read(softnet_data.xmit.recursion);
32723258
}
32733259

3274-
#define XMIT_RECURSION_LIMIT 8
3275-
static inline bool dev_xmit_recursion(void)
3276-
{
3277-
return unlikely(__this_cpu_read(softnet_data.xmit.recursion) >
3278-
XMIT_RECURSION_LIMIT);
3279-
}
3280-
3281-
static inline void dev_xmit_recursion_inc(void)
3282-
{
3283-
__this_cpu_inc(softnet_data.xmit.recursion);
3284-
}
3285-
3286-
static inline void dev_xmit_recursion_dec(void)
3287-
{
3288-
__this_cpu_dec(softnet_data.xmit.recursion);
3289-
}
3290-
3291-
void kick_defer_list_purge(struct softnet_data *sd, unsigned int cpu);
32923260
void __netif_schedule(struct Qdisc *q);
32933261
void netif_schedule_queue(struct netdev_queue *txq);
32943262

include/net/rps.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,32 @@ static inline void sock_rps_record_flow(const struct sock *sk)
122122
#endif
123123
}
124124

125+
static inline u32 rps_input_queue_tail_incr(struct softnet_data *sd)
126+
{
127+
#ifdef CONFIG_RPS
128+
return ++sd->input_queue_tail;
129+
#else
130+
return 0;
131+
#endif
132+
}
133+
134+
static inline void rps_input_queue_tail_save(u32 *dest, u32 tail)
135+
{
136+
#ifdef CONFIG_RPS
137+
WRITE_ONCE(*dest, tail);
138+
#endif
139+
}
140+
141+
static inline void rps_input_queue_head_add(struct softnet_data *sd, int val)
142+
{
143+
#ifdef CONFIG_RPS
144+
WRITE_ONCE(sd->input_queue_head, sd->input_queue_head + val);
145+
#endif
146+
}
147+
148+
static inline void rps_input_queue_head_incr(struct softnet_data *sd)
149+
{
150+
rps_input_queue_head_add(sd, 1);
151+
}
152+
125153
#endif /* _NET_RPS_H */

net/core/dev.c

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4528,7 +4528,7 @@ set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
45284528
out:
45294529
#endif
45304530
rflow->last_qtail =
4531-
per_cpu(softnet_data, next_cpu).input_queue_head;
4531+
READ_ONCE(per_cpu(softnet_data, next_cpu).input_queue_head);
45324532
}
45334533

45344534
rflow->cpu = next_cpu;
@@ -4610,8 +4610,8 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
46104610
*/
46114611
if (unlikely(tcpu != next_cpu) &&
46124612
(tcpu >= nr_cpu_ids || !cpu_online(tcpu) ||
4613-
((int)(per_cpu(softnet_data, tcpu).input_queue_head -
4614-
rflow->last_qtail)) >= 0)) {
4613+
((int)(READ_ONCE(per_cpu(softnet_data, tcpu).input_queue_head) -
4614+
READ_ONCE(rflow->last_qtail))) >= 0)) {
46154615
tcpu = next_cpu;
46164616
rflow = set_rps_cpu(dev, skb, rflow, next_cpu);
46174617
}
@@ -4665,8 +4665,8 @@ bool rps_may_expire_flow(struct net_device *dev, u16 rxq_index,
46654665
rflow = &flow_table->flows[flow_id];
46664666
cpu = READ_ONCE(rflow->cpu);
46674667
if (rflow->filter == filter_id && cpu < nr_cpu_ids &&
4668-
((int)(per_cpu(softnet_data, cpu).input_queue_head -
4669-
rflow->last_qtail) <
4668+
((int)(READ_ONCE(per_cpu(softnet_data, cpu).input_queue_head) -
4669+
READ_ONCE(rflow->last_qtail)) <
46704670
(int)(10 * flow_table->mask)))
46714671
expire = false;
46724672
}
@@ -4800,37 +4800,45 @@ static int enqueue_to_backlog(struct sk_buff *skb, int cpu,
48004800
struct softnet_data *sd;
48014801
unsigned long flags;
48024802
unsigned int qlen;
4803+
int max_backlog;
4804+
u32 tail;
48034805

4804-
reason = SKB_DROP_REASON_NOT_SPECIFIED;
4806+
reason = SKB_DROP_REASON_DEV_READY;
4807+
if (!netif_running(skb->dev))
4808+
goto bad_dev;
4809+
4810+
reason = SKB_DROP_REASON_CPU_BACKLOG;
48054811
sd = &per_cpu(softnet_data, cpu);
48064812

4813+
qlen = skb_queue_len_lockless(&sd->input_pkt_queue);
4814+
max_backlog = READ_ONCE(net_hotdata.max_backlog);
4815+
if (unlikely(qlen > max_backlog))
4816+
goto cpu_backlog_drop;
48074817
backlog_lock_irq_save(sd, &flags);
4808-
if (!netif_running(skb->dev))
4809-
goto drop;
48104818
qlen = skb_queue_len(&sd->input_pkt_queue);
4811-
if (qlen <= READ_ONCE(net_hotdata.max_backlog) &&
4812-
!skb_flow_limit(skb, qlen)) {
4813-
if (qlen) {
4814-
enqueue:
4815-
__skb_queue_tail(&sd->input_pkt_queue, skb);
4816-
input_queue_tail_incr_save(sd, qtail);
4817-
backlog_unlock_irq_restore(sd, &flags);
4818-
return NET_RX_SUCCESS;
4819+
if (qlen <= max_backlog && !skb_flow_limit(skb, qlen)) {
4820+
if (!qlen) {
4821+
/* Schedule NAPI for backlog device. We can use
4822+
* non atomic operation as we own the queue lock.
4823+
*/
4824+
if (!__test_and_set_bit(NAPI_STATE_SCHED,
4825+
&sd->backlog.state))
4826+
napi_schedule_rps(sd);
48194827
}
4828+
__skb_queue_tail(&sd->input_pkt_queue, skb);
4829+
tail = rps_input_queue_tail_incr(sd);
4830+
backlog_unlock_irq_restore(sd, &flags);
48204831

4821-
/* Schedule NAPI for backlog device
4822-
* We can use non atomic operation since we own the queue lock
4823-
*/
4824-
if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state))
4825-
napi_schedule_rps(sd);
4826-
goto enqueue;
4832+
/* save the tail outside of the critical section */
4833+
rps_input_queue_tail_save(qtail, tail);
4834+
return NET_RX_SUCCESS;
48274835
}
4828-
reason = SKB_DROP_REASON_CPU_BACKLOG;
48294836

4830-
drop:
4831-
sd->dropped++;
48324837
backlog_unlock_irq_restore(sd, &flags);
48334838

4839+
cpu_backlog_drop:
4840+
atomic_inc(&sd->dropped);
4841+
bad_dev:
48344842
dev_core_stats_rx_dropped_inc(skb->dev);
48354843
kfree_skb_reason(skb, reason);
48364844
return NET_RX_DROP;
@@ -5900,7 +5908,7 @@ static void flush_backlog(struct work_struct *work)
59005908
if (skb->dev->reg_state == NETREG_UNREGISTERING) {
59015909
__skb_unlink(skb, &sd->input_pkt_queue);
59025910
dev_kfree_skb_irq(skb);
5903-
input_queue_head_incr(sd);
5911+
rps_input_queue_head_incr(sd);
59045912
}
59055913
}
59065914
backlog_unlock_irq_enable(sd);
@@ -5909,7 +5917,7 @@ static void flush_backlog(struct work_struct *work)
59095917
if (skb->dev->reg_state == NETREG_UNREGISTERING) {
59105918
__skb_unlink(skb, &sd->process_queue);
59115919
kfree_skb(skb);
5912-
input_queue_head_incr(sd);
5920+
rps_input_queue_head_incr(sd);
59135921
}
59145922
}
59155923
local_bh_enable();
@@ -6037,9 +6045,10 @@ static int process_backlog(struct napi_struct *napi, int quota)
60376045
rcu_read_lock();
60386046
__netif_receive_skb(skb);
60396047
rcu_read_unlock();
6040-
input_queue_head_incr(sd);
6041-
if (++work >= quota)
6048+
if (++work >= quota) {
6049+
rps_input_queue_head_add(sd, work);
60426050
return work;
6051+
}
60436052

60446053
}
60456054

@@ -6062,6 +6071,8 @@ static int process_backlog(struct napi_struct *napi, int quota)
60626071
backlog_unlock_irq_enable(sd);
60636072
}
60646073

6074+
if (work)
6075+
rps_input_queue_head_add(sd, work);
60656076
return work;
60666077
}
60676078

@@ -11451,11 +11462,11 @@ static int dev_cpu_dead(unsigned int oldcpu)
1145111462
/* Process offline CPU's input_pkt_queue */
1145211463
while ((skb = __skb_dequeue(&oldsd->process_queue))) {
1145311464
netif_rx(skb);
11454-
input_queue_head_incr(oldsd);
11465+
rps_input_queue_head_incr(oldsd);
1145511466
}
1145611467
while ((skb = skb_dequeue(&oldsd->input_pkt_queue))) {
1145711468
netif_rx(skb);
11458-
input_queue_head_incr(oldsd);
11469+
rps_input_queue_head_incr(oldsd);
1145911470
}
1146011471

1146111472
return 0;

net/core/dev.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44

55
#include <linux/types.h>
66
#include <linux/rwsem.h>
7+
#include <linux/netdevice.h>
78

89
struct net;
9-
struct net_device;
10-
struct netdev_bpf;
11-
struct netdev_phys_item_id;
1210
struct netlink_ext_ack;
1311
struct cpumask;
1412

@@ -150,4 +148,23 @@ static inline void xdp_do_check_flushed(struct napi_struct *napi) { }
150148
#endif
151149

152150
struct napi_struct *napi_by_id(unsigned int napi_id);
151+
void kick_defer_list_purge(struct softnet_data *sd, unsigned int cpu);
152+
153+
#define XMIT_RECURSION_LIMIT 8
154+
static inline bool dev_xmit_recursion(void)
155+
{
156+
return unlikely(__this_cpu_read(softnet_data.xmit.recursion) >
157+
XMIT_RECURSION_LIMIT);
158+
}
159+
160+
static inline void dev_xmit_recursion_inc(void)
161+
{
162+
__this_cpu_inc(softnet_data.xmit.recursion);
163+
}
164+
165+
static inline void dev_xmit_recursion_dec(void)
166+
{
167+
__this_cpu_dec(softnet_data.xmit.recursion);
168+
}
169+
153170
#endif

net/core/net-procfs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ static int softnet_seq_show(struct seq_file *seq, void *v)
144144
seq_printf(seq,
145145
"%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x "
146146
"%08x %08x\n",
147-
sd->processed, sd->dropped, sd->time_squeeze, 0,
147+
sd->processed, atomic_read(&sd->dropped),
148+
sd->time_squeeze, 0,
148149
0, 0, 0, 0, /* was fastroute */
149150
0, /* was cpu_collision */
150151
sd->received_rps, flow_limit_count,

0 commit comments

Comments
 (0)