[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <8509950a-94fb-5005-dbdb-cd025b092cff@solarflare.com>
Date: Wed, 14 Nov 2018 18:09:53 +0000
From: Edward Cree <ecree@...arflare.com>
To: <linux-net-drivers@...arflare.com>, <davem@...emloft.net>
CC: <netdev@...r.kernel.org>, <eric.dumazet@...il.com>
Subject: [PATCH v3 net-next 3/4] net: make listified RX functions return
number of good packets
'Good' packets are defined as skbs for which netif_receive_skb() would
have returned %NET_RX_SUCCESS. Thus, drivers can use this number for
adaptive interrupt moderation where they previously reacted to the
return code from netif_receive_skb().
Signed-off-by: Edward Cree <ecree@...arflare.com>
---
include/linux/netdevice.h | 4 +--
include/net/ip.h | 4 +--
include/net/ipv6.h | 4 +--
net/core/dev.c | 63 +++++++++++++++++++++++++++++------------------
net/ipv4/ip_input.c | 39 ++++++++++++++++++-----------
net/ipv6/ip6_input.c | 37 +++++++++++++++++-----------
6 files changed, 92 insertions(+), 59 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 2cef1d0fb2b1..76b98386a5dd 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2357,7 +2357,7 @@ struct packet_type {
struct net_device *,
struct packet_type *,
struct net_device *);
- void (*list_func) (struct list_head *,
+ int (*list_func) (struct list_head *,
struct packet_type *,
struct net_device *);
bool (*id_match)(struct packet_type *ptype,
@@ -3587,7 +3587,7 @@ int netif_rx(struct sk_buff *skb);
int netif_rx_ni(struct sk_buff *skb);
int netif_receive_skb(struct sk_buff *skb);
int netif_receive_skb_core(struct sk_buff *skb);
-void netif_receive_skb_list(struct list_head *head);
+int netif_receive_skb_list(struct list_head *head);
gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb);
int napi_gro_receive_list(struct napi_struct *napi, struct list_head *head);
void napi_gro_flush(struct napi_struct *napi, bool flush_old);
diff --git a/include/net/ip.h b/include/net/ip.h
index 8866bfce6121..33ab464f7a09 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -152,8 +152,8 @@ int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk,
struct ip_options_rcu *opt);
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
struct net_device *orig_dev);
-void ip_list_rcv(struct list_head *head, struct packet_type *pt,
- struct net_device *orig_dev);
+int ip_list_rcv(struct list_head *head, struct packet_type *pt,
+ struct net_device *orig_dev);
int ip_local_deliver(struct sk_buff *skb);
void ip_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int proto);
int ip_mr_input(struct sk_buff *skb);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index daf80863d3a5..e25920829a94 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -914,8 +914,8 @@ static inline __be32 flowi6_get_flowlabel(const struct flowi6 *fl6)
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev);
-void ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
- struct net_device *orig_dev);
+int ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
+ struct net_device *orig_dev);
int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
diff --git a/net/core/dev.c b/net/core/dev.c
index 8f0fb56170b3..35427167f6fb 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4969,24 +4969,27 @@ int netif_receive_skb_core(struct sk_buff *skb)
}
EXPORT_SYMBOL(netif_receive_skb_core);
-static inline void __netif_receive_skb_list_ptype(struct list_head *head,
- struct packet_type *pt_prev,
- struct net_device *orig_dev)
+static inline int __netif_receive_skb_list_ptype(struct list_head *head,
+ struct packet_type *pt_prev,
+ struct net_device *orig_dev)
{
struct sk_buff *skb, *next;
+ int kept = 0;
if (!pt_prev)
- return;
+ return 0;
if (list_empty(head))
- return;
+ return 0;
if (pt_prev->list_func != NULL)
- pt_prev->list_func(head, pt_prev, orig_dev);
+ kept = pt_prev->list_func(head, pt_prev, orig_dev);
else
list_for_each_entry_safe(skb, next, head, list)
- pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
+ if (pt_prev->func(skb, skb->dev, pt_prev, orig_dev) == NET_RX_SUCCESS)
+ kept++;
+ return kept;
}
-static void __netif_receive_skb_list_core(struct list_head *head, bool pfmemalloc)
+static int __netif_receive_skb_list_core(struct list_head *head, bool pfmemalloc)
{
/* Fast-path assumptions:
* - There is no RX handler.
@@ -5003,6 +5006,7 @@ static void __netif_receive_skb_list_core(struct list_head *head, bool pfmemallo
struct net_device *od_curr = NULL;
struct list_head sublist;
struct sk_buff *skb, *next;
+ int kept = 0, ret;
INIT_LIST_HEAD(&sublist);
list_for_each_entry_safe(skb, next, head, list) {
@@ -5010,12 +5014,15 @@ static void __netif_receive_skb_list_core(struct list_head *head, bool pfmemallo
struct packet_type *pt_prev = NULL;
list_del(&skb->list);
- __netif_receive_skb_core(skb, pfmemalloc, &pt_prev);
- if (!pt_prev)
+ ret = __netif_receive_skb_core(skb, pfmemalloc, &pt_prev);
+ if (!pt_prev) {
+ if (ret == NET_RX_SUCCESS)
+ kept++;
continue;
+ }
if (pt_curr != pt_prev || od_curr != orig_dev) {
/* dispatch old sublist */
- __netif_receive_skb_list_ptype(&sublist, pt_curr, od_curr);
+ kept += __netif_receive_skb_list_ptype(&sublist, pt_curr, od_curr);
/* start new sublist */
INIT_LIST_HEAD(&sublist);
pt_curr = pt_prev;
@@ -5025,7 +5032,8 @@ static void __netif_receive_skb_list_core(struct list_head *head, bool pfmemallo
}
/* dispatch final sublist */
- __netif_receive_skb_list_ptype(&sublist, pt_curr, od_curr);
+ kept += __netif_receive_skb_list_ptype(&sublist, pt_curr, od_curr);
+ return kept;
}
static int __netif_receive_skb(struct sk_buff *skb)
@@ -5053,11 +5061,12 @@ static int __netif_receive_skb(struct sk_buff *skb)
return ret;
}
-static void __netif_receive_skb_list(struct list_head *head)
+static int __netif_receive_skb_list(struct list_head *head)
{
unsigned long noreclaim_flag = 0;
struct sk_buff *skb, *next;
bool pfmemalloc = false; /* Is current sublist PF_MEMALLOC? */
+ int kept = 0;
list_for_each_entry_safe(skb, next, head, list) {
if ((sk_memalloc_socks() && skb_pfmemalloc(skb)) != pfmemalloc) {
@@ -5066,7 +5075,7 @@ static void __netif_receive_skb_list(struct list_head *head)
/* Handle the previous sublist */
list_cut_before(&sublist, head, &skb->list);
if (!list_empty(&sublist))
- __netif_receive_skb_list_core(&sublist, pfmemalloc);
+ kept += __netif_receive_skb_list_core(&sublist, pfmemalloc);
pfmemalloc = !pfmemalloc;
/* See comments in __netif_receive_skb */
if (pfmemalloc)
@@ -5077,10 +5086,11 @@ static void __netif_receive_skb_list(struct list_head *head)
}
/* Handle the remaining sublist */
if (!list_empty(head))
- __netif_receive_skb_list_core(head, pfmemalloc);
+ kept += __netif_receive_skb_list_core(head, pfmemalloc);
/* Restore pflags */
if (pfmemalloc)
memalloc_noreclaim_restore(noreclaim_flag);
+ return kept;
}
static int generic_xdp_install(struct net_device *dev, struct netdev_bpf *xdp)
@@ -5156,17 +5166,20 @@ static int netif_receive_skb_internal(struct sk_buff *skb)
return ret;
}
-static void netif_receive_skb_list_internal(struct list_head *head)
+static int netif_receive_skb_list_internal(struct list_head *head)
{
struct bpf_prog *xdp_prog = NULL;
struct sk_buff *skb, *next;
struct list_head sublist;
+ int kept = 0;
INIT_LIST_HEAD(&sublist);
list_for_each_entry_safe(skb, next, head, list) {
net_timestamp_check(netdev_tstamp_prequeue, skb);
list_del(&skb->list);
- if (!skb_defer_rx_timestamp(skb))
+ if (skb_defer_rx_timestamp(skb))
+ kept++;
+ else
list_add_tail(&skb->list, &sublist);
}
list_splice_init(&sublist, head);
@@ -5196,13 +5209,15 @@ static void netif_receive_skb_list_internal(struct list_head *head)
if (cpu >= 0) {
/* Will be handled, remove from list */
list_del(&skb->list);
- enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
+ if (enqueue_to_backlog(skb, cpu, &rflow->last_qtail) == NET_RX_SUCCESS)
+ kept++;
}
}
}
#endif
- __netif_receive_skb_list(head);
+ kept += __netif_receive_skb_list(head);
rcu_read_unlock();
+ return kept;
}
/**
@@ -5232,21 +5247,21 @@ EXPORT_SYMBOL(netif_receive_skb);
* netif_receive_skb_list - process many receive buffers from network
* @head: list of skbs to process.
*
- * Since return value of netif_receive_skb() is normally ignored, and
- * wouldn't be meaningful for a list, this function returns void.
+ * Returns the number of skbs for which netif_receive_skb() would have
+ * returned %NET_RX_SUCCESS.
*
* This function may only be called from softirq context and interrupts
* should be enabled.
*/
-void netif_receive_skb_list(struct list_head *head)
+int netif_receive_skb_list(struct list_head *head)
{
struct sk_buff *skb;
if (list_empty(head))
- return;
+ return 0;
list_for_each_entry(skb, head, list)
trace_netif_receive_skb_list_entry(skb);
- netif_receive_skb_list_internal(head);
+ return netif_receive_skb_list_internal(head);
}
EXPORT_SYMBOL(netif_receive_skb_list);
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 72250b4e466d..fa4eb82f9e55 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -525,22 +525,26 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
ip_rcv_finish);
}
-static void ip_sublist_rcv_finish(struct list_head *head)
+static int ip_sublist_rcv_finish(struct list_head *head)
{
struct sk_buff *skb, *next;
+ int kept = 0;
list_for_each_entry_safe(skb, next, head, list) {
skb_list_del_init(skb);
- dst_input(skb);
+ if (dst_input(skb) == NET_RX_SUCCESS)
+ kept++;
}
+ return kept;
}
-static void ip_list_rcv_finish(struct net *net, struct sock *sk,
- struct list_head *head)
+static int ip_list_rcv_finish(struct net *net, struct sock *sk,
+ struct list_head *head)
{
struct dst_entry *curr_dst = NULL;
struct sk_buff *skb, *next;
struct list_head sublist;
+ int kept = 0;
INIT_LIST_HEAD(&sublist);
list_for_each_entry_safe(skb, next, head, list) {
@@ -551,8 +555,10 @@ static void ip_list_rcv_finish(struct net *net, struct sock *sk,
* skb to its handler for processing
*/
skb = l3mdev_ip_rcv(skb);
- if (!skb)
+ if (!skb) {
+ kept++;
continue;
+ }
if (ip_rcv_finish_core(net, sk, skb) == NET_RX_DROP)
continue;
@@ -560,7 +566,7 @@ static void ip_list_rcv_finish(struct net *net, struct sock *sk,
if (curr_dst != dst) {
/* dispatch old sublist */
if (!list_empty(&sublist))
- ip_sublist_rcv_finish(&sublist);
+ kept += ip_sublist_rcv_finish(&sublist);
/* start new sublist */
INIT_LIST_HEAD(&sublist);
curr_dst = dst;
@@ -568,25 +574,27 @@ static void ip_list_rcv_finish(struct net *net, struct sock *sk,
list_add_tail(&skb->list, &sublist);
}
/* dispatch final sublist */
- ip_sublist_rcv_finish(&sublist);
+ kept += ip_sublist_rcv_finish(&sublist);
+ return kept;
}
-static void ip_sublist_rcv(struct list_head *head, struct net_device *dev,
- struct net *net)
+static int ip_sublist_rcv(struct list_head *head, struct net_device *dev,
+ struct net *net)
{
NF_HOOK_LIST(NFPROTO_IPV4, NF_INET_PRE_ROUTING, net, NULL,
head, dev, NULL, ip_rcv_finish);
- ip_list_rcv_finish(net, NULL, head);
+ return ip_list_rcv_finish(net, NULL, head);
}
-/* Receive a list of IP packets */
-void ip_list_rcv(struct list_head *head, struct packet_type *pt,
- struct net_device *orig_dev)
+/* Receive a list of IP packets; return number of successful receives */
+int ip_list_rcv(struct list_head *head, struct packet_type *pt,
+ struct net_device *orig_dev)
{
struct net_device *curr_dev = NULL;
struct net *curr_net = NULL;
struct sk_buff *skb, *next;
struct list_head sublist;
+ int kept = 0;
INIT_LIST_HEAD(&sublist);
list_for_each_entry_safe(skb, next, head, list) {
@@ -601,7 +609,7 @@ void ip_list_rcv(struct list_head *head, struct packet_type *pt,
if (curr_dev != dev || curr_net != net) {
/* dispatch old sublist */
if (!list_empty(&sublist))
- ip_sublist_rcv(&sublist, curr_dev, curr_net);
+ kept += ip_sublist_rcv(&sublist, curr_dev, curr_net);
/* start new sublist */
INIT_LIST_HEAD(&sublist);
curr_dev = dev;
@@ -610,5 +618,6 @@ void ip_list_rcv(struct list_head *head, struct packet_type *pt,
list_add_tail(&skb->list, &sublist);
}
/* dispatch final sublist */
- ip_sublist_rcv(&sublist, curr_dev, curr_net);
+ kept += ip_sublist_rcv(&sublist, curr_dev, curr_net);
+ return kept;
}
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 3c06cc9e9b79..6e013672e1de 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -76,20 +76,24 @@ int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
return dst_input(skb);
}
-static void ip6_sublist_rcv_finish(struct list_head *head)
+static int ip6_sublist_rcv_finish(struct list_head *head)
{
struct sk_buff *skb, *next;
+ int kept = 0;
list_for_each_entry_safe(skb, next, head, list)
- dst_input(skb);
+ if (dst_input(skb) == NET_RX_SUCCESS)
+ kept++;
+ return kept;
}
-static void ip6_list_rcv_finish(struct net *net, struct sock *sk,
- struct list_head *head)
+static int ip6_list_rcv_finish(struct net *net, struct sock *sk,
+ struct list_head *head)
{
struct dst_entry *curr_dst = NULL;
struct sk_buff *skb, *next;
struct list_head sublist;
+ int kept = 0;
INIT_LIST_HEAD(&sublist);
list_for_each_entry_safe(skb, next, head, list) {
@@ -100,14 +104,16 @@ static void ip6_list_rcv_finish(struct net *net, struct sock *sk,
* skb to its handler for processing
*/
skb = l3mdev_ip6_rcv(skb);
- if (!skb)
+ if (!skb) {
+ kept++;
continue;
+ }
ip6_rcv_finish_core(net, sk, skb);
dst = skb_dst(skb);
if (curr_dst != dst) {
/* dispatch old sublist */
if (!list_empty(&sublist))
- ip6_sublist_rcv_finish(&sublist);
+ kept += ip6_sublist_rcv_finish(&sublist);
/* start new sublist */
INIT_LIST_HEAD(&sublist);
curr_dst = dst;
@@ -115,7 +121,8 @@ static void ip6_list_rcv_finish(struct net *net, struct sock *sk,
list_add_tail(&skb->list, &sublist);
}
/* dispatch final sublist */
- ip6_sublist_rcv_finish(&sublist);
+ kept += ip6_sublist_rcv_finish(&sublist);
+ return kept;
}
static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
@@ -274,22 +281,23 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
ip6_rcv_finish);
}
-static void ip6_sublist_rcv(struct list_head *head, struct net_device *dev,
- struct net *net)
+static int ip6_sublist_rcv(struct list_head *head, struct net_device *dev,
+ struct net *net)
{
NF_HOOK_LIST(NFPROTO_IPV6, NF_INET_PRE_ROUTING, net, NULL,
head, dev, NULL, ip6_rcv_finish);
- ip6_list_rcv_finish(net, NULL, head);
+ return ip6_list_rcv_finish(net, NULL, head);
}
/* Receive a list of IPv6 packets */
-void ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
- struct net_device *orig_dev)
+int ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
+ struct net_device *orig_dev)
{
struct net_device *curr_dev = NULL;
struct net *curr_net = NULL;
struct sk_buff *skb, *next;
struct list_head sublist;
+ int kept = 0;
INIT_LIST_HEAD(&sublist);
list_for_each_entry_safe(skb, next, head, list) {
@@ -304,7 +312,7 @@ void ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
if (curr_dev != dev || curr_net != net) {
/* dispatch old sublist */
if (!list_empty(&sublist))
- ip6_sublist_rcv(&sublist, curr_dev, curr_net);
+ kept += ip6_sublist_rcv(&sublist, curr_dev, curr_net);
/* start new sublist */
INIT_LIST_HEAD(&sublist);
curr_dev = dev;
@@ -313,7 +321,8 @@ void ipv6_list_rcv(struct list_head *head, struct packet_type *pt,
list_add_tail(&skb->list, &sublist);
}
/* dispatch final sublist */
- ip6_sublist_rcv(&sublist, curr_dev, curr_net);
+ kept += ip6_sublist_rcv(&sublist, curr_dev, curr_net);
+ return kept;
}
/*
Powered by blists - more mailing lists