* [PATCH v6 1/3] batman-adv: add dynamic, bridged-in TT VID detection support
2025-02-21 17:27 [PATCH v6 0/3] batman-adv: add dynamic, bridged-in TT VID detection Sven Eckelmann
@ 2025-02-21 17:27 ` Sven Eckelmann
2025-02-21 17:27 ` [PATCH v6 2/3] batman-adv: limit number of learned VLANs from bridged-in clients Sven Eckelmann
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Sven Eckelmann @ 2025-02-21 17:27 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
From: Linus Lüssing <linus.luessing@c0d3.blue>
So far, if we wanted to bridge VLAN tagged frames into the mesh one would
need to manually create an according VLAN interface on top of bat0
first, to trigger batman-adv to create the according structures
for a VID.
With this change the VLAN from bridged-in clients is now automatically
detected and added to the translation table on the fly.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
net/batman-adv/hard-interface.c | 2 +-
net/batman-adv/mesh-interface.c | 125 ++++++++++++++++++++-----------------
net/batman-adv/mesh-interface.h | 6 +-
net/batman-adv/multicast.c | 8 ++-
net/batman-adv/translation-table.c | 19 +++---
net/batman-adv/translation-table.h | 4 +-
6 files changed, 91 insertions(+), 73 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index f145f96626531053bbf8f58a31f28f625a9d80f9..e69091498f3f903b48c4ecdae040d714e29ef931 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -940,7 +940,7 @@ static int batadv_hard_if_event_meshif(unsigned long event,
switch (event) {
case NETDEV_REGISTER:
bat_priv = netdev_priv(net_dev);
- batadv_meshif_create_vlan(bat_priv, BATADV_NO_FLAGS);
+ batadv_meshif_create_vlan_own(bat_priv, BATADV_NO_FLAGS);
break;
}
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 6d3dc650a93f96aa5e2abd3b30a69e47a47607b0..1e3ffca3fcf03236fb2403d7c6696b6135fc72fc 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -141,6 +141,10 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
rcu_read_lock();
hlist_for_each_entry_rcu(vlan, &bat_priv->meshif_vlan_list, list) {
+ /* we don't use this VID ourself, avoid adding us to it */
+ if (!batadv_is_my_client(bat_priv, old_addr, vlan->vid))
+ continue;
+
batadv_tt_local_remove(bat_priv, old_addr, vlan->vid,
"mac address changed", false);
batadv_tt_local_add(dev, addr->sa_data, vlan->vid,
@@ -549,13 +553,15 @@ struct batadv_meshif_vlan *batadv_meshif_vlan_get(struct batadv_priv *bat_priv,
}
/**
- * batadv_meshif_create_vlan() - allocate the needed resources for a new vlan
+ * batadv_meshif_create_vlan() - create a meshif vlan struct
* @bat_priv: the bat priv with all the mesh interface information
* @vid: the VLAN identifier
*
- * Return: 0 on success, a negative error otherwise.
+ * Return: a pointer to the newly allocated meshif vlan struct on success, NULL
+ * otherwise.
*/
-int batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
+static struct batadv_meshif_vlan *
+batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
{
struct batadv_meshif_vlan *vlan;
@@ -563,55 +569,93 @@ int batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
vlan = batadv_meshif_vlan_get(bat_priv, vid);
if (vlan) {
- batadv_meshif_vlan_put(vlan);
spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
- return -EEXIST;
+ return vlan;
}
vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
if (!vlan) {
spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
- return -ENOMEM;
+ return NULL;
}
vlan->bat_priv = bat_priv;
vlan->vid = vid;
+ /* hold only one refcount, caller will store a reference to us in
+ * tt_local->vlan without releasing any refcount
+ */
kref_init(&vlan->refcount);
atomic_set(&vlan->ap_isolation, 0);
- kref_get(&vlan->refcount);
hlist_add_head_rcu(&vlan->list, &bat_priv->meshif_vlan_list);
spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
+ return vlan;
+}
+
+/**
+ * batadv_meshif_vlan_get_or_create() - retrieve or create a meshif vlan struct
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @vid: the VLAN identifier
+ *
+ * Return: the meshif vlan struct if found or created or NULL otherwise.
+ */
+struct batadv_meshif_vlan *
+batadv_meshif_vlan_get_or_create(struct batadv_priv *bat_priv,
+ unsigned short vid)
+{
+ struct batadv_meshif_vlan *vlan = batadv_meshif_vlan_get(bat_priv, vid);
+
+ if (vlan)
+ return vlan;
+
+ return batadv_meshif_create_vlan(bat_priv, vid);
+}
+
+/**
+ * batadv_meshif_create_vlan_own() - add our own meshif to the local TT
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @vid: the VLAN identifier
+ *
+ * Adds the MAC address of our own mesh interface with the given VLAN ID as
+ * a permanent local TT entry.
+ *
+ * Return: 0 on success, a negative error otherwise.
+ */
+int batadv_meshif_create_vlan_own(struct batadv_priv *bat_priv,
+ unsigned short vid)
+{
+ int ret;
+
/* add a new TT local entry. This one will be marked with the NOPURGE
* flag
*/
- batadv_tt_local_add(bat_priv->mesh_iface,
- bat_priv->mesh_iface->dev_addr, vid,
- BATADV_NULL_IFINDEX, BATADV_NO_MARK);
-
- /* don't return reference to new meshif_vlan */
- batadv_meshif_vlan_put(vlan);
+ ret = batadv_tt_local_add(bat_priv->mesh_iface,
+ bat_priv->mesh_iface->dev_addr, vid,
+ BATADV_NULL_IFINDEX, BATADV_NO_MARK);
+ if (ret < 0)
+ return ret;
return 0;
}
/**
- * batadv_meshif_destroy_vlan() - remove and destroy a meshif_vlan object
+ * batadv_meshif_destroy_vlan_own() - remove our own meshif from the local TT
* @bat_priv: the bat priv with all the mesh interface information
- * @vlan: the object to remove
+ * @vid: the VLAN identifier
+ *
+ * Removes the MAC address of our own mesh interface with the given VLAN ID from
+ * the local TT.
*/
-static void batadv_meshif_destroy_vlan(struct batadv_priv *bat_priv,
- struct batadv_meshif_vlan *vlan)
+static void batadv_meshif_destroy_vlan_own(struct batadv_priv *bat_priv,
+ unsigned short vid)
{
/* explicitly remove the associated TT local entry because it is marked
* with the NOPURGE flag
*/
- batadv_tt_local_remove(bat_priv, bat_priv->mesh_iface->dev_addr,
- vlan->vid, "vlan interface destroyed", false);
-
- batadv_meshif_vlan_put(vlan);
+ batadv_tt_local_remove(bat_priv, bat_priv->mesh_iface->dev_addr, vid,
+ "vlan interface destroyed", false);
}
/**
@@ -629,7 +673,6 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
unsigned short vid)
{
struct batadv_priv *bat_priv = netdev_priv(dev);
- struct batadv_meshif_vlan *vlan;
/* only 802.1Q vlans are supported.
* batman-adv does not know how to handle other types
@@ -647,25 +690,7 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
vid |= BATADV_VLAN_HAS_TAG;
- /* if a new vlan is getting created and it already exists, it means that
- * it was not deleted yet. batadv_meshif_vlan_get() increases the
- * refcount in order to revive the object.
- *
- * if it does not exist then create it.
- */
- vlan = batadv_meshif_vlan_get(bat_priv, vid);
- if (!vlan)
- return batadv_meshif_create_vlan(bat_priv, vid);
-
- /* add a new TT local entry. This one will be marked with the NOPURGE
- * flag. This must be added again, even if the vlan object already
- * exists, because the entry was deleted by kill_vid()
- */
- batadv_tt_local_add(bat_priv->mesh_iface,
- bat_priv->mesh_iface->dev_addr, vid,
- BATADV_NULL_IFINDEX, BATADV_NO_MARK);
-
- return 0;
+ return batadv_meshif_create_vlan_own(bat_priv, vid);
}
/**
@@ -684,7 +709,6 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
unsigned short vid)
{
struct batadv_priv *bat_priv = netdev_priv(dev);
- struct batadv_meshif_vlan *vlan;
/* only 802.1Q vlans are supported. batman-adv does not know how to
* handle other types
@@ -698,15 +722,7 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
if (vid == 0)
return 0;
- vlan = batadv_meshif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG);
- if (!vlan)
- return -ENOENT;
-
- batadv_meshif_destroy_vlan(bat_priv, vlan);
-
- /* finally free the vlan object */
- batadv_meshif_vlan_put(vlan);
-
+ batadv_meshif_destroy_vlan_own(bat_priv, vid | BATADV_VLAN_HAS_TAG);
return 0;
}
@@ -1119,7 +1135,6 @@ static void batadv_meshif_destroy_netlink(struct net_device *mesh_iface,
{
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
struct batadv_hard_iface *hard_iface;
- struct batadv_meshif_vlan *vlan;
list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->mesh_iface == mesh_iface)
@@ -1127,11 +1142,7 @@ static void batadv_meshif_destroy_netlink(struct net_device *mesh_iface,
}
/* destroy the "untagged" VLAN */
- vlan = batadv_meshif_vlan_get(bat_priv, BATADV_NO_FLAGS);
- if (vlan) {
- batadv_meshif_destroy_vlan(bat_priv, vlan);
- batadv_meshif_vlan_put(vlan);
- }
+ batadv_meshif_destroy_vlan_own(bat_priv, BATADV_NO_FLAGS);
unregister_netdevice_queue(mesh_iface, head);
}
diff --git a/net/batman-adv/mesh-interface.h b/net/batman-adv/mesh-interface.h
index 7ba055b2bc269d57719fa5cdd50888155cbd3d44..afa29e99df85f7fc60bdf2754f32febabaddb9b2 100644
--- a/net/batman-adv/mesh-interface.h
+++ b/net/batman-adv/mesh-interface.h
@@ -21,10 +21,14 @@ void batadv_interface_rx(struct net_device *mesh_iface,
struct batadv_orig_node *orig_node);
bool batadv_meshif_is_valid(const struct net_device *net_dev);
extern struct rtnl_link_ops batadv_link_ops;
-int batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
+int batadv_meshif_create_vlan_own(struct batadv_priv *bat_priv,
+ unsigned short vid);
void batadv_meshif_vlan_release(struct kref *ref);
struct batadv_meshif_vlan *batadv_meshif_vlan_get(struct batadv_priv *bat_priv,
unsigned short vid);
+struct batadv_meshif_vlan *
+batadv_meshif_vlan_get_or_create(struct batadv_priv *bat_priv,
+ unsigned short vid);
/**
* batadv_meshif_vlan_put() - decrease the vlan object refcounter and
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index f26892b362e299c7d13a784a845b781958de98c0..97665c3005c54591b205d0f429c98ce056260335 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -723,6 +723,7 @@ static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
{
struct batadv_hw_addr *mcast_entry;
struct hlist_node *tmp;
+ int ret;
if (!mcast_list)
return;
@@ -732,9 +733,10 @@ static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
&bat_priv->mcast.mla_list))
continue;
- if (!batadv_tt_local_add(bat_priv->mesh_iface,
- mcast_entry->addr, BATADV_NO_FLAGS,
- BATADV_NULL_IFINDEX, BATADV_NO_MARK))
+ ret = batadv_tt_local_add(bat_priv->mesh_iface,
+ mcast_entry->addr, BATADV_NO_FLAGS,
+ BATADV_NULL_IFINDEX, BATADV_NO_MARK);
+ if (ret <= 0)
continue;
hlist_del(&mcast_entry->list);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 23cb44185a5ceb2ad836ffa1e8446e8c3a41d02e..efbe7addc121a777393f71d3b07f152d5b039113 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -626,8 +626,8 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
*
* Return: true if the client was successfully added, false otherwise.
*/
-bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
- unsigned short vid, int ifindex, u32 mark)
+int batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
+ unsigned short vid, int ifindex, u32 mark)
{
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
struct batadv_tt_local_entry *tt_local;
@@ -639,10 +639,10 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
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;
u8 remote_flags;
u32 match_mark;
+ int ret = 0;
if (ifindex != BATADV_NULL_IFINDEX)
in_dev = dev_get_by_index(net, ifindex);
@@ -693,21 +693,22 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
net_ratelimited_function(batadv_info, mesh_iface,
"Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
table_size, packet_size_max, addr);
+ ret = -E2BIG;
goto out;
}
tt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC);
- if (!tt_local)
+ if (!tt_local) {
+ ret = -ENOMEM;
goto out;
+ }
/* increase the refcounter of the related vlan */
- vlan = batadv_meshif_vlan_get(bat_priv, vid);
+ vlan = batadv_meshif_vlan_get_or_create(bat_priv, vid);
if (!vlan) {
- net_ratelimited_function(batadv_info, mesh_iface,
- "adding TT local entry %pM to non-existent VLAN %d\n",
- addr, batadv_print_vid(vid));
kmem_cache_free(batadv_tl_cache, tt_local);
tt_local = NULL;
+ ret = -ENOMEM;
goto out;
}
@@ -804,7 +805,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK))
batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
- ret = true;
+ ret = 1;
out:
batadv_hardif_put(in_hardif);
dev_put(in_dev);
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h
index 618d9dbca5eac48c06f99922ce5902ecce500821..9a972c5a7a7559e8c4a89aac63cf7e24585c63b6 100644
--- a/net/batman-adv/translation-table.h
+++ b/net/batman-adv/translation-table.h
@@ -16,8 +16,8 @@
#include <linux/types.h>
int batadv_tt_init(struct batadv_priv *bat_priv);
-bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
- unsigned short vid, int ifindex, u32 mark);
+int batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
+ unsigned short vid, int ifindex, u32 mark);
u16 batadv_tt_local_remove(struct batadv_priv *bat_priv,
const u8 *addr, unsigned short vid,
const char *message, bool roaming);
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v6 2/3] batman-adv: limit number of learned VLANs from bridged-in clients
2025-02-21 17:27 [PATCH v6 0/3] batman-adv: add dynamic, bridged-in TT VID detection Sven Eckelmann
2025-02-21 17:27 ` [PATCH v6 1/3] batman-adv: add dynamic, bridged-in TT VID detection support Sven Eckelmann
@ 2025-02-21 17:27 ` Sven Eckelmann
2025-02-21 17:27 ` [PATCH v6 3/3] batman-adv: avoid adding bridge VLAN IDs through ndo_vlan_rx_add_vid() Sven Eckelmann
2025-05-09 14:17 ` [PATCH v6 0/3] batman-adv: add dynamic, bridged-in TT VID detection Linus Lüssing
3 siblings, 0 replies; 5+ messages in thread
From: Sven Eckelmann @ 2025-02-21 17:27 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
From: Linus Lüssing <linus.luessing@c0d3.blue>
Currently with batman-adv compatibility version 15 each added VLAN
increases the OGM protocol overhead of this node considerably. Therefore
adding a configurable knob to limit the number of learned, snooped VLANs
from traffic from bridged-in clients.
There are currently also still issues in the BLA code that would
temporarily break any broadcast transmissions with every newly learned
VLAN. Therefore setting the default limit for externally learned VLANs to
zero for now.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
include/uapi/linux/batman_adv.h | 6 ++++++
net/batman-adv/mesh-interface.c | 32 ++++++++++++++++++++++++++++----
net/batman-adv/mesh-interface.h | 4 ++--
net/batman-adv/netlink.c | 15 +++++++++++++++
net/batman-adv/translation-table.c | 3 ++-
net/batman-adv/types.h | 6 ++++++
6 files changed, 59 insertions(+), 7 deletions(-)
diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h
index 936bcac270b5e3b6fc10a0df64ee2f2925cef4bb..893140821c2a8e551c4ffee2a47144abb2069369 100644
--- a/include/uapi/linux/batman_adv.h
+++ b/include/uapi/linux/batman_adv.h
@@ -481,6 +481,12 @@ enum batadv_nl_attrs {
*/
BATADV_ATTR_MULTICAST_FANOUT,
+ /**
+ * @BATADV_ATTR_VLAN_DYN_MAX: defines the maximum number of allowed
+ * learned VLANs from bridged-in clients.
+ */
+ BATADV_ATTR_VLAN_DYN_MAX,
+
/* add attributes above here, update the policy in netlink.c */
/**
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 1e3ffca3fcf03236fb2403d7c6696b6135fc72fc..4a83e6b97afc801e6a1b3b7514a57f0996c68e7c 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -23,6 +23,7 @@
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/lockdep.h>
+#include <linux/net.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/percpu.h>
@@ -46,6 +47,7 @@
#include "distributed-arp-table.h"
#include "gateway_client.h"
#include "hard-interface.h"
+#include "log.h"
#include "multicast.h"
#include "network-coding.h"
#include "send.h"
@@ -556,13 +558,15 @@ struct batadv_meshif_vlan *batadv_meshif_vlan_get(struct batadv_priv *bat_priv,
* batadv_meshif_create_vlan() - create a meshif vlan struct
* @bat_priv: the bat priv with all the mesh interface information
* @vid: the VLAN identifier
+ * @own: VLAN was not detected via bridged in traffic
*
* Return: a pointer to the newly allocated meshif vlan struct on success, NULL
* otherwise.
*/
static struct batadv_meshif_vlan *
-batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
+batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid, bool own)
{
+ unsigned short vlan_dyn_max, vlan_dyn_count;
struct batadv_meshif_vlan *vlan;
spin_lock_bh(&bat_priv->meshif_vlan_list_lock);
@@ -573,6 +577,19 @@ batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
return vlan;
}
+ vlan_dyn_max = bat_priv->meshif_vlan_dyn_max;
+ vlan_dyn_count = bat_priv->meshif_vlan_dyn_count;
+
+ if (vid & BATADV_VLAN_HAS_TAG && !own &&
+ vlan_dyn_max <= vlan_dyn_count) {
+ spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
+
+ net_ratelimited_function(batadv_info, bat_priv->mesh_iface,
+ "not adding VLAN %d, already learned %hu VID(s)\n",
+ batadv_print_vid(vid), vlan_dyn_max);
+ return NULL;
+ }
+
vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
if (!vlan) {
spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
@@ -588,6 +605,9 @@ batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
atomic_set(&vlan->ap_isolation, 0);
+ if (vid & BATADV_VLAN_HAS_TAG && !own)
+ bat_priv->meshif_vlan_dyn_count++;
+
hlist_add_head_rcu(&vlan->list, &bat_priv->meshif_vlan_list);
spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
@@ -597,20 +617,22 @@ batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
/**
* batadv_meshif_vlan_get_or_create() - retrieve or create a meshif vlan struct
* @bat_priv: the bat priv with all the mesh interface information
+ * @addr: the mac address of the client to add
* @vid: the VLAN identifier
+ * @own: VLAN was not detected via bridged in traffic
*
* Return: the meshif vlan struct if found or created or NULL otherwise.
*/
struct batadv_meshif_vlan *
-batadv_meshif_vlan_get_or_create(struct batadv_priv *bat_priv,
- unsigned short vid)
+batadv_meshif_vlan_get_or_create(struct batadv_priv *bat_priv, const u8 *addr,
+ unsigned short vid, bool own)
{
struct batadv_meshif_vlan *vlan = batadv_meshif_vlan_get(bat_priv, vid);
if (vlan)
return vlan;
- return batadv_meshif_create_vlan(bat_priv, vid);
+ return batadv_meshif_create_vlan(bat_priv, vid, own);
}
/**
@@ -824,6 +846,8 @@ static int batadv_meshif_init_late(struct net_device *dev)
bat_priv->tt.last_changeset_len = 0;
bat_priv->isolation_mark = 0;
bat_priv->isolation_mark_mask = 0;
+ bat_priv->meshif_vlan_dyn_max = 0;
+ bat_priv->meshif_vlan_dyn_count = 0;
/* randomize initial seqno to avoid collision */
get_random_bytes(&random_seqno, sizeof(random_seqno));
diff --git a/net/batman-adv/mesh-interface.h b/net/batman-adv/mesh-interface.h
index afa29e99df85f7fc60bdf2754f32febabaddb9b2..48971400cacdf9485e48bd9be1657e1194c2292e 100644
--- a/net/batman-adv/mesh-interface.h
+++ b/net/batman-adv/mesh-interface.h
@@ -27,8 +27,8 @@ void batadv_meshif_vlan_release(struct kref *ref);
struct batadv_meshif_vlan *batadv_meshif_vlan_get(struct batadv_priv *bat_priv,
unsigned short vid);
struct batadv_meshif_vlan *
-batadv_meshif_vlan_get_or_create(struct batadv_priv *bat_priv,
- unsigned short vid);
+batadv_meshif_vlan_get_or_create(struct batadv_priv *bat_priv, const u8 *addr,
+ unsigned short vid, bool own);
/**
* batadv_meshif_vlan_put() - decrease the vlan object refcounter and
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 1836f64ce8aa247331b003f69c1212f8128baf33..aa63bf92a5d5d46801ff2ea0cc84e58c7d2b0775 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -129,6 +129,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = {
[BATADV_ATTR_MCAST_FLAGS] = { .type = NLA_U32 },
[BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NLA_U32 },
[BATADV_ATTR_VLANID] = { .type = NLA_U16 },
+ [BATADV_ATTR_VLAN_DYN_MAX] = { .type = NLA_U16 },
[BATADV_ATTR_AGGREGATED_OGMS_ENABLED] = { .type = NLA_U8 },
[BATADV_ATTR_AP_ISOLATION_ENABLED] = { .type = NLA_U8 },
[BATADV_ATTR_ISOLATION_MARK] = { .type = NLA_U32 },
@@ -356,6 +357,10 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg,
atomic_read(&bat_priv->orig_interval)))
goto nla_put_failure;
+ if (nla_put_u16(msg, BATADV_ATTR_VLAN_DYN_MAX,
+ bat_priv->meshif_vlan_dyn_max))
+ goto nla_put_failure;
+
batadv_hardif_put(primary_if);
genlmsg_end(msg, hdr);
@@ -610,6 +615,16 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info)
atomic_set(&bat_priv->orig_interval, orig_interval);
}
+ if (info->attrs[BATADV_ATTR_VLAN_DYN_MAX]) {
+ u16 vlan_dyn_max;
+
+ attr = info->attrs[BATADV_ATTR_VLAN_DYN_MAX];
+ vlan_dyn_max = nla_get_u16(attr);
+ vlan_dyn_max = min_t(u16, vlan_dyn_max, VLAN_N_VID);
+
+ bat_priv->meshif_vlan_dyn_max = vlan_dyn_max;
+ }
+
batadv_netlink_notify_mesh(bat_priv);
return 0;
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index efbe7addc121a777393f71d3b07f152d5b039113..75140cb1374d6a476e2e5a0d033423f137925a7c 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -629,6 +629,7 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
int batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
unsigned short vid, int ifindex, u32 mark)
{
+ bool own = (ifindex == BATADV_NULL_IFINDEX) ? true : false;
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
struct batadv_tt_local_entry *tt_local;
struct batadv_tt_global_entry *tt_global = NULL;
@@ -704,7 +705,7 @@ int batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
}
/* increase the refcounter of the related vlan */
- vlan = batadv_meshif_vlan_get_or_create(bat_priv, vid);
+ vlan = batadv_meshif_vlan_get_or_create(bat_priv, addr, vid, own);
if (!vlan) {
kmem_cache_free(batadv_tl_cache, tt_local);
tt_local = NULL;
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 0ca0fc072fc9c1bac810d2a166ee2942f8176720..5f2f467b74a86661a075a9fc71075c32d934f453 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1751,6 +1751,12 @@ struct batadv_priv {
/** @meshif_vlan_list_lock: lock protecting meshif_vlan_list */
spinlock_t meshif_vlan_list_lock;
+ /** @meshif_vlan_dyn_max: maximum number of allowed learned VLANs */
+ unsigned short meshif_vlan_dyn_max;
+
+ /** @meshif_vlan_dyn_count: current number of learned VLANs */
+ unsigned short meshif_vlan_dyn_count;
+
#ifdef CONFIG_BATMAN_ADV_BLA
/** @bla: bridge loop avoidance data */
struct batadv_priv_bla bla;
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v6 3/3] batman-adv: avoid adding bridge VLAN IDs through ndo_vlan_rx_add_vid()
2025-02-21 17:27 [PATCH v6 0/3] batman-adv: add dynamic, bridged-in TT VID detection Sven Eckelmann
2025-02-21 17:27 ` [PATCH v6 1/3] batman-adv: add dynamic, bridged-in TT VID detection support Sven Eckelmann
2025-02-21 17:27 ` [PATCH v6 2/3] batman-adv: limit number of learned VLANs from bridged-in clients Sven Eckelmann
@ 2025-02-21 17:27 ` Sven Eckelmann
2025-05-09 14:17 ` [PATCH v6 0/3] batman-adv: add dynamic, bridged-in TT VID detection Linus Lüssing
3 siblings, 0 replies; 5+ messages in thread
From: Sven Eckelmann @ 2025-02-21 17:27 UTC (permalink / raw)
To: b.a.t.m.a.n; +Cc: Linus Lüssing
From: Linus Lüssing <linus.luessing@c0d3.blue>
The Linux bridge by default adds the PVID of a port (default VID 1) and
by that triggers our ndo_vlan_rx_add_vid() handler. The PVID is
for ingress traffic from bat0 to the bridge and other bridge ports.
However this makes no statement about what is received or send on bat0
itself, bat0 might as well be an untagged access port, even with a PVID
configured. Therefore ignoring here when a bridge is involved.
Also, similarly a "bridge vlan add vid 42 dev bat0 untagged" would call
this handler with VID 42. Even though we wouldn't be interested in this
VLAN as its traffic would be untagged on our side.
The issue is that any extra VLAN currently increases our own
OGM protocol overhead quite a bit, so we want to avoid that
by only adding VLANs that we are sure someone will be using.
So only add VLANs through snooping of actual, VLAN tagged
traffic, not through kernel internal network events
if we have a bridge on top.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
---
net/batman-adv/mesh-interface.c | 47 +++++++++++++++++++++++++++++++++++++++++
net/batman-adv/mesh-interface.h | 1 +
net/batman-adv/multicast.c | 30 +++-----------------------
3 files changed, 51 insertions(+), 27 deletions(-)
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 4a83e6b97afc801e6a1b3b7514a57f0996c68e7c..f1ae8d1b8458b8597121b783697d39032eae2600 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -680,6 +680,31 @@ static void batadv_meshif_destroy_vlan_own(struct batadv_priv *bat_priv,
"vlan interface destroyed", false);
}
+/**
+ * batadv_meshif_get_bridge() - get the bridge on top of the meshif if it exists
+ * @mesh_iface: netdev struct of the mesh interface
+ *
+ * If the given mesh interface has a bridge on top then the refcount
+ * of the according net device is increased.
+ *
+ * Return: NULL if no such bridge exists. Otherwise the net device of the
+ * bridge.
+ */
+struct net_device *batadv_meshif_get_bridge(struct net_device *mesh_iface)
+{
+ struct net_device *upper = mesh_iface;
+
+ rcu_read_lock();
+ do {
+ upper = netdev_master_upper_dev_get_rcu(upper);
+ } while (upper && !netif_is_bridge_master(upper));
+
+ dev_hold(upper);
+ rcu_read_unlock();
+
+ return upper;
+}
+
/**
* batadv_interface_add_vid() - ndo_add_vid API implementation
* @dev: the netdev of the mesh interface
@@ -695,6 +720,7 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
unsigned short vid)
{
struct batadv_priv *bat_priv = netdev_priv(dev);
+ struct net_device *bridge;
/* only 802.1Q vlans are supported.
* batman-adv does not know how to handle other types
@@ -710,6 +736,20 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
if (vid == 0)
return 0;
+ /* The Linux bridge adds the PVID of a port (default VID 1) and
+ * triggers this handler. The PVID is for ingress traffic from
+ * bat0 to the bridge and other bridge ports. However this makes no
+ * statement about what is received or send on bat0 itself, bat0
+ * might as well be an untagged access port, even with a PVID
+ * configured. Therefore ignoring here when a bridge is involved.
+ * Instead learn VLANs on the fly from traffic.
+ */
+ bridge = batadv_meshif_get_bridge(dev);
+ if (bridge) {
+ dev_put(bridge);
+ return 0;
+ }
+
vid |= BATADV_VLAN_HAS_TAG;
return batadv_meshif_create_vlan_own(bat_priv, vid);
@@ -731,6 +771,7 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
unsigned short vid)
{
struct batadv_priv *bat_priv = netdev_priv(dev);
+ struct net_device *bridge;
/* only 802.1Q vlans are supported. batman-adv does not know how to
* handle other types
@@ -744,6 +785,12 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
if (vid == 0)
return 0;
+ bridge = batadv_meshif_get_bridge(dev);
+ if (bridge) {
+ dev_put(bridge);
+ return 0;
+ }
+
batadv_meshif_destroy_vlan_own(bat_priv, vid | BATADV_VLAN_HAS_TAG);
return 0;
}
diff --git a/net/batman-adv/mesh-interface.h b/net/batman-adv/mesh-interface.h
index 48971400cacdf9485e48bd9be1657e1194c2292e..290440b86484a52f313f6f6ca757d27cf44cf5e9 100644
--- a/net/batman-adv/mesh-interface.h
+++ b/net/batman-adv/mesh-interface.h
@@ -19,6 +19,7 @@ int batadv_skb_head_push(struct sk_buff *skb, unsigned int len);
void batadv_interface_rx(struct net_device *mesh_iface,
struct sk_buff *skb, int hdr_size,
struct batadv_orig_node *orig_node);
+struct net_device *batadv_meshif_get_bridge(struct net_device *mesh_iface);
bool batadv_meshif_is_valid(const struct net_device *net_dev);
extern struct rtnl_link_ops batadv_link_ops;
int batadv_meshif_create_vlan_own(struct batadv_priv *bat_priv,
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 97665c3005c54591b205d0f429c98ce056260335..17463c28c04491711239e4f917092415f182ba19 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -56,6 +56,7 @@
#include "log.h"
#include "netlink.h"
#include "send.h"
+#include "mesh-interface.h"
#include "translation-table.h"
#include "tvlv.h"
@@ -71,31 +72,6 @@ static void batadv_mcast_start_timer(struct batadv_priv *bat_priv)
msecs_to_jiffies(BATADV_MCAST_WORK_PERIOD));
}
-/**
- * batadv_mcast_get_bridge() - get the bridge on top of the meshif if it exists
- * @mesh_iface: netdev struct of the mesh interface
- *
- * If the given mesh interface has a bridge on top then the refcount
- * of the according net device is increased.
- *
- * Return: NULL if no such bridge exists. Otherwise the net device of the
- * bridge.
- */
-static struct net_device *batadv_mcast_get_bridge(struct net_device *mesh_iface)
-{
- struct net_device *upper = mesh_iface;
-
- rcu_read_lock();
- do {
- upper = netdev_master_upper_dev_get_rcu(upper);
- } while (upper && !netif_is_bridge_master(upper));
-
- dev_hold(upper);
- rcu_read_unlock();
-
- return upper;
-}
-
/**
* batadv_mcast_mla_rtr_flags_meshif_get_ipv4() - get mcast router flags from
* node for IPv4
@@ -288,7 +264,7 @@ batadv_mcast_mla_flags_get(struct batadv_priv *bat_priv)
struct batadv_mcast_mla_flags mla_flags;
struct net_device *bridge;
- bridge = batadv_mcast_get_bridge(dev);
+ bridge = batadv_meshif_get_bridge(dev);
memset(&mla_flags, 0, sizeof(mla_flags));
mla_flags.enabled = 1;
@@ -530,7 +506,7 @@ batadv_mcast_mla_meshif_get(struct net_device *dev,
struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{
- struct net_device *bridge = batadv_mcast_get_bridge(dev);
+ struct net_device *bridge = batadv_meshif_get_bridge(dev);
int ret4, ret6 = 0;
if (bridge)
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread