* [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03
@ 2026-06-03 7:25 Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 01/15] batman-adv: tp_meter: keep unacked list in ascending ordered Simon Wunderlich
` (14 more replies)
0 siblings, 15 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Simon Wunderlich
Dear net maintainers,
here is another cleanup pull request of batman-adv to go into net-next.
Note that this pull request includes multiple fixes which we consider
non-critical and/or minor, and therefore want to send them via net-next
instead of net as per Linus' direction [1].
Please pull or let me know of any problem!
Thank you,
Simon
[1] https://lore.kernel.org/lkml/CAHk-=wjt1NiKOdyAMz_DT7NmZ++SizPOhRSi492ukdTnpDzHQw@mail.gmail.com/T/#u
The following changes since commit 3bd64ca11d9a1672d67d3130a7264c2cf7f93cdf:
batman-adv: use neigh_node's orig_node only as id (2026-06-01 14:22:03 +0200)
are available in the Git repository at:
https://git.open-mesh.org/batadv.git tags/batadv-next-pullrequest-20260603
for you to fetch changes up to 626fd14371614b7a8177f79b357fd323a7b91032:
batman-adv: tt: directly retrieve wifi flags of net_device (2026-06-03 08:27:17 +0200)
----------------------------------------------------------------
This cleanup patchset includes the following patches, all by
Sven Eckelmann:
- tp_meter: fix various minor issues (8 patches)
- tp_meter: split generic session type in sender and receiver type
- tp_meter: consolidate locking for congestion control (2 patches)
- bla: annotate lasttime access with READ/WRITE_ONCE
- elp: prevent transmission interval underflow
- tt: sync local and global tvlv preparation return values
- tt: directly retrieve wifi flags of net_device
----------------------------------------------------------------
Sven Eckelmann (15):
batman-adv: tp_meter: keep unacked list in ascending ordered
batman-adv: tp_meter: initialize dup_acks explicitly
batman-adv: tp_meter: initialize dec_cwnd explicitly
batman-adv: tp_meter: avoid window underflow
batman-adv: tp_meter: avoid divide-by-zero for dec_cwnd
batman-adv: tp_meter: fix fast recovery precondition
batman-adv: tp_meter: handle seqno wrap-around for fast recovery detection
batman-adv: tp_meter: add only finished tp_vars to lists
batman-adv: tp_meter: split vars into sender and receiver types
batman-adv: tp_meter: use locking for all congestion control variables
batman-adv: tp_meter: consolidate congestion control variables
batman-adv: bla: annotate lasttime access with READ/WRITE_ONCE
batman-adv: prevent ELP transmission interval underflow
batman-adv: tt: sync local and global tvlv preparation return values
batman-adv: tt: directly retrieve wifi flags of net_device
net/batman-adv/bridge_loop_avoidance.c | 28 +-
net/batman-adv/hard-interface.c | 25 +-
net/batman-adv/hard-interface.h | 1 +
net/batman-adv/main.c | 3 +-
net/batman-adv/netlink.c | 8 +-
net/batman-adv/tp_meter.c | 739 +++++++++++++++++++--------------
net/batman-adv/translation-table.c | 32 +-
net/batman-adv/types.h | 141 ++++---
8 files changed, 572 insertions(+), 405 deletions(-)
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH net-next 01/15] batman-adv: tp_meter: keep unacked list in ascending ordered
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-05 2:20 ` patchwork-bot+netdevbpf
2026-06-03 7:25 ` [PATCH net-next 02/15] batman-adv: tp_meter: initialize dup_acks explicitly Simon Wunderlich
` (13 subsequent siblings)
14 siblings, 1 reply; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
When batadv_tp_handle_out_of_order inserts a new entry in the list of
unacked (out of order) packets, it searches from the entry with the newest
sequence number towards oldest sequence number. If an entry is found which
is older than the newly entry, the new entry has to be added after the
found one to keep the ascending order.
But for this operation list_add_tail() was used. But this function adds an
entry _before_ another one. As result, the list would contain a lot of
swapped sequence numbers. The consumer of this list
(batadv_tp_ack_unordered()) would then fail to correctly ack packets.
Cc: stable@kernel.org
Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index aefe757277b20..0e39ea33e5f27 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -1325,7 +1325,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
* one is attached _after_ it. In this way the list is kept in
* ascending order
*/
- list_add_tail(&new->list, &un->list);
+ list_add(&new->list, &un->list);
added = true;
break;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 02/15] batman-adv: tp_meter: initialize dup_acks explicitly
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 01/15] batman-adv: tp_meter: keep unacked list in ascending ordered Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 03/15] batman-adv: tp_meter: initialize dec_cwnd explicitly Simon Wunderlich
` (12 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
When an ack with a sequence number equal to the last_acked is received, the
dup_acks counter is increased to decide whether fast retransmit should be
performed. Only when the sequence numbers are not equal, the dup_acks is
set to the initial value (0).
But if the initial packet would have the sequence number
BATADV_TP_FIRST_SEQ, dup_acks would not be initialized and atomic_inc would
operate on an undefined starting value. It is therefore required to have it
explicitly initialized during the start of the sender session.
Cc: stable@kernel.org
Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 0e39ea33e5f27..8d7308327a9bf 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -1045,6 +1045,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
tp_vars->icmp_uid = icmp_uid;
tp_vars->last_sent = BATADV_TP_FIRST_SEQ;
+ atomic_set(&tp_vars->dup_acks, 0);
atomic_set(&tp_vars->last_acked, BATADV_TP_FIRST_SEQ);
tp_vars->fast_recovery = false;
tp_vars->recover = BATADV_TP_FIRST_SEQ;
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 03/15] batman-adv: tp_meter: initialize dec_cwnd explicitly
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 01/15] batman-adv: tp_meter: keep unacked list in ascending ordered Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 02/15] batman-adv: tp_meter: initialize dup_acks explicitly Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 04/15] batman-adv: tp_meter: avoid window underflow Simon Wunderlich
` (11 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
When batadv_tp_update_cwnd() is called, dec_cwnd is increased. But dec_cwnd
is only initialixed (to 0) when a duplicate Ack was received or when cwnd
is below the ss_threshold.
Just initialize the cwnd during the initialization to avoid any potential
access of uninitialized data.
Cc: stable@kernel.org
Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 8d7308327a9bf..beabc264a4f16 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -1055,6 +1055,8 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
* mesh_interface, hence its MTU
*/
tp_vars->cwnd = BATADV_TP_PLEN * 3;
+ tp_vars->dec_cwnd = 0;
+
/* at the beginning initialise the SS threshold to the biggest possible
* window size, hence the AWND size
*/
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 04/15] batman-adv: tp_meter: avoid window underflow
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (2 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 03/15] batman-adv: tp_meter: initialize dec_cwnd explicitly Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 05/15] batman-adv: tp_meter: avoid divide-by-zero for dec_cwnd Simon Wunderlich
` (10 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
In batadv_tp_avail(), win_left is calculated with 32-bit unsigned
arithmetic: win_left = win_limit - tp_vars->last_sent;
During Fast Recovery, cwnd is inflated and last_sent advances rapidly. When
Fast Recovery ends, cwnd drops abruptly back to ss_threshold. If the newly
shrunk win_limit is less than last_sent, the unsigned subtraction will
underflow, wrapping to a massive positive value. Instead of returning that
the window is full (unavailable), it returns that the sender can continue
sending.
To handle this situation, it must be checked whether the windows end
sequence number (win_limit) has to be compared with the last sent sequence
number. If it would be before the last sent sequence number, then more acks
are needed before the transmission can be started again.
Cc: stable@kernel.org
Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index beabc264a4f16..9ecbc6023cfc9 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -817,10 +817,15 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
static bool batadv_tp_avail(struct batadv_tp_vars *tp_vars,
size_t payload_len)
{
+ u32 last_sent = READ_ONCE(tp_vars->last_sent);
u32 win_left, win_limit;
win_limit = atomic_read(&tp_vars->last_acked) + tp_vars->cwnd;
- win_left = win_limit - tp_vars->last_sent;
+
+ if (batadv_seq_before(last_sent, win_limit))
+ win_left = win_limit - last_sent;
+ else
+ win_left = 0;
return win_left >= payload_len;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 05/15] batman-adv: tp_meter: avoid divide-by-zero for dec_cwnd
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (3 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 04/15] batman-adv: tp_meter: avoid window underflow Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 06/15] batman-adv: tp_meter: fix fast recovery precondition Simon Wunderlich
` (9 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
The cwnd is always MSS <= cwnd <= 0x20000000. But the calculation in
batadv_tp_update_cwnd() assumes unsigned 32 bit arithmetics.
((mss * 8) ** 2) / (cwnd * 8)
In case cwnd is actually 0x20000000, it will be shifted by 3 bit to the
left end up at 0x100000000 or U32_MAX + 1. It will therefore wrap around
and be 0 - resulting in:
((mss * 8) ** 2) / 0
This is of course invalid and cannot be calculated. The calculation should
must be simplified to avoid this overflow:
(mss ** 2) * 8 / cwnd
It will keep the precision enhancement from the scaling (by 8) but avoid
the overflow in the divisor.
In theory, there could still be an overflow in the dividend. It is at the
moment fixed to BATADV_TP_PLEN in batadv_tp_recv_ack() - so it is not an
imminent problem. But allowing it to use the whole u32 bit range, would
mean that it can still use up to 67 bits. To keep this calculation safe for
32 bit arithmetic, mss must never use more than floor((32 - 3) / 2) bits -
or in other words: must never be larger than 16383.
Cc: stable@kernel.org
Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 9ecbc6023cfc9..1655f181c9293 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -154,9 +154,12 @@ static void batadv_tp_update_cwnd(struct batadv_tp_vars *tp_vars, u32 mss)
return;
}
+ /* prevent overflow in (mss * mss) << 3 */
+ mss = min_t(u32, mss, (1U << 14) - 1);
+
/* increment CWND at least of 1 (section 3.1 of RFC5681) */
tp_vars->dec_cwnd += max_t(u32, 1U << 3,
- ((mss * mss) << 6) / (tp_vars->cwnd << 3));
+ ((mss * mss) << 3) / tp_vars->cwnd);
if (tp_vars->dec_cwnd < (mss << 3)) {
spin_unlock_bh(&tp_vars->cwnd_lock);
return;
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 06/15] batman-adv: tp_meter: fix fast recovery precondition
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (4 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 05/15] batman-adv: tp_meter: avoid divide-by-zero for dec_cwnd Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 07/15] batman-adv: tp_meter: handle seqno wrap-around for fast recovery detection Simon Wunderlich
` (8 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
The fast recovery precondition checks if the recover (initialized to
BATADV_TP_FIRST_SEQ) is bigger than the received ack. But since recover is
only updated when this check is successful, it will never enter the fast
recovery mode.
According to RFC6582 Section 3.2 step 2, the check should actually be
different:
> When the third duplicate ACK is received, the TCP sender first
> checks the value of recover to see if the Cumulative
> Acknowledgment field covers more than recover
The precondition must therefore check if recover is smaller than the
received ack - basically swapping the operands of the current check.
Cc: stable@kernel.org
Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 1655f181c9293..ae6acbc60c8ed 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -733,7 +733,7 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
if (atomic_read(&tp_vars->dup_acks) != 3)
goto out;
- if (recv_ack >= tp_vars->recover)
+ if (tp_vars->recover >= recv_ack)
goto out;
/* if this is the third duplicate ACK do Fast Retransmit */
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 07/15] batman-adv: tp_meter: handle seqno wrap-around for fast recovery detection
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (5 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 06/15] batman-adv: tp_meter: fix fast recovery precondition Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 08/15] batman-adv: tp_meter: add only finished tp_vars to lists Simon Wunderlich
` (7 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
The recover variable and the last_sent sequence number are initialized on
purpose as a really high value which will wrap-around after the first 2000
bytes. The fast recovery precondition must therefore not use simple integer
comparisons but use helpers which are aware of the sequence number
wrap-arounds.
Cc: stable@kernel.org
Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index ae6acbc60c8ed..3d3d06c88e1c9 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -733,7 +733,7 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
if (atomic_read(&tp_vars->dup_acks) != 3)
goto out;
- if (tp_vars->recover >= recv_ack)
+ if (!batadv_seq_before(tp_vars->recover, recv_ack))
goto out;
/* if this is the third duplicate ACK do Fast Retransmit */
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 08/15] batman-adv: tp_meter: add only finished tp_vars to lists
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (6 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 07/15] batman-adv: tp_meter: handle seqno wrap-around for fast recovery detection Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 09/15] batman-adv: tp_meter: split vars into sender and receiver types Simon Wunderlich
` (6 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
When the receiver variables (aka "session") are initialized, then they are
added to the list of sessions before the timer is set up. A RCU protected
reader could therefore find the entry and run mod_setup before
batadv_tp_init_recv() finished the timer initialization.
The same is true for batadv_tp_start(), which must first initialize the
finish_work and the test_length to avoid a similar problem.
Cc: stable@kernel.org
Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 3d3d06c88e1c9..5498cdc972e98 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -1096,21 +1096,21 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
tp_vars->prerandom_offset = 0;
spin_lock_init(&tp_vars->prerandom_lock);
- kref_get(&tp_vars->refcount);
- hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
- spin_unlock_bh(&bat_priv->tp_list_lock);
-
tp_vars->test_length = test_length;
if (!tp_vars->test_length)
tp_vars->test_length = BATADV_TP_DEF_TEST_LENGTH;
+ /* init work item for finished tp tests */
+ INIT_DELAYED_WORK(&tp_vars->finish_work, batadv_tp_sender_finish);
+
+ kref_get(&tp_vars->refcount);
+ hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
+ spin_unlock_bh(&bat_priv->tp_list_lock);
+
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: starting throughput meter towards %pM (length=%ums)\n",
dst, test_length);
- /* init work item for finished tp tests */
- INIT_DELAYED_WORK(&tp_vars->finish_work, batadv_tp_sender_finish);
-
/* start tp kthread. This way the write() call issued from userspace can
* happily return and avoid to block
*/
@@ -1430,10 +1430,10 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv,
INIT_LIST_HEAD(&tp_vars->unacked_list);
kref_get(&tp_vars->refcount);
- hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
+ timer_setup(&tp_vars->timer, batadv_tp_receiver_shutdown, 0);
kref_get(&tp_vars->refcount);
- timer_setup(&tp_vars->timer, batadv_tp_receiver_shutdown, 0);
+ hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
batadv_tp_reset_receiver_timer(tp_vars);
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 09/15] batman-adv: tp_meter: split vars into sender and receiver types
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (7 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 08/15] batman-adv: tp_meter: add only finished tp_vars to lists Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 10/15] batman-adv: tp_meter: use locking for all congestion control variables Simon Wunderlich
` (5 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
The monolithic batadv_tp_vars struct holds fields for both sender and
receiver roles, distinguished only by a runtime enum role. This makes it
easy to accidentally access a field intended for the opposite role, since
neither the compiler nor the type system provide any guard against such
mistakes. The role check also adds unnecessary branching in several code
paths.
Introduce batadv_tp_vars_common to hold fields shared across both roles,
then derive two separate types (sender/receiver) from it. The functions can
operate on them without any ambiguity about the available fields. This also
reduces the memory footprint of receiver sessions, which no longer carry
the substantial sender-only fields.
Care must be taken to prevent concurrent TP sessions between the same two
peers in opposite directions, since sender and receiver sessions are now
tracked in separate lists and a lookup in one list no longer detects a
session in the other.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/main.c | 3 +-
net/batman-adv/tp_meter.c | 396 ++++++++++++++++++++++----------------
net/batman-adv/types.h | 101 +++++-----
3 files changed, 281 insertions(+), 219 deletions(-)
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 60d4f60066c80..3c4572284b532 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -194,7 +194,8 @@ int batadv_mesh_init(struct net_device *mesh_iface)
INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
INIT_HLIST_HEAD(&bat_priv->meshif_vlan_list);
- INIT_HLIST_HEAD(&bat_priv->tp_list);
+ INIT_HLIST_HEAD(&bat_priv->tp_sender_list);
+ INIT_HLIST_HEAD(&bat_priv->tp_receiver_list);
bat_priv->gw.generation = 0;
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 5498cdc972e98..c088d88804533 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -142,7 +142,7 @@ static u32 batadv_tp_cwnd(u32 base, u32 increment, u32 min)
* 2) if the session is in Congestion Avoidance, the CWND has to be
* increased by MSS * MSS / CWND for every unique received ACK
*/
-static void batadv_tp_update_cwnd(struct batadv_tp_vars *tp_vars, u32 mss)
+static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss)
{
spin_lock_bh(&tp_vars->cwnd_lock);
@@ -176,7 +176,7 @@ static void batadv_tp_update_cwnd(struct batadv_tp_vars *tp_vars, u32 mss)
* @tp_vars: the private data of the current TP meter session
* @new_rtt: new roundtrip time in msec
*/
-static void batadv_tp_update_rto(struct batadv_tp_vars *tp_vars,
+static void batadv_tp_update_rto(struct batadv_tp_sender *tp_vars,
u32 new_rtt)
{
long m = new_rtt;
@@ -255,35 +255,30 @@ static void batadv_tp_batctl_error_notify(enum batadv_tp_meter_reason reason,
}
/**
- * batadv_tp_list_find() - find a tp_vars object in the global list
+ * batadv_tp_list_find_sender() - find a sender tp_vars object in the global list
* @bat_priv: the bat priv with all the mesh interface information
* @dst: the other endpoint MAC address to look for
- * @role: role of the session
*
* Look for a tp_vars object matching dst as end_point and return it after
* having increment the refcounter. Return NULL is not found
*
* Return: matching tp_vars or NULL when no tp_vars with @dst was found
*/
-static struct batadv_tp_vars *batadv_tp_list_find(struct batadv_priv *bat_priv,
- const u8 *dst,
- enum batadv_tp_meter_role role)
+static struct batadv_tp_sender *
+batadv_tp_list_find_sender(struct batadv_priv *bat_priv, const u8 *dst)
{
- struct batadv_tp_vars *pos, *tp_vars = NULL;
+ struct batadv_tp_sender *pos, *tp_vars = NULL;
rcu_read_lock();
- hlist_for_each_entry_rcu(pos, &bat_priv->tp_list, list) {
- if (!batadv_compare_eth(pos->other_end, dst))
- continue;
-
- if (pos->role != role)
+ hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) {
+ if (!batadv_compare_eth(pos->common.other_end, dst))
continue;
/* most of the time this function is invoked during the normal
* process..it makes sens to pay more when the session is
* finished and to speed the process up during the measurement
*/
- if (unlikely(!kref_get_unless_zero(&pos->refcount)))
+ if (unlikely(!kref_get_unless_zero(&pos->common.refcount)))
continue;
tp_vars = pos;
@@ -304,10 +299,16 @@ static struct batadv_tp_vars *batadv_tp_list_find(struct batadv_priv *bat_priv,
static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst)
__must_hold(&bat_priv->tp_list_lock)
{
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_receiver *tp_receiver;
+ struct batadv_tp_sender *tp_sender;
+
+ hlist_for_each_entry_rcu(tp_sender, &bat_priv->tp_sender_list, common.list) {
+ if (batadv_compare_eth(tp_sender->common.other_end, dst))
+ return true;
+ }
- hlist_for_each_entry_rcu(tp_vars, &bat_priv->tp_list, list) {
- if (batadv_compare_eth(tp_vars->other_end, dst))
+ hlist_for_each_entry_rcu(tp_receiver, &bat_priv->tp_receiver_list, common.list) {
+ if (batadv_compare_eth(tp_receiver->common.other_end, dst))
return true;
}
@@ -315,12 +316,11 @@ static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst)
}
/**
- * batadv_tp_list_find_session() - find tp_vars session object in the global
- * list
+ * batadv_tp_list_find_sender_session() - find tp_vars sender session
+ * object in the global list
* @bat_priv: the bat priv with all the mesh interface information
* @dst: the other endpoint MAC address to look for
* @session: session identifier
- * @role: role of the session
*
* Look for a tp_vars object matching dst as end_point, session as tp meter
* session and return it after having increment the refcounter. Return NULL
@@ -328,28 +328,25 @@ static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst)
*
* Return: matching tp_vars or NULL when no tp_vars was found
*/
-static struct batadv_tp_vars *
-batadv_tp_list_find_session(struct batadv_priv *bat_priv, const u8 *dst,
- const u8 *session, enum batadv_tp_meter_role role)
+static struct batadv_tp_sender *
+batadv_tp_list_find_sender_session(struct batadv_priv *bat_priv, const u8 *dst,
+ const u8 *session)
{
- struct batadv_tp_vars *pos, *tp_vars = NULL;
+ struct batadv_tp_sender *pos, *tp_vars = NULL;
rcu_read_lock();
- hlist_for_each_entry_rcu(pos, &bat_priv->tp_list, list) {
- if (!batadv_compare_eth(pos->other_end, dst))
+ hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) {
+ if (!batadv_compare_eth(pos->common.other_end, dst))
continue;
- if (memcmp(pos->session, session, sizeof(pos->session)) != 0)
- continue;
-
- if (pos->role != role)
+ if (memcmp(pos->common.session, session, sizeof(pos->common.session)) != 0)
continue;
/* most of the time this function is invoked during the normal
* process..it makes sense to pay more when the session is
* finished and to speed the process up during the measurement
*/
- if (unlikely(!kref_get_unless_zero(&pos->refcount)))
+ if (unlikely(!kref_get_unless_zero(&pos->common.refcount)))
continue;
tp_vars = pos;
@@ -361,16 +358,16 @@ batadv_tp_list_find_session(struct batadv_priv *bat_priv, const u8 *dst,
}
/**
- * batadv_tp_vars_release() - release batadv_tp_vars from lists and queue for
- * free after rcu grace period
+ * batadv_tp_vars_common_release() - release batadv_tp_vars_common from lists
+ * and queue for free after rcu grace period
* @ref: kref pointer of the batadv_tp_vars
*/
-static void batadv_tp_vars_release(struct kref *ref)
+static void batadv_tp_vars_common_release(struct kref *ref)
{
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_vars_common *tp_vars;
struct batadv_tp_unacked *un, *safe;
- tp_vars = container_of(ref, struct batadv_tp_vars, refcount);
+ tp_vars = container_of(ref, struct batadv_tp_vars_common, refcount);
/* lock should not be needed because this object is now out of any
* context!
@@ -386,23 +383,25 @@ static void batadv_tp_vars_release(struct kref *ref)
}
/**
- * batadv_tp_vars_put() - decrement the batadv_tp_vars refcounter and possibly
- * release it
+ * batadv_tp_sender_put() - decrement the batadv_tp_sender
+ * refcounter and possibly release it
* @tp_vars: the private data of the current TP meter session to be free'd
*/
-static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_sender_put(struct batadv_tp_sender *tp_vars)
{
if (!tp_vars)
return;
- kref_put(&tp_vars->refcount, batadv_tp_vars_release);
+ kref_put(&tp_vars->common.refcount, batadv_tp_vars_common_release);
}
/**
- * batadv_tp_list_detach() - remove tp session from mesh session list once
+ * batadv_tp_list_detach() - remove tp receiver session from mesh session list once
* @tp_vars: the private data of the current TP meter session
+ *
+ * Return: whether tp_vars was detached from list and reference must be freed
*/
-static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars)
+static bool batadv_tp_list_detach(struct batadv_tp_vars_common *tp_vars)
{
bool detached = false;
@@ -414,27 +413,27 @@ static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars)
spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
if (!detached)
- return;
+ return false;
atomic_dec(&tp_vars->bat_priv->tp_num);
- /* drop list reference */
- batadv_tp_vars_put(tp_vars);
+ return true;
}
/**
* batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
* @tp_vars: the private data of the current TP meter session to cleanup
*/
-static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_sender_cleanup(struct batadv_tp_sender *tp_vars)
{
cancel_delayed_work_sync(&tp_vars->finish_work);
- batadv_tp_list_detach(tp_vars);
+ if (batadv_tp_list_detach(&tp_vars->common))
+ batadv_tp_sender_put(tp_vars);
/* kill the timer and remove its reference */
- timer_shutdown_sync(&tp_vars->timer);
- batadv_tp_vars_put(tp_vars);
+ timer_shutdown_sync(&tp_vars->common.timer);
+ batadv_tp_sender_put(tp_vars);
}
/**
@@ -443,7 +442,7 @@ static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars)
* @tp_vars: the private data of the current TP meter session
*/
static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
- struct batadv_tp_vars *tp_vars)
+ struct batadv_tp_sender *tp_vars)
{
enum batadv_tp_meter_reason reason;
u32 session_cookie;
@@ -452,7 +451,7 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Test towards %pM finished..shutting down (reason=%d)\n",
- tp_vars->other_end, reason);
+ tp_vars->common.other_end, reason);
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Last timing stats: SRTT=%ums RTTVAR=%ums RTO=%ums\n",
@@ -462,11 +461,11 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
"Final values: cwnd=%u ss_threshold=%u\n",
tp_vars->cwnd, tp_vars->ss_threshold);
- session_cookie = batadv_tp_session_cookie(tp_vars->session,
+ session_cookie = batadv_tp_session_cookie(tp_vars->common.session,
tp_vars->icmp_uid);
batadv_tp_batctl_notify(reason,
- tp_vars->other_end,
+ tp_vars->common.other_end,
bat_priv,
tp_vars->start_time,
atomic64_read(&tp_vars->tot_sent),
@@ -478,7 +477,7 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
* @tp_vars: the private data of the current TP meter session
* @reason: reason for tp meter session stop
*/
-static void batadv_tp_sender_shutdown(struct batadv_tp_vars *tp_vars,
+static void batadv_tp_sender_shutdown(struct batadv_tp_sender *tp_vars,
enum batadv_tp_meter_reason reason)
{
atomic_cmpxchg(&tp_vars->send_result, 0, reason);
@@ -490,7 +489,7 @@ static void batadv_tp_sender_shutdown(struct batadv_tp_vars *tp_vars,
*
* Return: whether stop reason was found
*/
-static bool batadv_tp_sender_stopped(struct batadv_tp_vars *tp_vars)
+static bool batadv_tp_sender_stopped(struct batadv_tp_sender *tp_vars)
{
return atomic_read(&tp_vars->send_result) != 0;
}
@@ -502,10 +501,10 @@ static bool batadv_tp_sender_stopped(struct batadv_tp_vars *tp_vars)
static void batadv_tp_sender_finish(struct work_struct *work)
{
struct delayed_work *delayed_work;
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_sender *tp_vars;
delayed_work = to_delayed_work(work);
- tp_vars = container_of(delayed_work, struct batadv_tp_vars,
+ tp_vars = container_of(delayed_work, struct batadv_tp_sender,
finish_work);
batadv_tp_sender_shutdown(tp_vars, BATADV_TP_REASON_COMPLETE);
@@ -517,7 +516,7 @@ static void batadv_tp_sender_finish(struct work_struct *work)
*
* Reschedule the timer using tp_vars->rto as delay
*/
-static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_reset_sender_timer(struct batadv_tp_sender *tp_vars)
{
/* most of the time this function is invoked while normal packet
* reception...
@@ -526,7 +525,7 @@ static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars)
/* timer ref will be dropped in batadv_tp_sender_cleanup */
return;
- mod_timer(&tp_vars->timer, jiffies + msecs_to_jiffies(tp_vars->rto));
+ mod_timer(&tp_vars->common.timer, jiffies + msecs_to_jiffies(tp_vars->rto));
}
/**
@@ -539,8 +538,8 @@ static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars)
*/
static void batadv_tp_sender_timeout(struct timer_list *t)
{
- struct batadv_tp_vars *tp_vars = timer_container_of(tp_vars, t, timer);
- struct batadv_priv *bat_priv = tp_vars->bat_priv;
+ struct batadv_tp_sender *tp_vars = timer_container_of(tp_vars, t, common.timer);
+ struct batadv_priv *bat_priv = tp_vars->common.bat_priv;
if (batadv_tp_sender_stopped(tp_vars))
return;
@@ -565,7 +564,7 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: RTO fired during test towards %pM! cwnd=%u new ss_thr=%u, resetting last_sent to %u\n",
- tp_vars->other_end, tp_vars->cwnd, tp_vars->ss_threshold,
+ tp_vars->common.other_end, tp_vars->cwnd, tp_vars->ss_threshold,
atomic_read(&tp_vars->last_acked));
tp_vars->cwnd = BATADV_TP_PLEN * 3;
@@ -585,7 +584,7 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
* @buf: Buffer to fill with bytes
* @nbytes: amount of pseudorandom bytes
*/
-static void batadv_tp_fill_prerandom(struct batadv_tp_vars *tp_vars,
+static void batadv_tp_fill_prerandom(struct batadv_tp_sender *tp_vars,
u8 *buf, size_t nbytes)
{
u32 local_offset;
@@ -628,7 +627,7 @@ static void batadv_tp_fill_prerandom(struct batadv_tp_vars *tp_vars,
* not reachable, BATADV_TP_REASON_MEMORY_ERROR if the packet couldn't be
* allocated
*/
-static int batadv_tp_send_msg(struct batadv_tp_vars *tp_vars, const u8 *src,
+static int batadv_tp_send_msg(struct batadv_tp_sender *tp_vars, const u8 *src,
struct batadv_orig_node *orig_node,
u32 seqno, size_t len, const u8 *session,
int uid, u32 timestamp)
@@ -684,7 +683,7 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
struct batadv_hard_iface *primary_if = NULL;
struct batadv_orig_node *orig_node = NULL;
const struct batadv_icmp_tp_packet *icmp;
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_sender *tp_vars;
const unsigned char *dev_addr;
size_t packet_len, mss;
u32 rtt, recv_ack, cwnd;
@@ -696,8 +695,8 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
icmp = (struct batadv_icmp_tp_packet *)skb->data;
/* find the tp_vars */
- tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig,
- icmp->session, BATADV_TP_SENDER);
+ tp_vars = batadv_tp_list_find_sender_session(bat_priv, icmp->orig,
+ icmp->session);
if (unlikely(!tp_vars))
return;
@@ -807,7 +806,7 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
out:
batadv_hardif_put(primary_if);
batadv_orig_node_put(orig_node);
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
}
/**
@@ -817,7 +816,7 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
*
* Return: true when congestion window is not full, false otherwise
*/
-static bool batadv_tp_avail(struct batadv_tp_vars *tp_vars,
+static bool batadv_tp_avail(struct batadv_tp_sender *tp_vars,
size_t payload_len)
{
u32 last_sent = READ_ONCE(tp_vars->last_sent);
@@ -844,7 +843,7 @@ static bool batadv_tp_avail(struct batadv_tp_vars *tp_vars,
* remaining jiffies (at least 1) if the condition evaluated to true before
* the timeout elapsed, or -ERESTARTSYS if it was interrupted by a signal.
*/
-static int batadv_tp_wait_available(struct batadv_tp_vars *tp_vars, size_t plen)
+static int batadv_tp_wait_available(struct batadv_tp_sender *tp_vars, size_t plen)
{
int ret;
@@ -863,20 +862,14 @@ static int batadv_tp_wait_available(struct batadv_tp_vars *tp_vars, size_t plen)
*/
static int batadv_tp_send(void *arg)
{
- struct batadv_tp_vars *tp_vars = arg;
- struct batadv_priv *bat_priv = tp_vars->bat_priv;
+ struct batadv_tp_sender *tp_vars = arg;
+ struct batadv_priv *bat_priv = tp_vars->common.bat_priv;
struct batadv_hard_iface *primary_if = NULL;
struct batadv_orig_node *orig_node = NULL;
size_t payload_len, packet_len;
int err = 0;
- if (unlikely(tp_vars->role != BATADV_TP_SENDER)) {
- err = BATADV_TP_REASON_DST_UNREACHABLE;
- batadv_tp_sender_shutdown(tp_vars, err);
- goto out;
- }
-
- orig_node = batadv_orig_hash_find(bat_priv, tp_vars->other_end);
+ orig_node = batadv_orig_hash_find(bat_priv, tp_vars->common.other_end);
if (unlikely(!orig_node)) {
err = BATADV_TP_REASON_DST_UNREACHABLE;
batadv_tp_sender_shutdown(tp_vars, err);
@@ -919,7 +912,7 @@ static int batadv_tp_send(void *arg)
err = batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr,
orig_node, tp_vars->last_sent,
packet_len,
- tp_vars->session, tp_vars->icmp_uid,
+ tp_vars->common.session, tp_vars->icmp_uid,
jiffies_to_msecs(jiffies));
/* something went wrong during the preparation/transmission */
@@ -947,7 +940,7 @@ static int batadv_tp_send(void *arg)
batadv_tp_sender_cleanup(tp_vars);
complete(&tp_vars->finished);
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
return 0;
}
@@ -957,24 +950,24 @@ static int batadv_tp_send(void *arg)
* sender
* @tp_vars: the private data of the current TP meter session
*/
-static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_start_kthread(struct batadv_tp_sender *tp_vars)
{
struct task_struct *kthread;
- struct batadv_priv *bat_priv = tp_vars->bat_priv;
+ struct batadv_priv *bat_priv = tp_vars->common.bat_priv;
u32 session_cookie;
- kref_get(&tp_vars->refcount);
+ kref_get(&tp_vars->common.refcount);
kthread = kthread_create(batadv_tp_send, tp_vars, "kbatadv_tp_meter");
if (IS_ERR(kthread)) {
- session_cookie = batadv_tp_session_cookie(tp_vars->session,
+ session_cookie = batadv_tp_session_cookie(tp_vars->common.session,
tp_vars->icmp_uid);
pr_err("batadv: cannot create tp meter kthread\n");
batadv_tp_batctl_error_notify(BATADV_TP_REASON_MEMORY_ERROR,
- tp_vars->other_end,
+ tp_vars->common.other_end,
bat_priv, session_cookie);
/* drop reserved reference for kthread */
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
/* cleanup of failed tp meter variables */
batadv_tp_sender_cleanup(tp_vars);
@@ -995,7 +988,7 @@ static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars)
void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
u32 test_length, u32 *cookie)
{
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_sender *tp_vars;
u8 session_id[2];
u8 icmp_uid;
u32 session_cookie;
@@ -1045,11 +1038,10 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
}
/* initialize tp_vars */
- ether_addr_copy(tp_vars->other_end, dst);
- kref_init(&tp_vars->refcount);
- tp_vars->role = BATADV_TP_SENDER;
+ ether_addr_copy(tp_vars->common.other_end, dst);
+ kref_init(&tp_vars->common.refcount);
atomic_set(&tp_vars->send_result, 0);
- memcpy(tp_vars->session, session_id, sizeof(session_id));
+ memcpy(tp_vars->common.session, session_id, sizeof(session_id));
tp_vars->icmp_uid = icmp_uid;
tp_vars->last_sent = BATADV_TP_FIRST_SEQ;
@@ -1079,17 +1071,17 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
atomic64_set(&tp_vars->tot_sent, 0);
- kref_get(&tp_vars->refcount);
- timer_setup(&tp_vars->timer, batadv_tp_sender_timeout, 0);
+ kref_get(&tp_vars->common.refcount);
+ timer_setup(&tp_vars->common.timer, batadv_tp_sender_timeout, 0);
- tp_vars->bat_priv = bat_priv;
+ tp_vars->common.bat_priv = bat_priv;
tp_vars->start_time = jiffies;
init_waitqueue_head(&tp_vars->more_bytes);
init_completion(&tp_vars->finished);
- spin_lock_init(&tp_vars->unacked_lock);
- INIT_LIST_HEAD(&tp_vars->unacked_list);
+ spin_lock_init(&tp_vars->common.unacked_lock);
+ INIT_LIST_HEAD(&tp_vars->common.unacked_list);
spin_lock_init(&tp_vars->cwnd_lock);
@@ -1103,8 +1095,8 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
/* init work item for finished tp tests */
INIT_DELAYED_WORK(&tp_vars->finish_work, batadv_tp_sender_finish);
- kref_get(&tp_vars->refcount);
- hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
+ kref_get(&tp_vars->common.refcount);
+ hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_sender_list);
spin_unlock_bh(&bat_priv->tp_list_lock);
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
@@ -1117,7 +1109,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
batadv_tp_start_kthread(tp_vars);
/* don't return reference to new tp_vars */
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
}
/**
@@ -1130,7 +1122,7 @@ void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
u8 return_value)
{
struct batadv_orig_node *orig_node;
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_sender *tp_vars;
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: stopping test towards %pM\n", dst);
@@ -1139,7 +1131,7 @@ void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
if (!orig_node)
return;
- tp_vars = batadv_tp_list_find(bat_priv, orig_node->orig, BATADV_TP_SENDER);
+ tp_vars = batadv_tp_list_find_sender(bat_priv, orig_node->orig);
if (!tp_vars) {
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: trying to interrupt an already over connection\n");
@@ -1147,20 +1139,75 @@ void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
}
batadv_tp_sender_shutdown(tp_vars, return_value);
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
out_put_orig_node:
batadv_orig_node_put(orig_node);
}
+/**
+ * batadv_tp_list_find_receiver_session() - find tp_vars receiver session
+ * object in the global list
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @dst: the other endpoint MAC address to look for
+ * @session: session identifier
+ *
+ * Look for a tp_vars object matching dst as end_point, session as tp meter
+ * session and return it after having increment the refcounter. Return NULL
+ * is not found
+ *
+ * Return: matching tp_vars or NULL when no tp_vars was found
+ */
+static struct batadv_tp_receiver *
+batadv_tp_list_find_receiver_session(struct batadv_priv *bat_priv, const u8 *dst,
+ const u8 *session)
+{
+ struct batadv_tp_receiver *pos, *tp_vars = NULL;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(pos, &bat_priv->tp_receiver_list, common.list) {
+ if (!batadv_compare_eth(pos->common.other_end, dst))
+ continue;
+
+ if (memcmp(pos->common.session, session, sizeof(pos->common.session)) != 0)
+ continue;
+
+ /* most of the time this function is invoked during the normal
+ * process..it makes sense to pay more when the session is
+ * finished and to speed the process up during the measurement
+ */
+ if (unlikely(!kref_get_unless_zero(&pos->common.refcount)))
+ continue;
+
+ tp_vars = pos;
+ break;
+ }
+ rcu_read_unlock();
+
+ return tp_vars;
+}
+
+/**
+ * batadv_tp_receiver_put() - decrement the batadv_tp_receiver
+ * refcounter and possibly release it
+ * @tp_vars: the private data of the current TP meter session to be free'd
+ */
+static void batadv_tp_receiver_put(struct batadv_tp_receiver *tp_vars)
+{
+ if (!tp_vars)
+ return;
+
+ kref_put(&tp_vars->common.refcount, batadv_tp_vars_common_release);
+}
+
/**
* batadv_tp_reset_receiver_timer() - reset the receiver shutdown timer
* @tp_vars: the private data of the current TP meter session
*
* start the receiver shutdown timer or reset it if already started
*/
-static void batadv_tp_reset_receiver_timer(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_reset_receiver_timer(struct batadv_tp_receiver *tp_vars)
{
- mod_timer(&tp_vars->timer,
+ mod_timer(&tp_vars->common.timer,
jiffies + msecs_to_jiffies(BATADV_TP_RECV_TIMEOUT));
}
@@ -1171,11 +1218,11 @@ static void batadv_tp_reset_receiver_timer(struct batadv_tp_vars *tp_vars)
*/
static void batadv_tp_receiver_shutdown(struct timer_list *t)
{
- struct batadv_tp_vars *tp_vars = timer_container_of(tp_vars, t, timer);
+ struct batadv_tp_receiver *tp_vars = timer_container_of(tp_vars, t, common.timer);
struct batadv_tp_unacked *un, *safe;
struct batadv_priv *bat_priv;
- bat_priv = tp_vars->bat_priv;
+ bat_priv = tp_vars->common.bat_priv;
/* if there is recent activity rearm the timer */
if (!batadv_has_timed_out(tp_vars->last_recv_time,
@@ -1187,22 +1234,23 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t)
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Shutting down for inactivity (more than %dms) from %pM\n",
- BATADV_TP_RECV_TIMEOUT, tp_vars->other_end);
+ BATADV_TP_RECV_TIMEOUT, tp_vars->common.other_end);
- batadv_tp_list_detach(tp_vars);
+ if (batadv_tp_list_detach(&tp_vars->common))
+ batadv_tp_receiver_put(tp_vars);
- spin_lock_bh(&tp_vars->unacked_lock);
- list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
+ spin_lock_bh(&tp_vars->common.unacked_lock);
+ list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) {
list_del(&un->list);
kfree(un);
}
- spin_unlock_bh(&tp_vars->unacked_lock);
+ spin_unlock_bh(&tp_vars->common.unacked_lock);
/* drop reference of timer */
if (WARN_ON(atomic_xchg(&tp_vars->receiving, 0) != 1))
return;
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_receiver_put(tp_vars);
}
/**
@@ -1286,7 +1334,7 @@ static int batadv_tp_send_ack(struct batadv_priv *bat_priv, const u8 *dst,
*
* Return: true if the packed has been successfully processed, false otherwise
*/
-static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
+static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars,
const struct sk_buff *skb)
{
const struct batadv_icmp_tp_packet *icmp;
@@ -1304,10 +1352,10 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
payload_len = skb->len - sizeof(struct batadv_unicast_packet);
new->len = payload_len;
- spin_lock_bh(&tp_vars->unacked_lock);
+ spin_lock_bh(&tp_vars->common.unacked_lock);
/* if the list is empty immediately attach this new object */
- if (list_empty(&tp_vars->unacked_list)) {
- list_add(&new->list, &tp_vars->unacked_list);
+ if (list_empty(&tp_vars->common.unacked_list)) {
+ list_add(&new->list, &tp_vars->common.unacked_list);
goto out;
}
@@ -1318,7 +1366,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
* the last received packet (the one being processed now) has a bigger
* seqno than all the others already stored.
*/
- list_for_each_entry_reverse(un, &tp_vars->unacked_list, list) {
+ list_for_each_entry_reverse(un, &tp_vars->common.unacked_list, list) {
/* check for duplicates */
if (new->seqno == un->seqno) {
if (new->len > un->len)
@@ -1343,10 +1391,10 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
/* received packet with smallest seqno out of order; add it to front */
if (!added)
- list_add(&new->list, &tp_vars->unacked_list);
+ list_add(&new->list, &tp_vars->common.unacked_list);
out:
- spin_unlock_bh(&tp_vars->unacked_lock);
+ spin_unlock_bh(&tp_vars->common.unacked_lock);
return true;
}
@@ -1356,7 +1404,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
* without gaps
* @tp_vars: the private data of the current TP meter session
*/
-static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars)
{
struct batadv_tp_unacked *un, *safe;
u32 to_ack;
@@ -1364,8 +1412,8 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)
/* go through the unacked packet list and possibly ACK them as
* well
*/
- spin_lock_bh(&tp_vars->unacked_lock);
- list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
+ spin_lock_bh(&tp_vars->common.unacked_lock);
+ list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) {
/* the list is ordered, therefore it is possible to stop as soon
* there is a gap between the last acked seqno and the seqno of
* the packet under inspection
@@ -1381,7 +1429,7 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)
list_del(&un->list);
kfree(un);
}
- spin_unlock_bh(&tp_vars->unacked_lock);
+ spin_unlock_bh(&tp_vars->common.unacked_lock);
}
/**
@@ -1391,18 +1439,18 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)
*
* Return: corresponding tp_vars or NULL on errors
*/
-static struct batadv_tp_vars *
+static struct batadv_tp_receiver *
batadv_tp_init_recv(struct batadv_priv *bat_priv,
const struct batadv_icmp_tp_packet *icmp)
{
- struct batadv_tp_vars *tp_vars = NULL;
+ struct batadv_tp_receiver *tp_vars = NULL;
spin_lock_bh(&bat_priv->tp_list_lock);
if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
goto out_unlock;
- tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig,
- icmp->session, BATADV_TP_RECEIVER);
+ tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig,
+ icmp->session);
if (tp_vars)
goto out_unlock;
@@ -1418,22 +1466,21 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv,
goto out_unlock;
}
- ether_addr_copy(tp_vars->other_end, icmp->orig);
- tp_vars->role = BATADV_TP_RECEIVER;
+ ether_addr_copy(tp_vars->common.other_end, icmp->orig);
atomic_set(&tp_vars->receiving, 1);
- memcpy(tp_vars->session, icmp->session, sizeof(tp_vars->session));
+ memcpy(tp_vars->common.session, icmp->session, sizeof(tp_vars->common.session));
tp_vars->last_recv = BATADV_TP_FIRST_SEQ;
- tp_vars->bat_priv = bat_priv;
- kref_init(&tp_vars->refcount);
+ tp_vars->common.bat_priv = bat_priv;
+ kref_init(&tp_vars->common.refcount);
- spin_lock_init(&tp_vars->unacked_lock);
- INIT_LIST_HEAD(&tp_vars->unacked_list);
+ spin_lock_init(&tp_vars->common.unacked_lock);
+ INIT_LIST_HEAD(&tp_vars->common.unacked_list);
- kref_get(&tp_vars->refcount);
- timer_setup(&tp_vars->timer, batadv_tp_receiver_shutdown, 0);
+ kref_get(&tp_vars->common.refcount);
+ timer_setup(&tp_vars->common.timer, batadv_tp_receiver_shutdown, 0);
- kref_get(&tp_vars->refcount);
- hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
+ kref_get(&tp_vars->common.refcount);
+ hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_receiver_list);
batadv_tp_reset_receiver_timer(tp_vars);
@@ -1454,7 +1501,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
const struct sk_buff *skb)
{
const struct batadv_icmp_tp_packet *icmp;
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_receiver *tp_vars;
size_t packet_size;
u32 seqno;
@@ -1472,8 +1519,8 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
goto out;
}
} else {
- tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig,
- icmp->session, BATADV_TP_RECEIVER);
+ tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig,
+ icmp->session);
if (!tp_vars) {
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Unexpected packet from %pM!\n",
@@ -1517,7 +1564,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
batadv_tp_send_ack(bat_priv, icmp->orig, tp_vars->last_recv,
icmp->timestamp, icmp->session, icmp->uid);
out:
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_receiver_put(tp_vars);
}
/**
@@ -1557,45 +1604,58 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb)
*/
void batadv_tp_stop_all(struct batadv_priv *bat_priv)
{
- struct batadv_tp_vars *tp_vars[BATADV_TP_MAX_NUM];
- struct batadv_tp_vars *tp_var;
- size_t count = 0;
+ struct batadv_tp_receiver *tp_receivers[BATADV_TP_MAX_NUM];
+ struct batadv_tp_sender *tp_senders[BATADV_TP_MAX_NUM];
+ struct batadv_tp_receiver *tp_receiver;
+ struct batadv_tp_sender *tp_sender;
+ size_t receiver_count = 0;
+ size_t sender_count = 0;
size_t i;
spin_lock_bh(&bat_priv->tp_list_lock);
- hlist_for_each_entry(tp_var, &bat_priv->tp_list, list) {
- if (WARN_ON_ONCE(count >= BATADV_TP_MAX_NUM))
+ hlist_for_each_entry(tp_receiver, &bat_priv->tp_receiver_list, common.list) {
+ if (WARN_ON_ONCE(receiver_count >= BATADV_TP_MAX_NUM))
break;
- if (!kref_get_unless_zero(&tp_var->refcount))
+ if (!kref_get_unless_zero(&tp_receiver->common.refcount))
continue;
- tp_vars[count++] = tp_var;
+ tp_receivers[receiver_count++] = tp_receiver;
+ }
+
+ hlist_for_each_entry(tp_sender, &bat_priv->tp_sender_list, common.list) {
+ if (WARN_ON_ONCE(sender_count >= BATADV_TP_MAX_NUM))
+ break;
+
+ if (!kref_get_unless_zero(&tp_sender->common.refcount))
+ continue;
+
+ tp_senders[sender_count++] = tp_sender;
}
spin_unlock_bh(&bat_priv->tp_list_lock);
- for (i = 0; i < count; i++) {
- tp_var = tp_vars[i];
+ for (i = 0; i < receiver_count; i++) {
+ tp_receiver = tp_receivers[i];
- switch (tp_var->role) {
- case BATADV_TP_SENDER:
- batadv_tp_sender_shutdown(tp_var,
- BATADV_TP_REASON_CANCEL);
- wake_up(&tp_var->more_bytes);
- wait_for_completion(&tp_var->finished);
- break;
- case BATADV_TP_RECEIVER:
- batadv_tp_list_detach(tp_var);
- timer_shutdown_sync(&tp_var->timer);
+ if (batadv_tp_list_detach(&tp_receiver->common))
+ batadv_tp_receiver_put(tp_receiver);
- if (atomic_xchg(&tp_var->receiving, 0) != 1)
- break;
+ timer_shutdown_sync(&tp_receiver->common.timer);
- batadv_tp_vars_put(tp_var);
- break;
- }
+ if (atomic_xchg(&tp_receiver->receiving, 0) != 0)
+ batadv_tp_receiver_put(tp_receiver);
+
+ batadv_tp_receiver_put(tp_receiver);
+ }
+
+ for (i = 0; i < sender_count; i++) {
+ tp_sender = tp_senders[i];
+
+ batadv_tp_sender_shutdown(tp_sender, BATADV_TP_REASON_CANCEL);
+ wake_up(&tp_sender->more_bytes);
+ wait_for_completion(&tp_sender->finished);
- batadv_tp_vars_put(tp_var);
+ batadv_tp_sender_put(tp_sender);
}
synchronize_net();
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 19c7316889b6e..f7817a68a29ca 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1336,21 +1336,10 @@ struct batadv_tp_unacked {
};
/**
- * enum batadv_tp_meter_role - Modus in tp meter session
+ * struct batadv_tp_vars_common - common tp meter private variables per session
*/
-enum batadv_tp_meter_role {
- /** @BATADV_TP_RECEIVER: Initialized as receiver */
- BATADV_TP_RECEIVER,
-
- /** @BATADV_TP_SENDER: Initialized as sender */
- BATADV_TP_SENDER
-};
-
-/**
- * struct batadv_tp_vars - tp meter private variables per session
- */
-struct batadv_tp_vars {
- /** @list: list node for &bat_priv.tp_list */
+struct batadv_tp_vars_common {
+ /** @list: list node for &bat_priv.tp_sender_list/&bat_priv.tp_receiver_list */
struct hlist_node list;
/** @timer: timer for ack (receiver) and retry (sender) */
@@ -1359,14 +1348,34 @@ struct batadv_tp_vars {
/** @bat_priv: pointer to the mesh object */
struct batadv_priv *bat_priv;
- /** @start_time: start time in jiffies */
- unsigned long start_time;
-
/** @other_end: mac address of remote */
u8 other_end[ETH_ALEN];
- /** @role: receiver/sender modi */
- enum batadv_tp_meter_role role;
+ /** @session: TP session identifier */
+ u8 session[2];
+
+ /** @unacked_list: list of unacked packets (meta-info only) */
+ struct list_head unacked_list;
+
+ /** @unacked_lock: protect unacked_list */
+ spinlock_t unacked_lock;
+
+ /** @refcount: number of context where the object is used */
+ struct kref refcount;
+
+ /** @rcu: struct used for freeing in an RCU-safe manner */
+ struct rcu_head rcu;
+};
+
+/**
+ * struct batadv_tp_sender - sender tp meter private variables per session
+ */
+struct batadv_tp_sender {
+ /** @common: common batadv_tp_vars (best be first member) */
+ struct batadv_tp_vars_common common;
+
+ /** @start_time: start time in jiffies */
+ unsigned long start_time;
/**
* @send_result: 0 when sending is ongoing and otherwise
@@ -1374,8 +1383,14 @@ struct batadv_tp_vars {
*/
atomic_t send_result;
- /** @receiving: receiving binary semaphore: 1 if receiving, 0 is not */
- atomic_t receiving;
+ /** @last_sent: last sent byte, not yet acked */
+ u32 last_sent;
+
+ /** @fast_recovery: true if in Fast Recovery mode */
+ unsigned char fast_recovery:1;
+
+ /** @recover: last sent seqno when entering Fast Recovery */
+ u32 recover;
/** @finish_work: work item for the finishing procedure */
struct delayed_work finish_work;
@@ -1386,14 +1401,9 @@ struct batadv_tp_vars {
/** @test_length: test length in milliseconds */
u32 test_length;
- /** @session: TP session identifier */
- u8 session[2];
-
/** @icmp_uid: local ICMP "socket" index */
u8 icmp_uid;
- /* sender variables */
-
/** @dec_cwnd: decimal part of the cwnd used during linear growth */
u16 dec_cwnd;
@@ -1412,21 +1422,12 @@ struct batadv_tp_vars {
/** @last_acked: last acked byte */
atomic_t last_acked;
- /** @last_sent: last sent byte, not yet acked */
- u32 last_sent;
-
/** @tot_sent: amount of data sent/ACKed so far */
atomic64_t tot_sent;
/** @dup_acks: duplicate ACKs counter */
atomic_t dup_acks;
- /** @fast_recovery: true if in Fast Recovery mode */
- unsigned char fast_recovery:1;
-
- /** @recover: last sent seqno when entering Fast Recovery */
- u32 recover;
-
/** @rto: sender timeout */
u32 rto;
@@ -1447,26 +1448,23 @@ struct batadv_tp_vars {
/** @prerandom_lock: spinlock protecting access to prerandom_offset */
spinlock_t prerandom_lock;
+};
- /* receiver variables */
+/**
+ * struct batadv_tp_receiver - receiver tp meter private variables per session
+ */
+struct batadv_tp_receiver {
+ /** @common: common batadv_tp_vars (best be first member) */
+ struct batadv_tp_vars_common common;
+
+ /** @receiving: receiving binary semaphore: 1 if receiving, 0 is not */
+ atomic_t receiving;
/** @last_recv: last in-order received packet */
u32 last_recv;
- /** @unacked_list: list of unacked packets (meta-info only) */
- struct list_head unacked_list;
-
- /** @unacked_lock: protect unacked_list */
- spinlock_t unacked_lock;
-
/** @last_recv_time: time (jiffies) a msg was received */
unsigned long last_recv_time;
-
- /** @refcount: number of context where the object is used */
- struct kref refcount;
-
- /** @rcu: struct used for freeing in an RCU-safe manner */
- struct rcu_head rcu;
};
/**
@@ -1643,8 +1641,11 @@ struct batadv_priv {
*/
struct hlist_head forw_bcast_list;
- /** @tp_list: list of tp sessions */
- struct hlist_head tp_list;
+ /** @tp_sender_list: list of tp sender sessions */
+ struct hlist_head tp_sender_list;
+
+ /** @tp_receiver_list: list of tp receiver sessions */
+ struct hlist_head tp_receiver_list;
/** @orig_hash: hash table containing mesh participants (orig nodes) */
struct batadv_hashtable *orig_hash;
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 10/15] batman-adv: tp_meter: use locking for all congestion control variables
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (8 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 09/15] batman-adv: tp_meter: split vars into sender and receiver types Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 11/15] batman-adv: tp_meter: consolidate " Simon Wunderlich
` (4 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
Some variables used atomic_t for concurrent access while others relied on
cwnd_lock, leading to an inconsistent locking model. This can be simplified
by:
* keeping all congestion control decisions inside the cc_lock
* variables which can be accessed without a lock must use
READ_ONCE/WRITE_ONE
This is only possible, by extracting the congestion control logic from
batadv_tp_recv_ack() into a new helper batadv_tp_handle_ack(). Its
decisions are returned as a batadv_tp_ack_reaction enum value and then
applied by the caller. This separates the algorithm (deciding what to do)
from the mechanism (actually doing it).
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 272 +++++++++++++++++++++++---------------
net/batman-adv/types.h | 8 +-
2 files changed, 170 insertions(+), 110 deletions(-)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index c088d88804533..e9ba1c45a285d 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -143,14 +143,12 @@ static u32 batadv_tp_cwnd(u32 base, u32 increment, u32 min)
* increased by MSS * MSS / CWND for every unique received ACK
*/
static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss)
+ __must_hold(&tp_vars->cwnd_lock)
{
- spin_lock_bh(&tp_vars->cwnd_lock);
-
/* slow start... */
if (tp_vars->cwnd <= tp_vars->ss_threshold) {
tp_vars->dec_cwnd = 0;
tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd, mss, mss);
- spin_unlock_bh(&tp_vars->cwnd_lock);
return;
}
@@ -160,15 +158,11 @@ static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss)
/* increment CWND at least of 1 (section 3.1 of RFC5681) */
tp_vars->dec_cwnd += max_t(u32, 1U << 3,
((mss * mss) << 3) / tp_vars->cwnd);
- if (tp_vars->dec_cwnd < (mss << 3)) {
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ if (tp_vars->dec_cwnd < (mss << 3))
return;
- }
tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd, mss, mss);
tp_vars->dec_cwnd = 0;
-
- spin_unlock_bh(&tp_vars->cwnd_lock);
}
/**
@@ -178,6 +172,7 @@ static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss)
*/
static void batadv_tp_update_rto(struct batadv_tp_sender *tp_vars,
u32 new_rtt)
+ __must_hold(&tp_vars->cwnd_lock)
{
long m = new_rtt;
@@ -197,14 +192,14 @@ static void batadv_tp_update_rto(struct batadv_tp_sender *tp_vars,
tp_vars->rttvar += m; /* mdev ~= 3/4 rttvar + 1/4 new */
} else {
/* first measure getting in */
- tp_vars->srtt = m << 3; /* take the measured time to be srtt */
+ tp_vars->srtt = m << 3; /* take the measured time to be srtt */
tp_vars->rttvar = m << 1; /* new_rtt / 2 */
}
/* rto = srtt + 4 * rttvar.
* rttvar is scaled by 4, therefore doesn't need to be multiplied
*/
- tp_vars->rto = (tp_vars->srtt >> 3) + tp_vars->rttvar;
+ WRITE_ONCE(tp_vars->rto, (tp_vars->srtt >> 3) + tp_vars->rttvar);
}
/**
@@ -525,7 +520,8 @@ static void batadv_tp_reset_sender_timer(struct batadv_tp_sender *tp_vars)
/* timer ref will be dropped in batadv_tp_sender_cleanup */
return;
- mod_timer(&tp_vars->common.timer, jiffies + msecs_to_jiffies(tp_vars->rto));
+ mod_timer(&tp_vars->common.timer,
+ jiffies + msecs_to_jiffies(READ_ONCE(tp_vars->rto)));
}
/**
@@ -544,8 +540,11 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
if (batadv_tp_sender_stopped(tp_vars))
return;
+ spin_lock_bh(&tp_vars->cwnd_lock);
+
/* if the user waited long enough...shutdown the test */
if (unlikely(tp_vars->rto >= BATADV_TP_MAX_RTO)) {
+ spin_unlock_bh(&tp_vars->cwnd_lock);
batadv_tp_sender_shutdown(tp_vars,
BATADV_TP_REASON_DST_UNREACHABLE);
return;
@@ -554,9 +553,7 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
/* RTO exponential backoff
* Details in Section 5.5 of RFC6298
*/
- tp_vars->rto <<= 1;
-
- spin_lock_bh(&tp_vars->cwnd_lock);
+ WRITE_ONCE(tp_vars->rto, tp_vars->rto * 2);
tp_vars->ss_threshold = tp_vars->cwnd >> 1;
if (tp_vars->ss_threshold < BATADV_TP_PLEN * 2)
@@ -565,14 +562,15 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: RTO fired during test towards %pM! cwnd=%u new ss_thr=%u, resetting last_sent to %u\n",
tp_vars->common.other_end, tp_vars->cwnd, tp_vars->ss_threshold,
- atomic_read(&tp_vars->last_acked));
+ tp_vars->last_acked);
tp_vars->cwnd = BATADV_TP_PLEN * 3;
+ WRITE_ONCE(tp_vars->last_sent, tp_vars->last_acked);
+
spin_unlock_bh(&tp_vars->cwnd_lock);
/* resend the non-ACKed packets.. */
- tp_vars->last_sent = atomic_read(&tp_vars->last_acked);
wake_up(&tp_vars->more_bytes);
batadv_tp_reset_sender_timer(tp_vars);
@@ -670,6 +668,115 @@ static int batadv_tp_send_msg(struct batadv_tp_sender *tp_vars, const u8 *src,
return BATADV_TP_REASON_CANT_SEND;
}
+/**
+ * enum batadv_tp_ack_reaction - expected reaction to ack packet
+ */
+enum batadv_tp_ack_reaction {
+ /** @BATADV_TP_ACK_REACTION_OLD_ACK: ignore old ack packet */
+ BATADV_TP_ACK_REACTION_OLD_ACK,
+
+ /** @BATADV_TP_ACK_REACTION_IGNORE: ignore duplicated ack but reset timer */
+ BATADV_TP_ACK_REACTION_IGNORE,
+
+ /** @BATADV_TP_ACK_REACTION_RESEND_WAKEUP: resend data and wakeup "more_bytes" */
+ BATADV_TP_ACK_REACTION_RESEND_WAKEUP,
+
+ /** @BATADV_TP_ACK_REACTION_WAKEUP: wakeup "more_bytes" */
+ BATADV_TP_ACK_REACTION_WAKEUP,
+};
+
+/**
+ * batadv_tp_handle_ack() - Calculate reaction to ACK and update congestion control
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @tp_vars: the private data of the current TP meter session
+ * @recv_ack: received ACK seqno
+ * @mss: maximum segment size for transmission
+ *
+ * Return: expected reaction to this ack
+ */
+static enum batadv_tp_ack_reaction
+batadv_tp_handle_ack(struct batadv_priv *bat_priv,
+ struct batadv_tp_sender *tp_vars,
+ u32 recv_ack, size_t mss)
+ __must_hold(&tp_vars->cwnd_lock)
+{
+ enum batadv_tp_ack_reaction reaction;
+
+ if (batadv_seq_before(recv_ack, tp_vars->last_acked))
+ return BATADV_TP_ACK_REACTION_OLD_ACK;
+
+ /* check if this ACK is a duplicate */
+ if (tp_vars->last_acked == recv_ack) {
+ /* if this is the third duplicate ACK do Fast Retransmit */
+ if (tp_vars->dup_acks > 3)
+ return BATADV_TP_ACK_REACTION_IGNORE;
+
+ tp_vars->dup_acks++;
+ if (tp_vars->dup_acks != 3)
+ return BATADV_TP_ACK_REACTION_IGNORE;
+
+ if (!batadv_seq_before(tp_vars->recover, recv_ack))
+ return BATADV_TP_ACK_REACTION_IGNORE;
+
+ /* Fast Recovery */
+ tp_vars->fast_recovery = true;
+
+ /* Set recover to the last outstanding seqno when Fast Recovery
+ * is entered. RFC6582, Section 3.2, step 1
+ */
+ tp_vars->recover = tp_vars->last_sent;
+ tp_vars->ss_threshold = tp_vars->cwnd >> 1;
+ batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
+ "Meter: Fast Recovery, (cur cwnd=%u) ss_thr=%u last_sent=%u recv_ack=%u\n",
+ tp_vars->cwnd, tp_vars->ss_threshold,
+ tp_vars->last_sent, recv_ack);
+ tp_vars->cwnd = batadv_tp_cwnd(tp_vars->ss_threshold, 3 * mss,
+ mss);
+ tp_vars->dec_cwnd = 0;
+ WRITE_ONCE(tp_vars->last_sent, recv_ack);
+
+ return BATADV_TP_ACK_REACTION_RESEND_WAKEUP;
+ }
+
+ /* count the acked data */
+ atomic64_add(recv_ack - tp_vars->last_acked, &tp_vars->tot_sent);
+
+ /* reset the duplicate ACKs counter */
+ tp_vars->dup_acks = 0;
+
+ if (tp_vars->fast_recovery) {
+ /* partial ACK */
+ if (batadv_seq_before(recv_ack, tp_vars->recover)) {
+ /* this is another hole in the window. React
+ * immediately as specified by NewReno (see
+ * Section 3.2 of RFC6582 for details)
+ */
+ reaction = BATADV_TP_ACK_REACTION_RESEND_WAKEUP;
+ tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd,
+ mss, mss);
+ } else {
+ tp_vars->fast_recovery = false;
+ /* set cwnd to the value of ss_threshold at the
+ * moment that Fast Recovery was entered.
+ * RFC6582, Section 3.2, step 3
+ */
+ tp_vars->cwnd = batadv_tp_cwnd(tp_vars->ss_threshold,
+ 0, mss);
+ reaction = BATADV_TP_ACK_REACTION_WAKEUP;
+ }
+ } else {
+ if (recv_ack - tp_vars->last_acked >= mss)
+ batadv_tp_update_cwnd(tp_vars, mss);
+
+ reaction = BATADV_TP_ACK_REACTION_WAKEUP;
+ }
+
+ /* move the Transmit Window */
+ WRITE_ONCE(tp_vars->last_acked, recv_ack);
+
+ return reaction;
+}
+
/**
* batadv_tp_recv_ack() - ACK receiving function
* @bat_priv: the bat priv with all the mesh interface information
@@ -683,16 +790,19 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
struct batadv_hard_iface *primary_if = NULL;
struct batadv_orig_node *orig_node = NULL;
const struct batadv_icmp_tp_packet *icmp;
+ enum batadv_tp_ack_reaction reaction;
struct batadv_tp_sender *tp_vars;
- const unsigned char *dev_addr;
- size_t packet_len, mss;
- u32 rtt, recv_ack, cwnd;
+ size_t packet_len;
+ u32 recv_ack;
+ size_t mss;
+ u32 rtt;
packet_len = BATADV_TP_PLEN;
mss = BATADV_TP_PLEN;
packet_len += sizeof(struct batadv_unicast_packet);
icmp = (struct batadv_icmp_tp_packet *)skb->data;
+ recv_ack = ntohl(icmp->seqno);
/* find the tp_vars */
tp_vars = batadv_tp_list_find_sender_session(bat_priv, icmp->orig,
@@ -704,8 +814,7 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
goto out;
/* old ACK? silently drop it.. */
- if (batadv_seq_before(ntohl(icmp->seqno),
- (u32)atomic_read(&tp_vars->last_acked)))
+ if (batadv_seq_before(recv_ack, READ_ONCE(tp_vars->last_acked)))
goto out;
primary_if = batadv_primary_if_get_selected(bat_priv);
@@ -716,93 +825,36 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
if (unlikely(!orig_node))
goto out;
+ spin_lock_bh(&tp_vars->cwnd_lock);
/* update RTO with the new sampled RTT, if any */
rtt = jiffies_to_msecs(jiffies) - ntohl(icmp->timestamp);
if (icmp->timestamp && rtt)
batadv_tp_update_rto(tp_vars, rtt);
- /* ACK for new data... reset the timer */
- batadv_tp_reset_sender_timer(tp_vars);
-
- recv_ack = ntohl(icmp->seqno);
+ reaction = batadv_tp_handle_ack(bat_priv, tp_vars, recv_ack, mss);
+ spin_unlock_bh(&tp_vars->cwnd_lock);
- /* check if this ACK is a duplicate */
- if (atomic_read(&tp_vars->last_acked) == recv_ack) {
- atomic_inc(&tp_vars->dup_acks);
- if (atomic_read(&tp_vars->dup_acks) != 3)
- goto out;
+ if (reaction == BATADV_TP_ACK_REACTION_OLD_ACK)
+ goto out;
- if (!batadv_seq_before(tp_vars->recover, recv_ack))
- goto out;
+ /* ACK for new data... reset the timer */
+ batadv_tp_reset_sender_timer(tp_vars);
- /* if this is the third duplicate ACK do Fast Retransmit */
+ switch (reaction) {
+ default:
+ case BATADV_TP_ACK_REACTION_IGNORE:
+ goto out;
+ case BATADV_TP_ACK_REACTION_RESEND_WAKEUP:
batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr,
orig_node, recv_ack, packet_len,
icmp->session, icmp->uid,
jiffies_to_msecs(jiffies));
-
- spin_lock_bh(&tp_vars->cwnd_lock);
-
- /* Fast Recovery */
- tp_vars->fast_recovery = true;
- /* Set recover to the last outstanding seqno when Fast Recovery
- * is entered. RFC6582, Section 3.2, step 1
- */
- tp_vars->recover = tp_vars->last_sent;
- tp_vars->ss_threshold = tp_vars->cwnd >> 1;
- batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
- "Meter: Fast Recovery, (cur cwnd=%u) ss_thr=%u last_sent=%u recv_ack=%u\n",
- tp_vars->cwnd, tp_vars->ss_threshold,
- tp_vars->last_sent, recv_ack);
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->ss_threshold, 3 * mss,
- mss);
- tp_vars->dec_cwnd = 0;
- tp_vars->last_sent = recv_ack;
-
- spin_unlock_bh(&tp_vars->cwnd_lock);
- } else {
- /* count the acked data */
- atomic64_add(recv_ack - atomic_read(&tp_vars->last_acked),
- &tp_vars->tot_sent);
- /* reset the duplicate ACKs counter */
- atomic_set(&tp_vars->dup_acks, 0);
-
- if (tp_vars->fast_recovery) {
- /* partial ACK */
- if (batadv_seq_before(recv_ack, tp_vars->recover)) {
- /* this is another hole in the window. React
- * immediately as specified by NewReno (see
- * Section 3.2 of RFC6582 for details)
- */
- dev_addr = primary_if->net_dev->dev_addr;
- batadv_tp_send_msg(tp_vars, dev_addr,
- orig_node, recv_ack,
- packet_len, icmp->session,
- icmp->uid,
- jiffies_to_msecs(jiffies));
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd,
- mss, mss);
- } else {
- tp_vars->fast_recovery = false;
- /* set cwnd to the value of ss_threshold at the
- * moment that Fast Recovery was entered.
- * RFC6582, Section 3.2, step 3
- */
- cwnd = batadv_tp_cwnd(tp_vars->ss_threshold, 0,
- mss);
- tp_vars->cwnd = cwnd;
- }
- goto move_twnd;
- }
-
- if (recv_ack - atomic_read(&tp_vars->last_acked) >= mss)
- batadv_tp_update_cwnd(tp_vars, mss);
-move_twnd:
- /* move the Transmit Window */
- atomic_set(&tp_vars->last_acked, recv_ack);
+ fallthrough;
+ case BATADV_TP_ACK_REACTION_WAKEUP:
+ wake_up(&tp_vars->more_bytes);
+ break;
}
- wake_up(&tp_vars->more_bytes);
out:
batadv_hardif_put(primary_if);
batadv_orig_node_put(orig_node);
@@ -819,16 +871,19 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
static bool batadv_tp_avail(struct batadv_tp_sender *tp_vars,
size_t payload_len)
{
- u32 last_sent = READ_ONCE(tp_vars->last_sent);
u32 win_left, win_limit;
- win_limit = atomic_read(&tp_vars->last_acked) + tp_vars->cwnd;
+ spin_lock_bh(&tp_vars->cwnd_lock);
+
+ win_limit = tp_vars->last_acked + tp_vars->cwnd;
- if (batadv_seq_before(last_sent, win_limit))
- win_left = win_limit - last_sent;
+ if (batadv_seq_before(tp_vars->last_sent, win_limit))
+ win_left = win_limit - tp_vars->last_sent;
else
win_left = 0;
+ spin_unlock_bh(&tp_vars->cwnd_lock);
+
return win_left >= payload_len;
}
@@ -867,6 +922,7 @@ static int batadv_tp_send(void *arg)
struct batadv_hard_iface *primary_if = NULL;
struct batadv_orig_node *orig_node = NULL;
size_t payload_len, packet_len;
+ u32 last_sent;
int err = 0;
orig_node = batadv_orig_hash_find(bat_priv, tp_vars->common.other_end);
@@ -908,10 +964,10 @@ static int batadv_tp_send(void *arg)
* the size of the unicast header
*/
packet_len = payload_len + sizeof(struct batadv_unicast_packet);
+ last_sent = READ_ONCE(tp_vars->last_sent);
err = batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr,
- orig_node, tp_vars->last_sent,
- packet_len,
+ orig_node, last_sent, packet_len,
tp_vars->common.session, tp_vars->icmp_uid,
jiffies_to_msecs(jiffies));
@@ -926,8 +982,12 @@ static int batadv_tp_send(void *arg)
}
/* right-shift the TWND */
- if (!err)
- tp_vars->last_sent += payload_len;
+ if (!err) {
+ spin_lock_bh(&tp_vars->cwnd_lock);
+ if (tp_vars->last_sent == last_sent)
+ WRITE_ONCE(tp_vars->last_sent, last_sent + payload_len);
+ spin_unlock_bh(&tp_vars->cwnd_lock);
+ }
cond_resched();
}
@@ -1044,9 +1104,9 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
memcpy(tp_vars->common.session, session_id, sizeof(session_id));
tp_vars->icmp_uid = icmp_uid;
- tp_vars->last_sent = BATADV_TP_FIRST_SEQ;
- atomic_set(&tp_vars->dup_acks, 0);
- atomic_set(&tp_vars->last_acked, BATADV_TP_FIRST_SEQ);
+ WRITE_ONCE(tp_vars->last_sent, BATADV_TP_FIRST_SEQ);
+ WRITE_ONCE(tp_vars->dup_acks, 0);
+ WRITE_ONCE(tp_vars->last_acked, BATADV_TP_FIRST_SEQ);
tp_vars->fast_recovery = false;
tp_vars->recover = BATADV_TP_FIRST_SEQ;
@@ -1065,7 +1125,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
/* RTO initial value is 3 seconds.
* Details in Section 2.1 of RFC6298
*/
- tp_vars->rto = 1000;
+ WRITE_ONCE(tp_vars->rto, 1000);
tp_vars->srtt = 0;
tp_vars->rttvar = 0;
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index f7817a68a29ca..c782f04aea9c4 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1387,7 +1387,7 @@ struct batadv_tp_sender {
u32 last_sent;
/** @fast_recovery: true if in Fast Recovery mode */
- unsigned char fast_recovery:1;
+ bool fast_recovery:1;
/** @recover: last sent seqno when entering Fast Recovery */
u32 recover;
@@ -1410,7 +1410,7 @@ struct batadv_tp_sender {
/** @cwnd: current size of the congestion window */
u32 cwnd;
- /** @cwnd_lock: lock do protect @cwnd & @dec_cwnd */
+ /** @cwnd_lock: lock do protect congestion control variables */
spinlock_t cwnd_lock;
/**
@@ -1420,13 +1420,13 @@ struct batadv_tp_sender {
u32 ss_threshold;
/** @last_acked: last acked byte */
- atomic_t last_acked;
+ u32 last_acked;
/** @tot_sent: amount of data sent/ACKed so far */
atomic64_t tot_sent;
/** @dup_acks: duplicate ACKs counter */
- atomic_t dup_acks;
+ u8 dup_acks;
/** @rto: sender timeout */
u32 rto;
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 11/15] batman-adv: tp_meter: consolidate congestion control variables
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (9 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 10/15] batman-adv: tp_meter: use locking for all congestion control variables Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 12/15] batman-adv: bla: annotate lasttime access with READ/WRITE_ONCE Simon Wunderlich
` (3 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
Congestion control variables in batadv_tp_sender were scattered across the
struct without clear grouping, making it difficult to reason about which
fields require cwnd_lock (now "cc_lock") protection. These should be
combined in a structure to make it more easily visible which variable
should be read/modified with the cc_lock held.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/tp_meter.c | 170 +++++++++++++++++++-------------------
net/batman-adv/types.h | 80 +++++++++---------
2 files changed, 128 insertions(+), 122 deletions(-)
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index e9ba1c45a285d..978e32d94e6c3 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -143,12 +143,12 @@ static u32 batadv_tp_cwnd(u32 base, u32 increment, u32 min)
* increased by MSS * MSS / CWND for every unique received ACK
*/
static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss)
- __must_hold(&tp_vars->cwnd_lock)
+ __must_hold(&tp_vars->cc_lock)
{
/* slow start... */
- if (tp_vars->cwnd <= tp_vars->ss_threshold) {
- tp_vars->dec_cwnd = 0;
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd, mss, mss);
+ if (tp_vars->cc.cwnd <= tp_vars->cc.ss_threshold) {
+ tp_vars->cc.dec_cwnd = 0;
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd, mss, mss);
return;
}
@@ -156,13 +156,13 @@ static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss)
mss = min_t(u32, mss, (1U << 14) - 1);
/* increment CWND at least of 1 (section 3.1 of RFC5681) */
- tp_vars->dec_cwnd += max_t(u32, 1U << 3,
- ((mss * mss) << 3) / tp_vars->cwnd);
- if (tp_vars->dec_cwnd < (mss << 3))
+ tp_vars->cc.dec_cwnd += max_t(u32, 1U << 3,
+ ((mss * mss) << 3) / tp_vars->cc.cwnd);
+ if (tp_vars->cc.dec_cwnd < (mss << 3))
return;
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd, mss, mss);
- tp_vars->dec_cwnd = 0;
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd, mss, mss);
+ tp_vars->cc.dec_cwnd = 0;
}
/**
@@ -172,7 +172,7 @@ static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss)
*/
static void batadv_tp_update_rto(struct batadv_tp_sender *tp_vars,
u32 new_rtt)
- __must_hold(&tp_vars->cwnd_lock)
+ __must_hold(&tp_vars->cc_lock)
{
long m = new_rtt;
@@ -182,24 +182,24 @@ static void batadv_tp_update_rto(struct batadv_tp_sender *tp_vars,
* It's tricky to understand. Don't lose hair please.
* Inspired by tcp_rtt_estimator() tcp_input.c
*/
- if (tp_vars->srtt != 0) {
- m -= (tp_vars->srtt >> 3); /* m is now error in rtt est */
- tp_vars->srtt += m; /* rtt = 7/8 srtt + 1/8 new */
+ if (tp_vars->cc.srtt != 0) {
+ m -= (tp_vars->cc.srtt >> 3); /* m is now error in rtt est */
+ tp_vars->cc.srtt += m; /* rtt = 7/8 srtt + 1/8 new */
if (m < 0)
m = -m;
- m -= (tp_vars->rttvar >> 2);
- tp_vars->rttvar += m; /* mdev ~= 3/4 rttvar + 1/4 new */
+ m -= (tp_vars->cc.rttvar >> 2);
+ tp_vars->cc.rttvar += m; /* mdev ~= 3/4 rttvar + 1/4 new */
} else {
/* first measure getting in */
- tp_vars->srtt = m << 3; /* take the measured time to be srtt */
- tp_vars->rttvar = m << 1; /* new_rtt / 2 */
+ tp_vars->cc.srtt = m << 3; /* take the measured time to be srtt */
+ tp_vars->cc.rttvar = m << 1; /* new_rtt / 2 */
}
/* rto = srtt + 4 * rttvar.
* rttvar is scaled by 4, therefore doesn't need to be multiplied
*/
- WRITE_ONCE(tp_vars->rto, (tp_vars->srtt >> 3) + tp_vars->rttvar);
+ WRITE_ONCE(tp_vars->cc.rto, (tp_vars->cc.srtt >> 3) + tp_vars->cc.rttvar);
}
/**
@@ -450,11 +450,11 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Last timing stats: SRTT=%ums RTTVAR=%ums RTO=%ums\n",
- tp_vars->srtt >> 3, tp_vars->rttvar >> 2, tp_vars->rto);
+ tp_vars->cc.srtt >> 3, tp_vars->cc.rttvar >> 2, tp_vars->cc.rto);
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Final values: cwnd=%u ss_threshold=%u\n",
- tp_vars->cwnd, tp_vars->ss_threshold);
+ tp_vars->cc.cwnd, tp_vars->cc.ss_threshold);
session_cookie = batadv_tp_session_cookie(tp_vars->common.session,
tp_vars->icmp_uid);
@@ -521,7 +521,7 @@ static void batadv_tp_reset_sender_timer(struct batadv_tp_sender *tp_vars)
return;
mod_timer(&tp_vars->common.timer,
- jiffies + msecs_to_jiffies(READ_ONCE(tp_vars->rto)));
+ jiffies + msecs_to_jiffies(READ_ONCE(tp_vars->cc.rto)));
}
/**
@@ -540,11 +540,11 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
if (batadv_tp_sender_stopped(tp_vars))
return;
- spin_lock_bh(&tp_vars->cwnd_lock);
+ spin_lock_bh(&tp_vars->cc_lock);
/* if the user waited long enough...shutdown the test */
- if (unlikely(tp_vars->rto >= BATADV_TP_MAX_RTO)) {
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ if (unlikely(tp_vars->cc.rto >= BATADV_TP_MAX_RTO)) {
+ spin_unlock_bh(&tp_vars->cc_lock);
batadv_tp_sender_shutdown(tp_vars,
BATADV_TP_REASON_DST_UNREACHABLE);
return;
@@ -553,22 +553,22 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
/* RTO exponential backoff
* Details in Section 5.5 of RFC6298
*/
- WRITE_ONCE(tp_vars->rto, tp_vars->rto * 2);
+ WRITE_ONCE(tp_vars->cc.rto, tp_vars->cc.rto * 2);
- tp_vars->ss_threshold = tp_vars->cwnd >> 1;
- if (tp_vars->ss_threshold < BATADV_TP_PLEN * 2)
- tp_vars->ss_threshold = BATADV_TP_PLEN * 2;
+ tp_vars->cc.ss_threshold = tp_vars->cc.cwnd >> 1;
+ if (tp_vars->cc.ss_threshold < BATADV_TP_PLEN * 2)
+ tp_vars->cc.ss_threshold = BATADV_TP_PLEN * 2;
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: RTO fired during test towards %pM! cwnd=%u new ss_thr=%u, resetting last_sent to %u\n",
- tp_vars->common.other_end, tp_vars->cwnd, tp_vars->ss_threshold,
- tp_vars->last_acked);
+ tp_vars->common.other_end, tp_vars->cc.cwnd, tp_vars->cc.ss_threshold,
+ tp_vars->cc.last_acked);
- tp_vars->cwnd = BATADV_TP_PLEN * 3;
+ tp_vars->cc.cwnd = BATADV_TP_PLEN * 3;
- WRITE_ONCE(tp_vars->last_sent, tp_vars->last_acked);
+ WRITE_ONCE(tp_vars->cc.last_sent, tp_vars->cc.last_acked);
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ spin_unlock_bh(&tp_vars->cc_lock);
/* resend the non-ACKed packets.. */
wake_up(&tp_vars->more_bytes);
@@ -698,81 +698,81 @@ static enum batadv_tp_ack_reaction
batadv_tp_handle_ack(struct batadv_priv *bat_priv,
struct batadv_tp_sender *tp_vars,
u32 recv_ack, size_t mss)
- __must_hold(&tp_vars->cwnd_lock)
+ __must_hold(&tp_vars->cc_lock)
{
enum batadv_tp_ack_reaction reaction;
- if (batadv_seq_before(recv_ack, tp_vars->last_acked))
+ if (batadv_seq_before(recv_ack, tp_vars->cc.last_acked))
return BATADV_TP_ACK_REACTION_OLD_ACK;
/* check if this ACK is a duplicate */
- if (tp_vars->last_acked == recv_ack) {
+ if (tp_vars->cc.last_acked == recv_ack) {
/* if this is the third duplicate ACK do Fast Retransmit */
- if (tp_vars->dup_acks > 3)
+ if (tp_vars->cc.dup_acks > 3)
return BATADV_TP_ACK_REACTION_IGNORE;
- tp_vars->dup_acks++;
- if (tp_vars->dup_acks != 3)
+ tp_vars->cc.dup_acks++;
+ if (tp_vars->cc.dup_acks != 3)
return BATADV_TP_ACK_REACTION_IGNORE;
- if (!batadv_seq_before(tp_vars->recover, recv_ack))
+ if (!batadv_seq_before(tp_vars->cc.recover, recv_ack))
return BATADV_TP_ACK_REACTION_IGNORE;
/* Fast Recovery */
- tp_vars->fast_recovery = true;
+ tp_vars->cc.fast_recovery = true;
/* Set recover to the last outstanding seqno when Fast Recovery
* is entered. RFC6582, Section 3.2, step 1
*/
- tp_vars->recover = tp_vars->last_sent;
- tp_vars->ss_threshold = tp_vars->cwnd >> 1;
+ tp_vars->cc.recover = tp_vars->cc.last_sent;
+ tp_vars->cc.ss_threshold = tp_vars->cc.cwnd >> 1;
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: Fast Recovery, (cur cwnd=%u) ss_thr=%u last_sent=%u recv_ack=%u\n",
- tp_vars->cwnd, tp_vars->ss_threshold,
- tp_vars->last_sent, recv_ack);
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->ss_threshold, 3 * mss,
- mss);
- tp_vars->dec_cwnd = 0;
- WRITE_ONCE(tp_vars->last_sent, recv_ack);
+ tp_vars->cc.cwnd, tp_vars->cc.ss_threshold,
+ tp_vars->cc.last_sent, recv_ack);
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.ss_threshold, 3 * mss,
+ mss);
+ tp_vars->cc.dec_cwnd = 0;
+ WRITE_ONCE(tp_vars->cc.last_sent, recv_ack);
return BATADV_TP_ACK_REACTION_RESEND_WAKEUP;
}
/* count the acked data */
- atomic64_add(recv_ack - tp_vars->last_acked, &tp_vars->tot_sent);
+ atomic64_add(recv_ack - tp_vars->cc.last_acked, &tp_vars->tot_sent);
/* reset the duplicate ACKs counter */
- tp_vars->dup_acks = 0;
+ tp_vars->cc.dup_acks = 0;
- if (tp_vars->fast_recovery) {
+ if (tp_vars->cc.fast_recovery) {
/* partial ACK */
- if (batadv_seq_before(recv_ack, tp_vars->recover)) {
+ if (batadv_seq_before(recv_ack, tp_vars->cc.recover)) {
/* this is another hole in the window. React
* immediately as specified by NewReno (see
* Section 3.2 of RFC6582 for details)
*/
reaction = BATADV_TP_ACK_REACTION_RESEND_WAKEUP;
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd,
- mss, mss);
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd,
+ mss, mss);
} else {
- tp_vars->fast_recovery = false;
+ tp_vars->cc.fast_recovery = false;
/* set cwnd to the value of ss_threshold at the
* moment that Fast Recovery was entered.
* RFC6582, Section 3.2, step 3
*/
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->ss_threshold,
- 0, mss);
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.ss_threshold,
+ 0, mss);
reaction = BATADV_TP_ACK_REACTION_WAKEUP;
}
} else {
- if (recv_ack - tp_vars->last_acked >= mss)
+ if (recv_ack - tp_vars->cc.last_acked >= mss)
batadv_tp_update_cwnd(tp_vars, mss);
reaction = BATADV_TP_ACK_REACTION_WAKEUP;
}
/* move the Transmit Window */
- WRITE_ONCE(tp_vars->last_acked, recv_ack);
+ WRITE_ONCE(tp_vars->cc.last_acked, recv_ack);
return reaction;
}
@@ -814,7 +814,7 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
goto out;
/* old ACK? silently drop it.. */
- if (batadv_seq_before(recv_ack, READ_ONCE(tp_vars->last_acked)))
+ if (batadv_seq_before(recv_ack, READ_ONCE(tp_vars->cc.last_acked)))
goto out;
primary_if = batadv_primary_if_get_selected(bat_priv);
@@ -825,14 +825,14 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
if (unlikely(!orig_node))
goto out;
- spin_lock_bh(&tp_vars->cwnd_lock);
+ spin_lock_bh(&tp_vars->cc_lock);
/* update RTO with the new sampled RTT, if any */
rtt = jiffies_to_msecs(jiffies) - ntohl(icmp->timestamp);
if (icmp->timestamp && rtt)
batadv_tp_update_rto(tp_vars, rtt);
reaction = batadv_tp_handle_ack(bat_priv, tp_vars, recv_ack, mss);
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ spin_unlock_bh(&tp_vars->cc_lock);
if (reaction == BATADV_TP_ACK_REACTION_OLD_ACK)
goto out;
@@ -873,16 +873,16 @@ static bool batadv_tp_avail(struct batadv_tp_sender *tp_vars,
{
u32 win_left, win_limit;
- spin_lock_bh(&tp_vars->cwnd_lock);
+ spin_lock_bh(&tp_vars->cc_lock);
- win_limit = tp_vars->last_acked + tp_vars->cwnd;
+ win_limit = tp_vars->cc.last_acked + tp_vars->cc.cwnd;
- if (batadv_seq_before(tp_vars->last_sent, win_limit))
- win_left = win_limit - tp_vars->last_sent;
+ if (batadv_seq_before(tp_vars->cc.last_sent, win_limit))
+ win_left = win_limit - tp_vars->cc.last_sent;
else
win_left = 0;
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ spin_unlock_bh(&tp_vars->cc_lock);
return win_left >= payload_len;
}
@@ -964,7 +964,7 @@ static int batadv_tp_send(void *arg)
* the size of the unicast header
*/
packet_len = payload_len + sizeof(struct batadv_unicast_packet);
- last_sent = READ_ONCE(tp_vars->last_sent);
+ last_sent = READ_ONCE(tp_vars->cc.last_sent);
err = batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr,
orig_node, last_sent, packet_len,
@@ -983,10 +983,10 @@ static int batadv_tp_send(void *arg)
/* right-shift the TWND */
if (!err) {
- spin_lock_bh(&tp_vars->cwnd_lock);
- if (tp_vars->last_sent == last_sent)
- WRITE_ONCE(tp_vars->last_sent, last_sent + payload_len);
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ spin_lock_bh(&tp_vars->cc_lock);
+ if (tp_vars->cc.last_sent == last_sent)
+ WRITE_ONCE(tp_vars->cc.last_sent, last_sent + payload_len);
+ spin_unlock_bh(&tp_vars->cc_lock);
}
cond_resched();
@@ -1104,30 +1104,30 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
memcpy(tp_vars->common.session, session_id, sizeof(session_id));
tp_vars->icmp_uid = icmp_uid;
- WRITE_ONCE(tp_vars->last_sent, BATADV_TP_FIRST_SEQ);
- WRITE_ONCE(tp_vars->dup_acks, 0);
- WRITE_ONCE(tp_vars->last_acked, BATADV_TP_FIRST_SEQ);
- tp_vars->fast_recovery = false;
- tp_vars->recover = BATADV_TP_FIRST_SEQ;
+ WRITE_ONCE(tp_vars->cc.last_sent, BATADV_TP_FIRST_SEQ);
+ WRITE_ONCE(tp_vars->cc.dup_acks, 0);
+ WRITE_ONCE(tp_vars->cc.last_acked, BATADV_TP_FIRST_SEQ);
+ tp_vars->cc.fast_recovery = false;
+ tp_vars->cc.recover = BATADV_TP_FIRST_SEQ;
/* initialise the CWND to 3*MSS (Section 3.1 in RFC5681).
* For batman-adv the MSS is the size of the payload received by the
* mesh_interface, hence its MTU
*/
- tp_vars->cwnd = BATADV_TP_PLEN * 3;
- tp_vars->dec_cwnd = 0;
+ tp_vars->cc.cwnd = BATADV_TP_PLEN * 3;
+ tp_vars->cc.dec_cwnd = 0;
/* at the beginning initialise the SS threshold to the biggest possible
* window size, hence the AWND size
*/
- tp_vars->ss_threshold = BATADV_TP_AWND;
+ tp_vars->cc.ss_threshold = BATADV_TP_AWND;
/* RTO initial value is 3 seconds.
* Details in Section 2.1 of RFC6298
*/
- WRITE_ONCE(tp_vars->rto, 1000);
- tp_vars->srtt = 0;
- tp_vars->rttvar = 0;
+ WRITE_ONCE(tp_vars->cc.rto, 1000);
+ tp_vars->cc.srtt = 0;
+ tp_vars->cc.rttvar = 0;
atomic64_set(&tp_vars->tot_sent, 0);
@@ -1143,7 +1143,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
spin_lock_init(&tp_vars->common.unacked_lock);
INIT_LIST_HEAD(&tp_vars->common.unacked_list);
- spin_lock_init(&tp_vars->cwnd_lock);
+ spin_lock_init(&tp_vars->cc_lock);
tp_vars->prerandom_offset = 0;
spin_lock_init(&tp_vars->prerandom_lock);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index c782f04aea9c4..5eb0371def83a 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1367,6 +1367,45 @@ struct batadv_tp_vars_common {
struct rcu_head rcu;
};
+/** struct batadv_tp_sender_cc - congestion control variables */
+struct batadv_tp_sender_cc {
+ /** @fast_recovery: true if in Fast Recovery mode */
+ bool fast_recovery:1;
+
+ /** @dup_acks: duplicate ACKs counter */
+ u8 dup_acks;
+
+ /** @dec_cwnd: decimal part of the cwnd used during linear growth */
+ u16 dec_cwnd;
+
+ /** @cwnd: current size of the congestion window */
+ u32 cwnd;
+
+ /**
+ * @ss_threshold: Slow Start threshold. Once cwnd exceeds this value the
+ * connection switches to the Congestion Avoidance state
+ */
+ u32 ss_threshold;
+
+ /** @last_acked: last acked byte */
+ u32 last_acked;
+
+ /** @last_sent: last sent byte, not yet acked */
+ u32 last_sent;
+
+ /** @recover: last sent seqno when entering Fast Recovery */
+ u32 recover;
+
+ /** @rto: sender timeout */
+ u32 rto;
+
+ /** @srtt: smoothed RTT scaled by 2^3 */
+ u32 srtt;
+
+ /** @rttvar: RTT variation scaled by 2^2 */
+ u32 rttvar;
+};
+
/**
* struct batadv_tp_sender - sender tp meter private variables per session
*/
@@ -1383,15 +1422,6 @@ struct batadv_tp_sender {
*/
atomic_t send_result;
- /** @last_sent: last sent byte, not yet acked */
- u32 last_sent;
-
- /** @fast_recovery: true if in Fast Recovery mode */
- bool fast_recovery:1;
-
- /** @recover: last sent seqno when entering Fast Recovery */
- u32 recover;
-
/** @finish_work: work item for the finishing procedure */
struct delayed_work finish_work;
@@ -1404,39 +1434,15 @@ struct batadv_tp_sender {
/** @icmp_uid: local ICMP "socket" index */
u8 icmp_uid;
- /** @dec_cwnd: decimal part of the cwnd used during linear growth */
- u16 dec_cwnd;
-
- /** @cwnd: current size of the congestion window */
- u32 cwnd;
-
- /** @cwnd_lock: lock do protect congestion control variables */
- spinlock_t cwnd_lock;
-
- /**
- * @ss_threshold: Slow Start threshold. Once cwnd exceeds this value the
- * connection switches to the Congestion Avoidance state
- */
- u32 ss_threshold;
+ /** @cc: congestion control variables */
+ struct batadv_tp_sender_cc cc;
- /** @last_acked: last acked byte */
- u32 last_acked;
+ /** @cc_lock: lock do protect @cc */
+ spinlock_t cc_lock;
/** @tot_sent: amount of data sent/ACKed so far */
atomic64_t tot_sent;
- /** @dup_acks: duplicate ACKs counter */
- u8 dup_acks;
-
- /** @rto: sender timeout */
- u32 rto;
-
- /** @srtt: smoothed RTT scaled by 2^3 */
- u32 srtt;
-
- /** @rttvar: RTT variation scaled by 2^2 */
- u32 rttvar;
-
/**
* @more_bytes: waiting queue anchor when waiting for more ack/retry
* timeout
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 12/15] batman-adv: bla: annotate lasttime access with READ/WRITE_ONCE
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (10 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 11/15] batman-adv: tp_meter: consolidate " Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 13/15] batman-adv: prevent ELP transmission interval underflow Simon Wunderlich
` (2 subsequent siblings)
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
The lasttime field for claim, backbone_gw, and loopdetect tracks the
jiffies value of the most recent activity and is used to detect timeouts.
These accesses are not consistently protected by a lock, so
READ_ONCE/WRITE_ONCE must be used to prevent data races caused by compiler
optimizations.
Cc: stable@kernel.org
Fixes: 23721387c409 ("batman-adv: add basic bridge loop avoidance code")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/bridge_loop_avoidance.c | 28 +++++++++++++-------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 87d6b11161e4a..0461f11227d06 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -513,7 +513,7 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, const u8 *orig,
return NULL;
entry->vid = vid;
- entry->lasttime = jiffies;
+ WRITE_ONCE(entry->lasttime, jiffies);
entry->crc = BATADV_BLA_CRC_INIT;
entry->bat_priv = bat_priv;
spin_lock_init(&entry->crc_lock);
@@ -581,7 +581,7 @@ batadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv,
if (unlikely(!backbone_gw))
return;
- backbone_gw->lasttime = jiffies;
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
batadv_backbone_gw_put(backbone_gw);
}
@@ -715,7 +715,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
ether_addr_copy(claim->addr, mac);
spin_lock_init(&claim->backbone_lock);
claim->vid = vid;
- claim->lasttime = jiffies;
+ WRITE_ONCE(claim->lasttime, jiffies);
kref_get(&backbone_gw->refcount);
claim->backbone_gw = backbone_gw;
kref_init(&claim->refcount);
@@ -737,7 +737,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
return;
}
} else {
- claim->lasttime = jiffies;
+ WRITE_ONCE(claim->lasttime, jiffies);
if (claim->backbone_gw == backbone_gw)
/* no need to register a new backbone */
goto claim_free_ref;
@@ -770,7 +770,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
spin_lock_bh(&backbone_gw->crc_lock);
backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
spin_unlock_bh(&backbone_gw->crc_lock);
- backbone_gw->lasttime = jiffies;
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
claim_free_ref:
batadv_claim_put(claim);
@@ -859,7 +859,7 @@ static bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
return true;
/* handle as ANNOUNCE frame */
- backbone_gw->lasttime = jiffies;
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
crc = ntohs(*((__force __be16 *)(&an_addr[4])));
batadv_dbg(BATADV_DBG_BLA, bat_priv,
@@ -1254,7 +1254,7 @@ static void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now)
head, hash_entry) {
if (now)
goto purge_now;
- if (!batadv_has_timed_out(backbone_gw->lasttime,
+ if (!batadv_has_timed_out(READ_ONCE(backbone_gw->lasttime),
BATADV_BLA_BACKBONE_TIMEOUT))
continue;
@@ -1335,7 +1335,7 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv,
primary_if->net_dev->dev_addr))
goto skip;
- if (!batadv_has_timed_out(claim->lasttime,
+ if (!batadv_has_timed_out(READ_ONCE(claim->lasttime),
BATADV_BLA_CLAIM_TIMEOUT))
goto skip;
@@ -1495,7 +1495,7 @@ static void batadv_bla_periodic_work(struct work_struct *work)
eth_random_addr(bat_priv->bla.loopdetect_addr);
bat_priv->bla.loopdetect_addr[0] = 0xba;
bat_priv->bla.loopdetect_addr[1] = 0xbe;
- bat_priv->bla.loopdetect_lasttime = jiffies;
+ WRITE_ONCE(bat_priv->bla.loopdetect_lasttime, jiffies);
atomic_set(&bat_priv->bla.loopdetect_next,
BATADV_BLA_LOOPDETECT_PERIODS);
@@ -1516,7 +1516,7 @@ static void batadv_bla_periodic_work(struct work_struct *work)
primary_if->net_dev->dev_addr))
continue;
- backbone_gw->lasttime = jiffies;
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
batadv_bla_send_announce(bat_priv, backbone_gw);
if (send_loopdetect)
@@ -1900,7 +1900,7 @@ batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,
/* If the packet came too late, don't forward it on the mesh
* but don't consider that as loop. It might be a coincidence.
*/
- if (batadv_has_timed_out(bat_priv->bla.loopdetect_lasttime,
+ if (batadv_has_timed_out(READ_ONCE(bat_priv->bla.loopdetect_lasttime),
BATADV_BLA_LOOPDETECT_TIMEOUT))
return true;
@@ -2015,7 +2015,7 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
if (own_claim) {
/* ... allow it in any case */
- claim->lasttime = jiffies;
+ WRITE_ONCE(claim->lasttime, jiffies);
goto allow;
}
@@ -2117,7 +2117,7 @@ bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
/* if yes, the client has roamed and we have
* to unclaim it.
*/
- if (batadv_has_timed_out(claim->lasttime, 100)) {
+ if (batadv_has_timed_out(READ_ONCE(claim->lasttime), 100)) {
/* only unclaim if the last claim entry is
* older than 100 ms to make sure we really
* have a roaming client here.
@@ -2362,7 +2362,7 @@ batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid,
backbone_crc = backbone_gw->crc;
spin_unlock_bh(&backbone_gw->crc_lock);
- msecs = jiffies_to_msecs(jiffies - backbone_gw->lasttime);
+ msecs = jiffies_to_msecs(jiffies - READ_ONCE(backbone_gw->lasttime));
if (is_own)
if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 13/15] batman-adv: prevent ELP transmission interval underflow
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (11 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 12/15] batman-adv: bla: annotate lasttime access with READ/WRITE_ONCE Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 14/15] batman-adv: tt: sync local and global tvlv preparation return values Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 15/15] batman-adv: tt: directly retrieve wifi flags of net_device Simon Wunderlich
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, stable,
Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
batadv_v_elp_start_timer() enqeues a delayed work. The time when it starts
is randomly chosen between (elp_interval - BATADV_JITTER) and
(elp_interval + BATADV_JITTER). The configured elp_interval must therefore
be larger or equal to BATADV_JITTER to avoid that it causes an underflow of
the unsigned integer. If this would happen, then a "fast" ELP interval
would turn into a "day long" delay.
At the same time, it must not be larger than the maximum value the variable
can store.
Cc: stable@kernel.org
Fixes: a10800829040 ("batman-adv: Add elp_interval hardif genl configuration")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/netlink.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index e5463003a3bd6..1ba206e402733 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -919,9 +919,15 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb,
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
if (info->attrs[BATADV_ATTR_ELP_INTERVAL]) {
+ u32 elp_interval;
+
attr = info->attrs[BATADV_ATTR_ELP_INTERVAL];
+ elp_interval = nla_get_u32(attr);
+
+ elp_interval = min_t(u32, elp_interval, INT_MAX);
+ elp_interval = max_t(u32, elp_interval, BATADV_JITTER);
- WRITE_ONCE(hard_iface->bat_v.elp_interval, nla_get_u32(attr));
+ WRITE_ONCE(hard_iface->bat_v.elp_interval, elp_interval);
}
if (info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) {
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 14/15] batman-adv: tt: sync local and global tvlv preparation return values
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (12 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 13/15] batman-adv: prevent ELP transmission interval underflow Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 15/15] batman-adv: tt: directly retrieve wifi flags of net_device Simon Wunderlich
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
The batadv_tt_prepare_tvlv_local_data() and
batadv_tt_prepare_tvlv_global_data() functions are supposed to work the
same - just with different sources for the TT entries. But both handled the
return values completely different. The global variant only made sure that
the *tt_len parameter was set to 0 and didn't care about the actual return
value of the function.
The local function never made sure that the *tt_len value was set to some
value when the operation failed. The callers were handling these
differences and made sure that they didn't access the incorrectly
initialized variable.
Sync both function as good as possible to avoid problems with new code
which might not be aware of these differences in the behavior.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 5e134d08a80fd..44bbaa3bb37d1 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -797,21 +797,22 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
struct batadv_tvlv_tt_change **tt_change,
s32 *tt_len)
{
- u16 num_vlan = 0;
- u16 tvlv_len = 0;
struct batadv_tvlv_tt_vlan_data *tt_vlan;
struct batadv_orig_node_vlan *vlan;
u16 total_entries = 0;
size_t change_offset;
u8 *tt_change_ptr;
+ u16 num_vlan = 0;
int vlan_entries;
u16 sum_entries;
+ u16 tvlv_len;
spin_lock_bh(&orig_node->vlan_list_lock);
hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
vlan_entries = atomic_read(&vlan->tt.num_entries);
if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
+ tvlv_len = 0;
*tt_len = 0;
goto out;
}
@@ -827,12 +828,14 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
*tt_len = batadv_tt_len(total_entries);
if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) {
+ tvlv_len = 0;
*tt_len = 0;
goto out;
}
*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
if (!*tt_data) {
+ tvlv_len = 0;
*tt_len = 0;
goto out;
}
@@ -867,6 +870,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
out:
spin_unlock_bh(&orig_node->vlan_list_lock);
+
return tvlv_len;
}
@@ -896,13 +900,13 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
{
struct batadv_tvlv_tt_vlan_data *tt_vlan;
struct batadv_meshif_vlan *vlan;
- size_t change_offset;
- u16 num_vlan = 0;
u16 total_entries = 0;
- u16 tvlv_len;
+ size_t change_offset;
u8 *tt_change_ptr;
+ u16 num_vlan = 0;
int vlan_entries;
u16 sum_entries;
+ u16 tvlv_len;
spin_lock_bh(&bat_priv->meshif_vlan_list_lock);
hlist_for_each_entry(vlan, &bat_priv->meshif_vlan_list, list) {
@@ -910,6 +914,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
tvlv_len = 0;
+ *tt_len = 0;
goto out;
}
@@ -925,12 +930,14 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) {
tvlv_len = 0;
+ *tt_len = 0;
goto out;
}
*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
if (!*tt_data) {
tvlv_len = 0;
+ *tt_len = 0;
goto out;
}
@@ -964,6 +971,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
out:
spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
+
return tvlv_len;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH net-next 15/15] batman-adv: tt: directly retrieve wifi flags of net_device
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
` (13 preceding siblings ...)
2026-06-03 7:25 ` [PATCH net-next 14/15] batman-adv: tt: sync local and global tvlv preparation return values Simon Wunderlich
@ 2026-06-03 7:25 ` Simon Wunderlich
14 siblings, 0 replies; 17+ messages in thread
From: Simon Wunderlich @ 2026-06-03 7:25 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
From: Sven Eckelmann <sven@narfation.org>
batadv_tt_local_add() tries to retrieve the wifi flags of an interface to
mark the TT entry as wifi client for the AP isolation feature. In the past,
it was necessary to look up the batadv_hard_iface because the wifi_flags
were stored inside this struct. But with the batadv_wifi_net_devices
rhashtable, it is preferred to directly retrieve the wifi_flags instead of
the indirect route via batadv_hard_iface - which at the end only provides
the net_device (which we used to find the batadv_hard_iface).
This will also be essential when the global batadv_hardif_list is removed
and each lookup via batadv_hardif_get_by_netdev() will require the RTNL
lock.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/hard-interface.c | 25 ++++++++++++++++++-------
net/batman-adv/hard-interface.h | 1 +
net/batman-adv/translation-table.c | 14 ++++++++------
3 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index bb3c31b5f259d..43ebf86e7b368 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -366,22 +366,19 @@ static u32 batadv_wifi_flags_evaluate(struct net_device *net_device)
}
/**
- * batadv_hardif_get_wifi_flags() - retrieve wifi flags for hard_iface
- * @hard_iface: the device to check
+ * batadv_netdev_get_wifi_flags() - retrieve wifi flags for net_device
+ * @net_dev: the device to check
*
* Return: batadv_hard_iface_wifi_flags flags of the device
*/
-u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface)
+u32 batadv_netdev_get_wifi_flags(struct net_device *net_dev)
{
struct batadv_wifi_net_device_state *device_state;
u32 wifi_flags = 0;
- if (!hard_iface)
- return 0;
-
rcu_read_lock();
device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices,
- &hard_iface->net_dev,
+ &net_dev,
batadv_wifi_net_devices_params);
if (device_state)
wifi_flags = READ_ONCE(device_state->wifi_flags);
@@ -390,6 +387,20 @@ u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface)
return wifi_flags;
}
+/**
+ * batadv_hardif_get_wifi_flags() - retrieve wifi flags for hard_iface
+ * @hard_iface: the device to check
+ *
+ * Return: batadv_hard_iface_wifi_flags flags of the device
+ */
+u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface)
+{
+ if (!hard_iface)
+ return 0;
+
+ return batadv_netdev_get_wifi_flags(hard_iface->net_dev);
+}
+
/**
* batadv_is_wifi_hardif() - check if the given hardif is a wifi interface
* @hard_iface: the device to check
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index 089e65c8a4817..822e7e378c4d1 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -70,6 +70,7 @@ extern struct notifier_block batadv_hard_if_notifier;
struct net_device *__batadv_get_real_netdev(struct net_device *net_device);
struct net_device *batadv_get_real_netdev(struct net_device *net_device);
+u32 batadv_netdev_get_wifi_flags(struct net_device *net_dev);
u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface);
bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface);
struct batadv_hard_iface*
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 44bbaa3bb37d1..c346e43d47b9b 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -596,20 +596,23 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
struct net *net = dev_net(mesh_iface);
struct batadv_meshif_vlan *vlan;
struct net_device *in_dev = NULL;
- struct batadv_hard_iface *in_hardif = NULL;
struct hlist_head *head;
struct batadv_tt_orig_list_entry *orig_entry;
int hash_added, table_size, packet_size_max;
bool ret = false;
bool roamed_back = false;
+ bool iif_is_wifi = false;
u8 remote_flags;
u32 match_mark;
if (ifindex != BATADV_NULL_IFINDEX)
in_dev = dev_get_by_index(net, ifindex);
- if (in_dev)
- in_hardif = batadv_hardif_get_by_netdev(in_dev);
+ if (in_dev) {
+ u32 wifi_flags = batadv_netdev_get_wifi_flags(in_dev);
+
+ iif_is_wifi = batadv_is_wifi(wifi_flags);
+ }
tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
@@ -684,7 +687,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
*/
tt_local->common.flags = BATADV_TT_CLIENT_NEW;
tt_local->common.vid = vid;
- if (batadv_is_wifi_hardif(in_hardif))
+ if (iif_is_wifi)
tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
kref_init(&tt_local->common.refcount);
tt_local->last_seen = jiffies;
@@ -743,7 +746,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
*/
remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK;
- if (batadv_is_wifi_hardif(in_hardif))
+ if (iif_is_wifi)
tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
else
tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
@@ -767,7 +770,6 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
ret = true;
out:
- batadv_hardif_put(in_hardif);
dev_put(in_dev);
batadv_tt_local_entry_put(tt_local);
batadv_tt_global_entry_put(tt_global);
--
2.47.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH net-next 01/15] batman-adv: tp_meter: keep unacked list in ascending ordered
2026-06-03 7:25 ` [PATCH net-next 01/15] batman-adv: tp_meter: keep unacked list in ascending ordered Simon Wunderlich
@ 2026-06-05 2:20 ` patchwork-bot+netdevbpf
0 siblings, 0 replies; 17+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-06-05 2:20 UTC (permalink / raw)
To: Simon Wunderlich
Cc: netdev, davem, edumazet, kuba, pabeni, horms, b.a.t.m.a.n, sven,
stable
Hello:
This series was applied to netdev/net-next.git (main)
by Sven Eckelmann <sven@narfation.org>:
On Wed, 3 Jun 2026 09:25:12 +0200 you wrote:
> From: Sven Eckelmann <sven@narfation.org>
>
> When batadv_tp_handle_out_of_order inserts a new entry in the list of
> unacked (out of order) packets, it searches from the entry with the newest
> sequence number towards oldest sequence number. If an entry is found which
> is older than the newly entry, the new entry has to be added after the
> found one to keep the ascending order.
>
> [...]
Here is the summary with links:
- [net-next,01/15] batman-adv: tp_meter: keep unacked list in ascending ordered
https://git.kernel.org/netdev/net-next/c/5aa8651527ea
- [net-next,02/15] batman-adv: tp_meter: initialize dup_acks explicitly
https://git.kernel.org/netdev/net-next/c/b2b68b32a715
- [net-next,03/15] batman-adv: tp_meter: initialize dec_cwnd explicitly
https://git.kernel.org/netdev/net-next/c/febfb1b86224
- [net-next,04/15] batman-adv: tp_meter: avoid window underflow
https://git.kernel.org/netdev/net-next/c/765947b81fb5
- [net-next,05/15] batman-adv: tp_meter: avoid divide-by-zero for dec_cwnd
https://git.kernel.org/netdev/net-next/c/33ccd52f3cc9
- [net-next,06/15] batman-adv: tp_meter: fix fast recovery precondition
https://git.kernel.org/netdev/net-next/c/2b0d08f08ed3
- [net-next,07/15] batman-adv: tp_meter: handle seqno wrap-around for fast recovery detection
https://git.kernel.org/netdev/net-next/c/f54c85ed42a1
- [net-next,08/15] batman-adv: tp_meter: add only finished tp_vars to lists
https://git.kernel.org/netdev/net-next/c/15ccbf685222
- [net-next,09/15] batman-adv: tp_meter: split vars into sender and receiver types
https://git.kernel.org/netdev/net-next/c/feb4a390a540
- [net-next,10/15] batman-adv: tp_meter: use locking for all congestion control variables
https://git.kernel.org/netdev/net-next/c/a7eff9402471
- [net-next,11/15] batman-adv: tp_meter: consolidate congestion control variables
https://git.kernel.org/netdev/net-next/c/4f117f562628
- [net-next,12/15] batman-adv: bla: annotate lasttime access with READ/WRITE_ONCE
https://git.kernel.org/netdev/net-next/c/98b0fb191c87
- [net-next,13/15] batman-adv: prevent ELP transmission interval underflow
https://git.kernel.org/netdev/net-next/c/5e50d4b8ae3e
- [net-next,14/15] batman-adv: tt: sync local and global tvlv preparation return values
https://git.kernel.org/netdev/net-next/c/5f80c363677c
- [net-next,15/15] batman-adv: tt: directly retrieve wifi flags of net_device
https://git.kernel.org/netdev/net-next/c/626fd1437161
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-06-05 2:20 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-03 7:25 [PATCH net-next 00/15] pull request for net-next: batman-adv 2026-06-03 Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 01/15] batman-adv: tp_meter: keep unacked list in ascending ordered Simon Wunderlich
2026-06-05 2:20 ` patchwork-bot+netdevbpf
2026-06-03 7:25 ` [PATCH net-next 02/15] batman-adv: tp_meter: initialize dup_acks explicitly Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 03/15] batman-adv: tp_meter: initialize dec_cwnd explicitly Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 04/15] batman-adv: tp_meter: avoid window underflow Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 05/15] batman-adv: tp_meter: avoid divide-by-zero for dec_cwnd Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 06/15] batman-adv: tp_meter: fix fast recovery precondition Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 07/15] batman-adv: tp_meter: handle seqno wrap-around for fast recovery detection Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 08/15] batman-adv: tp_meter: add only finished tp_vars to lists Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 09/15] batman-adv: tp_meter: split vars into sender and receiver types Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 10/15] batman-adv: tp_meter: use locking for all congestion control variables Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 11/15] batman-adv: tp_meter: consolidate " Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 12/15] batman-adv: bla: annotate lasttime access with READ/WRITE_ONCE Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 13/15] batman-adv: prevent ELP transmission interval underflow Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 14/15] batman-adv: tt: sync local and global tvlv preparation return values Simon Wunderlich
2026-06-03 7:25 ` [PATCH net-next 15/15] batman-adv: tt: directly retrieve wifi flags of net_device Simon Wunderlich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox