* [batadv,v12 0/5] batman-adv: increase DAT DHT timeout
@ 2026-10-03 7:26 Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 1/5] batman-adv: move local ARP reply code to subfunctions Linus Lüssing
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Linus Lüssing @ 2026-10-03 7:26 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
This patchset increases the DAT DHT timeout to reduce the amount
of broadcasted ARP Replies.
To increase the timeout only for DAT DHT entries added via DHT-PUT but
not for any other entry in the DAT cache the DAT cache and DAT DHT
concepts are split into two separate hash tables (PATCH 2/5).
PATCH 3/5 then increases the timeout for DAT DHT entries from 5 to
30 minutes, the main performance enhancement and goal of this patchset.
PATCH 4/5 and 5/5 are some small tweaks for a few unnecessary DHT additions
which we can now detect and avoid.
The motivation for this patchset is based on the observations made here:
https://www.open-mesh.org/projects/batman-adv/wiki/DAT_DHCP_Snooping
In tests at Freifunk Lübeck with ~180 mesh nodes and Gluon
this reduced the ARP broadcast overhead, measured over 7 days, as
follows:
- Total: 6677.66 bits/s -> 677.26 bits/s => -89.86%
11.92 pkts/s -> 1.21 pkts/s => -89.85%
- from gateways: 5618.02 bits/s -> 212.28 => -96.22%
10.03 pkts/s -> 0.38 pkts/s => -96.21%
Also see graphics and a few more test details here:
- https://www.open-mesh.org/projects/batman-adv/wiki/DAT_DHCP_Snooping#Result-2
Regards,
Linus
---
Changelog v12:
- PATCH 0/5:
- added mentioning of PATCH 4/5 and 5/5 in the summary
- PATCH 1/5 (was: 1/4):
- fix triggering of the "ARP request replied locally" debug message
by changing the batadv_dat_arp_self_reply() return type from bool
to int, ensuring to (keep) only trigger(ing) it when netif_rx()'ing
- PATCH 2/5 (was: 2/4):
- consistently use a "cands" variable name for the candidate array
instead of sometimes calling it "cand", sometimes "cands"
- add missing kerneldoc for batadv_dat_forward_data()'s "cands"
function argument
- renaming batadv_dat_check_self_candidate() to
batadv_dat_cmp_self_candidate()
- fix unprivileged DAT_DHT netlink usage
- add netlink .validate (and .resv_start_op for compat) for
uniform netlink ops
- adjust batadv_dat_dht_get_self_reply() to new
batadv_dat_arp_self_reply() int return type
(also avoiding an automatic type conversion from int
to bool by that)
- fix memory leak / missing orig_node put in
batadv_dat_forward_dht_get() if one self is a
candidate, move orig-node put from batadv_dat_forward_data()
to separate batadv_dat_candidates_free() function, called
later
- revert "update local DHT on DHCP ACKs received via DHT_PUTs, too"
from v11 as we never send DHT_PUT messages with a DHCP payload,
sashiko.dev seems to have missed that these are always ARP Replies
- PATCH 3/5 (was: 3/4): unchanged
- PATCH 4/5 (was: 4/4): unchanged
- PATCH 5/5: NEW, avoid superfluous DAT DHT_PUT additions to local DAT
Changelog v11:
- PATCH 1/4: NEW, simple restructuring in preparation for 2/4
(no functional change)
- PATCH 2/4 (was: 1/2):
- update local DHT on DHCP ACKs received via DHT_PUTs, too
- added self-candidate checks (batadv_dat_check_self_candidate()):
- update local DHT from/on own DHT_PUT if we are a DAT candidate
- (try to) reply to own DHT_GET from own DHT first if we are a
selected DAT candidate
- PATCH 3/4 (was 2/2): unchanged
- PATCH 4/4: NEW, avoid superfluous DAT DHT_PUT if self-candidate
Changelog v10:
- PATCH 1/3: removed, already applied
- PATCH 0/2: cover letter: removed test time period and "v5" reference
- PATCH 1/2:
- fixed kerneldoc in batadv_dat_hash_free(),
replaced "bat_priv" with "hash"
- added missing kerneldoc in batadv_dat_snoop_incoming_arp_reply()
for is_dht_put
- rebase to current main branch:
- adopted new bat_priv kernel doc description,
"soft interface" -> "mesh interface"
- adopted variable rename from soft_iface to mesh_iface
Changelog v9:
- PATCH 1/3:
- fixed typo in a comment: ENOENT -> ENONET
Changelog v8:
- PATCH 1/3:
- fixing / cleaning up includes
- fixing function kernel doc titles
- fixing bugs introduced in v7 in the error handling of
batadv_orig_dump() and batadv_neigh_dump(), using a goto
pattern with more explicit labels
Changelog v7:
- adding PATCH 1/3 to add the batadv_netlink_get_softif() wrapper to
reduce the amount of duplicate code, both in the current code base
but also for the next PATCH 2/3
Changelog v6:
- removed renaming+deprecation of BATADV_P_DAT_CACHE_REPLY in PATCH 1/2
- small commit message rewording in PATCH 1/2
Changelog v5:
- rebased to current main branch
-> removed now obsolete debugfs code
Changelog v4:
- rebased to: acfc9a214d01695
("batman-adv: genetlink: make policy common to family")
Changelog v3:
formerly:
"batman-adv: Increase purge timeout on DAT DHT candidates"
https://patchwork.open-mesh.org/patch/17728/
- fixed the potential jiffies overflow and jiffies initialization
issues by replacing the last_dht_update timeout variable with
a split of DAT cache and DAT DHT into two separate hash tables
-> instead of maintaining two timeouts in one DAT entry two DAT
entries are created and maintained in their respective DAT
cache and DAT DHT hash tables
Changelog v2:
formerly:
"batman-adv: Increase DHCP snooped DAT entry purge timeout in DHT"
(https://patchwork.open-mesh.org/patch/17364/)
- removed the extended timeouts flag in the DHT-PUT messages introduced
in v1 again
- removed DHCP dependency
Linus Lüssing (5):
batman-adv: move local ARP reply code to subfunctions
batman-adv: split DAT cache into DAT cache and DAT DHT
batman-adv: increase DAT DHT timeout
batman-adv: avoid superfluous DAT DHT_PUT if self-candidate
batman-adv: avoid superfluous DAT DHT_PUT additions to local DAT
include/uapi/linux/batadv_packet.h | 17 +-
include/uapi/linux/batman_adv.h | 5 +
net/batman-adv/distributed-arp-table.c | 889 ++++++++++++++++++++-----
net/batman-adv/distributed-arp-table.h | 24 +-
net/batman-adv/main.h | 3 +-
net/batman-adv/mesh-interface.c | 4 +
net/batman-adv/netlink.c | 8 +-
net/batman-adv/routing.c | 18 +-
net/batman-adv/send.c | 8 +-
net/batman-adv/send.h | 3 +-
net/batman-adv/types.h | 31 +-
11 files changed, 811 insertions(+), 199 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [batadv,v12 1/5] batman-adv: move local ARP reply code to subfunctions
2026-10-03 7:26 [batadv,v12 0/5] batman-adv: increase DAT DHT timeout Linus Lüssing
@ 2026-10-03 7:26 ` Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 2/5] batman-adv: split DAT cache into DAT cache and DAT DHT Linus Lüssing
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Linus Lüssing @ 2026-10-03 7:26 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
Shorten the length of batadv_dat_snoop_outgoing_arp_request() by moving
the checks for and generation of a local ARP reply to a new subfunction.
This is also in preparation for reuseability for the DAT cache/DHT
split.
No functional change.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
net/batman-adv/distributed-arp-table.c | 181 ++++++++++++++-----------
1 file changed, 105 insertions(+), 76 deletions(-)
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 74050bffedbc..1a0eb9d9812e 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -738,6 +738,103 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst,
return res;
}
+/**
+ * batadv_dat_arp_create_reply() - create an ARP Reply
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @ip_src: ARP sender IP
+ * @ip_dst: ARP target IP
+ * @hw_src: Ethernet source and ARP sender MAC
+ * @hw_dst: Ethernet destination and ARP target MAC
+ * @vid: VLAN identifier (optional, set to zero otherwise)
+ *
+ * Creates an ARP Reply from the given values, optionally encapsulated in a
+ * VLAN header.
+ *
+ * Return: An skb containing an ARP Reply.
+ */
+static struct sk_buff *
+batadv_dat_arp_create_reply(struct batadv_priv *bat_priv, __be32 ip_src,
+ __be32 ip_dst, u8 *hw_src, u8 *hw_dst,
+ unsigned short vid)
+{
+ struct sk_buff *skb;
+
+ skb = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_dst, bat_priv->mesh_iface,
+ ip_src, hw_dst, hw_src, hw_dst);
+ if (!skb)
+ return NULL;
+
+ skb_reset_mac_header(skb);
+
+ if (vid & BATADV_VLAN_HAS_TAG)
+ skb = vlan_insert_tag(skb, htons(ETH_P_8021Q),
+ vid & VLAN_VID_MASK);
+
+ return skb;
+}
+
+/**
+ * batadv_dat_arp_self_reply() - (maybe) reply to a local ARP request
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @ip_src: ARP request sender IP (and ARP reply target IP)
+ * @ip_dst: ARP request target IP (and ARP reply sender IP)
+ * @hw_src: Ethernet source and ARP sender MAC of ARP request
+ * @hw_dst: Ethernet destination and ARP target MAC of ARP request
+ * @vid: VLAN identifier (optional, set to zero otherwise)
+ * @arp_len: ARP packet size, including ethernet frame
+ *
+ * If the ARP request target is not a local client and if BLA is
+ * enabled and we have BLA claimed this target then generate and reply
+ * with an ARP reply locally on our mesh interface.
+ *
+ * Return: 0 if we transmitted an ARP reply, -ENOMEM if we should have but
+ * could not create an ARP reply (e.g. due to out-of-memory), -EACCSS
+ * otherwise (because the client is local or due to BLA suppression).
+ */
+static int
+batadv_dat_arp_self_reply(struct batadv_priv *bat_priv, __be32 ip_src,
+ __be32 ip_dst, u8 *hw_src, u8 *hw_dst,
+ unsigned short vid, unsigned int arp_len)
+{
+ struct sk_buff *skb;
+
+ /* If the ARP request is destined for a local client the local
+ * client will answer itself. DAT would only generate a
+ * duplicate packet.
+ *
+ * Moreover, if the mesh-interface is enslaved into a bridge, an
+ * additional DAT answer may trigger kernel warnings about
+ * a packet coming from the wrong port.
+ */
+ if (batadv_is_my_client(bat_priv, hw_dst, vid))
+ return -EACCES;
+
+ /* If BLA is enabled, only send ARP replies if we have claimed
+ * the destination for the ARP request or if no one else of
+ * the backbone gws belonging to our backbone has claimed the
+ * destination.
+ */
+ if (!batadv_bla_check_claim(bat_priv, hw_dst, vid)) {
+ batadv_dbg(BATADV_DBG_DAT, bat_priv,
+ "Device %pM claimed by another backbone gw. Don't send ARP reply!",
+ hw_dst);
+ return -EACCES;
+ }
+
+ skb = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src, hw_dst,
+ hw_src, vid);
+ if (!skb)
+ return -ENOMEM;
+
+ skb->protocol = eth_type_trans(skb, bat_priv->mesh_iface);
+
+ batadv_inc_counter(bat_priv, BATADV_CNT_RX);
+ batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES, arp_len);
+
+ netif_rx(skb);
+ return 0;
+}
+
/**
* batadv_dat_forward_data() - copy and send payload to the selected candidates
* @bat_priv: the bat priv with all the mesh interface information
@@ -1179,41 +1276,6 @@ static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size)
return vid;
}
-/**
- * batadv_dat_arp_create_reply() - create an ARP Reply
- * @bat_priv: the bat priv with all the mesh interface information
- * @ip_src: ARP sender IP
- * @ip_dst: ARP target IP
- * @hw_src: Ethernet source and ARP sender MAC
- * @hw_dst: Ethernet destination and ARP target MAC
- * @vid: VLAN identifier (optional, set to zero otherwise)
- *
- * Creates an ARP Reply from the given values, optionally encapsulated in a
- * VLAN header.
- *
- * Return: An skb containing an ARP Reply.
- */
-static struct sk_buff *
-batadv_dat_arp_create_reply(struct batadv_priv *bat_priv, __be32 ip_src,
- __be32 ip_dst, u8 *hw_src, u8 *hw_dst,
- unsigned short vid)
-{
- struct sk_buff *skb;
-
- skb = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_dst, bat_priv->mesh_iface,
- ip_src, hw_dst, hw_src, hw_dst);
- if (!skb)
- return NULL;
-
- skb_reset_mac_header(skb);
-
- if (vid & BATADV_VLAN_HAS_TAG)
- skb = vlan_insert_tag(skb, htons(ETH_P_8021Q),
- vid & VLAN_VID_MASK);
-
- return skb;
-}
-
/**
* batadv_dat_snoop_outgoing_arp_request() - snoop the ARP request and try to
* answer using DAT
@@ -1232,10 +1294,9 @@ batadv_dat_arp_create_reply(struct batadv_priv *bat_priv, __be32 ip_src,
bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
- struct net_device *mesh_iface = bat_priv->mesh_iface;
struct batadv_dat_entry *dat_entry = NULL;
u8 mac[ETH_ALEN] __aligned(2);
- struct sk_buff *skb_new;
+ unsigned int arp_len;
unsigned short vid;
bool ret = false;
int hdr_size = 0;
@@ -1244,6 +1305,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
u16 type = 0;
u64 u64_mac;
u8 *hw_src;
+ int rep;
if (!READ_ONCE(bat_priv->distributed_arp_table))
goto out;
@@ -1253,6 +1315,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
goto out;
vid = batadv_dat_get_vid(skb, &hdr_size);
+ arp_len = skb->len + ETH_HLEN + hdr_size;
type = batadv_arp_get_type(bat_priv, skb, hdr_size);
/* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast
@@ -1274,46 +1337,12 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
u64_mac = atomic64_read(&dat_entry->mac_addr);
u64_to_ether_addr(u64_mac, mac);
- /* If the ARP request is destined for a local client the local
- * client will answer itself. DAT would only generate a
- * duplicate packet.
- *
- * Moreover, if the mesh-interface is enslaved into a bridge, an
- * additional DAT answer may trigger kernel warnings about
- * a packet coming from the wrong port.
- */
- if (batadv_is_my_client(bat_priv, mac, vid)) {
- ret = true;
- goto out;
- }
-
- /* If BLA is enabled, only send ARP replies if we have claimed
- * the destination for the ARP request or if no one else of
- * the backbone gws belonging to our backbone has claimed the
- * destination.
- */
- if (!batadv_bla_check_claim(bat_priv, mac, vid)) {
+ rep = batadv_dat_arp_self_reply(bat_priv, ip_src, ip_dst,
+ hw_src, mac, vid, arp_len);
+ if (!rep)
batadv_dbg(BATADV_DBG_DAT, bat_priv,
- "Device %pM claimed by another backbone gw. Don't send ARP reply!",
- mac);
- ret = true;
- goto out;
- }
-
- skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
- mac, hw_src, vid);
- if (!skb_new)
- goto out;
-
- skb_new->protocol = eth_type_trans(skb_new, mesh_iface);
-
- batadv_inc_counter(bat_priv, BATADV_CNT_RX);
- batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
- skb->len + ETH_HLEN + hdr_size);
-
- netif_rx(skb_new);
- batadv_dbg(BATADV_DBG_DAT, bat_priv, "ARP request replied locally\n");
- ret = true;
+ "ARP request replied locally\n");
+ ret = (rep != -ENOMEM);
} else {
/* Send the request to the DHT */
ret = batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [batadv,v12 2/5] batman-adv: split DAT cache into DAT cache and DAT DHT
2026-10-03 7:26 [batadv,v12 0/5] batman-adv: increase DAT DHT timeout Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 1/5] batman-adv: move local ARP reply code to subfunctions Linus Lüssing
@ 2026-10-03 7:26 ` Linus Lüssing
2026-10-03 8:04 ` Sven Eckelmann
2026-10-03 7:26 ` [batadv,v12 3/5] batman-adv: increase DAT DHT timeout Linus Lüssing
` (2 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Linus Lüssing @ 2026-10-03 7:26 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
Similar to the translation table split the (mostly) locally maintained
DAT cache and the DAT DHT concepts into two separate tables.
This eases the monitoring and debugging regarding the origin of DAT
entries. And allows to apply differing properties to entries in the DAT
cache and DAT DHT in the future, like distinct timeouts.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
include/uapi/linux/batman_adv.h | 5 +
net/batman-adv/distributed-arp-table.c | 581 ++++++++++++++++++++-----
net/batman-adv/distributed-arp-table.h | 13 +-
net/batman-adv/netlink.c | 8 +-
net/batman-adv/routing.c | 7 +-
net/batman-adv/types.h | 7 +-
6 files changed, 511 insertions(+), 110 deletions(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h
index 936bcac270b5..7379c1509f77 100644
--- a/include/uapi/linux/batman_adv.h
+++ b/include/uapi/linux/batman_adv.h
@@ -613,6 +613,11 @@ enum batadv_nl_commands {
*/
BATADV_CMD_SET_VLAN,
+ /**
+ * @BATADV_CMD_GET_DAT_DHT: Query list of DAT DHT entries
+ */
+ BATADV_CMD_GET_DAT_DHT,
+
/* add new commands above here */
/**
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 1a0eb9d9812e..af08812c7ecd 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -211,17 +211,17 @@ static bool batadv_dat_to_purge(struct batadv_dat_entry *dat_entry)
}
/**
- * __batadv_dat_purge() - delete entries from the DAT local storage
- * @bat_priv: the bat priv with all the mesh interface information
+ * __batadv_dat_purge() - delete entries from a DAT hash table
+ * @hash: the hash table to delete from
* @to_purge: function in charge to decide whether an entry has to be purged or
* not. This function takes the dat_entry as argument and has to
* returns a boolean value: true is the entry has to be deleted,
* false otherwise
*
- * Loops over each entry in the DAT local storage and deletes it if and only if
+ * Loops over each entry in a DAT hash table and deletes it if and only if
* the to_purge function passed as argument returns true.
*/
-static void __batadv_dat_purge(struct batadv_priv *bat_priv,
+static void __batadv_dat_purge(struct batadv_hashtable *hash,
bool (*to_purge)(struct batadv_dat_entry *))
{
spinlock_t *list_lock; /* protects write access to the hash lists */
@@ -230,12 +230,12 @@ static void __batadv_dat_purge(struct batadv_priv *bat_priv,
struct hlist_head *head;
u32 i;
- if (!bat_priv->dat.hash)
+ if (!hash)
return;
- for (i = 0; i < bat_priv->dat.hash->size; i++) {
- head = &bat_priv->dat.hash->table[i];
- list_lock = &bat_priv->dat.hash->list_locks[i];
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock);
hlist_for_each_entry_safe(dat_entry, node_tmp, head,
@@ -268,7 +268,8 @@ static void batadv_dat_purge(struct work_struct *work)
priv_dat = container_of(delayed_work, struct batadv_priv_dat, work);
bat_priv = container_of(priv_dat, struct batadv_priv, dat);
- __batadv_dat_purge(bat_priv, batadv_dat_to_purge);
+ __batadv_dat_purge(bat_priv->dat.cache_hash, batadv_dat_to_purge);
+ __batadv_dat_purge(bat_priv->dat.dht_hash, batadv_dat_to_purge);
batadv_dat_start_timer(bat_priv);
}
@@ -387,19 +388,17 @@ static u32 batadv_hash_dat(const void *data, u32 size)
}
/**
- * batadv_dat_entry_hash_find() - look for a given dat_entry in the local hash
- * table
- * @bat_priv: the bat priv with all the mesh interface information
+ * batadv_dat_entry_hash_find() - look for a given dat_entry in a hash table
+ * @hash: the hash table to search in
* @ip: search key
* @vid: VLAN identifier
*
* Return: the dat_entry if found, NULL otherwise.
*/
static struct batadv_dat_entry *
-batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,
+batadv_dat_entry_hash_find(struct batadv_hashtable *hash, __be32 ip,
unsigned short vid)
{
- struct batadv_hashtable *hash = bat_priv->dat.hash;
struct batadv_dat_entry *dat_entry_tmp = NULL;
struct batadv_dat_entry *dat_entry;
struct batadv_dat_entry to_find;
@@ -434,29 +433,64 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,
return dat_entry_tmp;
}
+/**
+ * batadv_dat_cache_entry_find() - look for a given dat_entry in the DAT cache
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @ip: search key
+ * @vid: VLAN identifier
+ *
+ * Return: the dat_entry if found, NULL otherwise.
+ */
+static inline struct batadv_dat_entry *
+batadv_dat_cache_entry_find(struct batadv_priv *bat_priv, __be32 ip,
+ unsigned short vid)
+{
+ return batadv_dat_entry_hash_find(bat_priv->dat.cache_hash, ip, vid);
+}
+
+/**
+ * batadv_dat_dht_entry_find() - look for a given dat_entry in the DAT DHT
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @ip: search key
+ * @vid: VLAN identifier
+ *
+ * Return: the dat_entry if found, NULL otherwise.
+ */
+static inline struct batadv_dat_entry *
+batadv_dat_dht_entry_find(struct batadv_priv *bat_priv, __be32 ip,
+ unsigned short vid)
+{
+ return batadv_dat_entry_hash_find(bat_priv->dat.dht_hash, ip, vid);
+}
+
/**
* batadv_dat_entry_add() - add a new dat entry or update it if already exists
* @bat_priv: the bat priv with all the mesh interface information
+ * @hash: the hash table to add to
* @ip: ipv4 to add/edit
* @mac_addr: mac address to assign to the given ipv4
* @vid: VLAN identifier
+ * @tablename: the name of the hash table to add to
*/
-static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
- u8 *mac_addr, unsigned short vid)
+static void
+batadv_dat_entry_add(struct batadv_priv *bat_priv,
+ struct batadv_hashtable *hash, __be32 ip,
+ u8 *mac_addr, unsigned short vid,
+ const char *tablename)
{
u64 u64_mac = ether_addr_to_u64(mac_addr);
struct batadv_dat_entry *dat_entry;
int hash_added;
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid);
+ dat_entry = batadv_dat_entry_hash_find(hash, ip, vid);
/* if this entry is already known, just update it */
if (dat_entry) {
atomic64_set(&dat_entry->mac_addr, u64_mac);
dat_entry->last_update = jiffies;
batadv_dbg(BATADV_DBG_DAT, bat_priv,
- "Entry updated: %pI4 %pM (vid: %d)\n",
- &dat_entry->ip, mac_addr,
+ "Entry updated in %s: %pI4 %pM (vid: %d)\n",
+ tablename, &dat_entry->ip, mac_addr,
batadv_print_vid(vid));
goto out;
}
@@ -472,7 +506,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
kref_init(&dat_entry->refcount);
kref_get(&dat_entry->refcount);
- hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat,
+ hash_added = batadv_hash_add(hash, batadv_compare_dat,
batadv_hash_dat, dat_entry,
&dat_entry->hash_entry);
@@ -482,13 +516,44 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
goto out;
}
- batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)\n",
- &dat_entry->ip, mac_addr, batadv_print_vid(vid));
+ batadv_dbg(BATADV_DBG_DAT, bat_priv,
+ "New entry added in %s: %pI4 %pM (vid: %d)\n",
+ tablename, &dat_entry->ip, mac_addr, batadv_print_vid(vid));
out:
batadv_dat_entry_put(dat_entry);
}
+/**
+ * batadv_dat_cache_entry_add() - add or update dat_entry in the DAT cache
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ip: ipv4 to add/edit
+ * @mac_addr: mac address to assign to the given ipv4
+ * @vid: VLAN identifier
+ */
+static inline void
+batadv_dat_cache_entry_add(struct batadv_priv *bat_priv, __be32 ip,
+ u8 *mac_addr, unsigned short vid)
+{
+ batadv_dat_entry_add(bat_priv, bat_priv->dat.cache_hash, ip, mac_addr,
+ vid, "cache");
+}
+
+/**
+ * batadv_dat_dht_entry_add() - add or update dat_entry in the DAT DHT
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @ip: ipv4 to add/edit
+ * @mac_addr: mac address to assign to the given ipv4
+ * @vid: VLAN identifier
+ */
+static inline void
+batadv_dat_dht_entry_add(struct batadv_priv *bat_priv, __be32 ip,
+ u8 *mac_addr, unsigned short vid)
+{
+ batadv_dat_entry_add(bat_priv, bat_priv->dat.dht_hash, ip, mac_addr,
+ vid, "dht");
+}
+
#ifdef CONFIG_BATMAN_ADV_DEBUG
/**
@@ -692,12 +757,77 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
*last_max = max;
}
+/**
+ * batadv_dat_cmp_self_candidate() - check if we are a better DHT candidate
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @cands: candidates array
+ * @ip_key: key to look up in the DHT
+ * @last_max: address of the last selected candidate
+ *
+ * Check if we are a better candidate than the last placed, selected DHT
+ * candidate for the given IP address key.
+ *
+ * Return: true if we are a better candidate, false otherwise.
+ */
+static bool batadv_dat_cmp_self_candidate(struct batadv_priv *bat_priv,
+ struct batadv_dat_candidate *cands,
+ batadv_dat_addr_t ip_key,
+ batadv_dat_addr_t last_max)
+{
+ struct batadv_hard_iface *primary_if = NULL;
+ struct batadv_dat_candidate *last_cand;
+ const unsigned char *own_orig_addr;
+ batadv_dat_addr_t own_dat_addr;
+ batadv_dat_addr_t tmp_max;
+ bool ret = false;
+
+ last_cand = &cands[BATADV_DAT_CANDIDATES_NUM - 1];
+
+ /* a free slot? then it is for us */
+ if (last_cand->type == BATADV_DAT_CANDIDATE_NOT_FOUND) {
+ ret = true;
+ goto out;
+ }
+
+ primary_if = batadv_primary_if_get_selected(bat_priv);
+ if (!primary_if)
+ return false;
+
+ own_orig_addr = primary_if->net_dev->dev_addr;
+ own_dat_addr = batadv_choose_orig(own_orig_addr, BATADV_DAT_ADDR_MAX);
+ tmp_max = BATADV_DAT_ADDR_MAX - own_dat_addr + ip_key;
+
+ /* check if we are a better candidate than the last placed,
+ * selected candidate node
+ */
+ if (tmp_max < last_max)
+ goto out;
+
+ /* this is a hash collision with the last placed, selected candidate.
+ * Choose the one with the lowest address
+ */
+ if (tmp_max == last_max &&
+ memcmp(own_orig_addr, last_cand->orig_node->orig, ETH_ALEN) >= 0)
+ goto out;
+
+ ret = true;
+out:
+ if (ret)
+ batadv_dbg(BATADV_DBG_DAT, bat_priv,
+ "%s(): self-candidate for hash(IP)=%u, dist=%i\n",
+ __func__, ip_key, primary_if ? tmp_max : -1);
+
+ batadv_hardif_put(primary_if);
+ return ret;
+}
+
/**
* batadv_dat_select_candidates() - select the nodes which the DHT message has
* to be sent to
* @bat_priv: the bat priv with all the mesh interface information
* @ip_dst: ipv4 to look up in the DHT
* @vid: VLAN identifier
+ * @self_is_candidate: stores if we are a candidate (must not be NULL)
*
* An originator O is selected if and only if its DHT_ID value is one of three
* closest values (from the LEFT, with wrap around if needed) then the hash
@@ -707,7 +837,7 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
*/
static struct batadv_dat_candidate *
batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst,
- unsigned short vid)
+ unsigned short vid, bool *self_is_candidate)
{
batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX;
struct batadv_dat_candidate *res;
@@ -735,6 +865,9 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst,
batadv_choose_next_candidate(bat_priv, res, select, ip_key,
&last_max);
+ if (batadv_dat_cmp_self_candidate(bat_priv, res, ip_key, last_max))
+ *self_is_candidate = true;
+
return res;
}
@@ -835,9 +968,61 @@ batadv_dat_arp_self_reply(struct batadv_priv *bat_priv, __be32 ip_src,
return 0;
}
+/**
+ * batadv_dat_dht_get_self_reply() - reply to our DHT_GET locally
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @ip_src: ARP request sender IP (and ARP reply target IP)
+ * @ip_dst: ARP request target IP (and ARP reply sender IP)
+ * @hw_src: Ethernet source and ARP sender MAC of ARP request
+ * @hw_dst: Ethernet destination and ARP target MAC of ARP request
+ * @vid: VLAN identifier (optional, set to zero otherwise)
+ * @arp_len: ARP packet size, including ethernet frame
+ *
+ * If we have a suitable response in our local DAT DHT for a local
+ * ARP request and are a suitable responder then generate and respond
+ * with an ARP reply locally.
+ *
+ * Return: false if we could not find a DAT DHT entry locally or if we
+ * were a suitable responder but could not generate an ARP reply
+ * (e.g. due to out-of-memory), true otherwise.
+ */
+static bool
+batadv_dat_dht_get_self_reply(struct batadv_priv *bat_priv, __be32 ip_src,
+ __be32 ip_dst, u8 *hw_src, unsigned short vid,
+ unsigned int arp_len)
+{
+ struct batadv_dat_entry *dat_entry;
+ u8 mac[ETH_ALEN] __aligned(2);
+ u64 u64_mac;
+ int ret;
+
+ dat_entry = batadv_dat_dht_entry_find(bat_priv, ip_dst, vid);
+ if (!dat_entry)
+ return false;
+
+ u64_mac = atomic64_read(&dat_entry->mac_addr);
+ u64_to_ether_addr(u64_mac, mac);
+
+ /* we are a selected DAT DHT candidate, our DAT DHT entry should get
+ * updates, we can therefore safely copy it to our DAT cache for now
+ */
+ batadv_dat_cache_entry_add(bat_priv, ip_dst, mac, vid);
+
+ ret = batadv_dat_arp_self_reply(bat_priv, ip_src, ip_dst, hw_src, mac,
+ vid, arp_len);
+ if (!ret)
+ batadv_dbg(BATADV_DBG_DAT, bat_priv,
+ "ARP request for %pI4 replied locally (via local DHT)\n",
+ &ip_dst);
+
+ batadv_dat_entry_put(dat_entry);
+ return (ret != -ENOMEM);
+}
+
/**
* batadv_dat_forward_data() - copy and send payload to the selected candidates
* @bat_priv: the bat priv with all the mesh interface information
+ * @cands: candidates array
* @skb: payload to send
* @ip: the DHT key
* @vid: VLAN identifier
@@ -850,37 +1035,33 @@ batadv_dat_arp_self_reply(struct batadv_priv *bat_priv, __be32 ip_src,
* otherwise.
*/
static bool batadv_dat_forward_data(struct batadv_priv *bat_priv,
+ struct batadv_dat_candidate *cands,
struct sk_buff *skb, __be32 ip,
unsigned short vid, int packet_subtype)
{
struct batadv_neigh_node *neigh_node = NULL;
- struct batadv_dat_candidate *cand;
struct sk_buff *tmp_skb;
bool ret = false;
int send_status;
int i;
- cand = batadv_dat_select_candidates(bat_priv, ip, vid);
- if (!cand)
- return ret;
-
batadv_dbg(BATADV_DBG_DAT, bat_priv, "DHT_SEND for %pI4\n", &ip);
for (i = 0; i < BATADV_DAT_CANDIDATES_NUM; i++) {
- if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND)
+ if (cands[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND)
continue;
- neigh_node = batadv_orig_router_get(cand[i].orig_node,
+ neigh_node = batadv_orig_router_get(cands[i].orig_node,
BATADV_IF_DEFAULT);
if (!neigh_node)
- goto free_orig;
+ continue;
tmp_skb = pskb_copy_for_clone(skb, GFP_ATOMIC);
if (!tmp_skb)
goto free_neigh;
if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, tmp_skb,
- cand[i].orig_node,
+ cands[i].orig_node,
packet_subtype)) {
kfree_skb(tmp_skb);
goto free_neigh;
@@ -905,11 +1086,112 @@ static bool batadv_dat_forward_data(struct batadv_priv *bat_priv,
}
free_neigh:
batadv_neigh_node_put(neigh_node);
-free_orig:
- batadv_orig_node_put(cand[i].orig_node);
}
- kfree(cand);
+ return ret;
+}
+
+/**
+ * batadv_dat_candidates_free() - free a candidates array
+ * @cands: the candidates array to free
+ *
+ * Free the given candidate array and release any potential orig node references
+ * it held.
+ *
+ * If @cands is NULL, no operation is performed.
+ */
+static void batadv_dat_candidates_free(struct batadv_dat_candidate *cands)
+{
+ if (!cands)
+ return;
+
+ for (int i = 0; i < BATADV_DAT_CANDIDATES_NUM; i++)
+ if (cands[i].type == BATADV_DAT_CANDIDATE_ORIG)
+ batadv_orig_node_put(cands[i].orig_node);
+
+ kfree(cands);
+}
+
+/**
+ * batadv_dat_forward_dht_put() - send payload via DHT_PUT to DAT candidates
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @skb: payload to send
+ * @ip: the DHT key
+ * @hw_addr: the MAC address which the IP resolves to
+ * @vid: VLAN identifier
+ *
+ * Send the given payload via a DAT DHT_PUT message to the selected
+ * candidates.
+ *
+ * Return: true if the packet is sent to at least one candidate, false
+ * otherwise.
+ */
+static bool
+batadv_dat_forward_dht_put(struct batadv_priv *bat_priv, struct sk_buff *skb,
+ __be32 ip, u8 *hw_addr, unsigned short vid)
+{
+ struct batadv_dat_candidate *cands;
+ bool self_is_candidate = false;
+ bool ret;
+
+ cands = batadv_dat_select_candidates(bat_priv, ip, vid,
+ &self_is_candidate);
+ if (!cands)
+ return false;
+
+ if (self_is_candidate)
+ batadv_dat_dht_entry_add(bat_priv, ip, hw_addr, vid);
+
+ ret = batadv_dat_forward_data(bat_priv, cands, skb, ip, vid,
+ BATADV_P_DAT_DHT_PUT);
+
+ batadv_dat_candidates_free(cands);
+ return ret;
+}
+
+/**
+ * batadv_dat_forward_dht_get() - send payload via DHT_GET to DAT candidates
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @skb: payload to send
+ * @ip_src: ARP sender IP
+ * @ip_dst: ARP target IP
+ * @hw_src: Ethernet source and ARP sender MAC
+ * @hw_dst: Ethernet destination and ARP target MAC
+ * @vid: VLAN identifier
+ * @arp_len: ARP packet size, including ethernet frame
+ *
+ * Send the given payload via a DAT DHT_GET message to the selected
+ * candidates.
+ *
+ * Return: true if the packet is sent to at least one candidate, false
+ * otherwise.
+ */
+static bool
+batadv_dat_forward_dht_get(struct batadv_priv *bat_priv, struct sk_buff *skb,
+ __be32 ip_src, __be32 ip_dst, u8 *hw_src,
+ unsigned short vid, unsigned int arp_len)
+{
+ struct batadv_dat_candidate *cands;
+ bool self_is_candidate = false;
+ bool ret;
+
+ cands = batadv_dat_select_candidates(bat_priv, ip_dst, vid,
+ &self_is_candidate);
+ if (!cands)
+ return false;
+
+ if (self_is_candidate) {
+ ret = batadv_dat_dht_get_self_reply(bat_priv, ip_src, ip_dst,
+ hw_src, vid, arp_len);
+ if (ret)
+ goto skip_remote_forward;
+ }
+
+ ret = batadv_dat_forward_data(bat_priv, cands, skb, ip_dst, vid,
+ BATADV_P_DAT_DHT_GET);
+
+skip_remote_forward:
+ batadv_dat_candidates_free(cands);
return ret;
}
@@ -965,19 +1247,57 @@ static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
}
/**
- * batadv_dat_hash_free() - free the local DAT hash table
- * @bat_priv: the bat priv with all the mesh interface information
+ * batadv_dat_hash_free() - free a DAT hash table
+ * @hash: the hash table to free
*/
-static void batadv_dat_hash_free(struct batadv_priv *bat_priv)
+static void batadv_dat_hash_free(struct batadv_hashtable **hash)
{
- if (!bat_priv->dat.hash)
+ if (!(*hash))
return;
- __batadv_dat_purge(bat_priv, NULL);
+ __batadv_dat_purge(*hash, NULL);
- batadv_hash_destroy(bat_priv->dat.hash);
+ batadv_hash_destroy(*hash);
- bat_priv->dat.hash = NULL;
+ *hash = NULL;
+}
+
+/**
+ * batadv_dat_cache_hash_init() - initialise the DAT cache hash table
+ * @bat_priv: the bat priv with all the mesh interface information
+ *
+ * Return: 0 in case of success, a negative error code otherwise
+ */
+static int batadv_dat_cache_hash_init(struct batadv_priv *bat_priv)
+{
+ if (bat_priv->dat.cache_hash)
+ return 0;
+
+ bat_priv->dat.cache_hash = batadv_hash_new(1024);
+
+ if (!bat_priv->dat.cache_hash)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * batadv_dat_dht_hash_init() - initialise the DAT DHT hash table
+ * @bat_priv: the bat priv with all the mesh interface information
+ *
+ * Return: 0 in case of success, a negative error code otherwise
+ */
+static int batadv_dat_dht_hash_init(struct batadv_priv *bat_priv)
+{
+ if (bat_priv->dat.dht_hash)
+ return 0;
+
+ bat_priv->dat.dht_hash = batadv_hash_new(1024);
+
+ if (!bat_priv->dat.dht_hash)
+ return -ENOMEM;
+
+ return 0;
}
/**
@@ -988,13 +1308,15 @@ static void batadv_dat_hash_free(struct batadv_priv *bat_priv)
*/
int batadv_dat_init(struct batadv_priv *bat_priv)
{
- if (bat_priv->dat.hash)
- return 0;
+ int ret;
- bat_priv->dat.hash = batadv_hash_new(1024);
+ ret = batadv_dat_cache_hash_init(bat_priv);
+ if (ret < 0)
+ return ret;
- if (!bat_priv->dat.hash)
- return -ENOMEM;
+ ret = batadv_dat_dht_hash_init(bat_priv);
+ if (ret < 0)
+ return ret;
INIT_DELAYED_WORK(&bat_priv->dat.work, batadv_dat_purge);
batadv_dat_start_timer(bat_priv);
@@ -1017,23 +1339,25 @@ void batadv_dat_free(struct batadv_priv *bat_priv)
disable_delayed_work_sync(&bat_priv->dat.work);
- batadv_dat_hash_free(bat_priv);
+ batadv_dat_hash_free(&bat_priv->dat.cache_hash);
+ batadv_dat_hash_free(&bat_priv->dat.dht_hash);
}
/**
- * batadv_dat_cache_dump_entry() - dump one entry of the DAT cache table to a
- * netlink socket
+ * batadv_dat_dump_entry() - dump one entry of a DAT hash table to a netlink
+ * socket
* @msg: buffer for the message
* @portid: netlink port
* @cb: Control block containing additional options
* @dat_entry: entry to dump
+ * @cmd: generic netlink command
*
* Return: 0 or error code.
*/
static int
-batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,
- struct netlink_callback *cb,
- struct batadv_dat_entry *dat_entry)
+batadv_dat_dump_entry(struct sk_buff *msg, u32 portid,
+ struct netlink_callback *cb,
+ struct batadv_dat_entry *dat_entry, u8 cmd)
{
u8 mac[ETH_ALEN] __aligned(2);
u64 u64_mac;
@@ -1041,8 +1365,7 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,
void *hdr;
hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
- &batadv_netlink_family, NLM_F_MULTI,
- BATADV_CMD_GET_DAT_CACHE);
+ &batadv_netlink_family, NLM_F_MULTI, cmd);
if (!hdr)
return -ENOBUFS;
@@ -1066,22 +1389,23 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,
}
/**
- * batadv_dat_cache_dump_bucket() - dump one bucket of the DAT cache table to
- * a netlink socket
+ * batadv_dat_dump_bucket() - dump one bucket of a DAT hash table to a netlink
+ * socket
* @msg: buffer for the message
* @portid: netlink port
* @cb: Control block containing additional options
* @hash: hash to dump
* @bucket: bucket index to dump
* @idx_skip: How many entries to skip
+ * @cmd: generic netlink command
*
* Return: 0 or error code.
*/
static int
-batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid,
- struct netlink_callback *cb,
- struct batadv_hashtable *hash, unsigned int bucket,
- int *idx_skip)
+batadv_dat_dump_bucket(struct sk_buff *msg, u32 portid,
+ struct netlink_callback *cb,
+ struct batadv_hashtable *hash, unsigned int bucket,
+ int *idx_skip, u8 cmd)
{
struct batadv_dat_entry *dat_entry;
int idx = 0;
@@ -1093,7 +1417,7 @@ batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid,
if (idx < *idx_skip)
goto skip;
- if (batadv_dat_cache_dump_entry(msg, portid, cb, dat_entry)) {
+ if (batadv_dat_dump_entry(msg, portid, cb, dat_entry, cmd)) {
spin_unlock_bh(&hash->list_locks[bucket]);
*idx_skip = idx;
@@ -1109,30 +1433,26 @@ batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid,
}
/**
- * batadv_dat_cache_dump() - dump DAT cache table to a netlink socket
+ * batadv_dat_dump() - dump a DAT hash table to a netlink socket
+ * @bat_priv: the bat priv with all the mesh interface information
* @msg: buffer for the message
* @cb: callback structure containing arguments
+ * @hash: the hash table to dump from
+ * @cmd: generic netlink command
*
* Return: message length.
*/
-int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)
+static int
+batadv_dat_dump(struct batadv_priv *bat_priv, struct sk_buff *msg,
+ struct netlink_callback *cb, struct batadv_hashtable *hash,
+ u8 cmd)
{
- struct batadv_hard_iface *primary_if = NULL;
int portid = NETLINK_CB(cb->skb).portid;
- struct net_device *mesh_iface;
- struct batadv_hashtable *hash;
- struct batadv_priv *bat_priv;
+ struct batadv_hard_iface *primary_if;
int bucket = cb->args[0];
int idx = cb->args[1];
int ret = 0;
- mesh_iface = batadv_netlink_get_meshif(cb);
- if (IS_ERR(mesh_iface))
- return PTR_ERR(mesh_iface);
-
- bat_priv = netdev_priv(mesh_iface);
- hash = bat_priv->dat.hash;
-
primary_if = batadv_primary_if_get_selected(bat_priv);
if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
ret = -ENOENT;
@@ -1140,8 +1460,8 @@ int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)
}
while (bucket < hash->size) {
- if (batadv_dat_cache_dump_bucket(msg, portid, cb, hash, bucket,
- &idx))
+ if (batadv_dat_dump_bucket(msg, portid, cb, hash, bucket, &idx,
+ cmd))
break;
bucket++;
@@ -1156,8 +1476,58 @@ int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)
out:
batadv_hardif_put(primary_if);
+ return ret;
+}
+
+/**
+ * batadv_dat_cache_dump() - dump the DAT cache table to a netlink socket
+ * @msg: buffer for the message
+ * @cb: callback structure containing arguments
+ *
+ * Return: Message length on success or a negative error number otherwise.
+ */
+int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)
+{
+ struct net_device *mesh_iface;
+ struct batadv_priv *bat_priv;
+ int ret;
+
+ mesh_iface = batadv_netlink_get_meshif(cb);
+ if (IS_ERR(mesh_iface))
+ return PTR_ERR(mesh_iface);
+
+ bat_priv = netdev_priv(mesh_iface);
+
+ ret = batadv_dat_dump(bat_priv, msg, cb, bat_priv->dat.cache_hash,
+ BATADV_CMD_GET_DAT_CACHE);
+
dev_put(mesh_iface);
+ return ret;
+}
+/**
+ * batadv_dat_dht_dump() - dump the DAT DHT table to a netlink socket
+ * @msg: buffer for the message
+ * @cb: callback structure containing arguments
+ *
+ * Return: Message length on success or a negative error number otherwise.
+ */
+int batadv_dat_dht_dump(struct sk_buff *msg, struct netlink_callback *cb)
+{
+ struct net_device *mesh_iface;
+ struct batadv_priv *bat_priv;
+ int ret;
+
+ mesh_iface = batadv_netlink_get_meshif(cb);
+ if (IS_ERR(mesh_iface))
+ return PTR_ERR(mesh_iface);
+
+ bat_priv = netdev_priv(mesh_iface);
+
+ ret = batadv_dat_dump(bat_priv, msg, cb, bat_priv->dat.dht_hash,
+ BATADV_CMD_GET_DAT_DHT);
+
+ dev_put(mesh_iface);
return ret;
}
@@ -1330,9 +1700,9 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
hw_src = batadv_arp_hw_src(skb, hdr_size);
ip_dst = batadv_arp_ip_dst(skb, hdr_size);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
+ dat_entry = batadv_dat_cache_entry_find(bat_priv, ip_dst, vid);
if (dat_entry) {
u64_mac = atomic64_read(&dat_entry->mac_addr);
u64_to_ether_addr(u64_mac, mac);
@@ -1341,12 +1711,13 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
hw_src, mac, vid, arp_len);
if (!rep)
batadv_dbg(BATADV_DBG_DAT, bat_priv,
- "ARP request replied locally\n");
+ "ARP request for %pI4 replied locally (via DAT cache)\n",
+ &ip_dst);
ret = (rep != -ENOMEM);
} else {
/* Send the request to the DHT */
- ret = batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,
- BATADV_P_DAT_DHT_GET);
+ ret = batadv_dat_forward_dht_get(bat_priv, skb, ip_src, ip_dst,
+ hw_src, vid, arp_len);
}
out:
batadv_dat_entry_put(dat_entry);
@@ -1401,9 +1772,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing incoming ARP REQUEST");
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
+ dat_entry = batadv_dat_dht_entry_find(bat_priv, ip_dst, vid);
if (!dat_entry)
goto out;
@@ -1470,16 +1841,14 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
hw_dst = batadv_arp_hw_dst(skb, hdr_size);
ip_dst = batadv_arp_ip_dst(skb, hdr_size);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
- batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
+ batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_cache_entry_add(bat_priv, ip_dst, hw_dst, vid);
/* Send the ARP reply to the candidates for both the IP addresses that
* the node obtained from the ARP reply
*/
- batadv_dat_forward_data(bat_priv, skb, ip_src, vid,
- BATADV_P_DAT_DHT_PUT);
- batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,
- BATADV_P_DAT_DHT_PUT);
+ batadv_dat_forward_dht_put(bat_priv, skb, ip_src, hw_src, vid);
+ batadv_dat_forward_dht_put(bat_priv, skb, ip_dst, hw_dst, vid);
}
/**
@@ -1488,6 +1857,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
* @bat_priv: the bat priv with all the mesh interface information
* @skb: packet to check
* @hdr_size: size of the encapsulation header
+ * @is_dht_put: ARP reply is part of a unicast 4addr DHT PUT packet and should
+ * not only update our local DAT cache but also our local DAT DHT
*
* Warning: This function may reallocate the skb data buffer via
* batadv_dat_get_vid()/... Any pointer into the skb data (e.g. obtained
@@ -1498,7 +1869,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
* packet has to be delivered to the interface
*/
bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
- struct sk_buff *skb, int hdr_size)
+ struct sk_buff *skb, int hdr_size,
+ bool is_dht_put)
{
struct batadv_dat_entry *dat_entry = NULL;
u8 mac[ETH_ALEN] __aligned(2);
@@ -1531,13 +1903,18 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
hw_dst = batadv_arp_hw_dst(skb, hdr_size);
ip_dst = batadv_arp_ip_dst(skb, hdr_size);
+ if (is_dht_put) {
+ batadv_dat_dht_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_dht_entry_add(bat_priv, ip_dst, hw_dst, vid);
+ }
+
/* If ip_dst is already in cache and has the right mac address,
* drop this frame if this ARP reply is destined for us because it's
* most probably an ARP reply generated by another node of the DHT.
* We have most probably received already a reply earlier. Delivering
* this frame would lead to doubled receive of an ARP reply.
*/
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_src, vid);
+ dat_entry = batadv_dat_cache_entry_find(bat_priv, ip_src, vid);
if (dat_entry) {
u64_mac = atomic64_read(&dat_entry->mac_addr);
u64_to_ether_addr(u64_mac, mac);
@@ -1554,8 +1931,8 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
/* Update our internal cache with both the IP addresses the node got
* within the ARP reply
*/
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
- batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
+ batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_cache_entry_add(bat_priv, ip_dst, hw_dst, vid);
if (dropped)
goto out;
@@ -1809,13 +2186,11 @@ static void batadv_dat_put_dhcp(struct batadv_priv *bat_priv, u8 *chaddr,
skb_set_network_header(skb, ETH_HLEN);
- batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid);
- batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
+ batadv_dat_cache_entry_add(bat_priv, yiaddr, chaddr, vid);
+ batadv_dat_cache_entry_add(bat_priv, ip_dst, hw_dst, vid);
- batadv_dat_forward_data(bat_priv, skb, yiaddr, vid,
- BATADV_P_DAT_DHT_PUT);
- batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,
- BATADV_P_DAT_DHT_PUT);
+ batadv_dat_forward_dht_put(bat_priv, skb, yiaddr, chaddr, vid);
+ batadv_dat_forward_dht_put(bat_priv, skb, ip_dst, hw_dst, vid);
consume_skb(skb);
@@ -1945,8 +2320,8 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv,
ethhdr = (struct ethhdr *)(skb->data + hdr_size);
hw_src = ethhdr->h_source;
- batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid);
- batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
+ batadv_dat_cache_entry_add(bat_priv, yiaddr, chaddr, vid);
+ batadv_dat_cache_entry_add(bat_priv, ip_src, hw_src, vid);
batadv_dbg(BATADV_DBG_DAT, bat_priv,
"Snooped from incoming DHCPACK (server address): %pI4, %pM (vid: %i)\n",
@@ -1999,7 +2374,7 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
goto out;
ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size);
- dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
+ dat_entry = batadv_dat_cache_entry_find(bat_priv, ip_dst, vid);
/* check if the node already got this entry */
if (!dat_entry) {
batadv_dbg(BATADV_DBG_DAT, bat_priv,
diff --git a/net/batman-adv/distributed-arp-table.h b/net/batman-adv/distributed-arp-table.h
index e7b75e82eb1d..ad81b7db921e 100644
--- a/net/batman-adv/distributed-arp-table.h
+++ b/net/batman-adv/distributed-arp-table.h
@@ -31,7 +31,8 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb);
bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
- struct sk_buff *skb, int hdr_size);
+ struct sk_buff *skb, int hdr_size,
+ bool is_dht_put);
void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv,
struct sk_buff *skb,
__be16 proto,
@@ -74,6 +75,7 @@ batadv_dat_init_own_addr(struct batadv_priv *bat_priv,
int batadv_dat_init(struct batadv_priv *bat_priv);
void batadv_dat_free(struct batadv_priv *bat_priv);
int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb);
+int batadv_dat_dht_dump(struct sk_buff *msg, struct netlink_callback *cb);
/**
* batadv_dat_inc_counter() - increment the correct DAT packet counter
@@ -126,7 +128,8 @@ batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
static inline bool
batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
- struct sk_buff *skb, int hdr_size)
+ struct sk_buff *skb, int hdr_size,
+ bool is_dht_put)
{
return false;
}
@@ -176,6 +179,12 @@ batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)
return -EOPNOTSUPP;
}
+static inline int
+batadv_dat_dht_dump(struct sk_buff *msg, struct netlink_callback *cb)
+{
+ return -EOPNOTSUPP;
+}
+
static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv,
u8 subtype)
{
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 1177b3ceaf03..5250c3d1805e 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -1498,6 +1498,12 @@ static const struct genl_small_ops batadv_netlink_ops[] = {
.flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_dat_cache_dump,
},
+ {
+ .cmd = BATADV_CMD_GET_DAT_DHT,
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+ .flags = GENL_UNS_ADMIN_PERM,
+ .dumpit = batadv_dat_dht_dump,
+ },
{
.cmd = BATADV_CMD_GET_MCAST_FLAGS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -1550,7 +1556,7 @@ struct genl_family batadv_netlink_family __ro_after_init = {
.small_ops = batadv_netlink_ops,
.n_small_ops = ARRAY_SIZE(batadv_netlink_ops),
#if LINUX_VERSION_IS_GEQ(6, 1, 0) // UGLY_HACK_NEW
- .resv_start_op = BATADV_CMD_SET_VLAN + 1,
+ .resv_start_op = BATADV_CMD_GET_DAT_DHT + 1,
#endif // UGLY_HACK_STOP
.mcgrps = batadv_netlink_mcgrps,
.n_mcgrps = ARRAY_SIZE(batadv_netlink_mcgrps),
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 6442f5d0cc93..5cf26e8b3257 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -1046,6 +1046,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
struct batadv_orig_node *orig_node = NULL;
int hdr_size = sizeof(*unicast_packet);
enum batadv_subtype subtype;
+ bool is_dht_put = false;
int ret = NET_RX_DROP;
u8 *orig_addr_gw;
u8 *orig_addr;
@@ -1105,6 +1106,8 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
orig_addr = unicast_4addr_packet->src;
orig_node = batadv_orig_hash_find(bat_priv,
orig_addr);
+ } else if (subtype == BATADV_P_DAT_DHT_PUT) {
+ is_dht_put = true;
}
}
@@ -1112,7 +1115,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
hdr_size))
goto rx_success;
if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb,
- hdr_size))
+ hdr_size, is_dht_put))
goto rx_success;
batadv_dat_snoop_incoming_dhcp_ack(bat_priv, skb, hdr_size);
@@ -1353,7 +1356,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb, hdr_size))
goto rx_success;
- if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size))
+ if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size, false))
goto rx_success;
batadv_dat_snoop_incoming_dhcp_ack(bat_priv, skb, hdr_size);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index c19caa84e692..045727c3adc0 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1211,8 +1211,11 @@ struct batadv_priv_dat {
/** @addr: node DAT address */
batadv_dat_addr_t addr;
- /** @hash: hashtable representing the local ARP cache */
- struct batadv_hashtable *hash;
+ /** @cache_hash: hashtable representing the local ARP cache */
+ struct batadv_hashtable *cache_hash;
+
+ /** @dht_hash: hashtable representing the local DAT DHT */
+ struct batadv_hashtable *dht_hash;
/** @work: work queue callback item for cache purging */
struct delayed_work work;
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [batadv,v12 3/5] batman-adv: increase DAT DHT timeout
2026-10-03 7:26 [batadv,v12 0/5] batman-adv: increase DAT DHT timeout Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 1/5] batman-adv: move local ARP reply code to subfunctions Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 2/5] batman-adv: split DAT cache into DAT cache and DAT DHT Linus Lüssing
@ 2026-10-03 7:26 ` Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 4/5] batman-adv: avoid superfluous DAT DHT_PUT if self-candidate Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 5/5] batman-adv: avoid superfluous DAT DHT_PUT additions to local DAT Linus Lüssing
4 siblings, 0 replies; 7+ messages in thread
From: Linus Lüssing @ 2026-10-03 7:26 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
Currently, the DHT_GET messages of the DAT will likely be left
unanswered due to the following issues:
When a node has a matching DAT Cache entry for a local ARP Request then
this node will answer it directly with the information provided by the
cache. This however, will likely lead to missing ARP Replies from the
original host. Which in turn leads to the DAT DHT not being updated.
Then the local DAT cache entry will time out, triggering a unicasted
DHT_GET. However, as the 5min. timeout has passed, the DAT DHT
candidates will likely have purged their entry, too.
So basically this results in an ARP Request broadcast fallback every
five minutes.
A second issue is that it is quite common that a host which has long
gone offline will be tried to be contacted by another one at some remote
period larger than the current 5min. timeout. This too leads to flooded
ARP Requests.
With this patch the purge timeout for DAT DHT entries is increased to
30min to reduce the number of DAT ARP broadcast fallbacks.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
net/batman-adv/distributed-arp-table.c | 22 +++++++++++++++++-----
net/batman-adv/main.h | 3 ++-
2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index af08812c7ecd..321df338fb8d 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -199,15 +199,27 @@ static void batadv_dat_entry_put(struct batadv_dat_entry *dat_entry)
}
/**
- * batadv_dat_to_purge() - check whether a dat_entry has to be purged or not
+ * batadv_dat_cache_to_purge() - check if a cache entry has to be purged or not
* @dat_entry: the entry to check
*
* Return: true if the entry has to be purged now, false otherwise.
*/
-static bool batadv_dat_to_purge(struct batadv_dat_entry *dat_entry)
+static bool batadv_dat_cache_to_purge(struct batadv_dat_entry *dat_entry)
{
return batadv_has_timed_out(dat_entry->last_update,
- BATADV_DAT_ENTRY_TIMEOUT);
+ BATADV_DAT_CACHE_ENTRY_TIMEOUT);
+}
+
+/**
+ * batadv_dat_dht_to_purge() - check if a DHT entry has to be purged or not
+ * @dat_entry: the entry to check
+ *
+ * Return: true if the entry has to be purged now, false otherwise.
+ */
+static bool batadv_dat_dht_to_purge(struct batadv_dat_entry *dat_entry)
+{
+ return batadv_has_timed_out(dat_entry->last_update,
+ BATADV_DAT_DHT_ENTRY_TIMEOUT);
}
/**
@@ -268,8 +280,8 @@ static void batadv_dat_purge(struct work_struct *work)
priv_dat = container_of(delayed_work, struct batadv_priv_dat, work);
bat_priv = container_of(priv_dat, struct batadv_priv, dat);
- __batadv_dat_purge(bat_priv->dat.cache_hash, batadv_dat_to_purge);
- __batadv_dat_purge(bat_priv->dat.dht_hash, batadv_dat_to_purge);
+ __batadv_dat_purge(bat_priv->dat.cache_hash, batadv_dat_cache_to_purge);
+ __batadv_dat_purge(bat_priv->dat.dht_hash, batadv_dat_dht_to_purge);
batadv_dat_start_timer(bat_priv);
}
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index e738758ee4a7..17af6322e157 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -36,7 +36,8 @@
#define BATADV_TT_WORK_PERIOD 5000 /* 5 seconds */
#define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */
#define BATADV_MCAST_WORK_PERIOD 500 /* 0.5 seconds */
-#define BATADV_DAT_ENTRY_TIMEOUT (5 * 60000) /* 5 mins in milliseconds */
+#define BATADV_DAT_CACHE_ENTRY_TIMEOUT (5 * 60000) /* 5 mins in milliseconds */
+#define BATADV_DAT_DHT_ENTRY_TIMEOUT (30 * 60000) /* 30 mins in milliseconds */
/* sliding packet range of received originator messages in sequence numbers
* (should be a multiple of our word size)
*/
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [batadv,v12 4/5] batman-adv: avoid superfluous DAT DHT_PUT if self-candidate
2026-10-03 7:26 [batadv,v12 0/5] batman-adv: increase DAT DHT timeout Linus Lüssing
` (2 preceding siblings ...)
2026-10-03 7:26 ` [batadv,v12 3/5] batman-adv: increase DAT DHT timeout Linus Lüssing
@ 2026-10-03 7:26 ` Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 5/5] batman-adv: avoid superfluous DAT DHT_PUT additions to local DAT Linus Lüssing
4 siblings, 0 replies; 7+ messages in thread
From: Linus Lüssing @ 2026-10-03 7:26 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
If we are one of the three closest DAT DHT candidates for a given IPv4
address then three DHT_PUTs to three remote DAT DHT candidates, especially
the last selected DAT DHT candidate, is unnecessary: A DAT DHT_GET from
another node would typically not get to it anyway and would reach us
instead. Because the remote node will take us into account, while we so
far don't take ourself into account in batadv_choose_next_candidate().
Instead of reworking batadv_choose_next_candidate() to take ourself into
account, too, simply, potentially kick out the "worst" remote candidate
at the end of calculation if we are a better candidate. To avoid an
unnecessary DAT DHT_PUT / DHT_GET transmission.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
net/batman-adv/distributed-arp-table.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 321df338fb8d..52dff46a7c52 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -779,6 +779,9 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
* Check if we are a better candidate than the last placed, selected DHT
* candidate for the given IP address key.
*
+ * If we are a better candidate then deselects the last placed, selected
+ * DHT candidate.
+ *
* Return: true if we are a better candidate, false otherwise.
*/
static bool batadv_dat_cmp_self_candidate(struct batadv_priv *bat_priv,
@@ -822,6 +825,14 @@ static bool batadv_dat_cmp_self_candidate(struct batadv_priv *bat_priv,
memcmp(own_orig_addr, last_cand->orig_node->orig, ETH_ALEN) >= 0)
goto out;
+ /* deselect last placed, selected candidate, we take its spot */
+ batadv_dbg(BATADV_DBG_DAT, bat_priv,
+ "%s(): deselecting %pM for hash(IP)=%u\n",
+ __func__, last_cand->orig_node->orig, ip_key);
+
+ last_cand->type = BATADV_DAT_CANDIDATE_NOT_FOUND;
+ batadv_orig_node_put(last_cand->orig_node);
+
ret = true;
out:
if (ret)
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [batadv,v12 5/5] batman-adv: avoid superfluous DAT DHT_PUT additions to local DAT
2026-10-03 7:26 [batadv,v12 0/5] batman-adv: increase DAT DHT timeout Linus Lüssing
` (3 preceding siblings ...)
2026-10-03 7:26 ` [batadv,v12 4/5] batman-adv: avoid superfluous DAT DHT_PUT if self-candidate Linus Lüssing
@ 2026-10-03 7:26 ` Linus Lüssing
4 siblings, 0 replies; 7+ messages in thread
From: Linus Lüssing @ 2026-10-03 7:26 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
We send DHT_PUT ARP Replies to (typically) three DAT DHT candidates
for the sender MAC/IP pair and another three for the target MAC/IP
pair to likely different DAT DHT candidates. On the DHT_PUT
receiving side we would then add both the sender MAC/IP and target
MAC/IP to the local DHT, even if we are not actually a selected
DAT candidate for one of the pairs.
This way we typically unnecessarily populate our local DHT with
superfluous entries. Entries which no DAT DHT_GET will likely
ever query from us.
To avoid these unnecessary local DHT additions add a flag to DHT_PUT
messages to indicate which pair is supposed to be added to the local
DHT.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
include/uapi/linux/batadv_packet.h | 17 +++-
net/batman-adv/distributed-arp-table.c | 124 ++++++++++++++++++++++---
net/batman-adv/distributed-arp-table.h | 15 ++-
net/batman-adv/mesh-interface.c | 4 +
net/batman-adv/routing.c | 19 +++-
net/batman-adv/send.c | 8 +-
net/batman-adv/send.h | 3 +-
net/batman-adv/types.h | 24 +++++
8 files changed, 186 insertions(+), 28 deletions(-)
diff --git a/include/uapi/linux/batadv_packet.h b/include/uapi/linux/batadv_packet.h
index 32436560ecc8..6f4783887d37 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -70,6 +70,19 @@ enum batadv_subtype {
BATADV_P_DAT_CACHE_REPLY = 0x04,
};
+/**
+ * enum batadv_subtype_flags - unicast4addr packet subtype specific flags
+ * @BATADV_P_DAT_DHT_PUT_NO_SRC: do not add sender IP/MAC from DHT_PUT ARP Reply
+ * to local DHT
+ * @BATADV_P_DAT_DHT_PUT_NO_DST: do not add target IP/MAC from DHT_PUT ARP Reply
+ * to local DHT
+ */
+enum batadv_subtype_flags {
+ BATADV_P_DAT_DHT_PUT_NO_SRC = 0x01,
+ BATADV_P_DAT_DHT_PUT_NO_DST = 0x02,
+};
+
+
/* this file is included by batctl which needs these defines */
#define BATADV_COMPAT_VERSION 15
@@ -433,13 +446,13 @@ struct batadv_unicast_packet {
* @u: common unicast packet header
* @src: address of the source
* @subtype: packet subtype
- * @reserved: reserved byte for alignment
+ * @flags: packet subtype specific flags
*/
struct batadv_unicast_4addr_packet {
struct batadv_unicast_packet u;
__u8 src[ETH_ALEN];
__u8 subtype;
- __u8 reserved;
+ __u8 flags;
/* "4 bytes boundary + 2 bytes" long to make the payload after the
* following ethernet header again 4 bytes boundary aligned
*/
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 52dff46a7c52..739269a3b9d8 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -160,6 +160,9 @@ struct batadv_dhcp_option_header {
#define BATADV_DHCP_CHADDR_LEN sizeof(((struct batadv_dhcp_packet *)0)->chaddr)
static void batadv_dat_purge(struct work_struct *work);
+static bool
+batadv_dat_dht_check_self_is_candidate(struct batadv_priv *bat_priv,
+ __be32 ip, unsigned short vid);
/**
* batadv_dat_start_timer() - initialise the DAT periodic worker
@@ -562,6 +565,20 @@ static inline void
batadv_dat_dht_entry_add(struct batadv_priv *bat_priv, __be32 ip,
u8 *mac_addr, unsigned short vid)
{
+ /* Happens if a new node just beat us as a candidate, an old node
+ * does not have the more specific candidate selection enhancements yet
+ * or if future protocol enhancements, which this node does not have
+ * yet, added new/other candidate selections. For compatibility reasons
+ * do not bail out here.
+ */
+ if (!batadv_dat_dht_check_self_is_candidate(bat_priv, ip, vid)) {
+ batadv_inc_counter(bat_priv,
+ BATADV_CNT_DAT_DHT_ADD_NOT_CANDIDATE);
+ batadv_dbg(BATADV_DBG_DAT, bat_priv,
+ "Adding %pI4 %pM (vid: %d), although we are not a candidate\n",
+ &ip, mac_addr, batadv_print_vid(vid));
+ }
+
batadv_dat_entry_add(bat_priv, bat_priv->dat.dht_hash, ip, mac_addr,
vid, "dht");
}
@@ -1050,6 +1067,7 @@ batadv_dat_dht_get_self_reply(struct batadv_priv *bat_priv, __be32 ip_src,
* @ip: the DHT key
* @vid: VLAN identifier
* @packet_subtype: unicast4addr packet subtype to use
+ * @flags: packet subtype specific flags to set
*
* This function copies the skb with pskb_copy() and is sent as a unicast packet
* to each of the selected candidates.
@@ -1060,7 +1078,8 @@ batadv_dat_dht_get_self_reply(struct batadv_priv *bat_priv, __be32 ip_src,
static bool batadv_dat_forward_data(struct batadv_priv *bat_priv,
struct batadv_dat_candidate *cands,
struct sk_buff *skb, __be32 ip,
- unsigned short vid, int packet_subtype)
+ unsigned short vid, int packet_subtype,
+ int flags)
{
struct batadv_neigh_node *neigh_node = NULL;
struct sk_buff *tmp_skb;
@@ -1085,7 +1104,8 @@ static bool batadv_dat_forward_data(struct batadv_priv *bat_priv,
if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, tmp_skb,
cands[i].orig_node,
- packet_subtype)) {
+ packet_subtype,
+ flags)) {
kfree_skb(tmp_skb);
goto free_neigh;
}
@@ -1135,6 +1155,31 @@ static void batadv_dat_candidates_free(struct batadv_dat_candidate *cands)
kfree(cands);
}
+/**
+ * batadv_dat_dht_check_self_is_candidate() - check if we are a DHT candidate
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @ip: key to look up in the DHT
+ * @vid: VLAN identifier
+ *
+ * Check if we are a selected candidate for the given IP address key.
+ *
+ * Return: true if we are a selected candidate for the given @ip, false
+ * otherwise.
+ */
+static bool
+batadv_dat_dht_check_self_is_candidate(struct batadv_priv *bat_priv,
+ __be32 ip, unsigned short vid)
+{
+ struct batadv_dat_candidate *cands;
+ bool self_is_candidate = false;
+
+ cands = batadv_dat_select_candidates(bat_priv, ip, vid,
+ &self_is_candidate);
+ batadv_dat_candidates_free(cands);
+
+ return self_is_candidate;
+}
+
/**
* batadv_dat_forward_dht_put() - send payload via DHT_PUT to DAT candidates
* @bat_priv: the bat priv with all the mesh interface information
@@ -1142,6 +1187,7 @@ static void batadv_dat_candidates_free(struct batadv_dat_candidate *cands)
* @ip: the DHT key
* @hw_addr: the MAC address which the IP resolves to
* @vid: VLAN identifier
+ * @flags: packet subtype specific flags to set
*
* Send the given payload via a DAT DHT_PUT message to the selected
* candidates.
@@ -1151,7 +1197,8 @@ static void batadv_dat_candidates_free(struct batadv_dat_candidate *cands)
*/
static bool
batadv_dat_forward_dht_put(struct batadv_priv *bat_priv, struct sk_buff *skb,
- __be32 ip, u8 *hw_addr, unsigned short vid)
+ __be32 ip, u8 *hw_addr, unsigned short vid,
+ int flags)
{
struct batadv_dat_candidate *cands;
bool self_is_candidate = false;
@@ -1166,12 +1213,56 @@ batadv_dat_forward_dht_put(struct batadv_priv *bat_priv, struct sk_buff *skb,
batadv_dat_dht_entry_add(bat_priv, ip, hw_addr, vid);
ret = batadv_dat_forward_data(bat_priv, cands, skb, ip, vid,
- BATADV_P_DAT_DHT_PUT);
+ BATADV_P_DAT_DHT_PUT, flags);
batadv_dat_candidates_free(cands);
return ret;
}
+/**
+ * batadv_dat_forward_dht_put_src() - send source-specific DHT_PUTs
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @skb: payload to send
+ * @ip_src: the DHT key
+ * @hw_src: the MAC address which the IP resolves to
+ * @vid: VLAN identifier
+ *
+ * Send the given payload via a DAT DHT_PUT message to the selected
+ * candidates, with the PUT_NO_DST flag set.
+ *
+ * Return: true if the packet is sent to at least one candidate, false
+ * otherwise.
+ */
+static bool
+batadv_dat_forward_dht_put_src(struct batadv_priv *bat_priv, struct sk_buff *skb,
+ __be32 ip_src, u8 *hw_src, unsigned short vid)
+{
+ return batadv_dat_forward_dht_put(bat_priv, skb, ip_src, hw_src, vid,
+ BATADV_P_DAT_DHT_PUT_NO_DST);
+}
+
+/**
+ * batadv_dat_forward_dht_put_dst() - send destination-specific DHT_PUTs
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @skb: payload to send
+ * @ip_dst: the DHT key
+ * @hw_dst: the MAC address which the IP resolves to
+ * @vid: VLAN identifier
+ *
+ * Send the given payload via a DAT DHT_PUT message to the selected
+ * candidates, with the PUT_NO_SRC flag set.
+ *
+ * Return: true if the packet is sent to at least one candidate, false
+ * otherwise.
+ */
+static bool
+batadv_dat_forward_dht_put_dst(struct batadv_priv *bat_priv, struct sk_buff *skb,
+ __be32 ip_dst, u8 *hw_dst, unsigned short vid)
+{
+ return batadv_dat_forward_dht_put(bat_priv, skb, ip_dst, hw_dst, vid,
+ BATADV_P_DAT_DHT_PUT_NO_SRC);
+}
+
/**
* batadv_dat_forward_dht_get() - send payload via DHT_GET to DAT candidates
* @bat_priv: the bat priv with all the mesh interface information
@@ -1211,7 +1302,7 @@ batadv_dat_forward_dht_get(struct batadv_priv *bat_priv, struct sk_buff *skb,
}
ret = batadv_dat_forward_data(bat_priv, cands, skb, ip_dst, vid,
- BATADV_P_DAT_DHT_GET);
+ BATADV_P_DAT_DHT_GET, 0);
skip_remote_forward:
batadv_dat_candidates_free(cands);
@@ -1870,8 +1961,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
/* Send the ARP reply to the candidates for both the IP addresses that
* the node obtained from the ARP reply
*/
- batadv_dat_forward_dht_put(bat_priv, skb, ip_src, hw_src, vid);
- batadv_dat_forward_dht_put(bat_priv, skb, ip_dst, hw_dst, vid);
+ batadv_dat_forward_dht_put_src(bat_priv, skb, ip_src, hw_src, vid);
+ batadv_dat_forward_dht_put_dst(bat_priv, skb, ip_dst, hw_dst, vid);
}
/**
@@ -1880,8 +1971,12 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
* @bat_priv: the bat priv with all the mesh interface information
* @skb: packet to check
* @hdr_size: size of the encapsulation header
- * @is_dht_put: ARP reply is part of a unicast 4addr DHT PUT packet and should
- * not only update our local DAT cache but also our local DAT DHT
+ * @is_dht_put_src: ARP reply is part of a source-specific unicast 4addr DHT PUT
+ * packet and should not only update our local DAT cache but also our local
+ * DAT DHT
+ * @is_dht_put_dst: ARP reply is part of a destination-specific unicast 4addr
+ * DHT PUT packet and should not only update our local DAT cache but also our
+ * local DAT DHT
*
* Warning: This function may reallocate the skb data buffer via
* batadv_dat_get_vid()/... Any pointer into the skb data (e.g. obtained
@@ -1893,7 +1988,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
*/
bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size,
- bool is_dht_put)
+ bool is_dht_put_src,
+ bool is_dht_put_dst)
{
struct batadv_dat_entry *dat_entry = NULL;
u8 mac[ETH_ALEN] __aligned(2);
@@ -1926,10 +2022,10 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
hw_dst = batadv_arp_hw_dst(skb, hdr_size);
ip_dst = batadv_arp_ip_dst(skb, hdr_size);
- if (is_dht_put) {
+ if (is_dht_put_src)
batadv_dat_dht_entry_add(bat_priv, ip_src, hw_src, vid);
+ if (is_dht_put_dst)
batadv_dat_dht_entry_add(bat_priv, ip_dst, hw_dst, vid);
- }
/* If ip_dst is already in cache and has the right mac address,
* drop this frame if this ARP reply is destined for us because it's
@@ -2212,8 +2308,8 @@ static void batadv_dat_put_dhcp(struct batadv_priv *bat_priv, u8 *chaddr,
batadv_dat_cache_entry_add(bat_priv, yiaddr, chaddr, vid);
batadv_dat_cache_entry_add(bat_priv, ip_dst, hw_dst, vid);
- batadv_dat_forward_dht_put(bat_priv, skb, yiaddr, chaddr, vid);
- batadv_dat_forward_dht_put(bat_priv, skb, ip_dst, hw_dst, vid);
+ batadv_dat_forward_dht_put_src(bat_priv, skb, yiaddr, chaddr, vid);
+ batadv_dat_forward_dht_put_dst(bat_priv, skb, ip_dst, hw_dst, vid);
consume_skb(skb);
diff --git a/net/batman-adv/distributed-arp-table.h b/net/batman-adv/distributed-arp-table.h
index ad81b7db921e..d955fcb27ae0 100644
--- a/net/batman-adv/distributed-arp-table.h
+++ b/net/batman-adv/distributed-arp-table.h
@@ -32,7 +32,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb);
bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size,
- bool is_dht_put);
+ bool is_dht_put_src,
+ bool is_dht_put_dst);
void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv,
struct sk_buff *skb,
__be16 proto,
@@ -81,11 +82,12 @@ int batadv_dat_dht_dump(struct sk_buff *msg, struct netlink_callback *cb);
* batadv_dat_inc_counter() - increment the correct DAT packet counter
* @bat_priv: the bat priv with all the mesh interface information
* @subtype: the 4addr subtype of the packet to be counted
+ * @flags: packet subtype specific flags
*
* Updates the ethtool statistics for the received packet if it is a DAT subtype
*/
static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv,
- u8 subtype)
+ u8 subtype, u8 flags)
{
switch (subtype) {
case BATADV_P_DAT_DHT_GET:
@@ -95,6 +97,13 @@ static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv,
case BATADV_P_DAT_DHT_PUT:
batadv_inc_counter(bat_priv,
BATADV_CNT_DAT_PUT_RX);
+ if (!flags)
+ batadv_inc_counter(bat_priv,
+ BATADV_CNT_DAT_PUT_NOFLAGS_RX);
+ if (!(flags & BATADV_P_DAT_DHT_PUT_NO_SRC))
+ batadv_inc_counter(bat_priv, BATADV_CNT_DAT_PUT_SRC_RX);
+ if (!(flags & BATADV_P_DAT_DHT_PUT_NO_DST))
+ batadv_inc_counter(bat_priv, BATADV_CNT_DAT_PUT_DST_RX);
break;
}
}
@@ -129,7 +138,7 @@ batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
static inline bool
batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size,
- bool is_dht_put)
+ bool is_dht_put_src, bool is_dht_put_dst)
{
return false;
}
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 41d148634034..bdf9c21b0da2 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -1005,7 +1005,11 @@ static const struct {
{ "dat_get_rx" },
{ "dat_put_tx" },
{ "dat_put_rx" },
+ { "dat_put_src_rx" },
+ { "dat_put_dst_rx" },
+ { "dat_put_noflags_rx" },
{ "dat_cached_reply_tx" },
+ { "dat_dht_add_not_candidate" },
#endif
};
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 5cf26e8b3257..8dd4094d134b 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -1045,8 +1045,10 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
struct batadv_orig_node *orig_node_gw = NULL;
struct batadv_orig_node *orig_node = NULL;
int hdr_size = sizeof(*unicast_packet);
+ enum batadv_subtype_flags flags;
enum batadv_subtype subtype;
- bool is_dht_put = false;
+ bool is_dht_put_src = false;
+ bool is_dht_put_dst = false;
int ret = NET_RX_DROP;
u8 *orig_addr_gw;
u8 *orig_addr;
@@ -1094,7 +1096,8 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
unicast_4addr_packet =
(struct batadv_unicast_4addr_packet *)skb->data;
subtype = unicast_4addr_packet->subtype;
- batadv_dat_inc_counter(bat_priv, subtype);
+ flags = unicast_4addr_packet->flags;
+ batadv_dat_inc_counter(bat_priv, subtype, flags);
/* Only payload data should be considered for speedy
* join. For example, DAT also uses unicast 4addr
@@ -1107,7 +1110,10 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
orig_node = batadv_orig_hash_find(bat_priv,
orig_addr);
} else if (subtype == BATADV_P_DAT_DHT_PUT) {
- is_dht_put = true;
+ if (!(flags & BATADV_P_DAT_DHT_PUT_NO_SRC))
+ is_dht_put_src = true;
+ if (!(flags & BATADV_P_DAT_DHT_PUT_NO_DST))
+ is_dht_put_dst = true;
}
}
@@ -1115,7 +1121,9 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
hdr_size))
goto rx_success;
if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb,
- hdr_size, is_dht_put))
+ hdr_size,
+ is_dht_put_src,
+ is_dht_put_dst))
goto rx_success;
batadv_dat_snoop_incoming_dhcp_ack(bat_priv, skb, hdr_size);
@@ -1356,7 +1364,8 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb, hdr_size))
goto rx_success;
- if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size, false))
+ if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size, false,
+ false))
goto rx_success;
batadv_dat_snoop_incoming_dhcp_ack(bat_priv, skb, hdr_size);
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 929b6dd34c10..e6ebe311f79d 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -263,13 +263,15 @@ static bool batadv_send_skb_prepare_unicast(struct sk_buff *skb,
* @skb: the skb containing the payload to encapsulate
* @orig: the destination node
* @packet_subtype: the unicast 4addr packet subtype to use
+ * @flags: packet subtype specific flags to set
*
* Return: false if the payload could not be encapsulated or true otherwise.
*/
bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig,
- int packet_subtype)
+ int packet_subtype,
+ int flags)
{
struct batadv_unicast_4addr_packet *uc_4addr_packet;
struct batadv_hard_iface *primary_if;
@@ -291,7 +293,7 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
uc_4addr_packet->u.packet_type = BATADV_UNICAST_4ADDR;
ether_addr_copy(uc_4addr_packet->src, primary_if->net_dev->dev_addr);
uc_4addr_packet->subtype = packet_subtype;
- uc_4addr_packet->reserved = 0;
+ uc_4addr_packet->flags = flags;
ret = true;
out:
@@ -337,7 +339,7 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
case BATADV_UNICAST_4ADDR:
if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb,
orig_node,
- packet_subtype))
+ packet_subtype, 0))
goto out;
break;
default:
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index 3415afec4a0c..7481c4fa0681 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -53,7 +53,8 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig_node,
- int packet_subtype);
+ int packet_subtype,
+ int flags);
int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype,
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 045727c3adc0..68b753bb32f6 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -975,11 +975,35 @@ enum batadv_counters {
/** @BATADV_CNT_DAT_PUT_RX: received dht PUT traffic packet counter */
BATADV_CNT_DAT_PUT_RX,
+ /**
+ * @BATADV_CNT_DAT_PUT_SRC_RX: received source-specfic dht PUT traffic
+ * packet counter
+ */
+ BATADV_CNT_DAT_PUT_SRC_RX,
+
+ /**
+ * @BATADV_CNT_DAT_PUT_DST_RX: received destination-specfic dht PUT
+ * traffic packet counter
+ */
+ BATADV_CNT_DAT_PUT_DST_RX,
+
+ /**
+ * @BATADV_CNT_DAT_PUT_NOFLAGS_RX: received unspecific/unflagged dht PUT
+ * traffic packet counter
+ */
+ BATADV_CNT_DAT_PUT_NOFLAGS_RX,
+
/**
* @BATADV_CNT_DAT_CACHED_REPLY_TX: transmitted dat cache reply traffic
* packet counter
*/
BATADV_CNT_DAT_CACHED_REPLY_TX,
+
+ /**
+ * @BATADV_CNT_DAT_DHT_ADD_NOT_CANDIDATE: counter for local DHT
+ * additions without (supposedly) being a selected candidate
+ */
+ BATADV_CNT_DAT_DHT_ADD_NOT_CANDIDATE,
#endif
/** @BATADV_CNT_NUM: number of traffic counters */
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [batadv,v12 2/5] batman-adv: split DAT cache into DAT cache and DAT DHT
2026-10-03 7:26 ` [batadv,v12 2/5] batman-adv: split DAT cache into DAT cache and DAT DHT Linus Lüssing
@ 2026-10-03 8:04 ` Sven Eckelmann
0 siblings, 0 replies; 7+ messages in thread
From: Sven Eckelmann @ 2026-10-03 8:04 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
[-- Attachment #1: Type: text/plain, Size: 2183 bytes --]
On Saturday, 3 October 2026 09:26:25 CEST Linus Lüssing wrote:
> #if LINUX_VERSION_IS_GEQ(6, 1, 0) // UGLY_HACK_NEW
> - .resv_start_op = BATADV_CMD_SET_VLAN + 1,
> + .resv_start_op = BATADV_CMD_GET_DAT_DHT + 1,
> #endif // UGLY_HACK_STOP
No, this field is never to be changed for new commands.
* @resv_start_op: first operation for which reserved fields of the header
* can be validated and policies are required (see below);
* new families should leave this field at zero
[...]
* Attribute policies (the combination of @policy and @maxattr fields)
* can be attached at the family level or at the operation level.
* If both are present the per-operation policy takes precedence.
* For operations before @resv_start_op lack of policy means that the core
* will perform no attribute parsing or validation. For newer operations
* if policy is not provided core will reject all TLV attributes.
You should make sure that your new op has an appropriate policy and the client
does the right thing. The former is already the case because the family policy
is inherited.
See
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9c5d03d362519f36cd551aec596388f895c93d2d
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4fa86555d1cd338afc6e6308cc1ff890a014ec8c
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ce48ebdd56513fa5ad9dab683a96399e00dbf464
> @@ -1498,6 +1498,12 @@ static const struct genl_small_ops batadv_netlink_ops[] = {
> .flags = GENL_UNS_ADMIN_PERM,
> .dumpit = batadv_dat_cache_dump,
> },
> + {
> + .cmd = BATADV_CMD_GET_DAT_DHT,
> + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
> + .flags = GENL_UNS_ADMIN_PERM,
> + .dumpit = batadv_dat_dht_dump,
> + },
> {
> .cmd = BATADV_CMD_GET_MCAST_FLAGS,
> .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
>
Please keep it in the enum batadv_nl_commands order.
Regards,
Sven
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-03 8:04 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-03 7:26 [batadv,v12 0/5] batman-adv: increase DAT DHT timeout Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 1/5] batman-adv: move local ARP reply code to subfunctions Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 2/5] batman-adv: split DAT cache into DAT cache and DAT DHT Linus Lüssing
2026-10-03 8:04 ` Sven Eckelmann
2026-10-03 7:26 ` [batadv,v12 3/5] batman-adv: increase DAT DHT timeout Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 4/5] batman-adv: avoid superfluous DAT DHT_PUT if self-candidate Linus Lüssing
2026-10-03 7:26 ` [batadv,v12 5/5] batman-adv: avoid superfluous DAT DHT_PUT additions to local DAT Linus Lüssing
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox