Skip to content

Commit

Permalink
[nrf fromlist] net: iface: Introduce TX mutex locking
Browse files Browse the repository at this point in the history
A recent iface lock removal in ed17320
exposed issues with concurrent access on TX to drivers that are not
re-entrant.

Reverting that commit does not really solve the problem, as it would
still exist if multiple Traffic Class queues are in use.

Therefore, introduce a separate mutex for TX data path, protecting the
L2/driver from concurrent transfers from several threads.

Upstream PR: zephyrproject-rtos/zephyr#65049

Signed-off-by: Robert Lubos <[email protected]>
  • Loading branch information
rlubos committed Nov 10, 2023
1 parent a707fc7 commit 9ed7de1
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 0 deletions.
29 changes: 29 additions & 0 deletions include/zephyr/net/net_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ enum net_if_flag {
/** IPv6 Multicast Listener Discovery disabled. */
NET_IF_IPV6_NO_MLD,

/** Mutex locking on TX data path disabled on the interface. */
NET_IF_NO_TX_LOCK,

/** @cond INTERNAL_HIDDEN */
/* Total number of flags - must be at the end of the enum */
NET_IF_NUM_FLAGS
Expand Down Expand Up @@ -613,6 +616,7 @@ struct net_if {
#endif

struct k_mutex lock;
struct k_mutex tx_lock;
};

static inline void net_if_lock(struct net_if *iface)
Expand All @@ -629,6 +633,31 @@ static inline void net_if_unlock(struct net_if *iface)
k_mutex_unlock(&iface->lock);
}

static inline bool net_if_flag_is_set(struct net_if *iface,
enum net_if_flag value);

static inline void net_if_tx_lock(struct net_if *iface)
{
NET_ASSERT(iface);

if (net_if_flag_is_set(iface, NET_IF_NO_TX_LOCK)) {
return;
}

(void)k_mutex_lock(&iface->tx_lock, K_FOREVER);
}

static inline void net_if_tx_unlock(struct net_if *iface)
{
NET_ASSERT(iface);

if (net_if_flag_is_set(iface, NET_IF_NO_TX_LOCK)) {
return;
}

k_mutex_unlock(&iface->tx_lock);
}

/**
* @brief Set a value in network interface flags
*
Expand Down
3 changes: 3 additions & 0 deletions subsys/net/ip/net_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ static bool net_if_tx(struct net_if *iface, struct net_pkt *pkt)
}
}

net_if_tx_lock(iface);
status = net_if_l2(iface)->send(iface, pkt);
net_if_tx_unlock(iface);

if (IS_ENABLED(CONFIG_NET_PKT_TXTIME_STATS)) {
uint32_t end_tick = k_cycle_get_32();
Expand Down Expand Up @@ -437,6 +439,7 @@ static inline void init_iface(struct net_if *iface)
#endif

k_mutex_init(&iface->lock);
k_mutex_init(&iface->tx_lock);

api->init(iface);
}
Expand Down
2 changes: 2 additions & 0 deletions subsys/net/l2/ethernet/arp.c
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,9 @@ static void arp_update(struct net_if *iface,
* the pkt are not counted twice and the packet filter
* callbacks are only called once.
*/
net_if_tx_lock(iface);
ret = net_if_l2(iface)->send(iface, pkt);
net_if_tx_unlock(iface);
if (ret < 0) {
net_pkt_unref(pkt);
}
Expand Down

0 comments on commit 9ed7de1

Please sign in to comment.