Commit 8ffab51b authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

macvlan: lockless tx path

macvlan is a stacked device, like tunnels. We should use the lockless
mechanism we are using in tunnels and loopback.

This patch completely removes locking in TX path.

tx stat counters are added into existing percpu stat structure, renamed
from rx_stats to pcpu_stats.

Note : this reverts commit 2c114553 (macvlan: add multiqueue
capability)

Note : rx_errors converted to a 32bit counter, like tx_dropped, since
they dont need 64bit range.
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Ben Greear <greearb@candelatech.com>
Cc: Ben Hutchings <bhutchings@solarflare.com>
Acked-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0e3125c7
...@@ -243,18 +243,22 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -243,18 +243,22 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
int i = skb_get_queue_mapping(skb);
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
unsigned int len = skb->len; unsigned int len = skb->len;
int ret; int ret;
const struct macvlan_dev *vlan = netdev_priv(dev);
ret = macvlan_queue_xmit(skb, dev); ret = macvlan_queue_xmit(skb, dev);
if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) { if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
txq->tx_packets++; struct macvlan_pcpu_stats *pcpu_stats;
txq->tx_bytes += len;
} else
txq->tx_dropped++;
pcpu_stats = this_cpu_ptr(vlan->pcpu_stats);
u64_stats_update_begin(&pcpu_stats->syncp);
pcpu_stats->tx_packets++;
pcpu_stats->tx_bytes += len;
u64_stats_update_end(&pcpu_stats->syncp);
} else {
this_cpu_inc(vlan->pcpu_stats->tx_dropped);
}
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(macvlan_start_xmit); EXPORT_SYMBOL_GPL(macvlan_start_xmit);
...@@ -414,14 +418,15 @@ static int macvlan_init(struct net_device *dev) ...@@ -414,14 +418,15 @@ static int macvlan_init(struct net_device *dev)
dev->state = (dev->state & ~MACVLAN_STATE_MASK) | dev->state = (dev->state & ~MACVLAN_STATE_MASK) |
(lowerdev->state & MACVLAN_STATE_MASK); (lowerdev->state & MACVLAN_STATE_MASK);
dev->features = lowerdev->features & MACVLAN_FEATURES; dev->features = lowerdev->features & MACVLAN_FEATURES;
dev->features |= NETIF_F_LLTX;
dev->gso_max_size = lowerdev->gso_max_size; dev->gso_max_size = lowerdev->gso_max_size;
dev->iflink = lowerdev->ifindex; dev->iflink = lowerdev->ifindex;
dev->hard_header_len = lowerdev->hard_header_len; dev->hard_header_len = lowerdev->hard_header_len;
macvlan_set_lockdep_class(dev); macvlan_set_lockdep_class(dev);
vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats); vlan->pcpu_stats = alloc_percpu(struct macvlan_pcpu_stats);
if (!vlan->rx_stats) if (!vlan->pcpu_stats)
return -ENOMEM; return -ENOMEM;
return 0; return 0;
...@@ -431,7 +436,7 @@ static void macvlan_uninit(struct net_device *dev) ...@@ -431,7 +436,7 @@ static void macvlan_uninit(struct net_device *dev)
{ {
struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_dev *vlan = netdev_priv(dev);
free_percpu(vlan->rx_stats); free_percpu(vlan->pcpu_stats);
} }
static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
...@@ -439,33 +444,38 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, ...@@ -439,33 +444,38 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
{ {
struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_dev *vlan = netdev_priv(dev);
dev_txq_stats_fold(dev, stats); if (vlan->pcpu_stats) {
struct macvlan_pcpu_stats *p;
if (vlan->rx_stats) { u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
struct macvlan_rx_stats *p, accum = {0}; u32 rx_errors = 0, tx_dropped = 0;
u64 rx_packets, rx_bytes, rx_multicast;
unsigned int start; unsigned int start;
int i; int i;
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
p = per_cpu_ptr(vlan->rx_stats, i); p = per_cpu_ptr(vlan->pcpu_stats, i);
do { do {
start = u64_stats_fetch_begin_bh(&p->syncp); start = u64_stats_fetch_begin_bh(&p->syncp);
rx_packets = p->rx_packets; rx_packets = p->rx_packets;
rx_bytes = p->rx_bytes; rx_bytes = p->rx_bytes;
rx_multicast = p->rx_multicast; rx_multicast = p->rx_multicast;
tx_packets = p->tx_packets;
tx_bytes = p->tx_bytes;
} while (u64_stats_fetch_retry_bh(&p->syncp, start)); } while (u64_stats_fetch_retry_bh(&p->syncp, start));
accum.rx_packets += rx_packets;
accum.rx_bytes += rx_bytes; stats->rx_packets += rx_packets;
accum.rx_multicast += rx_multicast; stats->rx_bytes += rx_bytes;
/* rx_errors is an ulong, updated without syncp protection */ stats->multicast += rx_multicast;
accum.rx_errors += p->rx_errors; stats->tx_packets += tx_packets;
stats->tx_bytes += tx_bytes;
/* rx_errors & tx_dropped are u32, updated
* without syncp protection.
*/
rx_errors += p->rx_errors;
tx_dropped += p->tx_dropped;
} }
stats->rx_packets = accum.rx_packets; stats->rx_errors = rx_errors;
stats->rx_bytes = accum.rx_bytes; stats->rx_dropped = rx_errors;
stats->rx_errors = accum.rx_errors; stats->tx_dropped = tx_dropped;
stats->rx_dropped = accum.rx_errors;
stats->multicast = accum.rx_multicast;
} }
return stats; return stats;
} }
...@@ -601,25 +611,6 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) ...@@ -601,25 +611,6 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
return 0; return 0;
} }
static int macvlan_get_tx_queues(struct net *net,
struct nlattr *tb[],
unsigned int *num_tx_queues,
unsigned int *real_num_tx_queues)
{
struct net_device *real_dev;
if (!tb[IFLA_LINK])
return -EINVAL;
real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK]));
if (!real_dev)
return -ENODEV;
*num_tx_queues = real_dev->num_tx_queues;
*real_num_tx_queues = real_dev->real_num_tx_queues;
return 0;
}
int macvlan_common_newlink(struct net *src_net, struct net_device *dev, int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[], struct nlattr *tb[], struct nlattr *data[],
int (*receive)(struct sk_buff *skb), int (*receive)(struct sk_buff *skb),
...@@ -743,7 +734,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops) ...@@ -743,7 +734,6 @@ int macvlan_link_register(struct rtnl_link_ops *ops)
{ {
/* common fields */ /* common fields */
ops->priv_size = sizeof(struct macvlan_dev); ops->priv_size = sizeof(struct macvlan_dev);
ops->get_tx_queues = macvlan_get_tx_queues;
ops->validate = macvlan_validate; ops->validate = macvlan_validate;
ops->maxtype = IFLA_MACVLAN_MAX; ops->maxtype = IFLA_MACVLAN_MAX;
ops->policy = macvlan_policy; ops->policy = macvlan_policy;
......
...@@ -25,19 +25,25 @@ struct macvlan_port; ...@@ -25,19 +25,25 @@ struct macvlan_port;
struct macvtap_queue; struct macvtap_queue;
/** /**
* struct macvlan_rx_stats - MACVLAN percpu rx stats * struct macvlan_pcpu_stats - MACVLAN percpu stats
* @rx_packets: number of received packets * @rx_packets: number of received packets
* @rx_bytes: number of received bytes * @rx_bytes: number of received bytes
* @rx_multicast: number of received multicast packets * @rx_multicast: number of received multicast packets
* @tx_packets: number of transmitted packets
* @tx_bytes: number of transmitted bytes
* @syncp: synchronization point for 64bit counters * @syncp: synchronization point for 64bit counters
* @rx_errors: number of errors * @rx_errors: number of rx errors
* @tx_dropped: number of tx dropped packets
*/ */
struct macvlan_rx_stats { struct macvlan_pcpu_stats {
u64 rx_packets; u64 rx_packets;
u64 rx_bytes; u64 rx_bytes;
u64 rx_multicast; u64 rx_multicast;
u64 tx_packets;
u64 tx_bytes;
struct u64_stats_sync syncp; struct u64_stats_sync syncp;
unsigned long rx_errors; u32 rx_errors;
u32 tx_dropped;
}; };
/* /*
...@@ -52,7 +58,7 @@ struct macvlan_dev { ...@@ -52,7 +58,7 @@ struct macvlan_dev {
struct hlist_node hlist; struct hlist_node hlist;
struct macvlan_port *port; struct macvlan_port *port;
struct net_device *lowerdev; struct net_device *lowerdev;
struct macvlan_rx_stats __percpu *rx_stats; struct macvlan_pcpu_stats __percpu *pcpu_stats;
enum macvlan_mode mode; enum macvlan_mode mode;
int (*receive)(struct sk_buff *skb); int (*receive)(struct sk_buff *skb);
int (*forward)(struct net_device *dev, struct sk_buff *skb); int (*forward)(struct net_device *dev, struct sk_buff *skb);
...@@ -64,18 +70,18 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan, ...@@ -64,18 +70,18 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
unsigned int len, bool success, unsigned int len, bool success,
bool multicast) bool multicast)
{ {
struct macvlan_rx_stats *rx_stats;
rx_stats = this_cpu_ptr(vlan->rx_stats);
if (likely(success)) { if (likely(success)) {
u64_stats_update_begin(&rx_stats->syncp); struct macvlan_pcpu_stats *pcpu_stats;
rx_stats->rx_packets++;
rx_stats->rx_bytes += len; pcpu_stats = this_cpu_ptr(vlan->pcpu_stats);
u64_stats_update_begin(&pcpu_stats->syncp);
pcpu_stats->rx_packets++;
pcpu_stats->rx_bytes += len;
if (multicast) if (multicast)
rx_stats->rx_multicast++; pcpu_stats->rx_multicast++;
u64_stats_update_end(&rx_stats->syncp); u64_stats_update_end(&pcpu_stats->syncp);
} else { } else {
rx_stats->rx_errors++; this_cpu_inc(vlan->pcpu_stats->rx_errors);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment