From: Linus Lüssing <linus.luess...@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.luess...@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