mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 22:02:02 +00:00
netdevsim: forward skbs from one connected port to another
Forward skbs sent from one netdevsim port to its connected netdevsim port using dev_forward_skb, in a spirit similar to veth. Add a tx_dropped variable to struct netdevsim, tracking the number of skbs that could not be forwarded using dev_forward_skb(). The xmit() function accessing the peer ptr is protected by an RCU read critical section. The rcu_read_lock() is functionally redundant as since v5.0 all softirqs are implicitly RCU read critical sections; but it is useful for human readers. If another CPU is concurrently in nsim_destroy(), then it will first set the peer ptr to NULL. This does not affect any existing readers that dereferenced a non-NULL peer. Then, in unregister_netdevice(), there is a synchronize_rcu() before the netdev is actually unregistered and freed. This ensures that any readers i.e. xmit() that got a non-NULL peer will complete before the netdev is freed. Any readers after the RCU_INIT_POINTER() but before synchronize_rcu() will dereference NULL, making it safe. The codepath to nsim_destroy() and nsim_create() takes both the newly added nsim_dev_list_lock and rtnl_lock. This makes it safe with concurrent calls to linking two netdevsims together. Signed-off-by: David Wei <dw@davidwei.uk> Reviewed-by: Maciek Machnikowski <maciek@machnikowski.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f532957d76
commit
9eb95228a7
2 changed files with 23 additions and 5 deletions
|
@ -29,18 +29,35 @@
|
||||||
static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct netdevsim *ns = netdev_priv(dev);
|
struct netdevsim *ns = netdev_priv(dev);
|
||||||
|
unsigned int len = skb->len;
|
||||||
|
struct netdevsim *peer_ns;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
if (!nsim_ipsec_tx(ns, skb))
|
if (!nsim_ipsec_tx(ns, skb))
|
||||||
goto out;
|
goto out_drop_free;
|
||||||
|
|
||||||
|
peer_ns = rcu_dereference(ns->peer);
|
||||||
|
if (!peer_ns)
|
||||||
|
goto out_drop_free;
|
||||||
|
|
||||||
|
skb_tx_timestamp(skb);
|
||||||
|
if (unlikely(dev_forward_skb(peer_ns->netdev, skb) == NET_RX_DROP))
|
||||||
|
goto out_drop_cnt;
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
u64_stats_update_begin(&ns->syncp);
|
u64_stats_update_begin(&ns->syncp);
|
||||||
ns->tx_packets++;
|
ns->tx_packets++;
|
||||||
ns->tx_bytes += skb->len;
|
ns->tx_bytes += len;
|
||||||
u64_stats_update_end(&ns->syncp);
|
u64_stats_update_end(&ns->syncp);
|
||||||
|
return NETDEV_TX_OK;
|
||||||
|
|
||||||
out:
|
out_drop_free:
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
|
out_drop_cnt:
|
||||||
|
rcu_read_unlock();
|
||||||
|
u64_stats_update_begin(&ns->syncp);
|
||||||
|
ns->tx_dropped++;
|
||||||
|
u64_stats_update_end(&ns->syncp);
|
||||||
return NETDEV_TX_OK;
|
return NETDEV_TX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +87,7 @@ nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
|
||||||
start = u64_stats_fetch_begin(&ns->syncp);
|
start = u64_stats_fetch_begin(&ns->syncp);
|
||||||
stats->tx_bytes = ns->tx_bytes;
|
stats->tx_bytes = ns->tx_bytes;
|
||||||
stats->tx_packets = ns->tx_packets;
|
stats->tx_packets = ns->tx_packets;
|
||||||
|
stats->tx_dropped = ns->tx_dropped;
|
||||||
} while (u64_stats_fetch_retry(&ns->syncp, start));
|
} while (u64_stats_fetch_retry(&ns->syncp, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +320,6 @@ static void nsim_setup(struct net_device *dev)
|
||||||
eth_hw_addr_random(dev);
|
eth_hw_addr_random(dev);
|
||||||
|
|
||||||
dev->tx_queue_len = 0;
|
dev->tx_queue_len = 0;
|
||||||
dev->flags |= IFF_NOARP;
|
|
||||||
dev->flags &= ~IFF_MULTICAST;
|
dev->flags &= ~IFF_MULTICAST;
|
||||||
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE |
|
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE |
|
||||||
IFF_NO_QUEUE;
|
IFF_NO_QUEUE;
|
||||||
|
|
|
@ -98,6 +98,7 @@ struct netdevsim {
|
||||||
|
|
||||||
u64 tx_packets;
|
u64 tx_packets;
|
||||||
u64 tx_bytes;
|
u64 tx_bytes;
|
||||||
|
u64 tx_dropped;
|
||||||
struct u64_stats_sync syncp;
|
struct u64_stats_sync syncp;
|
||||||
|
|
||||||
struct nsim_bus_dev *nsim_bus_dev;
|
struct nsim_bus_dev *nsim_bus_dev;
|
||||||
|
|
Loading…
Reference in a new issue