Skip to content

Commit 9eb9522

Browse files
spikehdavem330
authored andcommitted
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 <[email protected]> Reviewed-by: Maciek Machnikowski <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f532957 commit 9eb9522

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

drivers/net/netdevsim/netdev.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,35 @@
2929
static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
3030
{
3131
struct netdevsim *ns = netdev_priv(dev);
32+
unsigned int len = skb->len;
33+
struct netdevsim *peer_ns;
3234

35+
rcu_read_lock();
3336
if (!nsim_ipsec_tx(ns, skb))
34-
goto out;
37+
goto out_drop_free;
3538

39+
peer_ns = rcu_dereference(ns->peer);
40+
if (!peer_ns)
41+
goto out_drop_free;
42+
43+
skb_tx_timestamp(skb);
44+
if (unlikely(dev_forward_skb(peer_ns->netdev, skb) == NET_RX_DROP))
45+
goto out_drop_cnt;
46+
47+
rcu_read_unlock();
3648
u64_stats_update_begin(&ns->syncp);
3749
ns->tx_packets++;
38-
ns->tx_bytes += skb->len;
50+
ns->tx_bytes += len;
3951
u64_stats_update_end(&ns->syncp);
52+
return NETDEV_TX_OK;
4053

41-
out:
54+
out_drop_free:
4255
dev_kfree_skb(skb);
43-
56+
out_drop_cnt:
57+
rcu_read_unlock();
58+
u64_stats_update_begin(&ns->syncp);
59+
ns->tx_dropped++;
60+
u64_stats_update_end(&ns->syncp);
4461
return NETDEV_TX_OK;
4562
}
4663

@@ -70,6 +87,7 @@ nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
7087
start = u64_stats_fetch_begin(&ns->syncp);
7188
stats->tx_bytes = ns->tx_bytes;
7289
stats->tx_packets = ns->tx_packets;
90+
stats->tx_dropped = ns->tx_dropped;
7391
} while (u64_stats_fetch_retry(&ns->syncp, start));
7492
}
7593

@@ -302,7 +320,6 @@ static void nsim_setup(struct net_device *dev)
302320
eth_hw_addr_random(dev);
303321

304322
dev->tx_queue_len = 0;
305-
dev->flags |= IFF_NOARP;
306323
dev->flags &= ~IFF_MULTICAST;
307324
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE |
308325
IFF_NO_QUEUE;

drivers/net/netdevsim/netdevsim.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ struct netdevsim {
9898

9999
u64 tx_packets;
100100
u64 tx_bytes;
101+
u64 tx_dropped;
101102
struct u64_stats_sync syncp;
102103

103104
struct nsim_bus_dev *nsim_bus_dev;

0 commit comments

Comments
 (0)