Re: Problem starting A.L.F.R.E.D on batman-adv?

2024-01-28 Thread Linus Lüssing
On Sun, Jan 28, 2024 at 10:29:00PM -, doug.faja...@gmail.com wrote:
> I cant seem to get A.L.F.R.E.D. to start:
> doug@dougwork:~/sdshome/alfred$ sudo alfred -b bat0
> Can't start server: interface missing

I think it's complaining because the "-i" parameter is missing.
Try using "alfread -i bat0" instead.

Regards, Linus


[PATCH net v2] bridge: mcast: fix disabled snooping after long uptime

2024-01-27 Thread Linus Lüssing
The original idea of the delay_time check was to not apply multicast
snooping too early when an MLD querier appears. And to instead wait at
least for MLD reports to arrive before switching from flooding to group
based, MLD snooped forwarding, to avoid temporary packet loss.

However in a batman-adv mesh network it was noticed that after 248 days of
uptime 32bit MIPS based devices would start to signal that they had
stopped applying multicast snooping due to missing queriers - even though
they were the elected querier and still sending MLD queries themselves.

While time_is_before_jiffies() generally is safe against jiffies
wrap-arounds, like the code comments in jiffies.h explain, it won't
be able to track a difference larger than ULONG_MAX/2. With a 32bit
large jiffies and one jiffies tick every 10ms (CONFIG_HZ=100) on these MIPS
devices running OpenWrt this would result in a difference larger than
ULONG_MAX/2 after 248 (= 2^32/100/60/60/24/2) days and
time_is_before_jiffies() would then start to return false instead of
true. Leading to multicast snooping not being applied to multicast
packets anymore.

Fix this issue by using a proper timer_list object which won't have this
ULONG_MAX/2 difference limitation.

Fixes: b00589af3b04 ("bridge: disable snooping if there is no querier")
Signed-off-by: Linus Lüssing 
---
Changelog v2:
* removed "inline" from br_multicast_query_delay_expired()

 net/bridge/br_multicast.c | 20 +++-
 net/bridge/br_private.h   |  4 ++--
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index d7d021af1029..2d7b73242958 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1762,6 +1762,10 @@ static void br_ip6_multicast_querier_expired(struct 
timer_list *t)
 }
 #endif
 
+static void br_multicast_query_delay_expired(struct timer_list *t)
+{
+}
+
 static void br_multicast_select_own_querier(struct net_bridge_mcast *brmctx,
struct br_ip *ip,
struct sk_buff *skb)
@@ -3198,7 +3202,7 @@ br_multicast_update_query_timer(struct net_bridge_mcast 
*brmctx,
unsigned long max_delay)
 {
if (!timer_pending(>timer))
-   query->delay_time = jiffies + max_delay;
+   mod_timer(>delay_timer, jiffies + max_delay);
 
mod_timer(>timer, jiffies + brmctx->multicast_querier_interval);
 }
@@ -4041,13 +4045,11 @@ void br_multicast_ctx_init(struct net_bridge *br,
brmctx->multicast_querier_interval = 255 * HZ;
brmctx->multicast_membership_interval = 260 * HZ;
 
-   brmctx->ip4_other_query.delay_time = 0;
brmctx->ip4_querier.port_ifidx = 0;
seqcount_spinlock_init(>ip4_querier.seq, >multicast_lock);
brmctx->multicast_igmp_version = 2;
 #if IS_ENABLED(CONFIG_IPV6)
brmctx->multicast_mld_version = 1;
-   brmctx->ip6_other_query.delay_time = 0;
brmctx->ip6_querier.port_ifidx = 0;
seqcount_spinlock_init(>ip6_querier.seq, >multicast_lock);
 #endif
@@ -4056,6 +4058,8 @@ void br_multicast_ctx_init(struct net_bridge *br,
br_ip4_multicast_local_router_expired, 0);
timer_setup(>ip4_other_query.timer,
br_ip4_multicast_querier_expired, 0);
+   timer_setup(>ip4_other_query.delay_timer,
+   br_multicast_query_delay_expired, 0);
timer_setup(>ip4_own_query.timer,
br_ip4_multicast_query_expired, 0);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -4063,6 +4067,8 @@ void br_multicast_ctx_init(struct net_bridge *br,
br_ip6_multicast_local_router_expired, 0);
timer_setup(>ip6_other_query.timer,
br_ip6_multicast_querier_expired, 0);
+   timer_setup(>ip6_other_query.delay_timer,
+   br_multicast_query_delay_expired, 0);
timer_setup(>ip6_own_query.timer,
br_ip6_multicast_query_expired, 0);
 #endif
@@ -4197,10 +4203,12 @@ static void __br_multicast_stop(struct net_bridge_mcast 
*brmctx)
 {
del_timer_sync(>ip4_mc_router_timer);
del_timer_sync(>ip4_other_query.timer);
+   del_timer_sync(>ip4_other_query.delay_timer);
del_timer_sync(>ip4_own_query.timer);
 #if IS_ENABLED(CONFIG_IPV6)
del_timer_sync(>ip6_mc_router_timer);
del_timer_sync(>ip6_other_query.timer);
+   del_timer_sync(>ip6_other_query.delay_timer);
del_timer_sync(>ip6_own_query.timer);
 #endif
 }
@@ -4643,13 +4651,15 @@ int br_multicast_set_querier(struct net_bridge_mcast 
*brmctx, unsigned long val)
max_delay = brmctx->multicast_query_response_interval;
 
if (!timer_pending(>ip4_other_query.timer))
-   brmctx->ip4_other_query.delay_time = 

[PATCH net] bridge: mcast: fix disabled snooping after long uptime

2024-01-26 Thread Linus Lüssing
The original idea of the delay_time check was to not apply multicast
snooping too early when an MLD querier appears. And to instead wait at
least for MLD reports to arrive before switching from flooding to group
based, MLD snooped forwarding, to avoid temporary packet loss.

However in a batman-adv mesh network it was noticed that after 248 days of
uptime 32bit MIPS based devices would start to signal that they had
stopped applying multicast snooping due to missing queriers - even though
they were the elected querier and still sending MLD queries themselves.

While time_is_before_jiffies() generally is safe against jiffies
wrap-arounds, like the code comments in jiffies.h explain, it won't
be able to track a difference larger than ULONG_MAX/2. With a 32bit
large jiffies and one jiffies tick every 10ms (CONFIG_HZ=100) on these MIPS
devices running OpenWrt this would result in a difference larger than
ULONG_MAX/2 after 248 (= 2^32/100/60/60/24/2) days and
time_is_before_jiffies() would then start to return false instead of
true. Leading to multicast snooping not being applied to multicast
packets anymore.

Fix this issue by using a proper timer_list object which won't have this
ULONG_MAX/2 difference limitation.

Fixes: b00589af3b04 ("bridge: disable snooping if there is no querier")
Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c | 20 +++-
 net/bridge/br_private.h   |  4 ++--
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index d7d021af1029..df14ee36ea20 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1762,6 +1762,10 @@ static void br_ip6_multicast_querier_expired(struct 
timer_list *t)
 }
 #endif
 
+static inline void br_multicast_query_delay_expired(struct timer_list *t)
+{
+}
+
 static void br_multicast_select_own_querier(struct net_bridge_mcast *brmctx,
struct br_ip *ip,
struct sk_buff *skb)
@@ -3198,7 +3202,7 @@ br_multicast_update_query_timer(struct net_bridge_mcast 
*brmctx,
unsigned long max_delay)
 {
if (!timer_pending(>timer))
-   query->delay_time = jiffies + max_delay;
+   mod_timer(>delay_timer, jiffies + max_delay);
 
mod_timer(>timer, jiffies + brmctx->multicast_querier_interval);
 }
@@ -4041,13 +4045,11 @@ void br_multicast_ctx_init(struct net_bridge *br,
brmctx->multicast_querier_interval = 255 * HZ;
brmctx->multicast_membership_interval = 260 * HZ;
 
-   brmctx->ip4_other_query.delay_time = 0;
brmctx->ip4_querier.port_ifidx = 0;
seqcount_spinlock_init(>ip4_querier.seq, >multicast_lock);
brmctx->multicast_igmp_version = 2;
 #if IS_ENABLED(CONFIG_IPV6)
brmctx->multicast_mld_version = 1;
-   brmctx->ip6_other_query.delay_time = 0;
brmctx->ip6_querier.port_ifidx = 0;
seqcount_spinlock_init(>ip6_querier.seq, >multicast_lock);
 #endif
@@ -4056,6 +4058,8 @@ void br_multicast_ctx_init(struct net_bridge *br,
br_ip4_multicast_local_router_expired, 0);
timer_setup(>ip4_other_query.timer,
br_ip4_multicast_querier_expired, 0);
+   timer_setup(>ip4_other_query.delay_timer,
+   br_multicast_query_delay_expired, 0);
timer_setup(>ip4_own_query.timer,
br_ip4_multicast_query_expired, 0);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -4063,6 +4067,8 @@ void br_multicast_ctx_init(struct net_bridge *br,
br_ip6_multicast_local_router_expired, 0);
timer_setup(>ip6_other_query.timer,
br_ip6_multicast_querier_expired, 0);
+   timer_setup(>ip6_other_query.delay_timer,
+   br_multicast_query_delay_expired, 0);
timer_setup(>ip6_own_query.timer,
br_ip6_multicast_query_expired, 0);
 #endif
@@ -4197,10 +4203,12 @@ static void __br_multicast_stop(struct net_bridge_mcast 
*brmctx)
 {
del_timer_sync(>ip4_mc_router_timer);
del_timer_sync(>ip4_other_query.timer);
+   del_timer_sync(>ip4_other_query.delay_timer);
del_timer_sync(>ip4_own_query.timer);
 #if IS_ENABLED(CONFIG_IPV6)
del_timer_sync(>ip6_mc_router_timer);
del_timer_sync(>ip6_other_query.timer);
+   del_timer_sync(>ip6_other_query.delay_timer);
del_timer_sync(>ip6_own_query.timer);
 #endif
 }
@@ -4643,13 +4651,15 @@ int br_multicast_set_querier(struct net_bridge_mcast 
*brmctx, unsigned long val)
max_delay = brmctx->multicast_query_response_interval;
 
if (!timer_pending(>ip4_other_query.timer))
-   brmctx->ip4_other_query.delay_time = jiffies + max_delay;
+   mod_timer(>ip4_other_query.delay_timer,
+   

[PATCH] batman-adv: mcast: fix memory leak on deleting a batman-adv interface

2024-01-16 Thread Linus Lüssing
The batman-adv multicast tracker TVLV handler is registered for the
new batman-adv multicast packet type upon creating a batman-adv interface,
but not unregistered again upon the interface's deletion, leading to a
memory leak.

Fix this memory leak by calling the according TVLV handler unregister
routine for the multicast tracker TVLV upon batman-adv interface
deletion.

Fixes: 8ed36122d709 ("batman-adv: mcast: implement multicast packet reception 
and forwarding")
Reported-by: syzbot+ebe64cc5950868e77...@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/beadc4060f0cb...@google.com/
Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index c8620905c2dc..38fab5e46ae2 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -2183,6 +2183,7 @@ void batadv_mcast_free(struct batadv_priv *bat_priv)
cancel_delayed_work_sync(_priv->mcast.work);
 
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
+   batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST_TRACKER, 1);
batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
 
/* safely calling outside of worker, as worker was canceled above */
-- 
2.43.0



[PATCH] batman-adv: mcast: fix mcast packet type counter on timeouted nodes

2024-01-09 Thread Linus Lüssing
When a node which does not have the new batman-adv multicast packet type
capability vanishes then the according, global counter erroneously would
not be reduced in response on other nodes. Which in turn leads to the mesh
never switching back to sending with the new multicast packet type.

Fix this by reducing the according counter when such a node times out.

Fixes: be9b0169c840 ("batman-adv: mcast: implement multicast packet generation")
Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 2981a2ed40cb..c8620905c2dc 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -2206,6 +2206,8 @@ void batadv_mcast_purge_orig(struct batadv_orig_node 
*orig)
  BATADV_MCAST_WANT_NO_RTR4);
batadv_mcast_want_rtr6_update(bat_priv, orig,
  BATADV_MCAST_WANT_NO_RTR6);
+   batadv_mcast_have_mc_ptype_update(bat_priv, orig,
+ BATADV_MCAST_HAVE_MC_PTYPE_CAPA);
 
spin_unlock_bh(>mcast_handler_lock);
 }
-- 
2.43.0



Re: [PATCH RFC 2/2] batman-adv: Better half duplex penalty estimation

2023-10-14 Thread Linus Lüssing
On Thu, Sep 28, 2023 at 02:39:36PM +0200, Remi Pommarel wrote:
> diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
> index 27597f4cdf3e..9b7d4de182d0 100644
> --- a/net/batman-adv/bat_v_ogm.c
> +++ b/net/batman-adv/bat_v_ogm.c
> @@ -866,10 +866,12 @@ static u32 batadv_v_get_throughput(struct 
> batadv_ogm2_packet *ogm,
[...]
>  
> - return min_t(u32, lth, oth);
> + /* OGM throughput was divided by two for retrocompatibility sake */
> + oth *= 2;
> + return oth * lth / (oth + lth);

Also looks like we'd have potential integer overflow issues
here as oth, lth and the return value are all u32.

In the worst case (oth + lth) could wrap around to 0 and we'd
divide by zero?


Re: [PATCH RFC 2/2] batman-adv: Better half duplex penalty estimation

2023-10-14 Thread Linus Lüssing
On Sat, Oct 14, 2023 at 07:10:28AM +0200, Linus Lüssing wrote:
> In the following scenario:
> 
> +---+  ch.1  +---+   ch.2  +---+   ch.2  +---+ 
> | Orig0 | <- | Orig1 | <-- | Orig2 | <-- | Orig3 | 
> +---+   300  +---+  3  +---+110  +---+ 
>  ^   |   
>  |ch.3   | 
>  +---+ 
>   100
> 
> Would the results on Orig2 to Orig1 be these?

Sorry, I ment "on Orig3 to Orig0" here.

> - via Orig2: 300*110 / (300+110) = 80.5
> - via Orig1: 100  <- selected
> 
> While it should have been this?
> - via Orig2: 3*110 / (3+110) = 109.6 <- selected
> - via Orig1: 100


Re: [PATCH RFC 2/2] batman-adv: Better half duplex penalty estimation

2023-10-13 Thread Linus Lüssing
Hi,

Thanks for taking your time to look into this and the detailed
explanations!

Generally, the issues both patches try to address make sense to me.


On Thu, Sep 28, 2023 at 02:39:36PM +0200, Remi Pommarel wrote:
> Let's consider the below topology
[...]
> However the following formula seems to be a more realistic approximation
> of PT_ac:
> 
> PT_ac =  PT_ab * LT_bc / (PT_ab * LT_bc)

Typo, I guess, as this would always be 1? What is actually
implemented makes more sense to me.

[...]
> - return min_t(u32, lth, oth);
> + /* OGM throughput was divided by two for retrocompatibility sake */
> + oth *= 2;
> + return oth * lth / (oth + lth);

Could we end up here with a (forged?) OGM that has both the new
half duplex flag set and a throughput value of 0? While also
having an lth of 0, therefore dividing by zero here?


In the following scenario:

+---+  ch.1  +---+   ch.2  +---+   ch.2  +---+ 
| Orig0 | <- | Orig1 | <-- | Orig2 | <-- | Orig3 | 
+---+   300  +---+  3  +---+110  +---+ 
 ^   |   
 |ch.3   | 
 +---+ 
  100

Would the results on Orig2 to Orig1 be these?
- via Orig2: 300*110 / (300+110) = 80.5
- via Orig1: 100  <- selected

While it should have been this?
- via Orig2: 3*110 / (3+110) = 109.6 <- selected
- via Orig1: 100

But we can't calculate the latter on Orig3, because we don't
know the two hop neighbor link throughput? Or am I missing
something?


Also, this seems to assume that time slices are divided equally.
That's probably only be true for WiFi drivers that have airtime
fairness changes integrated? So only recent versions of mt76,
ath9k and ath10k? Has anyone verified that this works fine not
only in AP but also in 11s mode?

And a third concern, but we'd probably have this issue with both
our current and your suggestion: Would we be off again 802.11be
and its "Multi-Link Operation" in the future?

Regards, Linus


Re: Fwd: Possibility of dual-licensing to ease bringing into FreeBSD

2023-09-15 Thread Linus Lüssing
Hi Aymetric,

Nice work!

For my part, I'd be a bit reluctant. We've had requests for batman-adv from big
companies in the past for an extra license, which we turned down.
So there might unfortunately be vultures out there who'd like
to build on top of batman-adv without giving back. And I'd feel a
bit uncomfortable to have spent so much free time on this project
to just "donate" it to such big companies. Who'd enhance it and
use that superior, closed source version in products which are in direct
competition to wireles community networks like Freifunk.

If there were some ways that non-commercial wireless community
projects like Freifunk were benefitting from a dual license then I
might be up for it. But right now I don't see how they would?

Regards, Linus


On Fri, Sep 15, 2023 at 04:11:44PM +0200, obiwac wrote:
> -- Forwarded message -
> From: obiwac 
> Date: Fri, 15 Sept 2023 at 16:10
> Subject: Possibility of dual-licensing to ease bringing into FreeBSD
> To: mmo...@freebsd.org , ,
> 
> 
> 
> Hia,
> 
> I recently ported batman-adv to FreeBSD as my GSoC project:
> 
> https://wiki.freebsd.org/SummerOfCode2023Projects/CallingTheBatmanFreeNetworksOnFreeBSD
> 
> I'd like to bring this work into the FreeBSD source tree, but they are
> reluctant to bring in any new GPL code. Would it be possible to
> dual-license batman-adv to GPL/BSD, or would you rather not (in which
> case I'll ask FreeBSD's core@ if an exception could be made for
> batman-adv)?
> 
> Thanks!
> Aymeric


[PATCH v7 3/3] batman-adv: mcast: shrink tracker packet after scrubbing

2023-09-06 Thread Linus Lüssing
Remove all zero MAC address entries (00:00:00:00:00:00) from a multicast
packet's tracker TVLV before transmitting it and update all headers
accordingly. This way, instead of keeping the multicast packet at a
constant size throughout its journey through the mesh, it will become
more lightweight, smaller with every interested receiver on the way and
on each splitting intersection. Which can save some valuable bandwidth.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast_forw.c | 207 
 1 file changed, 207 insertions(+)

diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c
index 1102090ae518..23aae4f60daa 100644
--- a/net/batman-adv/multicast_forw.c
+++ b/net/batman-adv/multicast_forw.c
@@ -698,6 +698,212 @@ batadv_mcast_forw_scrub_dests(struct batadv_priv 
*bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_shrink_fill() - swap slot with next non-zero destination
+ * @slot: the to be filled zero-MAC destination entry in a tracker TVLV
+ * @num_dests_slot: remaining entries in tracker TVLV from/including slot
+ *
+ * Searches for the next non-zero-MAC destination entry in a tracker TVLV after
+ * the given slot pointer. And if found, swaps it with the zero-MAC destination
+ * entry which the slot points to.
+ *
+ * Return: true if slot was swapped/filled successfully, false otherwise.
+ */
+static bool batadv_mcast_forw_shrink_fill(u8 *slot, u16 num_dests_slot)
+{
+   u16 num_dests_filler;
+   u8 *filler;
+
+   /* sanity check, should not happen */
+   if (!num_dests_slot)
+   return false;
+
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot + ETH_ALEN;
+
+   /* find a candidate to fill the empty slot */
+   batadv_mcast_forw_tracker_for_each_dest(filler, num_dests_filler) {
+   if (is_zero_ether_addr(filler))
+   continue;
+
+   ether_addr_copy(slot, filler);
+   eth_zero_addr(filler);
+   return true;
+   }
+
+   return false;
+}
+
+/**
+ * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV
+ * @skb: the batman-adv multicast packet to compact destinations in
+ *
+ * Compacts the originator destination MAC addresses in the multicast tracker
+ * TVLV of the given multicast packet. This is done by moving all non-zero
+ * MAC addresses in direction of the skb head and all zero MAC addresses in skb
+ * tail direction, within the multicast tracker TVLV.
+ *
+ * Return: The number of consecutive zero MAC address destinations which are
+ * now at the end of the multicast tracker TVLV.
+ */
+static int batadv_mcast_forw_shrink_pack_dests(struct sk_buff *skb)
+{
+   struct batadv_tvlv_mcast_tracker *mcast_tracker;
+   unsigned char *skb_net_hdr;
+   u16 num_dests_slot;
+   u8 *slot;
+
+   skb_net_hdr = skb_network_header(skb);
+   mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb_net_hdr;
+   num_dests_slot = ntohs(mcast_tracker->num_dests);
+
+   slot = (u8 *)mcast_tracker + sizeof(*mcast_tracker);
+
+   batadv_mcast_forw_tracker_for_each_dest(slot, num_dests_slot) {
+   /* find an empty slot */
+   if (!is_zero_ether_addr(slot))
+   continue;
+
+   if (!batadv_mcast_forw_shrink_fill(slot, num_dests_slot))
+   /* could not find a filler, so we successfully packed
+* and can stop - and must not reduce num_dests_slot!
+*/
+   break;
+   }
+
+   /* num_dests_slot is now the amount of reduced, zeroed
+* destinations at the end of the tracker TVLV
+*/
+   return num_dests_slot;
+}
+
+/**
+ * batadv_mcast_forw_shrink_align_offset() - get new alignment offset
+ * @num_dests_old: the old, to be updated amount of destination nodes
+ * @num_dests_reduce: the number of destinations that were removed
+ *
+ * Calculates the amount of potential extra alignment offset that is needed to
+ * adjust the TVLV padding after the change in destination nodes.
+ *
+ * Return:
+ * 0: If no change to padding is needed.
+ * 2: If padding needs to be removed.
+ * -2: If padding needs to be added.
+ */
+static short
+batadv_mcast_forw_shrink_align_offset(unsigned int num_dests_old,
+ unsigned int num_dests_reduce)
+{
+   /* even amount of removed destinations -> no alignment change */
+   if (!(num_dests_reduce % 2))
+   return 0;
+
+   /* even to odd amount of destinations -> remove padding */
+   if (!(num_dests_old % 2))
+   return 2;
+
+   /* odd to even amount of destinations -> add padding */
+   return -2;
+}
+
+/**
+ * batadv_mcast_forw_shrink_update_headers() - update shrunk mc packet headers
+ * @skb: the batman-adv multicast packet to update headers of
+ * @num_dests_reduce: the number of 

[PATCH v7 2/3] batman-adv: mcast: implement multicast packet generation

2023-09-06 Thread Linus Lüssing
Implement the preparation of a batman-adv multicast packet and use this
under certain conditions.

For one thing this implements the capability to push a complete
batman-adv multicast packet header, including a tracker TVLV with all
originator destinations that have signaled interest in it, onto a given
ethernet frame with an IP multicast packet inside.

For another checks are implemented to determine if encapsulating a
multicast packet in this new batman-adv multicast packet type and using
it is feasible. Those checks are:

1) Have all nodes signaled that they are capable of handling the new
   batman-adv multicast packet type?
2) Do all active hard interfaces of all nodes, including us, have an MTU
   of at least 1280 bytes?
3) Does a complete multicast packet header with all its destination
   addresses fit onto the given multicast packet / ethernet frame and
   does not exceed 1280 bytes?

If all checks passed then the new batman-adv multicast packet type will
be used for transmission and distribution. Otherwise we fall back to one or
more batman-adv unicast packet transmissions, if possible. Or if not
possible we will fall back to classic flooding through a batman-adv
broadcast packet.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  |  79 +++-
 net/batman-adv/multicast.h  |  25 +-
 net/batman-adv/multicast_forw.c | 732 
 net/batman-adv/soft-interface.c |   6 +-
 net/batman-adv/types.h  |   6 +
 5 files changed, 840 insertions(+), 8 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index f2b1e523fd85..d8ddb20fd732 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1177,17 +1177,62 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_mode_by_count() - get forwarding mode by count
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast packet to check
+ * @vid: the vlan identifier
+ * @is_routable: stores whether the destination is routable
+ * @count: the number of originators the multicast packet need to be sent to
+ *
+ * For a multicast packet with multiple destination originators, checks which
+ * mode to use. For BATADV_FORW_MCAST it also encapsulates the packet with a
+ * complete batman-adv multicast header.
+ *
+ * Return:
+ * BATADV_FORW_MCAST: If all nodes have multicast packet routing
+ * capabilities and an MTU >= 1280 on all hard interfaces (including us)
+ * and the encapsulated multicast packet with all destination addresses
+ * would still fit into an 1280 bytes batman-adv multicast packet
+ * (excluding the outer ethernet frame) and we could successfully push
+ * the full batman-adv multicast packet header.
+ * BATADV_FORW_UCASTS: If the packet cannot be sent in a batman-adv
+ * multicast packet and the amount of batman-adv unicast packets needed
+ * is smaller or equal to the configured multicast fanout.
+ * BATADV_FORW_BCAST: Otherwise.
+ */
+static enum batadv_forw_mode
+batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv,
+   struct sk_buff *skb, unsigned short vid,
+   int is_routable, int count)
+{
+   unsigned int mcast_hdrlen = batadv_mcast_forw_packet_hdrlen(count);
+   u8 own_tvlv_flags = bat_priv->mcast.mla_flags.tvlv_flags;
+
+   if (!atomic_read(_priv->mcast.num_no_mc_ptype_capa) &&
+   own_tvlv_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA &&
+   skb->len + mcast_hdrlen <= IPV6_MIN_MTU &&
+   batadv_mcast_forw_push(bat_priv, skb, vid, is_routable, count))
+   return BATADV_FORW_MCAST;
+
+   if (count <= atomic_read(_priv->multicast_fanout))
+   return BATADV_FORW_UCASTS;
+
+   return BATADV_FORW_BCAST;
+}
+
 /**
  * batadv_mcast_forw_mode() - check on how to forward a multicast packet
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the multicast packet to check
+ * @vid: the vlan identifier
  * @is_routable: stores whether the destination is routable
  *
  * Return: The forwarding mode as enum batadv_forw_mode.
  */
 enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  int *is_routable)
+  unsigned short vid, int *is_routable)
 {
int ret, tt_count, ip_count, unsnoop_count, total_count;
bool is_unsnoopable = false;
@@ -1217,10 +1262,8 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, 
struct sk_buff *skb,
else if (unsnoop_count)
return BATADV_FORW_BCAST;
 
-   if (total_count <= atomic_read(_priv->multicast_fanout))
-   return BATADV_FORW_UCASTS;
-
-   return BATADV_FORW_BCAST;
+   return batadv_mc

[PATCH v7 1/3] batman-adv: mcast: implement multicast packet reception and forwarding

2023-09-06 Thread Linus Lüssing
Implement functionality to receive and forward a new TVLV capable
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

Also a new OGM multicast TVLV flag is introduced to signal to other
nodes that we are capable of handling a batman-adv multicast packet and
multicast tracker TVLV. And that all of our hard interfaces have an MTU
of at least 1280 bytes (IPv6 minimum MTU), as a simple solution for now
to avoid MTU issues while forwarding.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  45 +-
 net/batman-adv/Makefile|   1 +
 net/batman-adv/fragmentation.c |   7 +-
 net/batman-adv/main.c  |   2 +
 net/batman-adv/multicast.c |  48 +-
 net/batman-adv/multicast.h |   5 +
 net/batman-adv/multicast_forw.c| 240 +
 net/batman-adv/originator.c|  28 
 net/batman-adv/originator.h|   3 +
 net/batman-adv/routing.c   |  70 +
 net/batman-adv/routing.h   |  11 ++
 net/batman-adv/soft-interface.c|  12 ++
 net/batman-adv/types.h |  64 
 13 files changed, 519 insertions(+), 17 deletions(-)
 create mode 100644 net/batman-adv/multicast_forw.c

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index 9204e4494b25..6e25753015df 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -116,6 +116,9 @@ enum batadv_icmp_packettype {
  * only need routable IPv4 multicast packets we signed up for explicitly
  * @BATADV_MCAST_WANT_NO_RTR6: we have no IPv6 multicast router and therefore
  * only need routable IPv6 multicast packets we signed up for explicitly
+ * @BATADV_MCAST_HAVE_MC_PTYPE_CAPA: we can parse, receive and forward
+ * batman-adv multicast packets with a multicast tracker TVLV. And all our
+ * hard interfaces have an MTU of at least 1280 bytes.
  */
 enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_UNSNOOPABLES  = 1UL << 0,
@@ -123,6 +126,7 @@ enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_IPV6  = 1UL << 2,
BATADV_MCAST_WANT_NO_RTR4   = 1UL << 3,
BATADV_MCAST_WANT_NO_RTR6   = 1UL << 4,
+   BATADV_MCAST_HAVE_MC_PTYPE_CAPA = 1UL << 5,
 };
 
 /* tt data subtypes */
@@ -174,14 +178,16 @@ enum batadv_bla_claimframe {
  * @BATADV_TVLV_TT: translation table tvlv
  * @BATADV_TVLV_ROAM: roaming advertisement tvlv
  * @BATADV_TVLV_MCAST: multicast capability tvlv
+ * @BATADV_TVLV_MCAST_TRACKER: multicast tracker tvlv
  */
 enum batadv_tvlv_type {
-   BATADV_TVLV_GW  = 0x01,
-   BATADV_TVLV_DAT = 0x02,
-   BATADV_TVLV_NC  = 0x03,
-   BATADV_TVLV_TT  = 0x04,
-   BATADV_TVLV_ROAM= 0x05,
-   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_GW  = 0x01,
+   BATADV_TVLV_DAT = 0x02,
+   BATADV_TVLV_NC  = 0x03,
+   BATADV_TVLV_TT  = 0x04,
+   BATADV_TVLV_ROAM= 0x05,
+   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_MCAST_TRACKER   = 0x07,
 };
 
 #pragma pack(2)
@@ -487,6 +493,25 @@ struct batadv_bcast_packet {
 */
 };
 
+/**
+ * struct batadv_mcast_packet - multicast packet for network payload
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the general header
+ * @ttl: time to live for this packet, part of the general header
+ * @reserved: reserved byte for alignment
+ * @tvlv_len: length of the appended tvlv buffer (in bytes)
+ */
+struct batadv_mcast_packet {
+   __u8 packet_type;
+   __u8 version;
+   __u8 ttl;
+   __u8 reserved;
+   __be16 tvlv_len;
+   /* "4 bytes boundary + 2 bytes" long to make the payload after the
+* following ethernet header again 4 bytes boundary aligned
+*/
+};
+
 /**
  * struct batadv_coded_packet - network coded packet
  * @packet_type: batman-adv packet type, part of the general header
@@ -628,6 +653,14 @@ struct batadv_tvlv_mcast_data {
__u8 reserved[3];
 };
 
+/**
+ * struct batadv_tvlv_mcast_tracker - payload of a multicast tracker tvlv
+ * @num_dests: number of subsequent destination originator MAC addresses
+ */
+struct batadv_tvlv_mcast_tracker {
+   __be16  num_dests;
+};
+
 #pragma pack()
 
 #endif /* _UAPI_LINUX_BATADV_PACKET_H_ */
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
index 3bd0760c76a2..b51d8b071b56 100644
--- a/net/batman-ad

[PATCH v7 0/3] Implementation of a Stateless Multicast Packet Type

2023-09-06 Thread Linus Lüssing
In-Reply-To: 

Hi,

The following patchset implements a stateless, TVLV capable batman-adv
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination MAC addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

The purpose of this new packet type is to allow to forward an IP
multicast packet with less transmissions / overhead than the 
multicast-via-multiple-unicasts approach. Or to reach a lot more
destinations (currently up to 196, depending on the payload size, see 
Wiki documentation for details) than with the default multicast fanout
for the via-unicasts approach.

This will allow using applications like mDNS again in several Freifunk
communities. And with less transmissions will also make more bulky
multicast applications, like media streaming (to an assessable amount of
receivers) a lot more feasible.

This approach is way simpler than the original multicast (tracker) packet
approach we envisioned years ago. As it involves no maintenance of an
extra, state based multicast routing table. However the TVLV capability
should allow to extend things later, to split control and data plane a bit
more for instance, to further increase the number of destinations, to
further reduce overhead.

A compact overview can be found in the Wiki here, including limitations:

https://www.open-mesh.org/projects/batman-adv/wiki/Multicast-Packet-Type

Regards, Linus

---

Changelog v7:
* PATCH 1/3:
  * rebased to current main/master branch (resolved net/multicast/routing.h)
  * renamed batadv_mcast_forw_orig_to_neigh() to
batadv_orig_to_router() and moved it to originator.c, for
reuse in fragmentation.c
  * added a SKB_LINEAR_ASSERT() to batadv_mcast_forw_packet()
  * adjusted batadv_mcast_forw_scrub_dests():
added a new macro that updates two dest pointers
to avoid confusion due to two different updating methods,
removed goto's and a little reordering
* PATCH 2/3:
  * added SKB_LINEAR_ASSERT() to batadv_mcast_forw_scrape()
* PATCH 3/3:
  * simplified batadv_mcast_forw_shrink_pack_dests():
moved parts to new sub function batadv_mcast_forw_shrink_fill(),
removed keeping track of filler over the whole function
(might be slower, as we might check+skip the same zero
 MAC entry multiple times, for each slot, but a lot easier
 to read - and we don't prioritize performance with this
 patchset yet)

Changelog v6:
* PATCH 2/3:
  * add missing include of linux/compiler.h for the newly added
likely() in v5
  * added kerneldoc for @num_dests_pushed to
the in v5 newly added batadv_mcast_forw_push_adjust_padding()
  * updated kerneldoc of batadv_mcast_forw_push_adjust_padding(),
original text was wrongly copy & pasted from
batadv_mcast_forw_push_est_padding() without adjustments
* PATCH 3/3:
  * added missing "static" attribute to the newly added
batadv_mcast_forw_shrink_align_offset() in v5

Changelog v5:
* removed patches 1/5 + 2/5, as they were already applied
* rebased to current main branch
* changed padding behaviour:
  * now 2 bytes padding on the end of the multicast
tracker TVLV, if number of destination nodes is
even
  * as number of destination nodes might change between
initial check until after pushing them, functions
to post-adjust padding after pushing were added
* added/fixed TTL handling
* removed skb_pull() bailing from sub-functions of
  batadv_mcast_forw_push(), to only have a single
  skb_pull() to keep track of in batadv_mcast_forw_push()
  to revert the changes to the skb; instead a
  "unsigned short *tvlv_len" is passsed along in 
  batadv_mcast_.*push.*() functions to keep track of
  how many bytes were pushed
* moved + verified skb->ip_summed invalidation
* batadv_mcast_forw_shrink_tracker() xmas tree ordering
* reword batadv_mcast_forw_push_dest() "Return:" kerneldoc
* fixed spelling: outter -> outer

Changelog v4:
* PATCH 4/5:
  * add missing include for linux/types.h in multicast.h
  * add missing kerneldoc for @bat_priv in batadv_mcast_forw_push_dest()
and batadv_mcast_forw_push_tvlvs()
  * use sizeof_field(type, field) instead of sizeof(((type *)0)->field)
in batadv_mcast_forw_push_dest()
* PATCH 5/5:
  * rename num_dests_remove to num_dests_reduce in
batadv_mcast_forw_shrink_align_offse() to fix kerneldocs and for
consistency
  * fix typo in kerneldoc in batadv_mcast_forw_shrink_update_headers()
-> @num_dest_reduce -> @num_dests_reduce
  * use sizeof_field(type, field) instead of sizeof(((type *)0)->field)
in batadv_mcast_forw_shrink_align_offset()

Changelog v3:
* PATCH 1/5:
  * remove now obsolete includes
* PATCH 2/5:
  * fix batadv_tvlv_handler_register() in network-coding.c
  * add missing 

[PATCH 1/2] batctl: mcast_flags: update to current state

2023-07-31 Thread Linus Lüssing
Add the new "P" flag, which signals support for the new batman-adv
multicast packet type, to the "batctl mcast_flags" and "batctl tcpdump"
outputs.

The examples in the README.rst are updated, too, including a description
for the R4 and R6 flags.

Signed-off-by: Linus Lüssing 
---
 README.rst  | 88 -
 batadv_packet.h | 45 +
 genl_json.c |  2 ++
 mcast_flags.c   |  8 +++--
 tcpdump.c   |  5 +--
 5 files changed, 100 insertions(+), 48 deletions(-)

diff --git a/README.rst b/README.rst
index 606d55721204..3495fba02e0e 100644
--- a/README.rst
+++ b/README.rst
@@ -323,15 +323,15 @@ Usage::
 
 Example::
 
-  Multicast flags (own flags: [U46])
+  Multicast flags (own flags: [U46R4R6.])
   * Bridged [U]   U
   * No IGMP/MLD Querier [4/6]:./.
   * Shadowing IGMP/MLD Querier [4/6]: 4/6
   ---
  Originator Flags
-  02:04:64:a4:39:c1 [U..]
-  02:04:64:a4:39:c2 [U..]
-  02:04:64:a4:39:c3 [...]
+  02:04:64:a4:39:c1 [U... . .]
+  02:04:64:a4:39:c2 [...R4R6.]
+  02:04:64:a4:39:c3 [ . P]
 
 where
 
@@ -348,6 +348,17 @@ U:
 6:
   wants all IPv6 multicast traffic, meaning other nodes need to always forward
   any IPv6 multicast traffic to it
+R4:
+  wants all routable IPv4 multicast traffic, meaning other nodes need to always
+  forward multicast traffic destined to 224.0.0.0/4 excluding 224.0.0.0/24 to
+  it
+R6:
+  wants all routable IPv6 multicast traffic, meaning other nodes need to always
+  forward multicast traffic destined to ffXY::/16 with Y > 2 (scope greater
+  than link-local) to it
+P:
+  the node either cannot handle batman-adv multicast packets with a multicast
+  tracker TVLV or one of its hard interfaces has an MTU smaller than 1280 bytes
 
 If a node does not have multicast optimizations available (e.g. old batman-adv
 version or optimizations not compiled in), therefore not announcing any
@@ -930,39 +941,42 @@ Example::
 
   $ batctl meshif bat0 mcast_flags_json | json_pp
   [
-  {
-  "mcast_flags": {
-  "all_unsnoopables": true,
-  "raw": 1,
-  "want_all_ipv4": false,
-  "want_all_ipv6": false,
-  "want_no_rtr_ipv4": false,
-  "want_no_rtr_ipv6": false
-  },
-  "orig_address": "9e:58:32:59:54:c3"
-  },
-  {
-  "mcast_flags": {
-  "all_unsnoopables": true,
-  "raw": 1,
-  "want_all_ipv4": false,
-  "want_all_ipv6": false,
-  "want_no_rtr_ipv4": false,
-  "want_no_rtr_ipv6": false
-  },
-  "orig_address": "32:12:17:0a:21:63"
-  },
-  {
-  "mcast_flags": {
-  "all_unsnoopables": true,
-  "raw": 1,
-  "want_all_ipv4": false,
-  "want_all_ipv6": false,
-  "want_no_rtr_ipv4": false,
-  "want_no_rtr_ipv6": false
-  },
-  "orig_address": "1a:34:8c:c4:fe:13"
-  },
+ {
+"mcast_flags" : {
+   "all_unsnoopables" : true,
+   "have_mc_ptype_capa" : true,
+   "raw" : 57,
+   "want_all_ipv4" : false,
+   "want_all_ipv6" : false,
+   "want_no_rtr_ipv4" : true,
+   "want_no_rtr_ipv6" : true
+},
+"orig_address" : "02:04:64:a4:39:c1"
+ },
+ {
+"mcast_flags" : {
+   "all_unsnoopables" : false,
+   "have_mc_ptype_capa" : true,
+   "raw" : 40,
+   "want_all_ipv4" : false,
+   "want_all_ipv6" : false,
+   "want_no_rtr_ipv4" : true,
+   "want_no_rtr_ipv6" : false
+},
+"orig_address" : "02:04:64:a4:39:c2"
+ },
+ {
+"mcast_flags" : {
+   "all_unsnoopables" : false,
+   "have_mc_ptype_capa" : false,
+   "raw" : 24,
+   "want_all_ipv4" : false,
+   "want_all_ipv6" : false,
+   "want_no_rtr_ipv4" : true,
+   "want_no_rtr_ipv6" : true
+},
+"orig_address" : "02:04:64:a4:39:c3"
+ },
   [...]
   ]
 
diff --git a/batadv_packet.h b/batadv_packet.h
index 9204e4494b25..6e25753015df 100644
--- a/batadv_packet.h
+++ b/batadv_packet.h
@@ -116,6 +116,9 @@ enum batadv_icmp_packettype {
  * only need routable I

[PATCH 2/2] batctl: tcpdump: parse batman-adv mcast packet type

2023-07-31 Thread Linus Lüssing
Implement a batctl tcpdump parsing of the new batman-adv multicast
packet type, including its multicast tracker TVLV and encapsulated
payload data.

Signed-off-by: Linus Lüssing 
---
 tcpdump.c | 134 +++---
 tcpdump.h |   1 +
 2 files changed, 119 insertions(+), 16 deletions(-)

diff --git a/tcpdump.c b/tcpdump.c
index debcb0ae517a..5e7c76c69bd1 100644
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -57,7 +57,8 @@ static unsigned short dump_level_all = DUMP_TYPE_BATOGM | 
DUMP_TYPE_BATOGM2 |
   DUMP_TYPE_BATELP | DUMP_TYPE_BATICMP |
   DUMP_TYPE_BATUCAST | DUMP_TYPE_BATBCAST |
   DUMP_TYPE_BATUTVLV | DUMP_TYPE_BATFRAG |
-  DUMP_TYPE_NONBAT | DUMP_TYPE_BATCODED;
+  DUMP_TYPE_NONBAT | DUMP_TYPE_BATCODED |
+  DUMP_TYPE_BATMCAST;
 static unsigned short dump_level;
 
 static void parse_eth_hdr(unsigned char *packet_buff, ssize_t buff_len, int 
read_opt, int time_printed);
@@ -82,6 +83,7 @@ static void tcpdump_usage(void)
fprintf(stderr, " \t\t%3d - batman unicast tvlv packets\n", 
DUMP_TYPE_BATUTVLV);
fprintf(stderr, " \t\t%3d - non batman packets\n", DUMP_TYPE_NONBAT);
fprintf(stderr, " \t\t%3d - batman coded packets\n", 
DUMP_TYPE_BATCODED);
+   fprintf(stderr, " \t\t%3d - batman multicast packets\n", 
DUMP_TYPE_BATMCAST);
fprintf(stderr, " \t\t%3d - batman ogm & non batman packets\n", 
DUMP_TYPE_BATOGM | DUMP_TYPE_NONBAT);
 }
 
@@ -101,7 +103,8 @@ static int print_time(void)
return 1;
 }
 
-static void batctl_tvlv_parse_gw_v1(void *buff, ssize_t buff_len)
+static void batctl_tvlv_parse_gw_v1(void *buff, ssize_t buff_len,
+   int read_opt __maybe_unused)
 {
struct batadv_tvlv_gateway_data *tvlv = buff;
uint32_t down, up;
@@ -119,8 +122,9 @@ static void batctl_tvlv_parse_gw_v1(void *buff, ssize_t 
buff_len)
   down / 10, down % 10, up / 10, up % 10);
 }
 
-static void batctl_tvlv_parse_dat_v1(void (*buff)__attribute__((unused)),
-ssize_t buff_len)
+static void batctl_tvlv_parse_dat_v1(void *buff __maybe_unused,
+ssize_t buff_len,
+int read_opt __maybe_unused)
 {
if (buff_len != 0) {
fprintf(stderr, "Warning - dropping received %s packet as it is 
not the correct size (0): %zu\n",
@@ -131,8 +135,9 @@ static void batctl_tvlv_parse_dat_v1(void 
(*buff)__attribute__((unused)),
printf("\tTVLV DATv1: enabled\n");
 }
 
-static void batctl_tvlv_parse_nc_v1(void (*buff)__attribute__((unused)),
-   ssize_t buff_len)
+static void batctl_tvlv_parse_nc_v1(void *buff __maybe_unused,
+   ssize_t buff_len,
+   int read_opt __maybe_unused)
 {
if (buff_len != 0) {
fprintf(stderr, "Warning - dropping received %s packet as it is 
not the correct size (0): %zu\n",
@@ -143,7 +148,8 @@ static void batctl_tvlv_parse_nc_v1(void 
(*buff)__attribute__((unused)),
printf("\tTVLV NCv1: enabled\n");
 }
 
-static void batctl_tvlv_parse_tt_v1(void *buff, ssize_t buff_len)
+static void batctl_tvlv_parse_tt_v1(void *buff, ssize_t buff_len,
+   int read_opt __maybe_unused)
 {
struct batadv_tvlv_tt_data *tvlv = buff;
struct batadv_tvlv_tt_vlan_data *vlan;
@@ -183,7 +189,8 @@ static void batctl_tvlv_parse_tt_v1(void *buff, ssize_t 
buff_len)
}
 }
 
-static void batctl_tvlv_parse_roam_v1(void *buff, ssize_t buff_len)
+static void batctl_tvlv_parse_roam_v1(void *buff, ssize_t buff_len,
+ int read_opt __maybe_unused)
 {
struct batadv_tvlv_roam_adv *tvlv = buff;
 
@@ -199,7 +206,8 @@ static void batctl_tvlv_parse_roam_v1(void *buff, ssize_t 
buff_len)
 }
 
 static void batctl_tvlv_parse_mcast_v1(void *buff __maybe_unused,
-  ssize_t buff_len)
+  ssize_t buff_len,
+  int read_opt __maybe_unused)
 {
struct batadv_tvlv_mcast_data *tvlv = buff;
uint8_t flags;
@@ -218,7 +226,8 @@ static void batctl_tvlv_parse_mcast_v1(void *buff 
__maybe_unused,
   flags & BATADV_MCAST_WANT_ALL_IPV6 ? '6' : '.');
 }
 
-static void batctl_tvlv_parse_mcast_v2(void *buff, ssize_t buff_len)
+static void batctl_tvlv_parse_mcast_v2(void *buff, ssize_t buff_len,
+  int read_opt __maybe_unused)
 {
struct batadv_tvlv_mcast_data *tvlv = buff;
uint8_t flags;
@@ -240,7 +249,

[PATCH v6 3/3] batman-adv: mcast: shrink tracker packet after scrubbing

2023-07-19 Thread Linus Lüssing
Remove all zero MAC address entries (00:00:00:00:00:00) from a multicast
packet's tracker TVLV before transmitting it and update all headers
accordingly. This way, instead of keeping the multicast packet at a
constant size throughout its journey through the mesh, it will become
more lightweight, smaller with every interested receiver on the way and
on each splitting intersection. Which can save some valuable bandwidth.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast_forw.c | 195 
 1 file changed, 195 insertions(+)

diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c
index d0f75a63de2a..d7b1aabd4b72 100644
--- a/net/batman-adv/multicast_forw.c
+++ b/net/batman-adv/multicast_forw.c
@@ -712,6 +712,200 @@ batadv_mcast_forw_scrub_dests(struct batadv_priv 
*bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV
+ * @skb: the batman-adv multicast packet to compact destinations in
+ *
+ * Compacts the originator destination MAC addresses in the multicast tracker
+ * TVLV of the given multicast packet. This is done by moving all non-zero
+ * MAC addresses in direction of the skb head and all zero MAC addresses in skb
+ * tail direction, within the multicast tracker TVLV.
+ *
+ * Return: The number of consecutive zero MAC address destinations which are
+ * now at the end of the multicast tracker TVLV.
+ */
+static int batadv_mcast_forw_shrink_pack_dests(struct sk_buff *skb)
+{
+   struct batadv_tvlv_mcast_tracker *mcast_tracker;
+   u16 num_dests_slot, num_dests_filler;
+   unsigned char *skb_net_hdr;
+   u8 *slot, *filler;
+
+   skb_net_hdr = skb_network_header(skb);
+   mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb_net_hdr;
+   num_dests_slot = ntohs(mcast_tracker->num_dests);
+
+   slot = (u8 *)mcast_tracker + sizeof(*mcast_tracker);
+
+   if (!num_dests_slot)
+   return 0;
+
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot + ETH_ALEN;
+
+   batadv_mcast_forw_tracker_for_each_dest(slot, num_dests_slot) {
+   /* find an empty slot */
+   if (!is_zero_ether_addr(slot))
+   continue;
+
+   /* keep filler ahead of slot */
+   if (filler <= slot) {
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot + ETH_ALEN;
+   }
+
+   /* find a candidate to fill the empty slot */
+   batadv_mcast_forw_tracker_for_each_dest(filler,
+   num_dests_filler) {
+   if (is_zero_ether_addr(filler))
+   continue;
+
+   ether_addr_copy(slot, filler);
+   eth_zero_addr(filler);
+   goto cont_next_slot;
+   }
+
+   /* could not find a filler, we can stop
+* - and must not advance the slot pointer!
+*/
+   if (!num_dests_filler)
+   break;
+
+cont_next_slot:
+   continue;
+   }
+
+   /* num_dests_slot is the amount of reduced destinations */
+   return num_dests_slot;
+}
+
+/**
+ * batadv_mcast_forw_shrink_align_offset() - get new alignment offset
+ * @num_dests_old: the old, to be updated amount of destination nodes
+ * @num_dests_reduce: the number of destinations that were removed
+ *
+ * Calculates the amount of potential extra alignment offset that is needed to
+ * adjust the TVLV padding after the change in destination nodes.
+ *
+ * Return:
+ * 0: If no change to padding is needed.
+ * 2: If padding needs to be removed.
+ * -2: If padding needs to be added.
+ */
+static short
+batadv_mcast_forw_shrink_align_offset(unsigned int num_dests_old,
+ unsigned int num_dests_reduce)
+{
+   /* even amount of removed destinations -> no alignment change */
+   if (!(num_dests_reduce % 2))
+   return 0;
+
+   /* even to odd amount of destinations -> remove padding */
+   if (!(num_dests_old % 2))
+   return 2;
+
+   /* odd to even amount of destinations -> add padding */
+   return -2;
+}
+
+/**
+ * batadv_mcast_forw_shrink_update_headers() - update shrunk mc packet headers
+ * @skb: the batman-adv multicast packet to update headers of
+ * @num_dests_reduce: the number of destinations that were removed
+ *
+ * This updates any fields of a batman-adv multicast packet that are affected
+ * by the reduced number of destinations in the multicast tracket TVLV. In
+ * particular this updates:
+ *
+ * The num_dest field of the multicast tracker TVLV.
+ * The TVLV length field of the according generic TVLV header.
+ * The batman-adv multicast packet's total TVLV length field.
+ *
+ * Return: The offset in skb's tail dir

[PATCH v6 2/3] batman-adv: mcast: implement multicast packet generation

2023-07-19 Thread Linus Lüssing
Implement the preparation of a batman-adv multicast packet and use this
under certain conditions.

For one thing this implements the capability to push a complete
batman-adv multicast packet header, including a tracker TVLV with all
originator destinations that have signaled interest in it, onto a given
ethernet frame with an IP multicast packet inside.

For another checks are implemented to determine if encapsulating a
multicast packet in this new batman-adv multicast packet type and using
it is feasible. Those checks are:

1) Have all nodes signaled that they are capable of handling the new
   batman-adv multicast packet type?
2) Do all active hard interfaces of all nodes, including us, have an MTU
   of at least 1280 bytes?
3) Does a complete multicast packet header with all its destination
   addresses fit onto the given multicast packet / ethernet frame and
   does not exceed 1280 bytes?

If all checks passed then the new batman-adv multicast packet type will
be used for transmission and distribution. Otherwise we fall back to one or
more batman-adv unicast packet transmissions, if possible. Or if not
possible we will fall back to classic flooding through a batman-adv
broadcast packet.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  |  79 +++-
 net/batman-adv/multicast.h  |  25 +-
 net/batman-adv/multicast_forw.c | 727 
 net/batman-adv/soft-interface.c |   6 +-
 net/batman-adv/types.h  |   6 +
 5 files changed, 835 insertions(+), 8 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index f2b1e523fd85..d8ddb20fd732 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1177,17 +1177,62 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_mode_by_count() - get forwarding mode by count
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast packet to check
+ * @vid: the vlan identifier
+ * @is_routable: stores whether the destination is routable
+ * @count: the number of originators the multicast packet need to be sent to
+ *
+ * For a multicast packet with multiple destination originators, checks which
+ * mode to use. For BATADV_FORW_MCAST it also encapsulates the packet with a
+ * complete batman-adv multicast header.
+ *
+ * Return:
+ * BATADV_FORW_MCAST: If all nodes have multicast packet routing
+ * capabilities and an MTU >= 1280 on all hard interfaces (including us)
+ * and the encapsulated multicast packet with all destination addresses
+ * would still fit into an 1280 bytes batman-adv multicast packet
+ * (excluding the outer ethernet frame) and we could successfully push
+ * the full batman-adv multicast packet header.
+ * BATADV_FORW_UCASTS: If the packet cannot be sent in a batman-adv
+ * multicast packet and the amount of batman-adv unicast packets needed
+ * is smaller or equal to the configured multicast fanout.
+ * BATADV_FORW_BCAST: Otherwise.
+ */
+static enum batadv_forw_mode
+batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv,
+   struct sk_buff *skb, unsigned short vid,
+   int is_routable, int count)
+{
+   unsigned int mcast_hdrlen = batadv_mcast_forw_packet_hdrlen(count);
+   u8 own_tvlv_flags = bat_priv->mcast.mla_flags.tvlv_flags;
+
+   if (!atomic_read(_priv->mcast.num_no_mc_ptype_capa) &&
+   own_tvlv_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA &&
+   skb->len + mcast_hdrlen <= IPV6_MIN_MTU &&
+   batadv_mcast_forw_push(bat_priv, skb, vid, is_routable, count))
+   return BATADV_FORW_MCAST;
+
+   if (count <= atomic_read(_priv->multicast_fanout))
+   return BATADV_FORW_UCASTS;
+
+   return BATADV_FORW_BCAST;
+}
+
 /**
  * batadv_mcast_forw_mode() - check on how to forward a multicast packet
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the multicast packet to check
+ * @vid: the vlan identifier
  * @is_routable: stores whether the destination is routable
  *
  * Return: The forwarding mode as enum batadv_forw_mode.
  */
 enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  int *is_routable)
+  unsigned short vid, int *is_routable)
 {
int ret, tt_count, ip_count, unsnoop_count, total_count;
bool is_unsnoopable = false;
@@ -1217,10 +1262,8 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, 
struct sk_buff *skb,
else if (unsnoop_count)
return BATADV_FORW_BCAST;
 
-   if (total_count <= atomic_read(_priv->multicast_fanout))
-   return BATADV_FORW_UCASTS;
-
-   return BATADV_FORW_BCAST;
+   return batadv_mc

[PATCH v6 1/3] batman-adv: mcast: implement multicast packet reception and forwarding

2023-07-19 Thread Linus Lüssing
Implement functionality to receive and forward a new TVLV capable
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

Also a new OGM multicast TVLV flag is introduced to signal to other
nodes that we are capable of handling a batman-adv multicast packet and
multicast tracker TVLV. And that all of our hard interfaces have an MTU
of at least 1280 bytes (IPv6 minimum MTU), as a simple solution for now
to avoid MTU issues while forwarding.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  45 -
 net/batman-adv/Makefile|   1 +
 net/batman-adv/main.c  |   2 +
 net/batman-adv/multicast.c |  48 +-
 net/batman-adv/multicast.h |   5 +
 net/batman-adv/multicast_forw.c| 256 +
 net/batman-adv/originator.c|   1 +
 net/batman-adv/routing.c   |  70 
 net/batman-adv/routing.h   |  11 ++
 net/batman-adv/soft-interface.c|  12 ++
 net/batman-adv/types.h |  64 
 11 files changed, 504 insertions(+), 11 deletions(-)
 create mode 100644 net/batman-adv/multicast_forw.c

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index 9204e4494b25..6e25753015df 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -116,6 +116,9 @@ enum batadv_icmp_packettype {
  * only need routable IPv4 multicast packets we signed up for explicitly
  * @BATADV_MCAST_WANT_NO_RTR6: we have no IPv6 multicast router and therefore
  * only need routable IPv6 multicast packets we signed up for explicitly
+ * @BATADV_MCAST_HAVE_MC_PTYPE_CAPA: we can parse, receive and forward
+ * batman-adv multicast packets with a multicast tracker TVLV. And all our
+ * hard interfaces have an MTU of at least 1280 bytes.
  */
 enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_UNSNOOPABLES  = 1UL << 0,
@@ -123,6 +126,7 @@ enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_IPV6  = 1UL << 2,
BATADV_MCAST_WANT_NO_RTR4   = 1UL << 3,
BATADV_MCAST_WANT_NO_RTR6   = 1UL << 4,
+   BATADV_MCAST_HAVE_MC_PTYPE_CAPA = 1UL << 5,
 };
 
 /* tt data subtypes */
@@ -174,14 +178,16 @@ enum batadv_bla_claimframe {
  * @BATADV_TVLV_TT: translation table tvlv
  * @BATADV_TVLV_ROAM: roaming advertisement tvlv
  * @BATADV_TVLV_MCAST: multicast capability tvlv
+ * @BATADV_TVLV_MCAST_TRACKER: multicast tracker tvlv
  */
 enum batadv_tvlv_type {
-   BATADV_TVLV_GW  = 0x01,
-   BATADV_TVLV_DAT = 0x02,
-   BATADV_TVLV_NC  = 0x03,
-   BATADV_TVLV_TT  = 0x04,
-   BATADV_TVLV_ROAM= 0x05,
-   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_GW  = 0x01,
+   BATADV_TVLV_DAT = 0x02,
+   BATADV_TVLV_NC  = 0x03,
+   BATADV_TVLV_TT  = 0x04,
+   BATADV_TVLV_ROAM= 0x05,
+   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_MCAST_TRACKER   = 0x07,
 };
 
 #pragma pack(2)
@@ -487,6 +493,25 @@ struct batadv_bcast_packet {
 */
 };
 
+/**
+ * struct batadv_mcast_packet - multicast packet for network payload
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the general header
+ * @ttl: time to live for this packet, part of the general header
+ * @reserved: reserved byte for alignment
+ * @tvlv_len: length of the appended tvlv buffer (in bytes)
+ */
+struct batadv_mcast_packet {
+   __u8 packet_type;
+   __u8 version;
+   __u8 ttl;
+   __u8 reserved;
+   __be16 tvlv_len;
+   /* "4 bytes boundary + 2 bytes" long to make the payload after the
+* following ethernet header again 4 bytes boundary aligned
+*/
+};
+
 /**
  * struct batadv_coded_packet - network coded packet
  * @packet_type: batman-adv packet type, part of the general header
@@ -628,6 +653,14 @@ struct batadv_tvlv_mcast_data {
__u8 reserved[3];
 };
 
+/**
+ * struct batadv_tvlv_mcast_tracker - payload of a multicast tracker tvlv
+ * @num_dests: number of subsequent destination originator MAC addresses
+ */
+struct batadv_tvlv_mcast_tracker {
+   __be16  num_dests;
+};
+
 #pragma pack()
 
 #endif /* _UAPI_LINUX_BATADV_PACKET_H_ */
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
index 3bd0760c76a2..b51d8b071b56 100644
--- a/net/batman-adv/Makefile
+++ b/net/batman-adv/Makefile
@@ -20,6 +20,7 @@ batman-adv-y += hash.o
 batman-adv-$(C

[PATCH v6 0/3] Implementation of a Stateless Multicast Packet Type

2023-07-19 Thread Linus Lüssing
Hi,

The following patchset implements a stateless, TVLV capable batman-adv
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination MAC addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

The purpose of this new packet type is to allow to forward an IP
multicast packet with less transmissions / overhead than the 
multicast-via-multiple-unicasts approach. Or to reach a lot more
destinations (currently up to 196, depending on the payload size, see 
Wiki documentation for details) than with the default multicast fanout
for the via-unicasts approach.

This will allow using applications like mDNS again in several Freifunk
communities. And with less transmissions will also make more bulky
multicast applications, like media streaming (to an assessable amount of
receivers) a lot more feasible.

This approach is way simpler than the original multicast (tracker) packet
approach we envisioned years ago. As it involves no maintenance of an
extra, state based multicast routing table. However the TVLV capability
should allow to extend things later, to split control and data plane a bit
more for instance, to further increase the number of destinations, to
further reduce overhead.

A compact overview can be found in the Wiki here, including limitations:

https://www.open-mesh.org/projects/batman-adv/wiki/Multicast-Packet-Type

Regards, Linus

---

Changelog v6:
* PATCH 2/3:
  * add missing include of linux/compiler.h for the newly added
likely() in v5
  * added kerneldoc for @num_dests_pushed to
the in v5 newly added batadv_mcast_forw_push_adjust_padding()
  * updated kerneldoc of batadv_mcast_forw_push_adjust_padding(),
original text was wrongly copy & pasted from
batadv_mcast_forw_push_est_padding() without adjustments
* PATCH 3/3:
  * added missing "static" attribute to the newly added
batadv_mcast_forw_shrink_align_offset() in v5

Changelog v5:
* removed patches 1/5 + 2/5, as they were already applied
* rebased to current main branch
* changed padding behaviour:
  * now 2 bytes padding on the end of the multicast
tracker TVLV, if number of destination nodes is
even
  * as number of destination nodes might change between
initial check until after pushing them, functions
to post-adjust padding after pushing were added
* added/fixed TTL handling
* removed skb_pull() bailing from sub-functions of
  batadv_mcast_forw_push(), to only have a single
  skb_pull() to keep track of in batadv_mcast_forw_push()
  to revert the changes to the skb; instead a
  "unsigned short *tvlv_len" is passsed along in 
  batadv_mcast_.*push.*() functions to keep track of
  how many bytes were pushed
* moved + verified skb->ip_summed invalidation
* batadv_mcast_forw_shrink_tracker() xmas tree ordering
* reword batadv_mcast_forw_push_dest() "Return:" kerneldoc
* fixed spelling: outter -> outer

Changelog v4:
* PATCH 4/5:
  * add missing include for linux/types.h in multicast.h
  * add missing kerneldoc for @bat_priv in batadv_mcast_forw_push_dest()
and batadv_mcast_forw_push_tvlvs()
  * use sizeof_field(type, field) instead of sizeof(((type *)0)->field)
in batadv_mcast_forw_push_dest()
* PATCH 5/5:
  * rename num_dests_remove to num_dests_reduce in
batadv_mcast_forw_shrink_align_offse() to fix kerneldocs and for
consistency
  * fix typo in kerneldoc in batadv_mcast_forw_shrink_update_headers()
-> @num_dest_reduce -> @num_dests_reduce
  * use sizeof_field(type, field) instead of sizeof(((type *)0)->field)
in batadv_mcast_forw_shrink_align_offset()

Changelog v3:
* PATCH 1/5:
  * remove now obsolete includes
* PATCH 2/5:
  * fix batadv_tvlv_handler_register() in network-coding.c
  * add missing include for linux/skbuff.h
  * move variable declarations out of the switch case
in batadv_tvlv_call_handler()
* PATCH 3/5:
  * remove unnecessary include of multicast.h in routing.c
  * add a few missing includes to multicast_forw.c
(linux/byteorder/generic.h, linux/errno.h, linux/gfp.h, linux/stddef.h
 uapi/linux/batadv_packet.h, multicast.h)
* PATCH 4/5:
  * add missing rcu_read_unlock() in error case before returning in
batadv_mcast_forw_push_dests_list()
  * remove unnecessary include of soft-interface.h in multicast_forw.c
  * add a few missing includes to multicast_forw.c
(linux/bug.h, linux/build_bug.h, linux/limits.h, linux/rculist.h,
 linux/rcupdate.h, linux/string.h)
  * make batadv_mcast_forw_mode_by_count() static
  * fix return types in the declaration of
batadv_mcast_forw_packet_hdrlen() and batadv_mcast_forw_push()
in multicast.h
  * fix typo in commit message: "that the are capable of"
-> "that the*y* are capable of"
* PATCH 5/5:
  

[PATCH v5 3/3] batman-adv: mcast: shrink tracker packet after scrubbing

2023-07-08 Thread Linus Lüssing
Remove all zero MAC address entries (00:00:00:00:00:00) from a multicast
packet's tracker TVLV before transmitting it and update all headers
accordingly. This way, instead of keeping the multicast packet at a
constant size throughout its journey through the mesh, it will become
more lightweight, smaller with every interested receiver on the way and
on each splitting intersection. Which can save some valuable bandwidth.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast_forw.c | 194 
 1 file changed, 194 insertions(+)

diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c
index e3a603ec8f51..917a89583ce3 100644
--- a/net/batman-adv/multicast_forw.c
+++ b/net/batman-adv/multicast_forw.c
@@ -700,6 +700,199 @@ batadv_mcast_forw_scrub_dests(struct batadv_priv 
*bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV
+ * @skb: the batman-adv multicast packet to compact destinations in
+ *
+ * Compacts the originator destination MAC addresses in the multicast tracker
+ * TVLV of the given multicast packet. This is done by moving all non-zero
+ * MAC addresses in direction of the skb head and all zero MAC addresses in skb
+ * tail direction, within the multicast tracker TVLV.
+ *
+ * Return: The number of consecutive zero MAC address destinations which are
+ * now at the end of the multicast tracker TVLV.
+ */
+static int batadv_mcast_forw_shrink_pack_dests(struct sk_buff *skb)
+{
+   struct batadv_tvlv_mcast_tracker *mcast_tracker;
+   u16 num_dests_slot, num_dests_filler;
+   unsigned char *skb_net_hdr;
+   u8 *slot, *filler;
+
+   skb_net_hdr = skb_network_header(skb);
+   mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb_net_hdr;
+   num_dests_slot = ntohs(mcast_tracker->num_dests);
+
+   slot = (u8 *)mcast_tracker + sizeof(*mcast_tracker);
+
+   if (!num_dests_slot)
+   return 0;
+
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot + ETH_ALEN;
+
+   batadv_mcast_forw_tracker_for_each_dest(slot, num_dests_slot) {
+   /* find an empty slot */
+   if (!is_zero_ether_addr(slot))
+   continue;
+
+   /* keep filler ahead of slot */
+   if (filler <= slot) {
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot + ETH_ALEN;
+   }
+
+   /* find a candidate to fill the empty slot */
+   batadv_mcast_forw_tracker_for_each_dest(filler,
+   num_dests_filler) {
+   if (is_zero_ether_addr(filler))
+   continue;
+
+   ether_addr_copy(slot, filler);
+   eth_zero_addr(filler);
+   goto cont_next_slot;
+   }
+
+   /* could not find a filler, we can stop
+* - and must not advance the slot pointer!
+*/
+   if (!num_dests_filler)
+   break;
+
+cont_next_slot:
+   continue;
+   }
+
+   /* num_dests_slot is the amount of reduced destinations */
+   return num_dests_slot;
+}
+
+/**
+ * batadv_mcast_forw_shrink_align_offset() - get new alignment offset
+ * @num_dests_old: the old, to be updated amount of destination nodes
+ * @num_dests_reduce: the number of destinations that were removed
+ *
+ * Calculates the amount of potential extra alignment offset that is needed to
+ * adjust the TVLV padding after the change in destination nodes.
+ *
+ * Return:
+ * 0: If no change to padding is needed.
+ * 2: If padding needs to be removed.
+ * -2: If padding needs to be added.
+ */
+short batadv_mcast_forw_shrink_align_offset(unsigned int num_dests_old,
+   unsigned int num_dests_reduce)
+{
+   /* even amount of removed destinations -> no alignment change */
+   if (!(num_dests_reduce % 2))
+   return 0;
+
+   /* even to odd amount of destinations -> remove padding */
+   if (!(num_dests_old % 2))
+   return 2;
+
+   /* odd to even amount of destinations -> add padding */
+   return -2;
+}
+
+/**
+ * batadv_mcast_forw_shrink_update_headers() - update shrunk mc packet headers
+ * @skb: the batman-adv multicast packet to update headers of
+ * @num_dests_reduce: the number of destinations that were removed
+ *
+ * This updates any fields of a batman-adv multicast packet that are affected
+ * by the reduced number of destinations in the multicast tracket TVLV. In
+ * particular this updates:
+ *
+ * The num_dest field of the multicast tracker TVLV.
+ * The TVLV length field of the according generic TVLV header.
+ * The batman-adv multicast packet's total TVLV length field.
+ *
+ * Return: The offset in skb's tail direction a

[PATCH v5 2/3] batman-adv: mcast: implement multicast packet generation

2023-07-08 Thread Linus Lüssing
Implement the preparation of a batman-adv multicast packet and use this
under certain conditions.

For one thing this implements the capability to push a complete
batman-adv multicast packet header, including a tracker TVLV with all
originator destinations that have signaled interest in it, onto a given
ethernet frame with an IP multicast packet inside.

For another checks are implemented to determine if encapsulating a
multicast packet in this new batman-adv multicast packet type and using
it is feasible. Those checks are:

1) Have all nodes signaled that they are capable of handling the new
   batman-adv multicast packet type?
2) Do all active hard interfaces of all nodes, including us, have an MTU
   of at least 1280 bytes?
3) Does a complete multicast packet header with all its destination
   addresses fit onto the given multicast packet / ethernet frame and
   does not exceed 1280 bytes?

If all checks passed then the new batman-adv multicast packet type will
be used for transmission and distribution. Otherwise we fall back to one or
more batman-adv unicast packet transmissions, if possible. Or if not
possible we will fall back to classic flooding through a batman-adv
broadcast packet.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  |  79 +++-
 net/batman-adv/multicast.h  |  25 +-
 net/batman-adv/multicast_forw.c | 715 
 net/batman-adv/soft-interface.c |   6 +-
 net/batman-adv/types.h  |   6 +
 5 files changed, 823 insertions(+), 8 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index f2b1e523fd85..d8ddb20fd732 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1177,17 +1177,62 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_mode_by_count() - get forwarding mode by count
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast packet to check
+ * @vid: the vlan identifier
+ * @is_routable: stores whether the destination is routable
+ * @count: the number of originators the multicast packet need to be sent to
+ *
+ * For a multicast packet with multiple destination originators, checks which
+ * mode to use. For BATADV_FORW_MCAST it also encapsulates the packet with a
+ * complete batman-adv multicast header.
+ *
+ * Return:
+ * BATADV_FORW_MCAST: If all nodes have multicast packet routing
+ * capabilities and an MTU >= 1280 on all hard interfaces (including us)
+ * and the encapsulated multicast packet with all destination addresses
+ * would still fit into an 1280 bytes batman-adv multicast packet
+ * (excluding the outer ethernet frame) and we could successfully push
+ * the full batman-adv multicast packet header.
+ * BATADV_FORW_UCASTS: If the packet cannot be sent in a batman-adv
+ * multicast packet and the amount of batman-adv unicast packets needed
+ * is smaller or equal to the configured multicast fanout.
+ * BATADV_FORW_BCAST: Otherwise.
+ */
+static enum batadv_forw_mode
+batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv,
+   struct sk_buff *skb, unsigned short vid,
+   int is_routable, int count)
+{
+   unsigned int mcast_hdrlen = batadv_mcast_forw_packet_hdrlen(count);
+   u8 own_tvlv_flags = bat_priv->mcast.mla_flags.tvlv_flags;
+
+   if (!atomic_read(_priv->mcast.num_no_mc_ptype_capa) &&
+   own_tvlv_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA &&
+   skb->len + mcast_hdrlen <= IPV6_MIN_MTU &&
+   batadv_mcast_forw_push(bat_priv, skb, vid, is_routable, count))
+   return BATADV_FORW_MCAST;
+
+   if (count <= atomic_read(_priv->multicast_fanout))
+   return BATADV_FORW_UCASTS;
+
+   return BATADV_FORW_BCAST;
+}
+
 /**
  * batadv_mcast_forw_mode() - check on how to forward a multicast packet
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the multicast packet to check
+ * @vid: the vlan identifier
  * @is_routable: stores whether the destination is routable
  *
  * Return: The forwarding mode as enum batadv_forw_mode.
  */
 enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  int *is_routable)
+  unsigned short vid, int *is_routable)
 {
int ret, tt_count, ip_count, unsnoop_count, total_count;
bool is_unsnoopable = false;
@@ -1217,10 +1262,8 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, 
struct sk_buff *skb,
else if (unsnoop_count)
return BATADV_FORW_BCAST;
 
-   if (total_count <= atomic_read(_priv->multicast_fanout))
-   return BATADV_FORW_UCASTS;
-
-   return BATADV_FORW_BCAST;
+   return batadv_mc

[PATCH v5 1/3] batman-adv: mcast: implement multicast packet reception and forwarding

2023-07-08 Thread Linus Lüssing
Implement functionality to receive and forward a new TVLV capable
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

Also a new OGM multicast TVLV flag is introduced to signal to other
nodes that we are capable of handling a batman-adv multicast packet and
multicast tracker TVLV. And that all of our hard interfaces have an MTU
of at least 1280 bytes (IPv6 minimum MTU), as a simple solution for now
to avoid MTU issues while forwarding.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  45 -
 net/batman-adv/Makefile|   1 +
 net/batman-adv/main.c  |   2 +
 net/batman-adv/multicast.c |  48 +-
 net/batman-adv/multicast.h |   5 +
 net/batman-adv/multicast_forw.c| 256 +
 net/batman-adv/originator.c|   1 +
 net/batman-adv/routing.c   |  70 
 net/batman-adv/routing.h   |  11 ++
 net/batman-adv/soft-interface.c|  12 ++
 net/batman-adv/types.h |  64 
 11 files changed, 504 insertions(+), 11 deletions(-)
 create mode 100644 net/batman-adv/multicast_forw.c

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index 9204e4494b25..6e25753015df 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -116,6 +116,9 @@ enum batadv_icmp_packettype {
  * only need routable IPv4 multicast packets we signed up for explicitly
  * @BATADV_MCAST_WANT_NO_RTR6: we have no IPv6 multicast router and therefore
  * only need routable IPv6 multicast packets we signed up for explicitly
+ * @BATADV_MCAST_HAVE_MC_PTYPE_CAPA: we can parse, receive and forward
+ * batman-adv multicast packets with a multicast tracker TVLV. And all our
+ * hard interfaces have an MTU of at least 1280 bytes.
  */
 enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_UNSNOOPABLES  = 1UL << 0,
@@ -123,6 +126,7 @@ enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_IPV6  = 1UL << 2,
BATADV_MCAST_WANT_NO_RTR4   = 1UL << 3,
BATADV_MCAST_WANT_NO_RTR6   = 1UL << 4,
+   BATADV_MCAST_HAVE_MC_PTYPE_CAPA = 1UL << 5,
 };
 
 /* tt data subtypes */
@@ -174,14 +178,16 @@ enum batadv_bla_claimframe {
  * @BATADV_TVLV_TT: translation table tvlv
  * @BATADV_TVLV_ROAM: roaming advertisement tvlv
  * @BATADV_TVLV_MCAST: multicast capability tvlv
+ * @BATADV_TVLV_MCAST_TRACKER: multicast tracker tvlv
  */
 enum batadv_tvlv_type {
-   BATADV_TVLV_GW  = 0x01,
-   BATADV_TVLV_DAT = 0x02,
-   BATADV_TVLV_NC  = 0x03,
-   BATADV_TVLV_TT  = 0x04,
-   BATADV_TVLV_ROAM= 0x05,
-   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_GW  = 0x01,
+   BATADV_TVLV_DAT = 0x02,
+   BATADV_TVLV_NC  = 0x03,
+   BATADV_TVLV_TT  = 0x04,
+   BATADV_TVLV_ROAM= 0x05,
+   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_MCAST_TRACKER   = 0x07,
 };
 
 #pragma pack(2)
@@ -487,6 +493,25 @@ struct batadv_bcast_packet {
 */
 };
 
+/**
+ * struct batadv_mcast_packet - multicast packet for network payload
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the general header
+ * @ttl: time to live for this packet, part of the general header
+ * @reserved: reserved byte for alignment
+ * @tvlv_len: length of the appended tvlv buffer (in bytes)
+ */
+struct batadv_mcast_packet {
+   __u8 packet_type;
+   __u8 version;
+   __u8 ttl;
+   __u8 reserved;
+   __be16 tvlv_len;
+   /* "4 bytes boundary + 2 bytes" long to make the payload after the
+* following ethernet header again 4 bytes boundary aligned
+*/
+};
+
 /**
  * struct batadv_coded_packet - network coded packet
  * @packet_type: batman-adv packet type, part of the general header
@@ -628,6 +653,14 @@ struct batadv_tvlv_mcast_data {
__u8 reserved[3];
 };
 
+/**
+ * struct batadv_tvlv_mcast_tracker - payload of a multicast tracker tvlv
+ * @num_dests: number of subsequent destination originator MAC addresses
+ */
+struct batadv_tvlv_mcast_tracker {
+   __be16  num_dests;
+};
+
 #pragma pack()
 
 #endif /* _UAPI_LINUX_BATADV_PACKET_H_ */
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
index 3bd0760c76a2..b51d8b071b56 100644
--- a/net/batman-adv/Makefile
+++ b/net/batman-adv/Makefile
@@ -20,6 +20,7 @@ batman-adv-y += hash.o
 batman-adv-$(C

[PATCH v5 0/3] Implementation of a Stateless Multicast Packet Type

2023-07-08 Thread Linus Lüssing
[PATCH v5 0/3] Implementation of a Stateless Multicast Packet Type

Hi,

The following patchset implements a stateless, TVLV capable batman-adv
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination MAC addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

The purpose of this new packet type is to allow to forward an IP
multicast packet with less transmissions / overhead than the 
multicast-via-multiple-unicasts approach. Or to reach a lot more
destinations (currently up to 196, depending on the payload size, see 
Wiki documentation for details) than with the default multicast fanout
for the via-unicasts approach.

This will allow using applications like mDNS again in several Freifunk
communities. And with less transmissions will also make more bulky
multicast applications, like media streaming (to an assessable amount of
receivers) a lot more feasible.

This approach is way simpler than the original multicast (tracker) packet
approach we envisioned years ago. As it involves no maintenance of an
extra, state based multicast routing table. However the TVLV capability
should allow to extend things later, to split control and data plane a bit
more for instance, to further increase the number of destinations, to
further reduce overhead.

A compact overview can be found in the Wiki here, including limitations:

https://www.open-mesh.org/projects/batman-adv/wiki/Multicast-Packet-Type

Regards, Linus

---

Changelog v5:
* removed patches 1/5 + 2/5, as they were already applied
* rebased to current main branch
* changed padding behaviour:
  * now 2 bytes padding on the end of the multicast
tracker TVLV, if number of destination nodes is
even
  * as number of destination nodes might change between
initial check until after pushing them, functions
to post-adjust padding after pushing were added
* added/fixed TTL handling
* removed skb_pull() bailing from sub-functions of
  batadv_mcast_forw_push(), to only have a single
  skb_pull() to keep track of in batadv_mcast_forw_push()
  to revert the changes to the skb; instead a
  "unsigned short *tvlv_len" is passsed along in 
  batadv_mcast_.*push.*() functions to keep track of
  how many bytes were pushed
* moved + verified skb->ip_summed invalidation
* batadv_mcast_forw_shrink_tracker() xmas tree ordering
* reword batadv_mcast_forw_push_dest() "Return:" kerneldoc
* fixed spelling: outter -> outer

Changelog v4:
* PATCH 4/5:
  * add missing include for linux/types.h in multicast.h
  * add missing kerneldoc for @bat_priv in batadv_mcast_forw_push_dest()
and batadv_mcast_forw_push_tvlvs()
  * use sizeof_field(type, field) instead of sizeof(((type *)0)->field)
in batadv_mcast_forw_push_dest()
* PATCH 5/5:
  * rename num_dests_remove to num_dests_reduce in
batadv_mcast_forw_shrink_align_offse() to fix kerneldocs and for
consistency
  * fix typo in kerneldoc in batadv_mcast_forw_shrink_update_headers()
-> @num_dest_reduce -> @num_dests_reduce
  * use sizeof_field(type, field) instead of sizeof(((type *)0)->field)
in batadv_mcast_forw_shrink_align_offset()

Changelog v3:
* PATCH 1/5:
  * remove now obsolete includes
* PATCH 2/5:
  * fix batadv_tvlv_handler_register() in network-coding.c
  * add missing include for linux/skbuff.h
  * move variable declarations out of the switch case
in batadv_tvlv_call_handler()
* PATCH 3/5:
  * remove unnecessary include of multicast.h in routing.c
  * add a few missing includes to multicast_forw.c
(linux/byteorder/generic.h, linux/errno.h, linux/gfp.h, linux/stddef.h
 uapi/linux/batadv_packet.h, multicast.h)
* PATCH 4/5:
  * add missing rcu_read_unlock() in error case before returning in
batadv_mcast_forw_push_dests_list()
  * remove unnecessary include of soft-interface.h in multicast_forw.c
  * add a few missing includes to multicast_forw.c
(linux/bug.h, linux/build_bug.h, linux/limits.h, linux/rculist.h,
 linux/rcupdate.h, linux/string.h)
  * make batadv_mcast_forw_mode_by_count() static
  * fix return types in the declaration of
batadv_mcast_forw_packet_hdrlen() and batadv_mcast_forw_push()
in multicast.h
  * fix typo in commit message: "that the are capable of"
-> "that the*y* are capable of"
* PATCH 5/5:
  * make batadv_mcast_forw_shrink_pack_dests() adhere to 80 characters
per line for consistency
  * add a "continue" statement after the jump label in
batadv_mcast_forw_shrink_pack_dests() to silence the sparse error
"error: label at end of compound statement"

Changelog v2:
* Add "[PATCH v2 0/5]" prefix to title of cover letter, so that
  Patchwork can hopefully find it - no other changes



Re: forwarding works fine with 802.1ad vlans

2023-07-04 Thread Linus Lüssing
Hi pony,

Thanks for the feedback! I've added a comment to this Wiki entry,
that you should not rely on packets being filtered.

I'm not sure if this filtering is 100% intentional or just a
byproduct of the early VLAN awareness implementation. So far we
typically advertised batman-adv as "it just works/behaves like a
(virtual) switch", which usually helps people to understand what
to expect or not to expect from a layer 2 mesh routing protocol.
And typically, a switch in its default configuration would not
drop VLAN tagged frames.

There are/were plans to autodetect VLANs, I think, so that
you wouldn't need to add something like a bat0.23 manually. But so
far nobody has implemented it.

Regards, Linus


On Sun, Jul 02, 2023 at 04:33:55PM +, pony wrote:
> Hello,
> 
> In 
> https://www.open-mesh.org/projects/batman-adv/wiki/Faq#VLAN-forwarding-doesnt-work
>  it is stated that batman advanced will only forward vlan frames when it 
> knows about the vlan. However this seems only to be true for 802.1q vlans. I 
> was able to send 802.1ad tagged frames over the mesh without configuring any 
> vlans on top of the soft interface. I am using batman-adv 2022.0-openwrt-6. 
> When I try the same with 802.1q it behaves as described in the wiki page.
> This may be be problematic when people rely on batman advanced not forwarding 
> vlan tagged frames.
> 
> Kind regards,
> pony
> 
> 


Re: [PATCH 1/5] batman-adv: Start new development cycle

2023-02-02 Thread Linus Lüssing
On Mon, Jan 30, 2023 at 03:55:08PM +0100, Jiri Pirko wrote:
> Fri, Jan 27, 2023 at 11:21:29AM CET, s...@simonwunderlich.de wrote:
> >This version will contain all the (major or even only minor) changes for
> >Linux 6.3.
> >
> >The version number isn't a semantic version number with major and minor
> >information. It is just encoding the year of the expected publishing as
> >Linux -rc1 and the number of published versions this year (starting at 0).
> 
> I wonder, what is this versioning good for?

The best reason in my opinion is that it's useful to convince
ordinary people that they should update :-).

Usually when debugging reported issues one of the first things we ask
users is to provide the output of "batctl -v":

```
$ batctl -v
batctl debian-2023.0-1 [batman-adv: 2022.3]
```

If there is a very old year in there I think it's easier to tell
and convince people to try again with newer versions and to
update.

And also as a developer I find it easier to (roughly) memorize
when a feature was added by year than by kernel version number.
So I know by heart that TVLVs were added in 2014 and multicast
snooping patches and new multicast handling was added around 2019
for instance. But don't ask me which kernel version that was :D.
I'd have to look that up. So if "batctl -v" displayed a kernel
version number that would be less helpful for me.

Also makes it easier for ordinary users to look up and
compare their version with our news archive:
https://www.open-mesh.org/projects/open-mesh/wiki/News-archive

Also note that we can't do a simple kernel version to year
notation mapping in userspace in batctl. OpenWrt uses the most
recent Linux LTS release. But might feature a backport of a more
recent batman-adv which is newer than the one this stable kernel
would provide. Or people also often use Debian stable but compile
and use the latest batman-adv version with it.

Does that make sense?


Re: [PATCH v4 3/5] batman-adv: mcast: implement multicast packet reception and forwarding

2023-01-21 Thread Linus Lüssing
On Thu, Jan 19, 2023 at 01:47:25PM +0100, Simon Wunderlich wrote:
> On Tuesday, December 27, 2022 8:34:07 PM CET Linus Lüssing wrote:
> > +/**
> > + * struct batadv_tvlv_mcast_tracker - payload of a multicast tracker tvlv
> > + * @num_dests: number of subsequent destination originator MAC addresses
> > + * @align: (optional) alignment bytes to make the tracker TVLV 4 bytes
> > aligned, + * present if num_dests are even, not present if odd
> > + */
> > +struct batadv_tvlv_mcast_tracker {
> > +   __be16  num_dests;
> > +   __u8align[2];
> > +};
> > +
> The one thing which I really don't like is to have the alignment in the 
> beginning, and depending on the number of entries. Normally, such alignments 
> should be at the end of the structure so it is straight forward for a parser 
> to omit it.
> 
> My understanding is that the alignment is due to technical reasons (mac 
> address list is assembled by pushing the data to the front), perhaps to save 
> another memove/memcpy. However, the data is collected by traversing various 
> lists, and if performance would be a concern, then this data should be cached 
> and this "technicality" wouldn't be needed either.

The technical reason was to have the payload data from the IP
header 4 bytes aligned. To allow efficient access in there once the
payload is decapsulated.

> 
> So please, skip the alignment in the front and have it in the back.

The reasons to put the aligment at the front are/were the following
two:

1) We do keep a count of receiving nodes, however it might change
while we are pushing destinations. So it is at the moment easier
to push the padding to the front, when we know exactly how many
destinations we have added to the packet. As discussed offline, I
guess that is what you were refering to above.

2) Alignment changes during routing everytime a router removes an
odd number of destinations from the tracker TVLV. Changing
alignment more to the front would in theory less memory movements.
Example for an ideal case:

[MC-HDR][pad][dest1][dest2]...[dest100][PAYLOAD]
-> dest1 is deleted
[MC-HDR][pad][0][dest2]...[dest100][PAYLOAD]
-> move only MC-HDR:
[MC-HDR][dest2]...[dest100][PAYLOAD]
 
If the alignment were behind dest100 then everything would need to
be moved.


Even though it's unconventional to have the padding in the front,
I found the idea quite tempting and useful to have the padding in
front, saves quite a bit of code and potential bugs I would hope :D.
And would hopefully (potentially allow to) make the packet routing
a bit faster. So from a "purely technical" point-of-view it seemed
advantageous to me :D.

Another idea would be to have the padding at the end by adding and
keeping a zero-MAC destination entry if the number of destinations
were otherwise even. Disadvantage: Might waste 4 more bytes than
necessary.

> 
> The rest of the packet format looks good from what I've seen.

Thanks for having a look at it!

Regards, Linus


Re: [PATCH v4 3/5] batman-adv: mcast: implement multicast packet reception and forwarding

2023-01-16 Thread Linus Lüssing
On Sun, Jan 15, 2023 at 06:56:37PM +0100, Sven Eckelmann wrote:
> [...]
> > +static void
> > +batadv_mcast_forw_scrub_dests(struct batadv_priv *bat_priv,
> > + struct batadv_neigh_node *comp_neigh, u8 *dest,
> > + u8 *next_dest, u16 num_dests)
> > +{
> > +   struct batadv_neigh_node *next_neigh;
> > +
> > +   /* skip first entry, this is what we are comparing with */
> > +   eth_zero_addr(dest);
> > +   dest += ETH_ALEN;
> > +   next_dest += ETH_ALEN;
> > +   num_dests--;
> > +
> > +   batadv_mcast_forw_tracker_for_each_dest(next_dest, num_dests) {
> > +   if (is_zero_ether_addr(next_dest))
> > +   goto scrub_next;
> > +
> > +   if (is_multicast_ether_addr(next_dest)) {
> > +   eth_zero_addr(dest);
> > +   eth_zero_addr(next_dest);
> > +   goto scrub_next;
> > +   }
> > +
> > +   next_neigh = batadv_mcast_forw_orig_to_neigh(bat_priv,
> > +next_dest);
> > +   if (!next_neigh) {
> > +   eth_zero_addr(next_dest);
> 
> Why is the original skb not touched in this case?
> 
> It might not be a problem because you are also doing the 
> batadv_mcast_forw_orig_to_neigh check in batadv_mcast_forw_packet. But I was 
> just wondering about it

I actually thought the same at some point, to potentially reduce the
number of neighbor node lookups, and tried it. And then
realized that it can break local reception. The destination
address might be our own one and then the neighbor node lookup
will return NULL, too.

So instead of adding another batadv_is_my_mac() check in yet
another place and branching here in scrub_dests(), I thought I'd keep
it simple.

I could also add these two lines in scrub_dests(), the check and zeroing,
I'm just not quite sure if we would overall gain something with it, as
batadv_is_my_mac() can be a bit expensive at the moment when there are
many interfaces?

> 
> 
> Btw. it could happen that you send out a packet with zero destinations in the 
> TVLV because the neighbor disappeared between the 
> batadv_mcast_forw_orig_to_neigh in batadv_mcast_forw_packet and in 
> batadv_mcast_forw_scrub_dests

Ah good point. Hm, the protocol should be robust enough on
the receiver side to handle it. And it should overall happen very rarely.
I'm indifferent to adding two more lines of code to check that.

> 
> Kind regards,
>   Sven



[PATCH v4 5/5] batman-adv: mcast: shrink tracker packet after scrubbing

2022-12-27 Thread Linus Lüssing
Remove all zero MAC address entries (00:00:00:00:00:00) from a multicast
packet's tracker TVLV before transmitting it and update all headers
accordingly. This way, instead of keeping the multicast packet at a
constant size throughout its journey through the mesh, it will become
more lightweight, smaller with every interested receiver on the way and
on each splitting intersection. Which can save some valuable bandwidth.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast_forw.c | 212 
 1 file changed, 212 insertions(+)

diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c
index 8414bd13f6e9..1f9e645a069d 100644
--- a/net/batman-adv/multicast_forw.c
+++ b/net/batman-adv/multicast_forw.c
@@ -35,6 +35,9 @@
 #define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) \
for (; num_dests; num_dests--, (dest) += ETH_ALEN)
 
+#define batadv_mcast_forw_tracker_for_each_dest_rev(dest, num_dests) \
+   for (; num_dests; num_dests--, (dest) -= ETH_ALEN)
+
 /**
  * batadv_mcast_forw_orig_entry() - get orig_node from an hlist node
  * @node: the hlist node to get the orig_node from
@@ -531,6 +534,214 @@ batadv_mcast_forw_scrub_dests(struct batadv_priv 
*bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_shrink_align_offset() - calculate alignment offset
+ * @num_dests_old: the number of destinations the tracker TVLV had originally
+ * @num_dests_reduce: the number of destinations that are going to be removed
+ *
+ * The multicast tracker TVLV has 2 alignment bytes if the number of 
destination
+ * entries are even, to make this TVLV 4 byte aligned to make the encapsulated
+ * IP packet 4 byte aligned. And no alignment bytes in the tracker TVLV if the
+ * number of destinations is odd.
+ *
+ * This calculates if the 2 alignment bytes in the multicast tracker TVLV need
+ * to be added, removed or left unchanged.
+ *
+ * Return: The number of extra offset in skb tail direction to compensate for
+ * alignment. Will be -2, 0 or +2.
+ */
+static int batadv_mcast_forw_shrink_align_offset(unsigned int num_dests_old,
+unsigned int num_dests_reduce)
+{
+   int ret = sizeof_field(struct batadv_tvlv_mcast_tracker, align);
+
+   /* no change in padding */
+   if (!(num_dests_reduce % 2))
+   return 0;
+
+   /* even had padding, remove it, increase the offset */
+   if (!(num_dests_old % 2))
+   return ret;
+   /* odd had no padding, add it, decrease the offset */
+   else
+   return -ret;
+}
+
+/**
+ * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV
+ * @skb: the batman-adv multicast packet to compact destinations in
+ *
+ * Compacts the originator destination MAC addresses in the multicast tracker
+ * TVLV of the given multicast packet. This is done by moving all non-zero
+ * MAC addresses in direction of the skb tail and all zero MAC addresses in skb
+ * head direction, within the multicast tracker TVLV.
+ *
+ * Return: The number of consecutive zero MAC address destinations which are
+ * now at the front within the multicast tracker TVLV.
+ */
+static int batadv_mcast_forw_shrink_pack_dests(struct sk_buff *skb)
+{
+   struct batadv_tvlv_mcast_tracker *mcast_tracker;
+   u16 num_dests_slot, num_dests_filler;
+   unsigned int tracker_hdrlen;
+   unsigned char *skb_net_hdr;
+   u8 *slot, *filler;
+
+   skb_net_hdr = skb_network_header(skb);
+   mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb_net_hdr;
+   num_dests_slot = ntohs(mcast_tracker->num_dests);
+
+   tracker_hdrlen = batadv_mcast_forw_tracker_hdrlen(num_dests_slot);
+   slot = (u8 *)mcast_tracker + tracker_hdrlen;
+   slot += ETH_ALEN * (num_dests_slot - 1);
+
+   if (!num_dests_slot)
+   return 0;
+
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot - ETH_ALEN;
+
+   batadv_mcast_forw_tracker_for_each_dest_rev(slot, num_dests_slot) {
+   /* find an empty slot */
+   if (!is_zero_ether_addr(slot))
+   continue;
+
+   /* keep filler ahead of slot */
+   if (filler >= slot) {
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot - ETH_ALEN;
+   }
+
+   /* find a candidate to fill the empty slot */
+   batadv_mcast_forw_tracker_for_each_dest_rev(filler,
+   num_dests_filler) {
+   if (is_zero_ether_addr(filler))
+   continue;
+
+   ether_addr_copy(slot, filler);
+   eth_zero_addr(filler);
+   goto cont_next_slot;
+   }
+
+   /* could not find a filler, we can stop
+* - and must not advance the slot p

[PATCH v4 4/5] batman-adv: mcast: implement multicast packet generation

2022-12-27 Thread Linus Lüssing
Implement the preparation of a batman-adv multicast packet and use this
under certain conditions.

For one thing this implements the capability to push a complete
batman-adv multicast packet header, including a tracker TVLV with all
originator destinations that have signaled interest in it, onto a given
ethernet frame with an IP multicast packet inside.

For another checks are implemented to determine if encapsulating a
multicast packet in this new batman-adv multicast packet type and using
it is feasible. Those checks are:

1) Have all nodes signaled that they are capable of handling the new
   batman-adv multicast packet type?
2) Do all active hard interfaces of all nodes, including us, have an MTU
   of at least 1280 bytes?
3) Does a complete multicast packet header with all its destination
   addresses fit onto the given multicast packet / ethernet frame and
   does not exceed 1280 bytes?

If all checks passed then the new batman-adv multicast packet type will
be used for transmission and distribution. Otherwise we fall back to one or
more batman-adv unicast packet transmissions, if possible. Or if not
possible we will fall back to classic flooding through a batman-adv
broadcast packet.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  |  79 -
 net/batman-adv/multicast.h  |  25 +-
 net/batman-adv/multicast_forw.c | 513 
 net/batman-adv/soft-interface.c |   6 +-
 net/batman-adv/types.h  |   6 +
 5 files changed, 621 insertions(+), 8 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index f2b1e523fd85..d74cb96896e9 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1177,17 +1177,62 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_mode_by_count() - get forwarding mode by count
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast packet to check
+ * @vid: the vlan identifier
+ * @is_routable: stores whether the destination is routable
+ * @count: the number of originators the multicast packet need to be sent to
+ *
+ * For a multicast packet with multiple destination originators, checks which
+ * mode to use. For BATADV_FORW_MCAST it also encapsulates the packet with a
+ * complete batman-adv multicast header.
+ *
+ * Return:
+ * BATADV_FORW_MCAST: If all nodes have multicast packet routing
+ * capabilities and an MTU >= 1280 on all hard interfaces (including us)
+ * and the encapsulated multicast packet with all destination addresses
+ * would still fit into an 1280 bytes batman-adv multicast packet
+ * (excluding the outter ethernet frame) and we could successfully push
+ * the full batman-adv multicast packet header.
+ * BATADV_FORW_UCASTS: If the packet cannot be sent in a batman-adv
+ * multicast packet and the amount of batman-adv unicast packets needed
+ * is smaller or equal to the configured multicast fanout.
+ * BATADV_FORW_BCAST: Otherwise.
+ */
+static enum batadv_forw_mode
+batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv,
+   struct sk_buff *skb, unsigned short vid,
+   int is_routable, int count)
+{
+   unsigned int mcast_hdrlen = batadv_mcast_forw_packet_hdrlen(count);
+   u8 own_tvlv_flags = bat_priv->mcast.mla_flags.tvlv_flags;
+
+   if (!atomic_read(_priv->mcast.num_no_mc_ptype_capa) &&
+   own_tvlv_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA &&
+   skb->len + mcast_hdrlen <= IPV6_MIN_MTU &&
+   batadv_mcast_forw_push(bat_priv, skb, vid, is_routable))
+   return BATADV_FORW_MCAST;
+
+   if (count <= atomic_read(_priv->multicast_fanout))
+   return BATADV_FORW_UCASTS;
+
+   return BATADV_FORW_BCAST;
+}
+
 /**
  * batadv_mcast_forw_mode() - check on how to forward a multicast packet
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the multicast packet to check
+ * @vid: the vlan identifier
  * @is_routable: stores whether the destination is routable
  *
  * Return: The forwarding mode as enum batadv_forw_mode.
  */
 enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  int *is_routable)
+  unsigned short vid, int *is_routable)
 {
int ret, tt_count, ip_count, unsnoop_count, total_count;
bool is_unsnoopable = false;
@@ -1217,10 +1262,8 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, 
struct sk_buff *skb,
else if (unsnoop_count)
return BATADV_FORW_BCAST;
 
-   if (total_count <= atomic_read(_priv->multicast_fanout))
-   return BATADV_FORW_UCASTS;
-
-   return BATADV_FORW_BCAST;
+   return batadv_mcast_forw_mode_by_count(bat_priv, skb, vid, *is_routable,
+  

[PATCH v4 3/5] batman-adv: mcast: implement multicast packet reception and forwarding

2022-12-27 Thread Linus Lüssing
Implement functionality to receive and forward a new TVLV capable
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

Also a new OGM multicast TVLV flag is introduced to signal to other
nodes that we are capable of handling a batman-adv multicast packet and
multicast tracker TVLV. And that all of our hard interfaces have an MTU
of at least 1280 bytes (IPv6 minimum MTU), as a simple solution for now
to avoid MTU issues while forwarding.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  48 -
 net/batman-adv/Makefile|   1 +
 net/batman-adv/main.c  |   2 +
 net/batman-adv/multicast.c |  48 -
 net/batman-adv/multicast.h |   5 +
 net/batman-adv/multicast_forw.c| 274 +
 net/batman-adv/originator.c|   1 +
 net/batman-adv/routing.c   |  68 +++
 net/batman-adv/routing.h   |  11 ++
 net/batman-adv/soft-interface.c|  12 ++
 net/batman-adv/types.h |  64 +++
 11 files changed, 523 insertions(+), 11 deletions(-)
 create mode 100644 net/batman-adv/multicast_forw.c

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index 9204e4494b25..77021519cd26 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -116,6 +116,9 @@ enum batadv_icmp_packettype {
  * only need routable IPv4 multicast packets we signed up for explicitly
  * @BATADV_MCAST_WANT_NO_RTR6: we have no IPv6 multicast router and therefore
  * only need routable IPv6 multicast packets we signed up for explicitly
+ * @BATADV_MCAST_HAVE_MC_PTYPE_CAPA: we can parse, receive and forward
+ * batman-adv multicast packets with a multicast tracker TVLV. And all our
+ * hard interfaces have an MTU of at least 1280 bytes.
  */
 enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_UNSNOOPABLES  = 1UL << 0,
@@ -123,6 +126,7 @@ enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_IPV6  = 1UL << 2,
BATADV_MCAST_WANT_NO_RTR4   = 1UL << 3,
BATADV_MCAST_WANT_NO_RTR6   = 1UL << 4,
+   BATADV_MCAST_HAVE_MC_PTYPE_CAPA = 1UL << 5,
 };
 
 /* tt data subtypes */
@@ -174,14 +178,16 @@ enum batadv_bla_claimframe {
  * @BATADV_TVLV_TT: translation table tvlv
  * @BATADV_TVLV_ROAM: roaming advertisement tvlv
  * @BATADV_TVLV_MCAST: multicast capability tvlv
+ * @BATADV_TVLV_MCAST_TRACKER: multicast tracker tvlv
  */
 enum batadv_tvlv_type {
-   BATADV_TVLV_GW  = 0x01,
-   BATADV_TVLV_DAT = 0x02,
-   BATADV_TVLV_NC  = 0x03,
-   BATADV_TVLV_TT  = 0x04,
-   BATADV_TVLV_ROAM= 0x05,
-   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_GW  = 0x01,
+   BATADV_TVLV_DAT = 0x02,
+   BATADV_TVLV_NC  = 0x03,
+   BATADV_TVLV_TT  = 0x04,
+   BATADV_TVLV_ROAM= 0x05,
+   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_MCAST_TRACKER   = 0x07,
 };
 
 #pragma pack(2)
@@ -487,6 +493,25 @@ struct batadv_bcast_packet {
 */
 };
 
+/**
+ * struct batadv_mcast_packet - multicast packet for network payload
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the general header
+ * @ttl: time to live for this packet, part of the general header
+ * @reserved: reserved byte for alignment
+ * @tvlv_len: length of the appended tvlv buffer (in bytes)
+ */
+struct batadv_mcast_packet {
+   __u8 packet_type;
+   __u8 version;
+   __u8 ttl;
+   __u8 reserved;
+   __be16 tvlv_len;
+   /* "4 bytes boundary + 2 bytes" long to make the payload after the
+* following ethernet header again 4 bytes boundary aligned
+*/
+};
+
 /**
  * struct batadv_coded_packet - network coded packet
  * @packet_type: batman-adv packet type, part of the general header
@@ -628,6 +653,17 @@ struct batadv_tvlv_mcast_data {
__u8 reserved[3];
 };
 
+/**
+ * struct batadv_tvlv_mcast_tracker - payload of a multicast tracker tvlv
+ * @num_dests: number of subsequent destination originator MAC addresses
+ * @align: (optional) alignment bytes to make the tracker TVLV 4 bytes aligned,
+ * present if num_dests are even, not present if odd
+ */
+struct batadv_tvlv_mcast_tracker {
+   __be16  num_dests;
+   __u8align[2];
+};
+
 #pragma pack()
 
 #endif /* _UAPI_LINUX_BATADV_PACKET_H_ */
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile

[PATCH v4 2/5] batman-adv: tvlv: prepare for tvlv enabled multicast packet type

2022-12-27 Thread Linus Lüssing
Prepare TVLV infrastructure for more packet types, in particular the
upcoming batman-adv multicast packet type.

For that swap the OGM vs. unicast-tvlv packet boolean indicator to an
explicit unsigned integer packet type variable. And provide the skb
to a call to batadv_tvlv_containers_process(), as later the multicast
packet's TVLV handler will need to have access not only to the TVLV but
the full skb for forwarding. Forwarding will be invoked from the
multicast packet's TVLVs' contents later.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  2 +
 net/batman-adv/bat_v_ogm.c |  4 +-
 net/batman-adv/distributed-arp-table.c |  2 +-
 net/batman-adv/gateway_common.c|  2 +-
 net/batman-adv/multicast.c |  2 +-
 net/batman-adv/network-coding.c|  2 +-
 net/batman-adv/routing.c   |  7 ++-
 net/batman-adv/translation-table.c |  4 +-
 net/batman-adv/tvlv.c  | 71 ++
 net/batman-adv/tvlv.h  |  9 ++--
 net/batman-adv/types.h |  6 +++
 11 files changed, 74 insertions(+), 37 deletions(-)

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index ea4692c339ce..9204e4494b25 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -26,6 +26,7 @@
  * @BATADV_CODED: network coded packets
  * @BATADV_ELP: echo location packets for B.A.T.M.A.N. V
  * @BATADV_OGM2: originator messages for B.A.T.M.A.N. V
+ * @BATADV_MCAST: multicast packet with multiple destination addresses
  *
  * @BATADV_UNICAST: unicast packets carrying unicast payload traffic
  * @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original
@@ -42,6 +43,7 @@ enum batadv_packettype {
BATADV_CODED= 0x02,
BATADV_ELP  = 0x03,
BATADV_OGM2 = 0x04,
+   BATADV_MCAST= 0x05,
/* 0x40 - 0x7f: unicast */
 #define BATADV_UNICAST_MIN 0x40
BATADV_UNICAST  = 0x40,
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
index 033639df96d8..296fcff487bc 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -800,8 +800,8 @@ batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
 
/* only unknown & newer OGMs contain TVLVs we are interested in */
if (seqno_age > 0 && if_outgoing == BATADV_IF_DEFAULT)
-   batadv_tvlv_containers_process(bat_priv, true, orig_node,
-  NULL, NULL,
+   batadv_tvlv_containers_process(bat_priv, BATADV_OGM2, orig_node,
+  NULL,
   (unsigned char *)(ogm2 + 1),
   ntohs(ogm2->tvlv_len));
 
diff --git a/net/batman-adv/distributed-arp-table.c 
b/net/batman-adv/distributed-arp-table.c
index fefb51a5f606..6968e55eb971 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -822,7 +822,7 @@ int batadv_dat_init(struct batadv_priv *bat_priv)
batadv_dat_start_timer(bat_priv);
 
batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1,
-NULL, BATADV_TVLV_DAT, 1,
+NULL, NULL, BATADV_TVLV_DAT, 1,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
batadv_dat_tvlv_container_update(bat_priv);
return 0;
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c
index 9349c76f30c5..6a964a773f57 100644
--- a/net/batman-adv/gateway_common.c
+++ b/net/batman-adv/gateway_common.c
@@ -259,7 +259,7 @@ void batadv_gw_init(struct batadv_priv *bat_priv)
atomic_set(_priv->gw.sel_class, 1);
 
batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1,
-NULL, BATADV_TVLV_GW, 1,
+NULL, NULL, BATADV_TVLV_GW, 1,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
 }
 
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 505f230dc49e..27511a063311 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1826,7 +1826,7 @@ static void batadv_mcast_tvlv_ogm_handler(struct 
batadv_priv *bat_priv,
 void batadv_mcast_init(struct batadv_priv *bat_priv)
 {
batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
-NULL, BATADV_TVLV_MCAST, 2,
+NULL, NULL, BATADV_TVLV_MCAST, 2,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
 
INIT_DELAYED_WORK(_priv->mcast.work, batadv_mcast_mla_update);
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c
index 5f4aeeb60dc4..82ef5cff151f

[PATCH v4 0/5] Implementation of a Stateless Multicast Packet Type

2022-12-27 Thread Linus Lüssing
Hi,

The following patchset implements a stateless, TVLV capable batman-adv
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination MAC addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

The purpose of this new packet type is to allow to forward an IP
multicast packet with less transmissions / overhead than the
multicast-via-multiple-unicasts approach. Or to reach a lot more
destinations (currently up to 196, depending on the payload size, see
Wiki documentation for details) than with the default multicast fanout
for the via-unicasts approach.

This will allow using applications like mDNS again in several Freifunk
communities. And with less transmissions will also make more bulky
multicast applications, like media streaming (to an assessable amount of
receivers) a lot more feasible.

This approach is way simpler than the original multicast (tracker) packet
approach we envisioned years ago. As it involves no maintenance of an
extra, state based multicast routing table. However the TVLV capability
should allow to extend things later, to split control and data plane a bit
more for instance, to further increase the number of destinations, to
further reduce overhead.

A compact overview can be found in the Wiki here, including limitations:

https://www.open-mesh.org/projects/batman-adv/wiki/Multicast-Packet-Type

Regards, Linus

___

Changelog v4:
* PATCH 4/5:
  * add missing include for linux/types.h in multicast.h
  * add missing kerneldoc for @bat_priv in batadv_mcast_forw_push_dest()
and batadv_mcast_forw_push_tvlvs()
  * use sizeof_field(type, field) instead of sizeof(((type *)0)->field)
in batadv_mcast_forw_push_dest()
* PATCH 5/5:
  * rename num_dests_remove to num_dests_reduce in
batadv_mcast_forw_shrink_align_offse() to fix kerneldocs and for
consistency 
  * fix typo in kerneldoc in batadv_mcast_forw_shrink_update_headers()
-> @num_dest_reduce -> @num_dests_reduce 
  * use sizeof_field(type, field) instead of sizeof(((type *)0)->field)
in batadv_mcast_forw_shrink_align_offset()

Changelog v3:
* PATCH 1/5:
  * remove now obsolete includes
* PATCH 2/5:
  * fix batadv_tvlv_handler_register() in network-coding.c
  * add missing include for linux/skbuff.h
  * move variable declarations out of the switch case
in batadv_tvlv_call_handler()
* PATCH 3/5:
  * remove unnecessary include of multicast.h in routing.c
  * add a few missing includes to multicast_forw.c
(linux/byteorder/generic.h, linux/errno.h, linux/gfp.h, linux/stddef.h
 uapi/linux/batadv_packet.h, multicast.h)
* PATCH 4/5:
  * add missing rcu_read_unlock() in error case before returning in
batadv_mcast_forw_push_dests_list()
  * remove unnecessary include of soft-interface.h in multicast_forw.c
  * add a few missing includes to multicast_forw.c
(linux/bug.h, linux/build_bug.h, linux/limits.h, linux/rculist.h,
 linux/rcupdate.h, linux/string.h)
  * make batadv_mcast_forw_mode_by_count() static
  * fix return types in the declaration of
batadv_mcast_forw_packet_hdrlen() and batadv_mcast_forw_push()
in multicast.h
  * fix typo in commit message: "that the are capable of"
-> "that the*y* are capable of"
* PATCH 5/5:
  * make batadv_mcast_forw_shrink_pack_dests() adhere to 80 characters
per line for consistency
  * add a "continue" statement after the jump label in
batadv_mcast_forw_shrink_pack_dests() to silence the sparse error
"error: label at end of compound statement"

Changelog v2:
* Add "[PATCH v2 0/5]" prefix to title of cover letter, so that
  Patchwork can hopefully find it - no other changes



[PATCH v4 1/5] batman-adv: mcast: remove now redundant single ucast forwarding

2022-12-27 Thread Linus Lüssing
The multicast code to send a multicast packet via multiple batman-adv
unicast packets is not only capable of sending to multiple but also to a
single node. Therefore we can safely remove the old, specialized, now
redundant multicast-to-single-unicast code.

The only functional change of this simplification is that the edge case
of allowing a multicast packet with an unsnoopable destination address
(224.0.0.0/24 or ff02::1) where only a single node has signaled interest
in it via the batman-adv want-all-unsnoopables multicast flag is now
transmitted via a batman-adv broadcast instead of a batman-adv unicast
packet. Maintaining this edge case feature does not seem worth the extra
lines of code and people should just not expect to be able to snoop and
optimize such unsnoopable multicast addresses when bridges are involved.

While at it also renaming a few items in the batadv_forw_mode enum to
prepare for the new batman-adv multicast packet type.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  | 249 ++--
 net/batman-adv/multicast.h  |  38 +
 net/batman-adv/soft-interface.c |  26 ++--
 3 files changed, 33 insertions(+), 280 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 34897a15ad9d..505f230dc49e 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -26,7 +26,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -1144,223 +1143,20 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
-/**
- * batadv_mcast_forw_tt_node_get() - get a multicast tt node
- * @bat_priv: the bat priv with all the soft interface information
- * @ethhdr: the ether header containing the multicast destination
- *
- * Return: an orig_node matching the multicast address provided by ethhdr
- * via a translation table lookup. This increases the returned nodes refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv,
- struct ethhdr *ethhdr)
-{
-   return batadv_transtable_search(bat_priv, NULL, ethhdr->h_dest,
-   BATADV_NO_FLAGS);
-}
-
-/**
- * batadv_mcast_forw_ipv4_node_get() - get a node with an ipv4 flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 flag set and
- * increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv)
-{
-   struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
-
-   rcu_read_lock();
-   hlist_for_each_entry_rcu(tmp_orig_node,
-_priv->mcast.want_all_ipv4_list,
-mcast_want_all_ipv4_node) {
-   if (!kref_get_unless_zero(_orig_node->refcount))
-   continue;
-
-   orig_node = tmp_orig_node;
-   break;
-   }
-   rcu_read_unlock();
-
-   return orig_node;
-}
-
-/**
- * batadv_mcast_forw_ipv6_node_get() - get a node with an ipv6 flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV6 flag set
- * and increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv)
-{
-   struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
-
-   rcu_read_lock();
-   hlist_for_each_entry_rcu(tmp_orig_node,
-_priv->mcast.want_all_ipv6_list,
-mcast_want_all_ipv6_node) {
-   if (!kref_get_unless_zero(_orig_node->refcount))
-   continue;
-
-   orig_node = tmp_orig_node;
-   break;
-   }
-   rcu_read_unlock();
-
-   return orig_node;
-}
-
-/**
- * batadv_mcast_forw_ip_node_get() - get a node with an ipv4/ipv6 flag
- * @bat_priv: the bat priv with all the soft interface information
- * @ethhdr: an ethernet header to determine the protocol family from
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 or
- * BATADV_MCAST_WANT_ALL_IPV6 flag, depending on the provided ethhdr, sets and
- * increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ip_node_get(struct batadv_priv *bat_priv,
- struct ethhdr *ethhdr)
-{
-   switch (ntohs(ethhdr->h_proto)) {
-   case ETH_P_IP:
-   return batadv_mcast_forw_ipv4_node_get(bat_priv);
-   case ETH_P_IPV6:
-   return batadv_mcast_forw_ipv6_node_get(bat_priv);
-   default:
-   /* we shouldn't be here... */
-   return NULL;
-   }
-}
-
-/**
- * batadv_mcast_forw_unsnoop_node_get() - get a node with an unsnoopable flag
- * @bat_priv: the bat priv with all 

[PATCH] build_test: don't warn about "Macro argument reuse" in multicast_forw.c

2022-12-27 Thread Linus Lüssing
It's tricky to avoid reusing an argument in a for-each like macro. This is
to silence the following warning:

  CHECK: Macro argument reuse 'num_dests' - possible side-effects?
  #789: FILE: net/batman-adv/multicast_forw.c:35:
  +#define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) \
  + for (; num_dests; num_dests--, (dest) += ETH_ALEN)

  CHECK: Macro argument reuse 'num_dests' - possible side-effects?
  #792: FILE: net/batman-adv/multicast_forw.c:38:
  +#define batadv_mcast_forw_tracker_for_each_dest_rev(dest, num_dests) \
  + for (; num_dests; num_dests--, (dest) -= ETH_ALEN)

Later, once < 5.18 is out of our compat range we can rely on C99 syntax
and use variable declarations inside a for loop, readd the check and
rewrite the macro to something like this:

  #define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests)\
  for (typeof(num_dests) __batadv_forw_num_dests = num_dests; \
   *__batadv_forw_num_dests;  \
   (*__batadv_forw_num_dests)--, (dest) += ETH_ALEN)

Signed-off-by: Linus Lüssing 
---
 checkstuff.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/checkstuff.sh b/checkstuff.sh
index 207652ce4fbe..be49709dcb3b 100755
--- a/checkstuff.sh
+++ b/checkstuff.sh
@@ -191,7 +191,7 @@ test_checkpatch()
continue
fi
 
-   if [ "${fname}" = "log.h" ]; then
+   if [ "${fname}" = "log.h" -o "${fname}" = "multicast_forw.c" ]; 
then
cp_extra_params="${cp_extra_params} --ignore 
MACRO_ARG_REUSE"
fi
 
-- 
2.39.0


Re: [PATCH v3 3/5] batman-adv: mcast: implement multicast packet reception and forwarding

2022-12-27 Thread Linus Lüssing
On Tue, Dec 27, 2022 at 10:07:36AM +0100, Sven Eckelmann wrote:
> ecsv/pu: checkpatch ./net/batman-adv/multicast_forw.c
> -
> 
> CHECK: Macro argument reuse 'num_dests' - possible side-effects?
> #25: FILE: ./net/batman-adv/multicast_forw.c:25:
> +#define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) \
> +   for (; num_dests; num_dests--, (dest) += ETH_ALEN)
> 
> total: 0 errors, 0 warnings, 1 checks, 274 lines checked
> 

For this I'm not quite sure how to best silence this. I tried
the workaround of passing num_dests as a pointer and dereferencing
it inside the macro:

#define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) \
for (; (*(num_dests)); (*(num_dests))--, (dest) += ETH_ALEN)

So just like you'd do if you would want intentional side-effects with
a normal function. But seems like checkpatch does not recoginze it.

Also all the other for_each macros in the kernel code have
side-effects, as far as I know?

Or would you have another idea?


[PATCH v3 5/5] batman-adv: mcast: shrink tracker packet after scrubbing

2022-12-26 Thread Linus Lüssing
Remove all zero MAC address entries (00:00:00:00:00:00) from a multicast
packet's tracker TVLV before transmitting it and update all headers
accordingly. This way, instead of keeping the multicast packet at a
constant size throughout its journey through the mesh, it will become
more lightweight, smaller with every interested receiver on the way and
on each splitting intersection. Which can save some valuable bandwidth.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast_forw.c | 212 
 1 file changed, 212 insertions(+)

diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c
index 9637c8fa4577..af4a7fd61352 100644
--- a/net/batman-adv/multicast_forw.c
+++ b/net/batman-adv/multicast_forw.c
@@ -35,6 +35,9 @@
 #define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) \
for (; num_dests; num_dests--, (dest) += ETH_ALEN)
 
+#define batadv_mcast_forw_tracker_for_each_dest_rev(dest, num_dests) \
+   for (; num_dests; num_dests--, (dest) -= ETH_ALEN)
+
 /**
  * batadv_mcast_forw_orig_entry() - get orig_node from an hlist node
  * @node: the hlist node to get the orig_node from
@@ -529,6 +532,214 @@ batadv_mcast_forw_scrub_dests(struct batadv_priv 
*bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_shrink_align_offset() - calculate alignment offset
+ * @num_dests_old: the number of destinations the tracker TVLV had originally
+ * @num_dests_reduce: the number of destinations that are going to be removed
+ *
+ * The multicast tracker TVLV has 2 alignment bytes if the number of 
destination
+ * entries are even, to make this TVLV 4 byte aligned to make the encapsulated
+ * IP packet 4 byte aligned. And no alignment bytes in the tracker TVLV if the
+ * number of destinations is odd.
+ *
+ * This calculates if the 2 alignment bytes in the multicast tracker TVLV need
+ * to be added, removed or left unchanged.
+ *
+ * Return: The number of extra offset in skb tail direction to compensate for
+ * alignment. Will be -2, 0 or +2.
+ */
+static int batadv_mcast_forw_shrink_align_offset(unsigned int num_dests_old,
+unsigned int num_dests_remove)
+{
+   int ret = sizeof(((struct batadv_tvlv_mcast_tracker *)0)->align);
+
+   /* no change in padding */
+   if (!(num_dests_remove % 2))
+   return 0;
+
+   /* even had padding, remove it, increase the offset */
+   if (!(num_dests_old % 2))
+   return ret;
+   /* odd had no padding, add it, decrease the offset */
+   else
+   return -ret;
+}
+
+/**
+ * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV
+ * @skb: the batman-adv multicast packet to compact destinations in
+ *
+ * Compacts the originator destination MAC addresses in the multicast tracker
+ * TVLV of the given multicast packet. This is done by moving all non-zero
+ * MAC addresses in direction of the skb tail and all zero MAC addresses in skb
+ * head direction, within the multicast tracker TVLV.
+ *
+ * Return: The number of consecutive zero MAC address destinations which are
+ * now at the front within the multicast tracker TVLV.
+ */
+static int batadv_mcast_forw_shrink_pack_dests(struct sk_buff *skb)
+{
+   struct batadv_tvlv_mcast_tracker *mcast_tracker;
+   u16 num_dests_slot, num_dests_filler;
+   unsigned int tracker_hdrlen;
+   unsigned char *skb_net_hdr;
+   u8 *slot, *filler;
+
+   skb_net_hdr = skb_network_header(skb);
+   mcast_tracker = (struct batadv_tvlv_mcast_tracker *)skb_net_hdr;
+   num_dests_slot = ntohs(mcast_tracker->num_dests);
+
+   tracker_hdrlen = batadv_mcast_forw_tracker_hdrlen(num_dests_slot);
+   slot = (u8 *)mcast_tracker + tracker_hdrlen;
+   slot += ETH_ALEN * (num_dests_slot - 1);
+
+   if (!num_dests_slot)
+   return 0;
+
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot - ETH_ALEN;
+
+   batadv_mcast_forw_tracker_for_each_dest_rev(slot, num_dests_slot) {
+   /* find an empty slot */
+   if (!is_zero_ether_addr(slot))
+   continue;
+
+   /* keep filler ahead of slot */
+   if (filler >= slot) {
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot - ETH_ALEN;
+   }
+
+   /* find a candidate to fill the empty slot */
+   batadv_mcast_forw_tracker_for_each_dest_rev(filler,
+   num_dests_filler) {
+   if (is_zero_ether_addr(filler))
+   continue;
+
+   ether_addr_copy(slot, filler);
+   eth_zero_addr(filler);
+   goto cont_next_slot;
+   }
+
+   /* could not find a filler, we can stop
+* - and must not advance the slo

[PATCH v3 4/5] batman-adv: mcast: implement multicast packet generation

2022-12-26 Thread Linus Lüssing
Implement the preparation of a batman-adv multicast packet and use this
under certain conditions.

For one thing this implements the capability to push a complete
batman-adv multicast packet header, including a tracker TVLV with all
originator destinations that have signaled interest in it, onto a given
ethernet frame with an IP multicast packet inside.

For another checks are implemented to determine if encapsulating a
multicast packet in this new batman-adv multicast packet type and using
it is feasible. Those checks are:

1) Have all nodes signaled that they are capable of handling the new
   batman-adv multicast packet type?
2) Do all active hard interfaces of all nodes, including us, have an MTU
   of at least 1280 bytes?
3) Does a complete multicast packet header with all its destination
   addresses fit onto the given multicast packet / ethernet frame and
   does not exceed 1280 bytes?

If all checks passed then the new batman-adv multicast packet type will
be used for transmission and distribution. Otherwise we fall back to one or
more batman-adv unicast packet transmissions, if possible. Or if not
possible we will fall back to classic flooding through a batman-adv
broadcast packet.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  |  79 -
 net/batman-adv/multicast.h  |  24 +-
 net/batman-adv/multicast_forw.c | 511 
 net/batman-adv/soft-interface.c |   6 +-
 net/batman-adv/types.h  |   6 +
 5 files changed, 618 insertions(+), 8 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index f2b1e523fd85..d74cb96896e9 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1177,17 +1177,62 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_mode_by_count() - get forwarding mode by count
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast packet to check
+ * @vid: the vlan identifier
+ * @is_routable: stores whether the destination is routable
+ * @count: the number of originators the multicast packet need to be sent to
+ *
+ * For a multicast packet with multiple destination originators, checks which
+ * mode to use. For BATADV_FORW_MCAST it also encapsulates the packet with a
+ * complete batman-adv multicast header.
+ *
+ * Return:
+ * BATADV_FORW_MCAST: If all nodes have multicast packet routing
+ * capabilities and an MTU >= 1280 on all hard interfaces (including us)
+ * and the encapsulated multicast packet with all destination addresses
+ * would still fit into an 1280 bytes batman-adv multicast packet
+ * (excluding the outter ethernet frame) and we could successfully push
+ * the full batman-adv multicast packet header.
+ * BATADV_FORW_UCASTS: If the packet cannot be sent in a batman-adv
+ * multicast packet and the amount of batman-adv unicast packets needed
+ * is smaller or equal to the configured multicast fanout.
+ * BATADV_FORW_BCAST: Otherwise.
+ */
+static enum batadv_forw_mode
+batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv,
+   struct sk_buff *skb, unsigned short vid,
+   int is_routable, int count)
+{
+   unsigned int mcast_hdrlen = batadv_mcast_forw_packet_hdrlen(count);
+   u8 own_tvlv_flags = bat_priv->mcast.mla_flags.tvlv_flags;
+
+   if (!atomic_read(_priv->mcast.num_no_mc_ptype_capa) &&
+   own_tvlv_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA &&
+   skb->len + mcast_hdrlen <= IPV6_MIN_MTU &&
+   batadv_mcast_forw_push(bat_priv, skb, vid, is_routable))
+   return BATADV_FORW_MCAST;
+
+   if (count <= atomic_read(_priv->multicast_fanout))
+   return BATADV_FORW_UCASTS;
+
+   return BATADV_FORW_BCAST;
+}
+
 /**
  * batadv_mcast_forw_mode() - check on how to forward a multicast packet
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the multicast packet to check
+ * @vid: the vlan identifier
  * @is_routable: stores whether the destination is routable
  *
  * Return: The forwarding mode as enum batadv_forw_mode.
  */
 enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  int *is_routable)
+  unsigned short vid, int *is_routable)
 {
int ret, tt_count, ip_count, unsnoop_count, total_count;
bool is_unsnoopable = false;
@@ -1217,10 +1262,8 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, 
struct sk_buff *skb,
else if (unsnoop_count)
return BATADV_FORW_BCAST;
 
-   if (total_count <= atomic_read(_priv->multicast_fanout))
-   return BATADV_FORW_UCASTS;
-
-   return BATADV_FORW_BCAST;
+   return batadv_mcast_forw_mode_by_count(bat_priv, skb, vid, *is_routable,
+  

[PATCH v3 3/5] batman-adv: mcast: implement multicast packet reception and forwarding

2022-12-26 Thread Linus Lüssing
Implement functionality to receive and forward a new TVLV capable
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

Also a new OGM multicast TVLV flag is introduced to signal to other
nodes that we are capable of handling a batman-adv multicast packet and
multicast tracker TVLV. And that all of our hard interfaces have an MTU
of at least 1280 bytes (IPv6 minimum MTU), as a simple solution for now
to avoid MTU issues while forwarding.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  48 -
 net/batman-adv/Makefile|   1 +
 net/batman-adv/main.c  |   2 +
 net/batman-adv/multicast.c |  48 -
 net/batman-adv/multicast.h |   5 +
 net/batman-adv/multicast_forw.c| 274 +
 net/batman-adv/originator.c|   1 +
 net/batman-adv/routing.c   |  68 +++
 net/batman-adv/routing.h   |  11 ++
 net/batman-adv/soft-interface.c|  12 ++
 net/batman-adv/types.h |  64 +++
 11 files changed, 523 insertions(+), 11 deletions(-)
 create mode 100644 net/batman-adv/multicast_forw.c

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index 9204e4494b25..77021519cd26 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -116,6 +116,9 @@ enum batadv_icmp_packettype {
  * only need routable IPv4 multicast packets we signed up for explicitly
  * @BATADV_MCAST_WANT_NO_RTR6: we have no IPv6 multicast router and therefore
  * only need routable IPv6 multicast packets we signed up for explicitly
+ * @BATADV_MCAST_HAVE_MC_PTYPE_CAPA: we can parse, receive and forward
+ * batman-adv multicast packets with a multicast tracker TVLV. And all our
+ * hard interfaces have an MTU of at least 1280 bytes.
  */
 enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_UNSNOOPABLES  = 1UL << 0,
@@ -123,6 +126,7 @@ enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_IPV6  = 1UL << 2,
BATADV_MCAST_WANT_NO_RTR4   = 1UL << 3,
BATADV_MCAST_WANT_NO_RTR6   = 1UL << 4,
+   BATADV_MCAST_HAVE_MC_PTYPE_CAPA = 1UL << 5,
 };
 
 /* tt data subtypes */
@@ -174,14 +178,16 @@ enum batadv_bla_claimframe {
  * @BATADV_TVLV_TT: translation table tvlv
  * @BATADV_TVLV_ROAM: roaming advertisement tvlv
  * @BATADV_TVLV_MCAST: multicast capability tvlv
+ * @BATADV_TVLV_MCAST_TRACKER: multicast tracker tvlv
  */
 enum batadv_tvlv_type {
-   BATADV_TVLV_GW  = 0x01,
-   BATADV_TVLV_DAT = 0x02,
-   BATADV_TVLV_NC  = 0x03,
-   BATADV_TVLV_TT  = 0x04,
-   BATADV_TVLV_ROAM= 0x05,
-   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_GW  = 0x01,
+   BATADV_TVLV_DAT = 0x02,
+   BATADV_TVLV_NC  = 0x03,
+   BATADV_TVLV_TT  = 0x04,
+   BATADV_TVLV_ROAM= 0x05,
+   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_MCAST_TRACKER   = 0x07,
 };
 
 #pragma pack(2)
@@ -487,6 +493,25 @@ struct batadv_bcast_packet {
 */
 };
 
+/**
+ * struct batadv_mcast_packet - multicast packet for network payload
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the general header
+ * @ttl: time to live for this packet, part of the general header
+ * @reserved: reserved byte for alignment
+ * @tvlv_len: length of the appended tvlv buffer (in bytes)
+ */
+struct batadv_mcast_packet {
+   __u8 packet_type;
+   __u8 version;
+   __u8 ttl;
+   __u8 reserved;
+   __be16 tvlv_len;
+   /* "4 bytes boundary + 2 bytes" long to make the payload after the
+* following ethernet header again 4 bytes boundary aligned
+*/
+};
+
 /**
  * struct batadv_coded_packet - network coded packet
  * @packet_type: batman-adv packet type, part of the general header
@@ -628,6 +653,17 @@ struct batadv_tvlv_mcast_data {
__u8 reserved[3];
 };
 
+/**
+ * struct batadv_tvlv_mcast_tracker - payload of a multicast tracker tvlv
+ * @num_dests: number of subsequent destination originator MAC addresses
+ * @align: (optional) alignment bytes to make the tracker TVLV 4 bytes aligned,
+ * present if num_dests are even, not present if odd
+ */
+struct batadv_tvlv_mcast_tracker {
+   __be16  num_dests;
+   __u8align[2];
+};
+
 #pragma pack()
 
 #endif /* _UAPI_LINUX_BATADV_PACKET_H_ */
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile

[PATCH v3 2/5] batman-adv: tvlv: prepare for tvlv enabled multicast packet type

2022-12-26 Thread Linus Lüssing
Prepare TVLV infrastructure for more packet types, in particular the
upcoming batman-adv multicast packet type.

For that swap the OGM vs. unicast-tvlv packet boolean indicator to an
explicit unsigned integer packet type variable. And provide the skb
to a call to batadv_tvlv_containers_process(), as later the multicast
packet's TVLV handler will need to have access not only to the TVLV but
the full skb for forwarding. Forwarding will be invoked from the
multicast packet's TVLVs' contents later.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  2 +
 net/batman-adv/bat_v_ogm.c |  4 +-
 net/batman-adv/distributed-arp-table.c |  2 +-
 net/batman-adv/gateway_common.c|  2 +-
 net/batman-adv/multicast.c |  2 +-
 net/batman-adv/network-coding.c|  2 +-
 net/batman-adv/routing.c   |  7 ++-
 net/batman-adv/translation-table.c |  4 +-
 net/batman-adv/tvlv.c  | 71 ++
 net/batman-adv/tvlv.h  |  9 ++--
 net/batman-adv/types.h |  6 +++
 11 files changed, 74 insertions(+), 37 deletions(-)

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index ea4692c339ce..9204e4494b25 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -26,6 +26,7 @@
  * @BATADV_CODED: network coded packets
  * @BATADV_ELP: echo location packets for B.A.T.M.A.N. V
  * @BATADV_OGM2: originator messages for B.A.T.M.A.N. V
+ * @BATADV_MCAST: multicast packet with multiple destination addresses
  *
  * @BATADV_UNICAST: unicast packets carrying unicast payload traffic
  * @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original
@@ -42,6 +43,7 @@ enum batadv_packettype {
BATADV_CODED= 0x02,
BATADV_ELP  = 0x03,
BATADV_OGM2 = 0x04,
+   BATADV_MCAST= 0x05,
/* 0x40 - 0x7f: unicast */
 #define BATADV_UNICAST_MIN 0x40
BATADV_UNICAST  = 0x40,
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
index 033639df96d8..296fcff487bc 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -800,8 +800,8 @@ batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
 
/* only unknown & newer OGMs contain TVLVs we are interested in */
if (seqno_age > 0 && if_outgoing == BATADV_IF_DEFAULT)
-   batadv_tvlv_containers_process(bat_priv, true, orig_node,
-  NULL, NULL,
+   batadv_tvlv_containers_process(bat_priv, BATADV_OGM2, orig_node,
+  NULL,
   (unsigned char *)(ogm2 + 1),
   ntohs(ogm2->tvlv_len));
 
diff --git a/net/batman-adv/distributed-arp-table.c 
b/net/batman-adv/distributed-arp-table.c
index fefb51a5f606..6968e55eb971 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -822,7 +822,7 @@ int batadv_dat_init(struct batadv_priv *bat_priv)
batadv_dat_start_timer(bat_priv);
 
batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1,
-NULL, BATADV_TVLV_DAT, 1,
+NULL, NULL, BATADV_TVLV_DAT, 1,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
batadv_dat_tvlv_container_update(bat_priv);
return 0;
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c
index 9349c76f30c5..6a964a773f57 100644
--- a/net/batman-adv/gateway_common.c
+++ b/net/batman-adv/gateway_common.c
@@ -259,7 +259,7 @@ void batadv_gw_init(struct batadv_priv *bat_priv)
atomic_set(_priv->gw.sel_class, 1);
 
batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1,
-NULL, BATADV_TVLV_GW, 1,
+NULL, NULL, BATADV_TVLV_GW, 1,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
 }
 
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 505f230dc49e..27511a063311 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1826,7 +1826,7 @@ static void batadv_mcast_tvlv_ogm_handler(struct 
batadv_priv *bat_priv,
 void batadv_mcast_init(struct batadv_priv *bat_priv)
 {
batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
-NULL, BATADV_TVLV_MCAST, 2,
+NULL, NULL, BATADV_TVLV_MCAST, 2,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
 
INIT_DELAYED_WORK(_priv->mcast.work, batadv_mcast_mla_update);
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c
index 5f4aeeb60dc4..82ef5cff151f

[PATCH v3 1/5] batman-adv: mcast: remove now redundant single ucast forwarding

2022-12-26 Thread Linus Lüssing
The multicast code to send a multicast packet via multiple batman-adv
unicast packets is not only capable of sending to multiple but also to a
single node. Therefore we can safely remove the old, specialized, now
redundant multicast-to-single-unicast code.

The only functional change of this simplification is that the edge case
of allowing a multicast packet with an unsnoopable destination address
(224.0.0.0/24 or ff02::1) where only a single node has signaled interest
in it via the batman-adv want-all-unsnoopables multicast flag is now
transmitted via a batman-adv broadcast instead of a batman-adv unicast
packet. Maintaining this edge case feature does not seem worth the extra
lines of code and people should just not expect to be able to snoop and
optimize such unsnoopable multicast addresses when bridges are involved.

While at it also renaming a few items in the batadv_forw_mode enum to
prepare for the new batman-adv multicast packet type.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  | 249 ++--
 net/batman-adv/multicast.h  |  38 +
 net/batman-adv/soft-interface.c |  26 ++--
 3 files changed, 33 insertions(+), 280 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 34897a15ad9d..505f230dc49e 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -26,7 +26,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -1144,223 +1143,20 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
-/**
- * batadv_mcast_forw_tt_node_get() - get a multicast tt node
- * @bat_priv: the bat priv with all the soft interface information
- * @ethhdr: the ether header containing the multicast destination
- *
- * Return: an orig_node matching the multicast address provided by ethhdr
- * via a translation table lookup. This increases the returned nodes refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv,
- struct ethhdr *ethhdr)
-{
-   return batadv_transtable_search(bat_priv, NULL, ethhdr->h_dest,
-   BATADV_NO_FLAGS);
-}
-
-/**
- * batadv_mcast_forw_ipv4_node_get() - get a node with an ipv4 flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 flag set and
- * increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv)
-{
-   struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
-
-   rcu_read_lock();
-   hlist_for_each_entry_rcu(tmp_orig_node,
-_priv->mcast.want_all_ipv4_list,
-mcast_want_all_ipv4_node) {
-   if (!kref_get_unless_zero(_orig_node->refcount))
-   continue;
-
-   orig_node = tmp_orig_node;
-   break;
-   }
-   rcu_read_unlock();
-
-   return orig_node;
-}
-
-/**
- * batadv_mcast_forw_ipv6_node_get() - get a node with an ipv6 flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV6 flag set
- * and increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv)
-{
-   struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
-
-   rcu_read_lock();
-   hlist_for_each_entry_rcu(tmp_orig_node,
-_priv->mcast.want_all_ipv6_list,
-mcast_want_all_ipv6_node) {
-   if (!kref_get_unless_zero(_orig_node->refcount))
-   continue;
-
-   orig_node = tmp_orig_node;
-   break;
-   }
-   rcu_read_unlock();
-
-   return orig_node;
-}
-
-/**
- * batadv_mcast_forw_ip_node_get() - get a node with an ipv4/ipv6 flag
- * @bat_priv: the bat priv with all the soft interface information
- * @ethhdr: an ethernet header to determine the protocol family from
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 or
- * BATADV_MCAST_WANT_ALL_IPV6 flag, depending on the provided ethhdr, sets and
- * increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ip_node_get(struct batadv_priv *bat_priv,
- struct ethhdr *ethhdr)
-{
-   switch (ntohs(ethhdr->h_proto)) {
-   case ETH_P_IP:
-   return batadv_mcast_forw_ipv4_node_get(bat_priv);
-   case ETH_P_IPV6:
-   return batadv_mcast_forw_ipv6_node_get(bat_priv);
-   default:
-   /* we shouldn't be here... */
-   return NULL;
-   }
-}
-
-/**
- * batadv_mcast_forw_unsnoop_node_get() - get a node with an unsnoopable flag
- * @bat_priv: the bat priv with all 

[PATCH v3 0/5] Implementation of a Stateless Multicast Packet Type

2022-12-26 Thread Linus Lüssing
Hi,

The following patchset implements a stateless, TVLV capable batman-adv
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination MAC addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

The purpose of this new packet type is to allow to forward an IP
multicast packet with less transmissions / overhead than the 
multicast-via-multiple-unicasts approach. Or to reach a lot more
destinations (currently up to 196, depending on the payload size, see 
Wiki documentation for details) than with the default multicast fanout
for the via-unicasts approach.

This will allow using applications like mDNS again in several Freifunk
communities. And with less transmissions will also make more bulky
multicast applications, like media streaming (to an assessable amount of
receivers) a lot more feasible.

This approach is way simpler than the original multicast (tracker) packet
approach we envisioned years ago. As it involves no maintenance of an
extra, state based multicast routing table. However the TVLV capability
should allow to extend things later, to split control and data plane a bit 
more for instance, to further increase the number of destinations, to
further reduce overhead.

A compact overview can be found in the Wiki here, including limitations:

https://www.open-mesh.org/projects/batman-adv/wiki/Multicast-Packet-Type

Regards, Linus

___

Changelog v3:
* PATCH 1/5:
  * remove now obsolete includes
* PATCH 2/5:
  * fix batadv_tvlv_handler_register() in network-coding.c
  * add missing include for linux/skbuff.h
  * move variable declarations out of the switch case
in batadv_tvlv_call_handler()
* PATCH 3/5:
  * remove unnecessary include of multicast.h in routing.c
  * add a few missing includes to multicast_forw.c
(linux/byteorder/generic.h, linux/errno.h, linux/gfp.h, linux/stddef.h
 uapi/linux/batadv_packet.h, multicast.h)
* PATCH 4/5:
  * add missing rcu_read_unlock() in error case before returning in
batadv_mcast_forw_push_dests_list()
  * remove unnecessary include of soft-interface.h in multicast_forw.c
  * add a few missing includes to multicast_forw.c
(linux/bug.h, linux/build_bug.h, linux/limits.h, linux/rculist.h,
 linux/rcupdate.h, linux/string.h)
  * make batadv_mcast_forw_mode_by_count() static
  * fix return types in the declaration of
batadv_mcast_forw_packet_hdrlen() and batadv_mcast_forw_push()
in multicast.h
  * fix typo in commit message: "that the are capable of"
-> "that the*y* are capable of"
* PATCH 5/5:
  * make batadv_mcast_forw_shrink_pack_dests() adhere to 80 characters
per line for consistency
  * add a "continue" statement after the jump label in
batadv_mcast_forw_shrink_pack_dests() to silence the sparse error
"error: label at end of compound statement"

Changelog v2: 
* Add "[PATCH v2 0/5]" prefix to title of cover letter, so that
  Patchwork can hopefully find it - no other changes


[PATCH v2 4/5] batman-adv: mcast: implement multicast packet generation

2022-12-26 Thread Linus Lüssing
Implement the preparation of a batman-adv multicast packet and use this
under certain conditions.

For one thing this implements the capability to push a complete
batman-adv multicast packet header, including a tracker TVLV with all
originator destinations that have signaled interest in it, onto a given
ethernet frame with an IP multicast packet inside.

For another checks are implemented to determine if encapsulating a
multicast packet in this new batman-adv multicast packet type and using
it is feasible. Those checks are:

1) Have all nodes signaled that the are capable of handling the new
   batman-adv multicast packet type?
2) Do all active hard interfaces of all nodes, including us, have an MTU
   of at least 1280 bytes?
3) Does a complete multicast packet header with all its destination
   addresses fit onto the given multicast packet / ethernet frame and
   does not exceed 1280 bytes?

If all checks passed then the new batman-adv multicast packet type will
be used for transmission and distribution. Otherwise we fall back to one or
more batman-adv unicast packet transmissions, if possible. Or if not
possible we will fall back to classic flooding through a batman-adv
broadcast packet.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  |  79 -
 net/batman-adv/multicast.h  |  24 +-
 net/batman-adv/multicast_forw.c | 504 
 net/batman-adv/soft-interface.c |   6 +-
 net/batman-adv/types.h  |   6 +
 5 files changed, 611 insertions(+), 8 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index d674e8394439..fb548924be04 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1178,17 +1178,62 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_mode_by_count() - get forwarding mode by count
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast packet to check
+ * @vid: the vlan identifier
+ * @is_routable: stores whether the destination is routable
+ * @count: the number of originators the multicast packet need to be sent to
+ *
+ * For a multicast packet with multiple destination originators, checks which
+ * mode to use. For BATADV_FORW_MCAST it also encapsulates the packet with a
+ * complete batman-adv multicast header.
+ *
+ * Return:
+ * BATADV_FORW_MCAST: If all nodes have multicast packet routing
+ * capabilities and an MTU >= 1280 on all hard interfaces (including us)
+ * and the encapsulated multicast packet with all destination addresses
+ * would still fit into an 1280 bytes batman-adv multicast packet
+ * (excluding the outter ethernet frame) and we could successfully push
+ * the full batman-adv multicast packet header.
+ * BATADV_FORW_UCASTS: If the packet cannot be sent in a batman-adv
+ * multicast packet and the amount of batman-adv unicast packets needed
+ * is smaller or equal to the configured multicast fanout.
+ * BATADV_FORW_BCAST: Otherwise.
+ */
+enum batadv_forw_mode
+batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv,
+   struct sk_buff *skb, unsigned short vid,
+   int is_routable, int count)
+{
+   unsigned int mcast_hdrlen = batadv_mcast_forw_packet_hdrlen(count);
+   u8 own_tvlv_flags = bat_priv->mcast.mla_flags.tvlv_flags;
+
+   if (!atomic_read(_priv->mcast.num_no_mc_ptype_capa) &&
+   own_tvlv_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA &&
+   skb->len + mcast_hdrlen <= IPV6_MIN_MTU &&
+   batadv_mcast_forw_push(bat_priv, skb, vid, is_routable))
+   return BATADV_FORW_MCAST;
+
+   if (count <= atomic_read(_priv->multicast_fanout))
+   return BATADV_FORW_UCASTS;
+
+   return BATADV_FORW_BCAST;
+}
+
 /**
  * batadv_mcast_forw_mode() - check on how to forward a multicast packet
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the multicast packet to check
+ * @vid: the vlan identifier
  * @is_routable: stores whether the destination is routable
  *
  * Return: The forwarding mode as enum batadv_forw_mode.
  */
 enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  int *is_routable)
+  unsigned short vid, int *is_routable)
 {
int ret, tt_count, ip_count, unsnoop_count, total_count;
bool is_unsnoopable = false;
@@ -1218,10 +1263,8 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, 
struct sk_buff *skb,
else if (unsnoop_count)
return BATADV_FORW_BCAST;
 
-   if (total_count <= atomic_read(_priv->multicast_fanout))
-   return BATADV_FORW_UCASTS;
-
-   return BATADV_FORW_BCAST;
+   return batadv_mcast_forw_mode_by_count(bat_priv, skb, vid, *is_routable,
+  

[PATCH v2 5/5] batman-adv: mcast: shrink tracker packet after scrubbing

2022-12-26 Thread Linus Lüssing
Remove all zero MAC address entries (00:00:00:00:00:00) from a multicast
packet's tracker TVLV before transmitting it and update all headers
accordingly. This way, instead of keeping the multicast packet at a
constant size throughout its journey through the mesh, it will become
more lightweight, smaller with every interested receiver on the way and
on each splitting intersection. Which can save some valuable bandwidth.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast_forw.c | 207 
 1 file changed, 207 insertions(+)

diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c
index e2b0cd51cec4..3f6fedc7a918 100644
--- a/net/batman-adv/multicast_forw.c
+++ b/net/batman-adv/multicast_forw.c
@@ -24,6 +24,9 @@
 #define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) \
for (; num_dests; num_dests--, (dest) += ETH_ALEN)
 
+#define batadv_mcast_forw_tracker_for_each_dest_rev(dest, num_dests) \
+   for (; num_dests; num_dests--, (dest) -= ETH_ALEN)
+
 /**
  * batadv_mcast_forw_orig_entry() - get orig_node from an hlist node
  * @node: the hlist node to get the orig_node from
@@ -516,6 +519,209 @@ batadv_mcast_forw_scrub_dests(struct batadv_priv 
*bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_shrink_align_offset() - calculate alignment offset
+ * @num_dests_old: the number of destinations the tracker TVLV had originally
+ * @num_dests_reduce: the number of destinations that are going to be removed
+ *
+ * The multicast tracker TVLV has 2 alignment bytes if the number of 
destination
+ * entries are even, to make this TVLV 4 byte aligned to make the encapsulated
+ * IP packet 4 byte aligned. And no alignment bytes in the tracker TVLV if the
+ * number of destinations is odd.
+ *
+ * This calculates if the 2 alignment bytes in the multicast tracker TVLV need
+ * to be added, removed or left unchanged.
+ *
+ * Return: The number of extra offset in skb tail direction to compensate for
+ * alignment. Will be -2, 0 or +2.
+ */
+static int batadv_mcast_forw_shrink_align_offset(unsigned int num_dests_old,
+unsigned int num_dests_remove)
+{
+   int ret = sizeof(((struct batadv_tvlv_mcast_tracker *)0)->align);
+
+   /* no change in padding */
+   if (!(num_dests_remove % 2))
+   return 0;
+
+   /* even had padding, remove it, increase the offset */
+   if (!(num_dests_old % 2))
+   return ret;
+   /* odd had no padding, add it, decrease the offset */
+   else
+   return -ret;
+}
+
+/**
+ * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV
+ * @skb: the batman-adv multicast packet to compact destinations in
+ *
+ * Compacts the originator destination MAC addresses in the multicast tracker
+ * TVLV of the given multicast packet. This is done by moving all non-zero
+ * MAC addresses in direction of the skb tail and all zero MAC addresses in skb
+ * head direction, within the multicast tracker TVLV.
+ *
+ * Return: The number of consecutive zero MAC address destinations which are
+ * now at the front within the multicast tracker TVLV.
+ */
+static int batadv_mcast_forw_shrink_pack_dests(struct sk_buff *skb)
+{
+   struct batadv_tvlv_mcast_tracker *mcast_tracker;
+   u16 num_dests_slot, num_dests_filler;
+   unsigned int tracker_hdrlen;
+   u8 *slot, *filler;
+
+   mcast_tracker = (struct batadv_tvlv_mcast_tracker 
*)skb_network_header(skb);
+   num_dests_slot = ntohs(mcast_tracker->num_dests);
+
+   tracker_hdrlen = batadv_mcast_forw_tracker_hdrlen(num_dests_slot);
+   slot = (u8 *)mcast_tracker + tracker_hdrlen;
+   slot += ETH_ALEN * (num_dests_slot - 1);
+
+   if (!num_dests_slot)
+   return 0;
+
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot - ETH_ALEN;
+
+   batadv_mcast_forw_tracker_for_each_dest_rev(slot, num_dests_slot) {
+   /* find an empty slot */
+   if (!is_zero_ether_addr(slot))
+   continue;
+
+   /* keep filler ahead of slot */
+   if (filler >= slot) {
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot - ETH_ALEN;
+   }
+
+   /* find a candidate to fill the empty slot */
+   batadv_mcast_forw_tracker_for_each_dest_rev(filler, 
num_dests_filler) {
+   if (is_zero_ether_addr(filler))
+   continue;
+
+   ether_addr_copy(slot, filler);
+   eth_zero_addr(filler);
+   goto cont_next_slot;
+   }
+
+   /* could not find a filler, we can stop
+* - and must not advance the slot pointer!
+*/
+   if (!num_dests_filler)
+   break;
+cont_

[PATCH v2 3/5] batman-adv: mcast: implement multicast packet reception and forwarding

2022-12-26 Thread Linus Lüssing
Implement functionality to receive and forward a new TVLV capable
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

Also a new OGM multicast TVLV flag is introduced to signal to other
nodes that we are capable of handling a batman-adv multicast packet and
multicast tracker TVLV. And that all of our hard interfaces have an MTU
of at least 1280 bytes (IPv6 minimum MTU), as a simple solution for now
to avoid MTU issues while forwarding.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  48 +-
 net/batman-adv/Makefile|   1 +
 net/batman-adv/main.c  |   2 +
 net/batman-adv/multicast.c |  48 +-
 net/batman-adv/multicast.h |   5 +
 net/batman-adv/multicast_forw.c| 268 +
 net/batman-adv/originator.c|   1 +
 net/batman-adv/routing.c   |  69 
 net/batman-adv/routing.h   |  11 ++
 net/batman-adv/soft-interface.c|  12 ++
 net/batman-adv/types.h |  64 +++
 11 files changed, 518 insertions(+), 11 deletions(-)
 create mode 100644 net/batman-adv/multicast_forw.c

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index 9204e4494b25..77021519cd26 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -116,6 +116,9 @@ enum batadv_icmp_packettype {
  * only need routable IPv4 multicast packets we signed up for explicitly
  * @BATADV_MCAST_WANT_NO_RTR6: we have no IPv6 multicast router and therefore
  * only need routable IPv6 multicast packets we signed up for explicitly
+ * @BATADV_MCAST_HAVE_MC_PTYPE_CAPA: we can parse, receive and forward
+ * batman-adv multicast packets with a multicast tracker TVLV. And all our
+ * hard interfaces have an MTU of at least 1280 bytes.
  */
 enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_UNSNOOPABLES  = 1UL << 0,
@@ -123,6 +126,7 @@ enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_IPV6  = 1UL << 2,
BATADV_MCAST_WANT_NO_RTR4   = 1UL << 3,
BATADV_MCAST_WANT_NO_RTR6   = 1UL << 4,
+   BATADV_MCAST_HAVE_MC_PTYPE_CAPA = 1UL << 5,
 };
 
 /* tt data subtypes */
@@ -174,14 +178,16 @@ enum batadv_bla_claimframe {
  * @BATADV_TVLV_TT: translation table tvlv
  * @BATADV_TVLV_ROAM: roaming advertisement tvlv
  * @BATADV_TVLV_MCAST: multicast capability tvlv
+ * @BATADV_TVLV_MCAST_TRACKER: multicast tracker tvlv
  */
 enum batadv_tvlv_type {
-   BATADV_TVLV_GW  = 0x01,
-   BATADV_TVLV_DAT = 0x02,
-   BATADV_TVLV_NC  = 0x03,
-   BATADV_TVLV_TT  = 0x04,
-   BATADV_TVLV_ROAM= 0x05,
-   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_GW  = 0x01,
+   BATADV_TVLV_DAT = 0x02,
+   BATADV_TVLV_NC  = 0x03,
+   BATADV_TVLV_TT  = 0x04,
+   BATADV_TVLV_ROAM= 0x05,
+   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_MCAST_TRACKER   = 0x07,
 };
 
 #pragma pack(2)
@@ -487,6 +493,25 @@ struct batadv_bcast_packet {
 */
 };
 
+/**
+ * struct batadv_mcast_packet - multicast packet for network payload
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the general header
+ * @ttl: time to live for this packet, part of the general header
+ * @reserved: reserved byte for alignment
+ * @tvlv_len: length of the appended tvlv buffer (in bytes)
+ */
+struct batadv_mcast_packet {
+   __u8 packet_type;
+   __u8 version;
+   __u8 ttl;
+   __u8 reserved;
+   __be16 tvlv_len;
+   /* "4 bytes boundary + 2 bytes" long to make the payload after the
+* following ethernet header again 4 bytes boundary aligned
+*/
+};
+
 /**
  * struct batadv_coded_packet - network coded packet
  * @packet_type: batman-adv packet type, part of the general header
@@ -628,6 +653,17 @@ struct batadv_tvlv_mcast_data {
__u8 reserved[3];
 };
 
+/**
+ * struct batadv_tvlv_mcast_tracker - payload of a multicast tracker tvlv
+ * @num_dests: number of subsequent destination originator MAC addresses
+ * @align: (optional) alignment bytes to make the tracker TVLV 4 bytes aligned,
+ * present if num_dests are even, not present if odd
+ */
+struct batadv_tvlv_mcast_tracker {
+   __be16  num_dests;
+   __u8align[2];
+};
+
 #pragma pack()
 
 #endif /* _UAPI_LINUX_BATADV_PACKET_H_ */
diff --git a/net/batman-adv/Makefile b/net/batman-adv/M

[PATCH v2 2/5] batman-adv: tvlv: prepare for tvlv enabled multicast packet type

2022-12-26 Thread Linus Lüssing
Prepare TVLV infrastructure for more packet types, in particular the
upcoming batman-adv multicast packet type.

For that swap the OGM vs. unicast-tvlv packet boolean indicator to an
explicit unsigned integer packet type variable. And provide the skb
to a call to batadv_tvlv_containers_process(), as later the multicast
packet's TVLV handler will need to have access not only to the TVLV but
the full skb for forwarding. Forwarding will be invoked from the
multicast packet's TVLVs' contents later.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  2 +
 net/batman-adv/bat_v_ogm.c |  4 +-
 net/batman-adv/distributed-arp-table.c |  2 +-
 net/batman-adv/gateway_common.c|  2 +-
 net/batman-adv/multicast.c |  2 +-
 net/batman-adv/routing.c   |  7 ++-
 net/batman-adv/translation-table.c |  4 +-
 net/batman-adv/tvlv.c  | 71 ++
 net/batman-adv/tvlv.h  |  8 +--
 net/batman-adv/types.h |  6 +++
 10 files changed, 73 insertions(+), 35 deletions(-)

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index ea4692c339ce..9204e4494b25 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -26,6 +26,7 @@
  * @BATADV_CODED: network coded packets
  * @BATADV_ELP: echo location packets for B.A.T.M.A.N. V
  * @BATADV_OGM2: originator messages for B.A.T.M.A.N. V
+ * @BATADV_MCAST: multicast packet with multiple destination addresses
  *
  * @BATADV_UNICAST: unicast packets carrying unicast payload traffic
  * @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original
@@ -42,6 +43,7 @@ enum batadv_packettype {
BATADV_CODED= 0x02,
BATADV_ELP  = 0x03,
BATADV_OGM2 = 0x04,
+   BATADV_MCAST= 0x05,
/* 0x40 - 0x7f: unicast */
 #define BATADV_UNICAST_MIN 0x40
BATADV_UNICAST  = 0x40,
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
index 033639df96d8..296fcff487bc 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -800,8 +800,8 @@ batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
 
/* only unknown & newer OGMs contain TVLVs we are interested in */
if (seqno_age > 0 && if_outgoing == BATADV_IF_DEFAULT)
-   batadv_tvlv_containers_process(bat_priv, true, orig_node,
-  NULL, NULL,
+   batadv_tvlv_containers_process(bat_priv, BATADV_OGM2, orig_node,
+  NULL,
   (unsigned char *)(ogm2 + 1),
   ntohs(ogm2->tvlv_len));
 
diff --git a/net/batman-adv/distributed-arp-table.c 
b/net/batman-adv/distributed-arp-table.c
index fefb51a5f606..6968e55eb971 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -822,7 +822,7 @@ int batadv_dat_init(struct batadv_priv *bat_priv)
batadv_dat_start_timer(bat_priv);
 
batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1,
-NULL, BATADV_TVLV_DAT, 1,
+NULL, NULL, BATADV_TVLV_DAT, 1,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
batadv_dat_tvlv_container_update(bat_priv);
return 0;
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c
index 9349c76f30c5..6a964a773f57 100644
--- a/net/batman-adv/gateway_common.c
+++ b/net/batman-adv/gateway_common.c
@@ -259,7 +259,7 @@ void batadv_gw_init(struct batadv_priv *bat_priv)
atomic_set(_priv->gw.sel_class, 1);
 
batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1,
-NULL, BATADV_TVLV_GW, 1,
+NULL, NULL, BATADV_TVLV_GW, 1,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
 }
 
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index dbe7fcfad512..548ab08d96fa 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1827,7 +1827,7 @@ static void batadv_mcast_tvlv_ogm_handler(struct 
batadv_priv *bat_priv,
 void batadv_mcast_init(struct batadv_priv *bat_priv)
 {
batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
-NULL, BATADV_TVLV_MCAST, 2,
+NULL, NULL, BATADV_TVLV_MCAST, 2,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
 
INIT_DELAYED_WORK(_priv->mcast.work, batadv_mcast_mla_update);
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 83f31494ea4d..163cd43c4821 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routi

[PATCH v2 1/5] batman-adv: mcast: remove now redundant single ucast forwarding

2022-12-26 Thread Linus Lüssing
The multicast code to send a multicast packet via multiple batman-adv
unicast packets is not only capable of sending to multiple but also to a
single node. Therefore we can safely remove the old, specialized, now
redundant multicast-to-single-unicast code.

The only functional change of this simplification is that the edge case
of allowing a multicast packet with an unsnoopable destination address
(224.0.0.0/24 or ff02::1) where only a single node has signaled interest
in it via the batman-adv want-all-unsnoopables multicast flag is now
transmitted via a batman-adv broadcast instead of a batman-adv unicast
packet. Maintaining this edge case feature does not seem worth the extra
lines of code and people should just not expect to be able to snoop and
optimize such unsnoopable multicast addresses when bridges are involved.

While at it also renaming a few items in the batadv_forw_mode enum to
prepare for the new batman-adv multicast packet type.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  | 248 ++--
 net/batman-adv/multicast.h  |  38 +
 net/batman-adv/soft-interface.c |  25 ++--
 3 files changed, 33 insertions(+), 278 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 34897a15ad9d..dbe7fcfad512 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1144,223 +1144,20 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
-/**
- * batadv_mcast_forw_tt_node_get() - get a multicast tt node
- * @bat_priv: the bat priv with all the soft interface information
- * @ethhdr: the ether header containing the multicast destination
- *
- * Return: an orig_node matching the multicast address provided by ethhdr
- * via a translation table lookup. This increases the returned nodes refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv,
- struct ethhdr *ethhdr)
-{
-   return batadv_transtable_search(bat_priv, NULL, ethhdr->h_dest,
-   BATADV_NO_FLAGS);
-}
-
-/**
- * batadv_mcast_forw_ipv4_node_get() - get a node with an ipv4 flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 flag set and
- * increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv)
-{
-   struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
-
-   rcu_read_lock();
-   hlist_for_each_entry_rcu(tmp_orig_node,
-_priv->mcast.want_all_ipv4_list,
-mcast_want_all_ipv4_node) {
-   if (!kref_get_unless_zero(_orig_node->refcount))
-   continue;
-
-   orig_node = tmp_orig_node;
-   break;
-   }
-   rcu_read_unlock();
-
-   return orig_node;
-}
-
-/**
- * batadv_mcast_forw_ipv6_node_get() - get a node with an ipv6 flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV6 flag set
- * and increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv)
-{
-   struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
-
-   rcu_read_lock();
-   hlist_for_each_entry_rcu(tmp_orig_node,
-_priv->mcast.want_all_ipv6_list,
-mcast_want_all_ipv6_node) {
-   if (!kref_get_unless_zero(_orig_node->refcount))
-   continue;
-
-   orig_node = tmp_orig_node;
-   break;
-   }
-   rcu_read_unlock();
-
-   return orig_node;
-}
-
-/**
- * batadv_mcast_forw_ip_node_get() - get a node with an ipv4/ipv6 flag
- * @bat_priv: the bat priv with all the soft interface information
- * @ethhdr: an ethernet header to determine the protocol family from
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 or
- * BATADV_MCAST_WANT_ALL_IPV6 flag, depending on the provided ethhdr, sets and
- * increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ip_node_get(struct batadv_priv *bat_priv,
- struct ethhdr *ethhdr)
-{
-   switch (ntohs(ethhdr->h_proto)) {
-   case ETH_P_IP:
-   return batadv_mcast_forw_ipv4_node_get(bat_priv);
-   case ETH_P_IPV6:
-   return batadv_mcast_forw_ipv6_node_get(bat_priv);
-   default:
-   /* we shouldn't be here... */
-   return NULL;
-   }
-}
-
-/**
- * batadv_mcast_forw_unsnoop_node_get() - get a node with an unsnoopable flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_UNSNOOP

[PATCH v2 0/5] Implementation of a Stateless Multicast Packet Type

2022-12-26 Thread Linus Lüssing
Hi,

The following patchset implements a stateless, TVLV capable batman-adv
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination MAC addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

The purpose of this new packet type is to allow to forward an IP
multicast packet with less transmissions / overhead than the
multicast-via-multiple-unicasts approach. Or to reach a lot more
destinations (currently up to 196, depending on the payload size, see
Wiki documentation for details) than with the default multicast fanout
for the via-unicasts approach.

This will allow using applications like mDNS again in several Freifunk
communities. And with less transmissions will also make more bulky
multicast applications, like media streaming (to an assessable amount of
receivers) a lot more feasible.

This approach is way simpler than the original multicast (tracker) packet
approach we envisioned years ago. As it involves no maintenance of an
extra, state based multicast routing table. However the TVLV capability
should allow to extend things later, to split control and data plane a bit
more for instance, to further increase the number of destinations, to
further reduce overhead.

A compact overview can be found in the Wiki here, including limitations:

https://www.open-mesh.org/projects/batman-adv/wiki/Multicast-Packet-Type

Regards, Linus

---

Changelog v2:
* Add "[PATCH v2 0/5]" prefix to title of cover letter, so that
  Patchwork can hopefully find it - no other changes



[PATCH 5/5] batman-adv: mcast: shrink tracker packet after scrubbing

2022-12-26 Thread Linus Lüssing
Remove all zero MAC address entries (00:00:00:00:00:00) from a multicast
packet's tracker TVLV before transmitting it and update all headers
accordingly. This way, instead of keeping the multicast packet at a
constant size throughout its journey through the mesh, it will become
more lightweight, smaller with every interested receiver on the way and
on each splitting intersection. Which can save some valuable bandwidth.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast_forw.c | 207 
 1 file changed, 207 insertions(+)

diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c
index e2b0cd51cec4..3f6fedc7a918 100644
--- a/net/batman-adv/multicast_forw.c
+++ b/net/batman-adv/multicast_forw.c
@@ -24,6 +24,9 @@
 #define batadv_mcast_forw_tracker_for_each_dest(dest, num_dests) \
for (; num_dests; num_dests--, (dest) += ETH_ALEN)
 
+#define batadv_mcast_forw_tracker_for_each_dest_rev(dest, num_dests) \
+   for (; num_dests; num_dests--, (dest) -= ETH_ALEN)
+
 /**
  * batadv_mcast_forw_orig_entry() - get orig_node from an hlist node
  * @node: the hlist node to get the orig_node from
@@ -516,6 +519,209 @@ batadv_mcast_forw_scrub_dests(struct batadv_priv 
*bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_shrink_align_offset() - calculate alignment offset
+ * @num_dests_old: the number of destinations the tracker TVLV had originally
+ * @num_dests_reduce: the number of destinations that are going to be removed
+ *
+ * The multicast tracker TVLV has 2 alignment bytes if the number of 
destination
+ * entries are even, to make this TVLV 4 byte aligned to make the encapsulated
+ * IP packet 4 byte aligned. And no alignment bytes in the tracker TVLV if the
+ * number of destinations is odd.
+ *
+ * This calculates if the 2 alignment bytes in the multicast tracker TVLV need
+ * to be added, removed or left unchanged.
+ *
+ * Return: The number of extra offset in skb tail direction to compensate for
+ * alignment. Will be -2, 0 or +2.
+ */
+static int batadv_mcast_forw_shrink_align_offset(unsigned int num_dests_old,
+unsigned int num_dests_remove)
+{
+   int ret = sizeof(((struct batadv_tvlv_mcast_tracker *)0)->align);
+
+   /* no change in padding */
+   if (!(num_dests_remove % 2))
+   return 0;
+
+   /* even had padding, remove it, increase the offset */
+   if (!(num_dests_old % 2))
+   return ret;
+   /* odd had no padding, add it, decrease the offset */
+   else
+   return -ret;
+}
+
+/**
+ * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV
+ * @skb: the batman-adv multicast packet to compact destinations in
+ *
+ * Compacts the originator destination MAC addresses in the multicast tracker
+ * TVLV of the given multicast packet. This is done by moving all non-zero
+ * MAC addresses in direction of the skb tail and all zero MAC addresses in skb
+ * head direction, within the multicast tracker TVLV.
+ *
+ * Return: The number of consecutive zero MAC address destinations which are
+ * now at the front within the multicast tracker TVLV.
+ */
+static int batadv_mcast_forw_shrink_pack_dests(struct sk_buff *skb)
+{
+   struct batadv_tvlv_mcast_tracker *mcast_tracker;
+   u16 num_dests_slot, num_dests_filler;
+   unsigned int tracker_hdrlen;
+   u8 *slot, *filler;
+
+   mcast_tracker = (struct batadv_tvlv_mcast_tracker 
*)skb_network_header(skb);
+   num_dests_slot = ntohs(mcast_tracker->num_dests);
+
+   tracker_hdrlen = batadv_mcast_forw_tracker_hdrlen(num_dests_slot);
+   slot = (u8 *)mcast_tracker + tracker_hdrlen;
+   slot += ETH_ALEN * (num_dests_slot - 1);
+
+   if (!num_dests_slot)
+   return 0;
+
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot - ETH_ALEN;
+
+   batadv_mcast_forw_tracker_for_each_dest_rev(slot, num_dests_slot) {
+   /* find an empty slot */
+   if (!is_zero_ether_addr(slot))
+   continue;
+
+   /* keep filler ahead of slot */
+   if (filler >= slot) {
+   num_dests_filler = num_dests_slot - 1;
+   filler = slot - ETH_ALEN;
+   }
+
+   /* find a candidate to fill the empty slot */
+   batadv_mcast_forw_tracker_for_each_dest_rev(filler, 
num_dests_filler) {
+   if (is_zero_ether_addr(filler))
+   continue;
+
+   ether_addr_copy(slot, filler);
+   eth_zero_addr(filler);
+   goto cont_next_slot;
+   }
+
+   /* could not find a filler, we can stop
+* - and must not advance the slot pointer!
+*/
+   if (!num_dests_filler)
+   break;
+cont_

[PATCH 4/5] batman-adv: mcast: implement multicast packet generation

2022-12-26 Thread Linus Lüssing
Implement the preparation of a batman-adv multicast packet and use this
under certain conditions.

For one thing this implements the capability to push a complete
batman-adv multicast packet header, including a tracker TVLV with all
originator destinations that have signaled interest in it, onto a given
ethernet frame with an IP multicast packet inside.

For another checks are implemented to determine if encapsulating a
multicast packet in this new batman-adv multicast packet type and using
it is feasible. Those checks are:

1) Have all nodes signaled that the are capable of handling the new
   batman-adv multicast packet type?
2) Do all active hard interfaces of all nodes, including us, have an MTU
   of at least 1280 bytes?
3) Does a complete multicast packet header with all its destination
   addresses fit onto the given multicast packet / ethernet frame and
   does not exceed 1280 bytes?

If all checks passed then the new batman-adv multicast packet type will
be used for transmission and distribution. Otherwise we fall back to one or
more batman-adv unicast packet transmissions, if possible. Or if not
possible we will fall back to classic flooding through a batman-adv
broadcast packet.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  |  79 -
 net/batman-adv/multicast.h  |  24 +-
 net/batman-adv/multicast_forw.c | 504 
 net/batman-adv/soft-interface.c |   6 +-
 net/batman-adv/types.h  |   6 +
 5 files changed, 611 insertions(+), 8 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index d674e8394439..fb548924be04 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1178,17 +1178,62 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
+/**
+ * batadv_mcast_forw_mode_by_count() - get forwarding mode by count
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast packet to check
+ * @vid: the vlan identifier
+ * @is_routable: stores whether the destination is routable
+ * @count: the number of originators the multicast packet need to be sent to
+ *
+ * For a multicast packet with multiple destination originators, checks which
+ * mode to use. For BATADV_FORW_MCAST it also encapsulates the packet with a
+ * complete batman-adv multicast header.
+ *
+ * Return:
+ * BATADV_FORW_MCAST: If all nodes have multicast packet routing
+ * capabilities and an MTU >= 1280 on all hard interfaces (including us)
+ * and the encapsulated multicast packet with all destination addresses
+ * would still fit into an 1280 bytes batman-adv multicast packet
+ * (excluding the outter ethernet frame) and we could successfully push
+ * the full batman-adv multicast packet header.
+ * BATADV_FORW_UCASTS: If the packet cannot be sent in a batman-adv
+ * multicast packet and the amount of batman-adv unicast packets needed
+ * is smaller or equal to the configured multicast fanout.
+ * BATADV_FORW_BCAST: Otherwise.
+ */
+enum batadv_forw_mode
+batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv,
+   struct sk_buff *skb, unsigned short vid,
+   int is_routable, int count)
+{
+   unsigned int mcast_hdrlen = batadv_mcast_forw_packet_hdrlen(count);
+   u8 own_tvlv_flags = bat_priv->mcast.mla_flags.tvlv_flags;
+
+   if (!atomic_read(_priv->mcast.num_no_mc_ptype_capa) &&
+   own_tvlv_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA &&
+   skb->len + mcast_hdrlen <= IPV6_MIN_MTU &&
+   batadv_mcast_forw_push(bat_priv, skb, vid, is_routable))
+   return BATADV_FORW_MCAST;
+
+   if (count <= atomic_read(_priv->multicast_fanout))
+   return BATADV_FORW_UCASTS;
+
+   return BATADV_FORW_BCAST;
+}
+
 /**
  * batadv_mcast_forw_mode() - check on how to forward a multicast packet
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the multicast packet to check
+ * @vid: the vlan identifier
  * @is_routable: stores whether the destination is routable
  *
  * Return: The forwarding mode as enum batadv_forw_mode.
  */
 enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  int *is_routable)
+  unsigned short vid, int *is_routable)
 {
int ret, tt_count, ip_count, unsnoop_count, total_count;
bool is_unsnoopable = false;
@@ -1218,10 +1263,8 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, 
struct sk_buff *skb,
else if (unsnoop_count)
return BATADV_FORW_BCAST;
 
-   if (total_count <= atomic_read(_priv->multicast_fanout))
-   return BATADV_FORW_UCASTS;
-
-   return BATADV_FORW_BCAST;
+   return batadv_mcast_forw_mode_by_count(bat_priv, skb, vid, *is_routable,
+  

[PATCH 3/5] batman-adv: mcast: implement multicast packet reception and forwarding

2022-12-26 Thread Linus Lüssing
Implement functionality to receive and forward a new TVLV capable
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

Also a new OGM multicast TVLV flag is introduced to signal to other
nodes that we are capable of handling a batman-adv multicast packet and
multicast tracker TVLV. And that all of our hard interfaces have an MTU
of at least 1280 bytes (IPv6 minimum MTU), as a simple solution for now
to avoid MTU issues while forwarding.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  48 +-
 net/batman-adv/Makefile|   1 +
 net/batman-adv/main.c  |   2 +
 net/batman-adv/multicast.c |  48 +-
 net/batman-adv/multicast.h |   5 +
 net/batman-adv/multicast_forw.c| 268 +
 net/batman-adv/originator.c|   1 +
 net/batman-adv/routing.c   |  69 
 net/batman-adv/routing.h   |  11 ++
 net/batman-adv/soft-interface.c|  12 ++
 net/batman-adv/types.h |  64 +++
 11 files changed, 518 insertions(+), 11 deletions(-)
 create mode 100644 net/batman-adv/multicast_forw.c

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index 9204e4494b25..77021519cd26 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -116,6 +116,9 @@ enum batadv_icmp_packettype {
  * only need routable IPv4 multicast packets we signed up for explicitly
  * @BATADV_MCAST_WANT_NO_RTR6: we have no IPv6 multicast router and therefore
  * only need routable IPv6 multicast packets we signed up for explicitly
+ * @BATADV_MCAST_HAVE_MC_PTYPE_CAPA: we can parse, receive and forward
+ * batman-adv multicast packets with a multicast tracker TVLV. And all our
+ * hard interfaces have an MTU of at least 1280 bytes.
  */
 enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_UNSNOOPABLES  = 1UL << 0,
@@ -123,6 +126,7 @@ enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_IPV6  = 1UL << 2,
BATADV_MCAST_WANT_NO_RTR4   = 1UL << 3,
BATADV_MCAST_WANT_NO_RTR6   = 1UL << 4,
+   BATADV_MCAST_HAVE_MC_PTYPE_CAPA = 1UL << 5,
 };
 
 /* tt data subtypes */
@@ -174,14 +178,16 @@ enum batadv_bla_claimframe {
  * @BATADV_TVLV_TT: translation table tvlv
  * @BATADV_TVLV_ROAM: roaming advertisement tvlv
  * @BATADV_TVLV_MCAST: multicast capability tvlv
+ * @BATADV_TVLV_MCAST_TRACKER: multicast tracker tvlv
  */
 enum batadv_tvlv_type {
-   BATADV_TVLV_GW  = 0x01,
-   BATADV_TVLV_DAT = 0x02,
-   BATADV_TVLV_NC  = 0x03,
-   BATADV_TVLV_TT  = 0x04,
-   BATADV_TVLV_ROAM= 0x05,
-   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_GW  = 0x01,
+   BATADV_TVLV_DAT = 0x02,
+   BATADV_TVLV_NC  = 0x03,
+   BATADV_TVLV_TT  = 0x04,
+   BATADV_TVLV_ROAM= 0x05,
+   BATADV_TVLV_MCAST   = 0x06,
+   BATADV_TVLV_MCAST_TRACKER   = 0x07,
 };
 
 #pragma pack(2)
@@ -487,6 +493,25 @@ struct batadv_bcast_packet {
 */
 };
 
+/**
+ * struct batadv_mcast_packet - multicast packet for network payload
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the general header
+ * @ttl: time to live for this packet, part of the general header
+ * @reserved: reserved byte for alignment
+ * @tvlv_len: length of the appended tvlv buffer (in bytes)
+ */
+struct batadv_mcast_packet {
+   __u8 packet_type;
+   __u8 version;
+   __u8 ttl;
+   __u8 reserved;
+   __be16 tvlv_len;
+   /* "4 bytes boundary + 2 bytes" long to make the payload after the
+* following ethernet header again 4 bytes boundary aligned
+*/
+};
+
 /**
  * struct batadv_coded_packet - network coded packet
  * @packet_type: batman-adv packet type, part of the general header
@@ -628,6 +653,17 @@ struct batadv_tvlv_mcast_data {
__u8 reserved[3];
 };
 
+/**
+ * struct batadv_tvlv_mcast_tracker - payload of a multicast tracker tvlv
+ * @num_dests: number of subsequent destination originator MAC addresses
+ * @align: (optional) alignment bytes to make the tracker TVLV 4 bytes aligned,
+ * present if num_dests are even, not present if odd
+ */
+struct batadv_tvlv_mcast_tracker {
+   __be16  num_dests;
+   __u8align[2];
+};
+
 #pragma pack()
 
 #endif /* _UAPI_LINUX_BATADV_PACKET_H_ */
diff --git a/net/batman-adv/Makefile b/net/batman-adv/M

[PATCH 2/5] batman-adv: tvlv: prepare for tvlv enabled multicast packet type

2022-12-26 Thread Linus Lüssing
Prepare TVLV infrastructure for more packet types, in particular the
upcoming batman-adv multicast packet type.

For that swap the OGM vs. unicast-tvlv packet boolean indicator to an
explicit unsigned integer packet type variable. And provide the skb
to a call to batadv_tvlv_containers_process(), as later the multicast
packet's TVLV handler will need to have access not only to the TVLV but
the full skb for forwarding. Forwarding will be invoked from the
multicast packet's TVLVs' contents later.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/batadv_packet.h |  2 +
 net/batman-adv/bat_v_ogm.c |  4 +-
 net/batman-adv/distributed-arp-table.c |  2 +-
 net/batman-adv/gateway_common.c|  2 +-
 net/batman-adv/multicast.c |  2 +-
 net/batman-adv/routing.c   |  7 ++-
 net/batman-adv/translation-table.c |  4 +-
 net/batman-adv/tvlv.c  | 71 ++
 net/batman-adv/tvlv.h  |  8 +--
 net/batman-adv/types.h |  6 +++
 10 files changed, 73 insertions(+), 35 deletions(-)

diff --git a/include/uapi/linux/batadv_packet.h 
b/include/uapi/linux/batadv_packet.h
index ea4692c339ce..9204e4494b25 100644
--- a/include/uapi/linux/batadv_packet.h
+++ b/include/uapi/linux/batadv_packet.h
@@ -26,6 +26,7 @@
  * @BATADV_CODED: network coded packets
  * @BATADV_ELP: echo location packets for B.A.T.M.A.N. V
  * @BATADV_OGM2: originator messages for B.A.T.M.A.N. V
+ * @BATADV_MCAST: multicast packet with multiple destination addresses
  *
  * @BATADV_UNICAST: unicast packets carrying unicast payload traffic
  * @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original
@@ -42,6 +43,7 @@ enum batadv_packettype {
BATADV_CODED= 0x02,
BATADV_ELP  = 0x03,
BATADV_OGM2 = 0x04,
+   BATADV_MCAST= 0x05,
/* 0x40 - 0x7f: unicast */
 #define BATADV_UNICAST_MIN 0x40
BATADV_UNICAST  = 0x40,
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
index 033639df96d8..296fcff487bc 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -800,8 +800,8 @@ batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
 
/* only unknown & newer OGMs contain TVLVs we are interested in */
if (seqno_age > 0 && if_outgoing == BATADV_IF_DEFAULT)
-   batadv_tvlv_containers_process(bat_priv, true, orig_node,
-  NULL, NULL,
+   batadv_tvlv_containers_process(bat_priv, BATADV_OGM2, orig_node,
+  NULL,
   (unsigned char *)(ogm2 + 1),
   ntohs(ogm2->tvlv_len));
 
diff --git a/net/batman-adv/distributed-arp-table.c 
b/net/batman-adv/distributed-arp-table.c
index fefb51a5f606..6968e55eb971 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -822,7 +822,7 @@ int batadv_dat_init(struct batadv_priv *bat_priv)
batadv_dat_start_timer(bat_priv);
 
batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1,
-NULL, BATADV_TVLV_DAT, 1,
+NULL, NULL, BATADV_TVLV_DAT, 1,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
batadv_dat_tvlv_container_update(bat_priv);
return 0;
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c
index 9349c76f30c5..6a964a773f57 100644
--- a/net/batman-adv/gateway_common.c
+++ b/net/batman-adv/gateway_common.c
@@ -259,7 +259,7 @@ void batadv_gw_init(struct batadv_priv *bat_priv)
atomic_set(_priv->gw.sel_class, 1);
 
batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1,
-NULL, BATADV_TVLV_GW, 1,
+NULL, NULL, BATADV_TVLV_GW, 1,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
 }
 
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index dbe7fcfad512..548ab08d96fa 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1827,7 +1827,7 @@ static void batadv_mcast_tvlv_ogm_handler(struct 
batadv_priv *bat_priv,
 void batadv_mcast_init(struct batadv_priv *bat_priv)
 {
batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
-NULL, BATADV_TVLV_MCAST, 2,
+NULL, NULL, BATADV_TVLV_MCAST, 2,
 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
 
INIT_DELAYED_WORK(_priv->mcast.work, batadv_mcast_mla_update);
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 83f31494ea4d..163cd43c4821 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routi

[PATCH 1/5] batman-adv: mcast: remove now redundant single ucast forwarding

2022-12-26 Thread Linus Lüssing
The multicast code to send a multicast packet via multiple batman-adv
unicast packets is not only capable of sending to multiple but also to a
single node. Therefore we can safely remove the old, specialized, now
redundant multicast-to-single-unicast code.

The only functional change of this simplification is that the edge case
of allowing a multicast packet with an unsnoopable destination address
(224.0.0.0/24 or ff02::1) where only a single node has signaled interest
in it via the batman-adv want-all-unsnoopables multicast flag is now
transmitted via a batman-adv broadcast instead of a batman-adv unicast
packet. Maintaining this edge case feature does not seem worth the extra
lines of code and people should just not expect to be able to snoop and
optimize such unsnoopable multicast addresses when bridges are involved.

While at it also renaming a few items in the batadv_forw_mode enum to
prepare for the new batman-adv multicast packet type.

Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  | 248 ++--
 net/batman-adv/multicast.h  |  38 +
 net/batman-adv/soft-interface.c |  25 ++--
 3 files changed, 33 insertions(+), 278 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 34897a15ad9d..dbe7fcfad512 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1144,223 +1144,20 @@ static int batadv_mcast_forw_rtr_count(struct 
batadv_priv *bat_priv,
}
 }
 
-/**
- * batadv_mcast_forw_tt_node_get() - get a multicast tt node
- * @bat_priv: the bat priv with all the soft interface information
- * @ethhdr: the ether header containing the multicast destination
- *
- * Return: an orig_node matching the multicast address provided by ethhdr
- * via a translation table lookup. This increases the returned nodes refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv,
- struct ethhdr *ethhdr)
-{
-   return batadv_transtable_search(bat_priv, NULL, ethhdr->h_dest,
-   BATADV_NO_FLAGS);
-}
-
-/**
- * batadv_mcast_forw_ipv4_node_get() - get a node with an ipv4 flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 flag set and
- * increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv)
-{
-   struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
-
-   rcu_read_lock();
-   hlist_for_each_entry_rcu(tmp_orig_node,
-_priv->mcast.want_all_ipv4_list,
-mcast_want_all_ipv4_node) {
-   if (!kref_get_unless_zero(_orig_node->refcount))
-   continue;
-
-   orig_node = tmp_orig_node;
-   break;
-   }
-   rcu_read_unlock();
-
-   return orig_node;
-}
-
-/**
- * batadv_mcast_forw_ipv6_node_get() - get a node with an ipv6 flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV6 flag set
- * and increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv)
-{
-   struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
-
-   rcu_read_lock();
-   hlist_for_each_entry_rcu(tmp_orig_node,
-_priv->mcast.want_all_ipv6_list,
-mcast_want_all_ipv6_node) {
-   if (!kref_get_unless_zero(_orig_node->refcount))
-   continue;
-
-   orig_node = tmp_orig_node;
-   break;
-   }
-   rcu_read_unlock();
-
-   return orig_node;
-}
-
-/**
- * batadv_mcast_forw_ip_node_get() - get a node with an ipv4/ipv6 flag
- * @bat_priv: the bat priv with all the soft interface information
- * @ethhdr: an ethernet header to determine the protocol family from
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 or
- * BATADV_MCAST_WANT_ALL_IPV6 flag, depending on the provided ethhdr, sets and
- * increases its refcount.
- */
-static struct batadv_orig_node *
-batadv_mcast_forw_ip_node_get(struct batadv_priv *bat_priv,
- struct ethhdr *ethhdr)
-{
-   switch (ntohs(ethhdr->h_proto)) {
-   case ETH_P_IP:
-   return batadv_mcast_forw_ipv4_node_get(bat_priv);
-   case ETH_P_IPV6:
-   return batadv_mcast_forw_ipv6_node_get(bat_priv);
-   default:
-   /* we shouldn't be here... */
-   return NULL;
-   }
-}
-
-/**
- * batadv_mcast_forw_unsnoop_node_get() - get a node with an unsnoopable flag
- * @bat_priv: the bat priv with all the soft interface information
- *
- * Return: an orig_node which has the BATADV_MCAST_WANT_ALL_UNSNOOP

Implementation of a Stateless Multicast Packet Type

2022-12-26 Thread Linus Lüssing
Hi,

The following patchset implements a stateless, TVLV capable batman-adv
multicast packet type.

The new batman-adv multicast packet type allows to contain several
originator destination MAC addresses within a TVLV. Routers on the way will
potentially split the batman-adv multicast packet and adjust its tracker
TVLV contents.

Routing decisions are still based on the selected BATMAN IV or BATMAN V
routing algorithm. So this new batman-adv multicast packet type retains
the same loop-free properties.

The purpose of this new packet type is to allow to forward an IP
multicast packet with less transmissions / overhead than the
multicast-via-multiple-unicasts approach. Or to reach a lot more
destinations (currently up to 196, depending on the payload size, see
Wiki documentation for details) than with the default multicast fanout
for the via-unicasts approach.

This will allow using applications like mDNS again in several Freifunk
communities. And with less transmissions will also make more bulky
multicast applications, like media streaming (to an assessable amount of
receivers) a lot more feasible.

This approach is way simpler than the original multicast (tracker) packet
approach we envisioned years ago. As it involves no maintenance of an
extra, state based multicast routing table. However the TVLV capability
should allow to extend things later, to split control and data plane a bit
more for instance, to further increase the number of destinations, to
further reduce overhead.

A compact overview can be found in the Wiki here, including limitations:

https://www.open-mesh.org/projects/batman-adv/wiki/Multicast-Packet-Type

Regards, Linus



Re: [pim] draft-ietf-6lo-multicast-registration-08 replacing MLD

2022-09-13 Thread Linus Lüssing
On Mon, Aug 08, 2022 at 10:21:05AM -0700, Stig Venaas wrote:
> Hi 6lo and draft authors
> 
> I have some concerns about this draft replacing MLD for group registration.
> 
> Having 2 different protocols for the same thing can be problematic.
> Hosts or routers may need to support both protocols. Is it clear which
> one should be used in different environments? Is there a chance that
> both may be used at the same time in a network? In particular, is
> there a chance that a router may need to simultaneously support both
> protocols on an L3 interface? In that case it must be considered how
> the two protocols interoperate.
> 
> Also, we have been pushing the use of SSM in the IETF for a very long
> time, but this draft only supports ASM since only a group address is
> provided.
> 
> It would be good to have some more info on the need to replace MLD. I
> understand there are concerns about packet loss, limited resources
> etc.
> 
> Regards,
> Stig

Hi,

Is there some good overview and/or presentation of this alternative
concept available somewhere? The introduction of
draft-ietf-6lo-multicast-registration-08 as is is a bit difficult
to start with as its introduction references a lot of other, fairly
new RFCs (which generally is fine for me, avoids duplication;
just not that easy to start with as a first read :D ).

I'm very interested in this topic as we too are experiencing
several drawbacks with the current MLD approach in our layer 2
mesh networks based on B.A.T.M.A.N. Advanced [0]. Typically people
use 802.11 based WiFi routers with fixed line power with batman-adv.
At least for larger installations. While if I understand correctly this
new RFC is focusing on off-grid LoRaWAN based mesh nodes, right? Might
be interesting to check if for these two different radio technologies
we face similar issues, but also if we might have differing requirements.
To avoid that we would need a third protocol later...

---

batman-adv currently makes use of MLD snooping [1]. The four main
issues we are/were facing:

1) MLD overhead is high with default intervals for the
   mesh network sizes we are working with (> 1000 mesh nodes and
   > 2000 client devices)
2) MLD is too slow and unreliable with default intervals for
   a lossy, dynamic mesh network.
   -> we can't fix both 1) + 2) by tuning MLD querier parameters
3) MLD querier selection is not robust enough in a dynamic
   mesh network, lowest MAC addrdess for the querier is a
   bad criteria, we don't want a barely connected node with
   high packet loss at the edge of the wifi mesh network to take
   over such an essential roll; actually we don't want any
   mesh node to take over a central role, batman-adv was designed
   to work as a fully decentral mesh of equal nodes without any reliabilities
4) IGMPv2/MLDv1 Report suppression [2]; RFC4541 ("Considerations
   for Internet Group Management Protocol (IGMP)
   and Multicast Listener Discovery (MLD) Snooping Switches"
   is not feasible solution/workaround for us always forwarding all
   multicast traffic to the querier would lead to congestion

On the other hand power consumption of MLD as noted in the draft is
not a big issue for us right now, though it might be related to 1).

The workaround for our four issues we came up with is to split the layer 2
broadcast domain per mesh node with layer 2 filtering of MLD [3].
So regarding MLD it is now behaving more like a layer 3 mesh network,
where each WiFi router / mesh node is its own querier for its local
Wifi clients. And between the mesh nodes we exchange listener state
through the batman-adv protocol, sort of like a one-way proxy,
as its more efficient for us right now. The downside is that it is
one-way right now, so each batman-adv node will have the listener
state which is enough for us right now to ensure that within the layer 2
broadcast domain multicast works fine. However a remote batman-adv
node won't translate it back to MLD, so layer 3 multicast routers
won't be informed. Also its ASM only at the moment.

But I would celebrate it if we could just get rid of these workarounds
by simply having a more robust, more decentral but also less costly
MLDv3 (and especially no more MLDv1).

---

I'll also be at the Wireless Battlemesh [4] in Rome, Italy, with several
other batman-adv developers next week and we will be talking about mesh
networks the whole week. Feel free to stop by if you can, it's
an awesome event :-). Or would anybody be interested to exchange our
experiences with MLD in mesh networks remotely during that week? I
could put an official slot on the Battlemesh schedule, if people would
be interested.

Regards, Linus


[0]: https://www.open-mesh.org/projects/batman-adv/wiki
[1]: https://www.open-mesh.org/projects/batman-adv/wiki/Multicast-optimizations
[2]: 
https://www.open-mesh.org/projects/batman-adv/wiki/Multicast-optimizations-report-suppresion
[3]: 

Re: [RFC PATCH v3 1/1] mac80211: use AQL airtime for expected throughput.

2022-05-31 Thread Linus Lüssing
On Tue, May 31, 2022 at 12:09:22PM +0200, Baligh Gasmi wrote:
> Since the integration of AQL, packet TX airtime estimation is
> calculated and counted to be used for the dequeue limit.
> 
> Use this estimated airtime to compute expected throughput for
> each station.
> 
> It will be a generic mac80211 implementation. If the driver has
> get_expected_throughput implementation, it will be used instead.
> 
> Useful for L2 routing protocols, like B.A.T.M.A.N.
> 
> Signed-off-by: Baligh Gasmi 

Hi Baligh,

Thanks for your work, this indeed sounds very relevant for
batman-adv. Do you have some test results on how this compares to
real throughput? And maybe how it compares to other methods we
already have in the kernel, like expected throughput via
minstrel_ht rate control or the estimates performed in 802.11s
HWMP [0]?

Is there a certain minimum amount of traffic you'd suggest to have
enough samples to get a meaningful result?

I'm also wondering if we are starting to accumulate too many
places to provide wifi expected throughput calculations. Do you
see a chance that this generic mac80211 implementation could be made
good enough to be used as the sole source for both batman-adv and
802.11s HWMP, for instance? Or do you see some pros and cons
between the different methods?

Regards, Linus


[0]: https://elixir.bootlin.com/linux/v5.18/source/net/mac80211/mesh_hwmp.c#L295


[PATCH maint] batman-adv: mcast: don't send link-local multicast to mcast routers

2021-12-31 Thread Linus Lüssing
The addition of routable multicast TX handling introduced a
bug/regression for packets with a link-local multicast destination:
These packets would be sent to all batman-adv nodes with a multicast
router and to all batman-adv nodes with an old version without multicast
router detection.

This even disregards the batman-adv multicast fanout setting, which can
potentially lead to an unwanted, high number of unicast transmissions or
even congestion.

Fixing this by avoiding to send link-local multicast packets to nodes in
the multicast router list.

Fixes: 3a8df00cd969 ("batman-adv: mcast: apply optimizations for routable 
packets, too")
Signed-off-by: Linus Lüssing 
---
 net/batman-adv/multicast.c  | 15 ++-
 net/batman-adv/multicast.h  |  5 +++--
 net/batman-adv/soft-interface.c |  7 +--
 3 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 433901dc..f4004cf0 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1339,6 +1339,7 @@ batadv_mcast_forw_rtr_node_get(struct batadv_priv 
*bat_priv,
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: The multicast packet to check
  * @orig: an originator to be set to forward the skb to
+ * @is_routable: stores whether the destination is routable
  *
  * Return: the forwarding mode as enum batadv_forw_mode and in case of
  * BATADV_FORW_SINGLE set the orig to the single originator the skb
@@ -1346,17 +1347,16 @@ batadv_mcast_forw_rtr_node_get(struct batadv_priv 
*bat_priv,
  */
 enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  struct batadv_orig_node **orig)
+  struct batadv_orig_node **orig, int *is_routable)
 {
int ret, tt_count, ip_count, unsnoop_count, total_count;
bool is_unsnoopable = false;
unsigned int mcast_fanout;
struct ethhdr *ethhdr;
-   int is_routable = 0;
int rtr_count = 0;
 
ret = batadv_mcast_forw_mode_check(bat_priv, skb, _unsnoopable,
-  _routable);
+  is_routable);
if (ret == -ENOMEM)
return BATADV_FORW_NONE;
else if (ret < 0)
@@ -1369,7 +1369,7 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, 
struct sk_buff *skb,
ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr);
unsnoop_count = !is_unsnoopable ? 0 :
atomic_read(_priv->mcast.num_want_all_unsnoopables);
-   rtr_count = batadv_mcast_forw_rtr_count(bat_priv, is_routable);
+   rtr_count = batadv_mcast_forw_rtr_count(bat_priv, *is_routable);
 
total_count = tt_count + ip_count + unsnoop_count + rtr_count;
 
@@ -1689,6 +1689,7 @@ batadv_mcast_forw_want_rtr(struct batadv_priv *bat_priv,
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the multicast packet to transmit
  * @vid: the vlan identifier
+ * @is_routable: stores whether the destination is routable
  *
  * Sends copies of a frame with multicast destination to any node that signaled
  * interest in it, that is either via the translation table or the according
@@ -1701,7 +1702,7 @@ batadv_mcast_forw_want_rtr(struct batadv_priv *bat_priv,
  * is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
  */
 int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  unsigned short vid)
+  unsigned short vid, int is_routable)
 {
int ret;
 
@@ -1717,12 +1718,16 @@ int batadv_mcast_forw_send(struct batadv_priv 
*bat_priv, struct sk_buff *skb,
return ret;
}
 
+   if (!is_routable)
+   goto skip_mc_router;
+
ret = batadv_mcast_forw_want_rtr(bat_priv, skb, vid);
if (ret != NET_XMIT_SUCCESS) {
kfree_skb(skb);
return ret;
}
 
+skip_mc_router:
consume_skb(skb);
return ret;
 }
diff --git a/net/batman-adv/multicast.h b/net/batman-adv/multicast.h
index 9fee5da0..c214304d 100644
--- a/net/batman-adv/multicast.h
+++ b/net/batman-adv/multicast.h
@@ -43,7 +43,8 @@ enum batadv_forw_mode {
 
 enum batadv_forw_mode
 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  struct batadv_orig_node **mcast_single_orig);
+  struct batadv_orig_node **mcast_single_orig,
+  int *is_routable);
 
 int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
struct sk_buff *skb,
@@ -51,7 +52,7 @@ int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node);
 
 int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
-  unsigned short vid);
+  

Re: Unable to get DHCP after join wlan0 WIFI mesh network

2021-11-06 Thread Linus Lüssing
On Fri, Nov 05, 2021 at 04:22:11PM -0700, Dweb Fan wrote:
> 4. I follow the document
> https://www.kernel.org/doc/Documentation/networking/batman-adv.txt,
> but seems like unable to see batman related files/folders under
> /sys/class/net/wlan0. Here is output:
> $ ls /sys/class/net/wlan0

Hm, seems this link is outdated. Not sure who can update this or
when it is going to be updated. Here is a more recent version of
this file:

https://www.kernel.org/doc/html/latest/networking/batman-adv.html

sysfs and debugfs supported is deprecated for a while. Instead
batctl and "ip link" should be used.

Regards, Linus


Re: Unable to get DHCP after join wlan0 WIFI mesh network

2021-11-06 Thread Linus Lüssing
Hi,

Glad to see that more and more people are experimenting with WiFi
mesh networks.

On Fri, Nov 05, 2021 at 04:22:11PM -0700, Dweb Fan wrote:
> Dear all,
> 
> Thanks for making such a great project!
> 
> I'm following the guide from
> https://github.com/binnes/WiFiMeshRaspberryPi, and setting up wifi
> mesh network on top of raspberry pi 3B+. Below steps are good now:
>  - batctl ping works (peer can ping each other through both IP and MAC 
> address)
>  - mac os wifi client can discover the ad-host network, and join the network

This guide seems to set up two WiFi interfaces. wlan0 in ad-hoc
mode and wlan1 in AP mode. wlan0 is a secondary interface of bat0
and wlan1+bat0 are bridged:

---br0---
   / \
 bat0  wlan1(ap)
  |
wlan0(adhoc)

On wlan0 is supposed to be only used to interconnect batman-adv
nodes. The batman-adv protocol is primarily spoken there.

Client traffic from your mac os wifi client is probably not able
to speak the batman-adv protocol and is therefore supposed to go
"over" bat0 instead of "under" bat0. So your mac os client should
connect to the wlan1 AP interface.

The traffic is then bridged from wlan1 to bat0 and batman-adv will
then encapsulate the client traffic. And then forward the
*encapsulated* traffic on wlan0 automatically to the correct
neighbor node.

Hope this helps.

Regards, Linus


[PATCHv3] batman-adv: allow netlink usage in unprivileged containers

2021-11-01 Thread Linus Lüssing
Currently, creating a batman-adv interface in an unprivileged LXD
container and attaching secondary interfaces to it with "ip" or "batctl"
works fine. However all batctl debug and configuration commands
fail:

  root@container:~# batctl originators
  Error received: Operation not permitted
  root@container:~# batctl orig_interval
  1000
  root@container:~# batctl orig_interval 2000
  root@container:~# batctl orig_interval
  1000

To fix this change the generic netlink permissions from GENL_ADMIN_PERM
to GENL_UNS_ADMIN_PERM. This way a batman-adv interface is fully
maintainable as root from within a user namespace, from an unprivileged
container.

All except one batman-adv netlink setting are per interface and do not
leak information or change settings from the host system and are
therefore save to retrieve or modify as root from within an unprivileged
container.

"batctl routing_algo" / BATADV_CMD_GET_ROUTING_ALGOS is the only
exception: It provides the batman-adv kernel module wide default routing
algorithm. However it is read-only from netlink and an unprivileged
container is still not allowed to modify
/sys/module/batman_adv/parameters/routing_algo. Instead it is advised to
use the newly introduced "batctl if create routing_algo RA_NAME" /
IFLA_BATADV_ALGO_NAME to set the routing algorithm on interface
creation, which already works fine in an unprivileged container.

Cc: Tycho Andersen 
Signed-off-by: Linus Lüssing 
---

Changelog v3:
* adding compatibility code for Linux < 4.6

Changelog v2:
* updating Tycho Andersen's email in Cc as @canonical.com returned an
  "Undelivered Mail Returned to Sender"

Cc'ing Tycho Andersen as he introduced the GENL_UNS_ADMIN_PERM in the 
following commit:

4a92602aa1cd ("openvswitch: allow management from inside user namespaces")

 compat-include/uapi/linux/genetlink.h | 22 
 net/batman-adv/netlink.c  | 30 +--
 2 files changed, 37 insertions(+), 15 deletions(-)
 create mode 100644 compat-include/uapi/linux/genetlink.h

diff --git a/compat-include/uapi/linux/genetlink.h 
b/compat-include/uapi/linux/genetlink.h
new file mode 100644
index ..5fd58e22
--- /dev/null
+++ b/compat-include/uapi/linux/genetlink.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner, Simon Wunderlich
+ *
+ * This file contains macros for maintaining compatibility with older versions
+ * of the Linux kernel.
+ */
+
+#ifndef _NET_BATMAN_ADV_COMPAT_UAPI_LINUX_GENETLINK_H_
+#define _NET_BATMAN_ADV_COMPAT_UAPI_LINUX_GENETLINK_H_
+
+#include 
+#include_next 
+
+#if LINUX_VERSION_IS_LESS(4, 6, 0)
+
+#define GENL_UNS_ADMIN_PERM GENL_ADMIN_PERM
+
+#endif /* LINUX_VERSION_IS_LESS(4, 6, 0) */
+
+#endif /* _NET_BATMAN_ADV_COMPAT_UAPI_LINUX_GENETLINK_H_ */
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 29276284..00875e1d 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -1368,21 +1368,21 @@ static const struct genl_small_ops batadv_netlink_ops[] 
= {
{
.cmd = BATADV_CMD_TP_METER,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_tp_meter_start,
.internal_flags = BATADV_FLAG_NEED_MESH,
},
{
.cmd = BATADV_CMD_TP_METER_CANCEL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_tp_meter_cancel,
.internal_flags = BATADV_FLAG_NEED_MESH,
},
{
.cmd = BATADV_CMD_GET_ROUTING_ALGOS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_algo_dump,
},
{
@@ -1397,68 +1397,68 @@ static const struct genl_small_ops batadv_netlink_ops[] 
= {
{
.cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_tt_local_dump,
},
{
.cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_tt_global_dump,
},
{
.cmd = BATADV_CMD_GET_ORIGINATORS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags 

[PATCHv2] batman-adv: allow netlink usage in unprivileged containers

2021-10-31 Thread Linus Lüssing
Currently, creating a batman-adv interface in an unprivileged LXD
container and attaching secondary interfaces to it with "ip" or "batctl"
works fine. However all batctl debug and configuration commands
fail:

  root@container:~# batctl originators
  Error received: Operation not permitted
  root@container:~# batctl orig_interval
  1000
  root@container:~# batctl orig_interval 2000
  root@container:~# batctl orig_interval
  1000

To fix this change the generic netlink permissions from GENL_ADMIN_PERM
to GENL_UNS_ADMIN_PERM. This way a batman-adv interface is fully
maintainable as root from within a user namespace, from an unprivileged
container.

All except one batman-adv netlink setting are per interface and do not
leak information or change settings from the host system and are
therefore save to retrieve or modify as root from within an unprivileged
container.

"batctl routing_algo" / BATADV_CMD_GET_ROUTING_ALGOS is the only
exception: It provides the batman-adv kernel module wide default routing
algorithm. However it is read-only from netlink and an unprivileged
container is still not allowed to modify
/sys/module/batman_adv/parameters/routing_algo. Instead it is advised to
use the newly introduced "batctl if create routing_algo RA_NAME" /
IFLA_BATADV_ALGO_NAME to set the routing algorithm on interface
creation, which already works fine in an unprivileged container.

Cc: Tycho Andersen 
Signed-off-by: Linus Lüssing 
---

Changelog v2:
* updating Tycho Andersen's email in Cc as @canonical.com returned an
  "Undelivered Mail Returned to Sender"

Cc'ing Tycho Andersen as he introduced the GENL_UNS_ADMIN_PERM in the 
following commit:

4a92602aa1cd ("openvswitch: allow management from inside user namespaces")

 net/batman-adv/netlink.c | 30 +++---
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 29276284..00875e1d 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -1368,21 +1368,21 @@ static const struct genl_small_ops batadv_netlink_ops[] 
= {
{
.cmd = BATADV_CMD_TP_METER,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_tp_meter_start,
.internal_flags = BATADV_FLAG_NEED_MESH,
},
{
.cmd = BATADV_CMD_TP_METER_CANCEL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_tp_meter_cancel,
.internal_flags = BATADV_FLAG_NEED_MESH,
},
{
.cmd = BATADV_CMD_GET_ROUTING_ALGOS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_algo_dump,
},
{
@@ -1397,68 +1397,68 @@ static const struct genl_small_ops batadv_netlink_ops[] 
= {
{
.cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_tt_local_dump,
},
{
.cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_tt_global_dump,
},
{
.cmd = BATADV_CMD_GET_ORIGINATORS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_orig_dump,
},
{
.cmd = BATADV_CMD_GET_NEIGHBORS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_hardif_neigh_dump,
},
{
.cmd = BATADV_CMD_GET_GATEWAYS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_gw_dump,
},
{
.cmd = BATADV_CMD_GET_BLA_CLAIM,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_bla_claim_dump,
},

[PATCH] batman-adv: allow netlink usage in unprivileged containers

2021-10-31 Thread Linus Lüssing
Currently, creating a batman-adv interface in an unprivileged LXD
container and attaching secondary interfaces to it with "ip" or "batctl"
works fine. However all batctl debug and configuration commands
fail:

  root@container:~# batctl originators
  Error received: Operation not permitted
  root@container:~# batctl orig_interval
  1000
  root@container:~# batctl orig_interval 2000
  root@container:~# batctl orig_interval
  1000

To fix this change the generic netlink permissions from GENL_ADMIN_PERM
to GENL_UNS_ADMIN_PERM. This way a batman-adv interface is fully
maintainable as root from within a user namespace, from an unprivileged
container.

All except one batman-adv netlink setting are per interface and do not
leak information or change settings from the host system and are
therefore save to retrieve or modify as root from within an unprivileged
container.

"batctl routing_algo" / BATADV_CMD_GET_ROUTING_ALGOS is the only
exception: It provides the batman-adv kernel module wide default routing
algorithm. However it is read-only from netlink and an unprivileged
container is still not allowed to modify
/sys/module/batman_adv/parameters/routing_algo. Instead it is advised to
use the newly introduced "batctl if create routing_algo RA_NAME" /
IFLA_BATADV_ALGO_NAME to set the routing algorithm on interface
creation, which already works fine in an unprivileged container.

Cc: Tycho Andersen 
Signed-off-by: Linus Lüssing 
---
Cc'ing Tycho Andersen as he introduced the GENL_UNS_ADMIN_PERM in the 
following commit:

4a92602aa1cd ("openvswitch: allow management from inside user namespaces")

 net/batman-adv/netlink.c | 30 +++---
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 29276284..00875e1d 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -1368,21 +1368,21 @@ static const struct genl_small_ops batadv_netlink_ops[] 
= {
{
.cmd = BATADV_CMD_TP_METER,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_tp_meter_start,
.internal_flags = BATADV_FLAG_NEED_MESH,
},
{
.cmd = BATADV_CMD_TP_METER_CANCEL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_tp_meter_cancel,
.internal_flags = BATADV_FLAG_NEED_MESH,
},
{
.cmd = BATADV_CMD_GET_ROUTING_ALGOS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_algo_dump,
},
{
@@ -1397,68 +1397,68 @@ static const struct genl_small_ops batadv_netlink_ops[] 
= {
{
.cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_tt_local_dump,
},
{
.cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_tt_global_dump,
},
{
.cmd = BATADV_CMD_GET_ORIGINATORS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_orig_dump,
},
{
.cmd = BATADV_CMD_GET_NEIGHBORS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_hardif_neigh_dump,
},
{
.cmd = BATADV_CMD_GET_GATEWAYS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_gw_dump,
},
{
.cmd = BATADV_CMD_GET_BLA_CLAIM,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-   .flags = GENL_ADMIN_PERM,
+   .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_bla_claim_dump,
},
{
.cmd = BATADV_CMD_GET_BLA_BACKBONE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- 

Re: Dynamic DHCP server assignment and spin-up on batman-adv mesh network

2021-09-01 Thread Linus Lüssing
On Wed, Sep 01, 2021 at 09:54:36PM +0200, Linus Lüssing wrote:
> On Tue, Aug 31, 2021 at 05:28:41PM -, tanner.perk...@cnftech.com wrote:
> > If this is not the best place to ask questions regarding mesh networks 
> > utilizing the batman-adv kernel module, I apologies and please point me to 
> > where I need to be.
> > 
> > I'm looking to set up distributed mesh network using the batman-adv Linux 
> > kernel module. However, I don't want to have to statically assign IP 
> > addresses to all my nodes therefore my first thought was to use DHCP. The 
> > problem arises in my scenario that any node could come and go in the mesh 
> > network as they move in and out range of the network. Therefore manually 
> > allocating a single or even a few DHCP servers isn't realistic as that DHCP 
> > server may drop out of the network at anytime. Is there a dynamic way to 
> > reassign the DHCP server based on the nodes still within the network when 
> > the previous DHCP server drops from the network?
> 
> Tricky question. DHCP was probably not designed with highly
> dynamic networks in mind back then.
> 
> Typically people run a few DHCP servers on hosts with a high
> availability and not mesh nodes that might go offline at "random"
> times. And then use the batman-adv gateway feature to stear DHCP
> requests to the "best" one [0]. For some topologies people also
> make use of the batman-adv "Bridge Loop Avoidance" [1] feature
> and place the DHCP server(s) on a common LAN backbone to which
> multiple nodes are connected via cable, which can add some
> extra fault tolerance. And maybe set the lease interval to
> something faster then the usual defaults.
> 
> Someone had also been writing DDHCP, a "Distributed DHCP Daemon" here
> [2] but I'm not sure if it is actually used by anyone at the moment.
> The original idea was to integrate it into the OpenWrt based
> mesh routing framework "Gluon" [3], so that every node would be a
> DHCP server for all its locally connected client devices and the
> DHCP requests from the client devices would be filtered from
> entering the mesh directly. And the DDHCP servers would
> organize leases among themselves. But there hasn't been a PR for
> Gluon yet. But it was tested (and developed) at Freifunk Kiel
> at some point. If you were to try it out, I'd be very interested to hear
> what your experiences with it are.
> 
> Next there is also AHCP [4] which was built for/with BABEL I
> think. But don't know how it actually works and if it could be
> useful on layer 2 at all or if it is only usable with a layer 3
> mesh routing protocol.
> 
> Regards, Linus
> 
> [0]: https://www.open-mesh.org/projects/batman-adv/wiki/Gateways
> [2]: https://github.com/sargon/ddhcpd
> [3]: 
> https://www.open-mesh.org/projects/batman-adv/wiki/Bridge-loop-avoidance-II#Situation
> [4]: https://www.irif.fr/~jch/software/ahcp/

Sorry, links and numberings are off, should have been:

[0]: https://www.open-mesh.org/projects/batman-adv/wiki/Gateways
[1]: 
https://www.open-mesh.org/projects/batman-adv/wiki/Bridge-loop-avoidance-II#Situation
[2]: https://github.com/sargon/ddhcpd
[3]: https://github.com/freifunk-gluon/gluon/
[4]: https://www.irif.fr/~jch/software/ahcp/


[PATCH v3 3/3] batman-adv: bcast: remove remaining skb-copy calls for broadcasts

2021-05-16 Thread Linus Lüssing
We currently have two code paths for broadcast packets: A)
self-generated, via batadv_interface_tx()->batadv_send_bcast_packet().
Or B) received/forwarded, via batadv_recv_bcast_packet()->
batadv_forw_bcast_packet().

For A), self-generated broadcast packets the only modifications to the
skb data is the ethernet header which is added/pushed to the skb in
batadv_send_broadcast_skb()->batadv_send_skb_packet(). However before
doing so batadv_skb_head_push() is called which calls skb_cow_head() to
unshare the space for the to be pushed ethernet header. So for this
case, it is safe to use skb clones.

For B), received/forwarded packets the same applies as in A) for the
to be forwarded packets. Only the ethernet header is added. However
after (queueing for) forwarding the packet in
batadv_recv_bcast_packet()->batadv_forw_bcast_packet() a packet is
additionally decapsulated and is sent up the stack through
batadv_recv_bcast_packet()->batadv_interface_rx(). Which needs an
unshared skb data for potential modifications from other protocols.
To be able to use skb clones for (re)broadcasted batman-adv broadcast
packets while still ensuring that interface_rx() has a freely writeable
skb we use skb_cow() to avoid sharing skb data with the skb clones in
the forwarding calls.

Signed-off-by: Linus Lüssing 
---

Changelog v3:

* newly added this patch, to move skb_copy()->skb_clone() changes from
  PATCH 01/03 to a separate patch with its own explanation

 net/batman-adv/send.c | 24 +---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 0b9dd29d..1db6b217 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -748,6 +748,10 @@ void batadv_forw_packet_ogmv1_queue(struct batadv_priv 
*bat_priv,
  * Adds a broadcast packet to the queue and sets up timers. Broadcast packets
  * are sent multiple times to increase probability for being received.
  *
+ * This call clones the given skb, hence the caller needs to take into
+ * account that the data segment of the original skb might not be
+ * modifiable anymore.
+ *
  * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY on errors.
  */
 static int batadv_forw_bcast_packet_to_list(struct batadv_priv *bat_priv,
@@ -761,7 +765,7 @@ static int batadv_forw_bcast_packet_to_list(struct 
batadv_priv *bat_priv,
unsigned long send_time = jiffies;
struct sk_buff *newskb;
 
-   newskb = skb_copy(skb, GFP_ATOMIC);
+   newskb = skb_clone(skb, GFP_ATOMIC);
if (!newskb)
goto err;
 
@@ -800,6 +804,10 @@ static int batadv_forw_bcast_packet_to_list(struct 
batadv_priv *bat_priv,
  * or if a delay is given after that. Furthermore, queues additional
  * retransmissions if this interface is a wireless one.
  *
+ * This call clones the given skb, hence the caller needs to take into
+ * account that the data segment of the original skb might not be
+ * modifiable anymore.
+ *
  * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY on errors.
  */
 static int batadv_forw_bcast_packet_if(struct batadv_priv *bat_priv,
@@ -814,7 +822,7 @@ static int batadv_forw_bcast_packet_if(struct batadv_priv 
*bat_priv,
int ret = NETDEV_TX_OK;
 
if (!delay) {
-   newskb = skb_copy(skb, GFP_ATOMIC);
+   newskb = skb_clone(skb, GFP_ATOMIC);
if (!newskb)
return NETDEV_TX_BUSY;
 
@@ -966,6 +974,8 @@ static int __batadv_forw_bcast_packet(struct batadv_priv 
*bat_priv,
  * after that. Furthermore, queues additional retransmissions on wireless
  * interfaces.
  *
+ * This call might reallocate skb data.
+ *
  * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY on errors.
  */
 int batadv_forw_bcast_packet(struct batadv_priv *bat_priv,
@@ -973,7 +983,15 @@ int batadv_forw_bcast_packet(struct batadv_priv *bat_priv,
 unsigned long delay,
 bool own_packet)
 {
-   return __batadv_forw_bcast_packet(bat_priv, skb, delay, own_packet);
+   int ret = __batadv_forw_bcast_packet(bat_priv, skb, delay, own_packet);
+
+   if (ret == NETDEV_TX_BUSY)
+   return ret;
+
+   /* __batadv_forw_bcast_packet clones, make sure original
+* skb stays writeable
+*/
+   return (skb_cow(skb, 0) < 0) ? NETDEV_TX_BUSY : NETDEV_TX_OK;
 }
 
 /**
-- 
2.31.0


[PATCH v3 2/3] batman-adv: bcast: avoid skb-copy for (re)queued broadcasts

2021-05-16 Thread Linus Lüssing
Broadcast packets send via batadv_send_outstanding_bcast_packet() were
originally copied in batadv_forw_bcast_packet_to_list() before being
queued. And after that only the ethernet header will be pushed through
batadv_send_broadcast_skb()->batadv_send_skb_packet() which works safely
on skb clones as it uses batadv_skb_head_push()->skb_cow_head().

Signed-off-by: Linus Lüssing 
---

Changelog v3:

* newly added this patch, to move skb_copy()->skb_clone() change from
  PATCH 01/03 to a separate patch with its own explanation

 net/batman-adv/send.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 07b0ba26..0b9dd29d 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -1072,7 +1072,7 @@ static void batadv_send_outstanding_bcast_packet(struct 
work_struct *work)
}
 
/* send a copy of the saved skb */
-   skb1 = skb_copy(forw_packet->skb, GFP_ATOMIC);
+   skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
if (!skb1)
goto out;
 
-- 
2.31.0


[PATCH v3 1/3] batman-adv: bcast: queue per interface, if needed

2021-05-16 Thread Linus Lüssing
Currently we schedule a broadcast packet like:

3x: [ [(re-)queue] --> for(hard-if): maybe-transmit ]

The intention of queueing a broadcast packet multiple times is to
increase robustness for wireless interfaces. However on interfaces
which we only broadcast on once the queueing induces an unnecessary
penalty. This patch restructures the queueing to be performed on a per
interface basis:

for(hard-if):
- transmit
- if wireless: [queue] --> transmit --> [requeue] --> transmit

Next to the performance benefits on non-wireless interfaces this
should also make it easier to apply alternative strategies for
transmissions on wireless interfaces in the future (for instance sending
via unicast transmissions on wireless interfaces, without queueing in
batman-adv, if appropriate).

Signed-off-by: Linus Lüssing 
---

Changelog v3:

* changed all skb_clone() calls to skb_copy(), to move the
  skb_copy()->skb_clone() changes to extra commits with their own
  explanation

Changelog v2:

* fixed spelling of "unnecessary" in commit message (thanks Sven)
* removed now superflous kerneldoc for hard_iface in
  batadv_forw_packet_bcasts_left() (thanks Sven)
* removed delay check for queued (re)broadcasts in
  batadv_forw_bcast_packet_if(): the only case where a delay is set
  for this function is for a delayed, DAT fallback ARP Request from
  this node, then however num_bcasts will be >=1, too, and the fallback
  ARP Request will be scheduled anyway
---
 net/batman-adv/main.h   |   1 -
 net/batman-adv/routing.c|   9 +-
 net/batman-adv/send.c   | 374 +---
 net/batman-adv/send.h   |  12 +-
 net/batman-adv/soft-interface.c |  12 +-
 5 files changed, 270 insertions(+), 138 deletions(-)

diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 8f0102b7..baa9fcbe 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -88,7 +88,6 @@
 /* number of packets to send for broadcasts on different interface types */
 #define BATADV_NUM_BCASTS_DEFAULT 1
 #define BATADV_NUM_BCASTS_WIRELESS 3
-#define BATADV_NUM_BCASTS_MAX 3
 
 /* length of the single packet used by the TP meter */
 #define BATADV_TP_PACKET_LEN ETH_DATA_LEN
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 40f5cffd..bb9e93e3 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -1182,9 +1182,9 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
struct batadv_bcast_packet *bcast_packet;
struct ethhdr *ethhdr;
int hdr_size = sizeof(*bcast_packet);
-   int ret = NET_RX_DROP;
s32 seq_diff;
u32 seqno;
+   int ret;
 
/* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, hdr_size)))
@@ -1210,7 +1210,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
if (batadv_is_my_mac(bat_priv, bcast_packet->orig))
goto free_skb;
 
-   if (bcast_packet->ttl < 2)
+   if (bcast_packet->ttl-- < 2)
goto free_skb;
 
orig_node = batadv_orig_hash_find(bat_priv, bcast_packet->orig);
@@ -1249,7 +1249,9 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
batadv_skb_set_priority(skb, sizeof(struct batadv_bcast_packet));
 
/* rebroadcast packet */
-   batadv_add_bcast_packet_to_list(bat_priv, skb, 1, false);
+   ret = batadv_forw_bcast_packet(bat_priv, skb, 0, false);
+   if (ret == NETDEV_TX_BUSY)
+   goto free_skb;
 
/* don't hand the broadcast up if it is from an originator
 * from the same backbone.
@@ -1275,6 +1277,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
spin_unlock_bh(_node->bcast_seqno_lock);
 free_skb:
kfree_skb(skb);
+   ret = NET_RX_DROP;
 out:
if (orig_node)
batadv_orig_node_put(orig_node);
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 157abe92..07b0ba26 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -737,57 +737,48 @@ void batadv_forw_packet_ogmv1_queue(struct batadv_priv 
*bat_priv,
 }
 
 /**
- * batadv_add_bcast_packet_to_list() - queue broadcast packet for multiple 
sends
+ * batadv_forw_bcast_packet_to_list() - queue broadcast packet for 
transmissions
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: broadcast packet to add
  * @delay: number of jiffies to wait before sending
  * @own_packet: true if it is a self-generated broadcast packet
+ * @if_in: the interface where the packet was received on
+ * @if_out: the outgoing interface to queue on
  *
- * add a broadcast packet to the queue and setup timers. broadcast packets
+ * Adds a broadcast packet to the queue and sets up timers. Broadcast packets
  * are sent multiple times to increase probability for being received.
  *
- * The skb is not consumed, so the caller should make sure that the
- * skb is freed.
- *
  * Return: NETDEV_TX_OK o

[PATCH] batman-adv: mcast: add MRD + routable IPv4 multicast with bridges support

2021-05-15 Thread Linus Lüssing
This adds support for routable IPv4 multicast addresses
(224.0.0.0/4, excluding 224.0.0.0/24) in bridged setups.

This utilizes the Multicast Router Discovery (MRD, RFC4286) support
in the Linux bridge. batman-adv will now query the Linux bridge for
IPv4 multicast routers, which the bridge has previously learned about
via MRD.

This allows us to then safely send routable IPv4 multicast packets in
bridged setups to multicast listeners and multicast routers only. Before
we had to flood such packets to avoid potential multicast packet loss to
IPv4 multicast routers, which we were not able to detect before.

With the bridge MRD integration, we are now also able to perform more
fine-grained detection of IPv6 multicast routers in bridged setups:
Before we were "guessing" IPv6 multicast routers by looking up multicast
listeners for the link-local All Routers multicast address (ff02::2),
which every IPv6 multicast router is listening to. However this would
also include more nodes than necessary: For instance nodes which are
just a router for unicast, but not multicast would be included, too.

Signed-off-by: Linus Lüssing 
---

Please double check the Linux version in
compat-include/linux/if_bridge.h.

Commit 3b85f9ba3480c1 ("net: bridge: mcast: export multicast router presence 
adjacent to a port")
was added to net-next just recently
(CommitDate: Thu May 13 14:04:31 2021 -0700).
So br_multicast_has_router_adjacent() should be part of >= 5.14?

 compat-include/linux/if_bridge.h | 42 
 net/batman-adv/multicast.c   | 41 ---
 2 files changed, 47 insertions(+), 36 deletions(-)

diff --git a/compat-include/linux/if_bridge.h b/compat-include/linux/if_bridge.h
index da00c8b0..dfc4a092 100644
--- a/compat-include/linux/if_bridge.h
+++ b/compat-include/linux/if_bridge.h
@@ -53,4 +53,46 @@ inline void __batadv_br_ip_list_check(void)
 
 #endif /* LINUX_VERSION_IS_LESS(5, 10, 0) */
 
+#if LINUX_VERSION_IS_LESS(5, 14, 0)
+
+#include 
+
+#if IS_ENABLED(CONFIG_IPV6)
+static inline bool
+br_multicast_has_router_adjacent(struct net_device *dev, int proto)
+{
+   struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
+   struct br_ip_list *br_ip_entry, *tmp;
+   int ret;
+
+   if (proto != ETH_P_IPV6)
+   return true;
+
+   ret = br_multicast_list_adjacent(dev, _mcast_list);
+   if (ret < 0)
+   return true;
+
+   ret = false;
+
+   list_for_each_entry_safe(br_ip_entry, tmp, _mcast_list, list) {
+   if (br_ip_entry->addr.proto == htons(ETH_P_IPV6) &&
+   ipv6_addr_is_ll_all_routers(_ip_entry->addr.dst.ip6))
+   ret = true;
+
+   list_del(_ip_entry->list);
+   kfree(br_ip_entry);
+   }
+
+   return ret;
+}
+#else
+static inline bool
+br_multicast_has_router_adjacent(struct net_device *dev, int proto)
+{
+   return true;
+}
+#endif
+
+#endif /* LINUX_VERSION_IS_LESS(5, 14, 0) */
+
 #endif /* _NET_BATMAN_ADV_COMPAT_LINUX_IF_BRIDGE_H_ */
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 1d63c8cb..923e2197 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -193,53 +193,22 @@ static u8 batadv_mcast_mla_rtr_flags_softif_get(struct 
batadv_priv *bat_priv,
  * BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
  * The former two OR'd: no multicast router is present
  */
-#if IS_ENABLED(CONFIG_IPV6)
 static u8 batadv_mcast_mla_rtr_flags_bridge_get(struct batadv_priv *bat_priv,
struct net_device *bridge)
 {
-   struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
struct net_device *dev = bat_priv->soft_iface;
-   struct br_ip_list *br_ip_entry, *tmp;
-   u8 flags = BATADV_MCAST_WANT_NO_RTR6;
-   int ret;
+   u8 flags = BATADV_NO_FLAGS;
 
if (!bridge)
return BATADV_MCAST_WANT_NO_RTR4 | BATADV_MCAST_WANT_NO_RTR6;
 
-   /* TODO: ask the bridge if a multicast router is present (the bridge
-* is capable of performing proper RFC4286 multicast router
-* discovery) instead of searching for a ff02::2 listener here
-*/
-   ret = br_multicast_list_adjacent(dev, _mcast_list);
-   if (ret < 0)
-   return BATADV_NO_FLAGS;
-
-   list_for_each_entry_safe(br_ip_entry, tmp, _mcast_list, list) {
-   /* the bridge snooping does not maintain IPv4 link-local
-* addresses - therefore we won't find any IPv4 multicast router
-* address here, only IPv6 ones
-*/
-   if (br_ip_entry->addr.proto == htons(ETH_P_IPV6) &&
-   ipv6_addr_is_ll_all_routers(_ip_entry->addr.dst.ip6))
-   flags &= ~BATADV_MCAST_WANT_NO_RTR6;
-
-

Re: [PATCH v2] batman-adv: bcast: queue per interface, if needed

2021-05-14 Thread Linus Lüssing
On Fri, May 14, 2021 at 10:28:53AM +0200, Sven Eckelmann wrote:
> On Tuesday, 27 April 2021 20:45:27 CEST Linus Lüssing wrote:
> > - * The skb is not consumed, so the caller should make sure that the
> > - * skb is freed.
> > + * This call clones the given skb, hence the caller needs to take into
> > + * account that the data segment of the original skb might not be
> > + * modifiable anymore.
> 
> But none of your callers is now taking care of it because you've removed all 
> skb_copy's. All you do is to clone the control data and give it to the 
> underlying layers. And they may write freely to the data. Thus breaking 
> parallel (and under some circumstances sequential) running code which 
> operates 
> on the skbs.

Hi Sven,

Thanks for looking at it so far. I'm not quite sure if the
skb_copy() is needed though. Because there is a new skb_cow(). Let
me explain my thoughts:


We have two cases: A) Packet originating from ourself, via
batadv_interface_tx(). Or B) received+forwarded from a neighbor
node via batadv_recv_bcast_packet().

For case A), self generated:

When we send the packet multiple times, for each rebroadcast or
interface we will push the ethernet header and write the ether-src,
ether-dest and ether protocol in  batadv_send_skb_packet(). Before that
batadv_send_skb_packet() calls batadv_skb_head_push() which calls
skb_cow_head(). So the ethernet header should be modifiable safely then,
even if it is an skb clone.

For case B), received/forwarded:

Rebroadcasts same as in A), but additionally after rebroadcasting
with potential requeuing in batadv_recv_bcast_packet() via
batadv_forw_bcast_packet() we will also call
batadv_interface_rx() and strip the batman header. Betweeen these
calls there is the following though:

batadv_forw_bcast_packet(skb, ...)
-> __batadv_forw_bcast_packet(skb, ...);
   ...
   skb_cow(skb, 0)

So the original skb will have been made uncloned/writeable again
via the skb_cow() before being handed to batadv_interface_rx().

Let me know if I'm missing something.

Regards, Linus


Re: [net-next v2 09/11] net: bridge: mcast: split multicast router state for IPv4 and IPv6

2021-05-11 Thread Linus Lüssing
On Tue, May 11, 2021 at 12:29:41PM +0300, Nikolay Aleksandrov wrote:
> [...]
> > -static void br_multicast_mark_router(struct net_bridge *br,
> > -struct net_bridge_port *port)
> > +#if IS_ENABLED(CONFIG_IPV6)
> > +struct hlist_node *
> > +br_ip6_multicast_get_rport_slot(struct net_bridge *br, struct 
> > net_bridge_port *port)
> > +{
> > +   struct hlist_node *slot = NULL;
> > +   struct net_bridge_port *p;
> > +
> > +   hlist_for_each_entry(p, >ip6_mc_router_list, ip6_rlist) {
> > +   if ((unsigned long)port >= (unsigned long)p)
> > +   break;
> > +   slot = >ip6_rlist;
> > +   }
> > +
> > +   return slot;
> > +}
> 
> The ip4/ip6 get_rport_slot functions are identical, why not add a list pointer
> and use one function ?

Hi Nikolay,

Thanks for all the feedback and reviewing again! I'll
remove (most of) the inlines as the router list modifications are
not in the fast path.

For the get_rport_slot functions, maybe I'm missing a simple
solution. Note that "ip6_rlist" in hlist_for_each_entry() is not a
pointer but will be expanded by the macro. I currently don't see
how I could solve this with just one hlist_for_each_entry().

Regards, Linus


[net-next v2 11/11] net: bridge: mcast: export multicast router presence adjacent to a port

2021-05-09 Thread Linus Lüssing
To properly support routable multicast addresses in batman-adv in a
group-aware way, a batman-adv node needs to know if it serves multicast
routers.

This adds a function to the bridge to export this so that batman-adv
can then make full use of the Multicast Router Discovery capability of
the bridge.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c | 58 +++
 1 file changed, 58 insertions(+)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index b625fd6..e963de5 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -4061,6 +4061,64 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(br_multicast_has_querier_adjacent);
 
+/**
+ * br_multicast_has_router_adjacent - Checks for a router behind a bridge port
+ * @dev: The bridge port adjacent to which to check for a multicast router
+ * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> 
ETH_P_IPV6
+ *
+ * Checks whether the given interface has a bridge on top and if so returns
+ * true if a multicast router is behind one of the other ports of this
+ * bridge. Otherwise returns false.
+ */
+bool br_multicast_has_router_adjacent(struct net_device *dev, int proto)
+{
+   struct net_bridge_port *port, *p;
+   bool ret = false;
+
+   rcu_read_lock();
+   if (!netif_is_bridge_port(dev))
+   goto unlock;
+
+   port = br_port_get_rcu(dev);
+   if (!port || !port->br)
+   goto unlock;
+
+   switch (proto) {
+   case ETH_P_IP:
+   hlist_for_each_entry_rcu(p, >br->ip4_mc_router_list,
+ip4_rlist) {
+   if (p == port)
+   continue;
+
+   ret = true;
+   goto unlock;
+   }
+   break;
+#if IS_ENABLED(CONFIG_IPV6)
+   case ETH_P_IPV6:
+   hlist_for_each_entry_rcu(p, >br->ip6_mc_router_list,
+ip6_rlist) {
+   if (p == port)
+   continue;
+
+   ret = true;
+   goto unlock;
+   }
+   break;
+#endif
+   default:
+   /* when compiled without IPv6 support, be conservative and
+* always assume presence of an IPv6 multicast router
+*/
+   ret = true;
+   }
+
+unlock:
+   rcu_read_unlock();
+   return ret;
+}
+EXPORT_SYMBOL_GPL(br_multicast_has_router_adjacent);
+
 static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats,
   const struct sk_buff *skb, u8 type, u8 dir)
 {
-- 
2.31.0


[net-next v2 10/11] net: bridge: mcast: add ip4+ip6 mcast router timers to mdb netlink

2021-05-09 Thread Linus Lüssing
Now that we have split the multicast router state into two, one for IPv4
and one for IPv6, also add individual timers to the mdb netlink router
port dump. Leaving the old timer attribute for backwards compatibility.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/if_bridge.h | 2 ++
 net/bridge/br_mdb.c| 8 +++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index 13d59c5..6b56a75 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -627,6 +627,8 @@ enum {
MDBA_ROUTER_PATTR_UNSPEC,
MDBA_ROUTER_PATTR_TIMER,
MDBA_ROUTER_PATTR_TYPE,
+   MDBA_ROUTER_PATTR_INET_TIMER,
+   MDBA_ROUTER_PATTR_INET6_TIMER,
__MDBA_ROUTER_PATTR_MAX
 };
 #define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1)
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 3c608da..2cdd9b6 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -79,7 +79,13 @@ static int br_rports_fill_info(struct sk_buff *skb, struct 
netlink_callback *cb,
nla_put_u32(skb, MDBA_ROUTER_PATTR_TIMER,
max(ip4_timer, ip6_timer)) ||
nla_put_u8(skb, MDBA_ROUTER_PATTR_TYPE,
-  p->multicast_router)) {
+  p->multicast_router) ||
+   (have_ip4_mc_rtr &&
+nla_put_u32(skb, MDBA_ROUTER_PATTR_INET_TIMER,
+ip4_timer)) ||
+   (have_ip6_mc_rtr &&
+nla_put_u32(skb, MDBA_ROUTER_PATTR_INET6_TIMER,
+ip6_timer))) {
nla_nest_cancel(skb, port_nest);
goto fail;
}
-- 
2.31.0


[net-next v2 09/11] net: bridge: mcast: split multicast router state for IPv4 and IPv6

2021-05-09 Thread Linus Lüssing
A multicast router for IPv4 does not imply that the same host also is a
multicast router for IPv6 and vice versa.

To reduce multicast traffic when a host is only a multicast router for
one of these two protocol families, keep router state for IPv4 and IPv6
separately. Similar to how querier state is kept separately.

For backwards compatibility for netlink and switchdev notifications
these two will still only notify if a port switched from either no
IPv4/IPv6 multicast router to any IPv4/IPv6 multicast router or the
other way round. However a full netlink MDB router dump will now also
include a multicast router timeout for both IPv4 and IPv6.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_forward.c   |   8 ++
 net/bridge/br_mdb.c   |  10 ++
 net/bridge/br_multicast.c | 197 ++
 net/bridge/br_private.h   |   6 +-
 4 files changed, 201 insertions(+), 20 deletions(-)

diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index b5ec4f9..31a02c5 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -266,11 +266,19 @@ static void maybe_deliver_addr(struct net_bridge_port *p, 
struct sk_buff *skb,
 
 static inline struct hlist_node *
 br_multicast_get_first_rport_node(struct net_bridge *b, struct sk_buff *skb) {
+#if IS_ENABLED(CONFIG_IPV6)
+   if (skb->protocol == htons(ETH_P_IPV6))
+   return rcu_dereference(hlist_first_rcu(>ip6_mc_router_list));
+#endif
return rcu_dereference(hlist_first_rcu(>ip4_mc_router_list));
 }
 
 static inline struct net_bridge_port *
 br_multicast_rport_from_node(struct hlist_node *rp, struct sk_buff *skb) {
+#if IS_ENABLED(CONFIG_IPV6)
+   if (skb->protocol == htons(ETH_P_IPV6))
+   return hlist_entry_safe(rp, struct net_bridge_port, ip6_rlist);
+#endif
return hlist_entry_safe(rp, struct net_bridge_port, ip4_rlist);
 }
 
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 6937d3b..3c608da 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -18,7 +18,12 @@
 
 static inline bool br_rports_have_mc_router(struct net_bridge *br)
 {
+#if IS_ENABLED(CONFIG_IPV6)
+   return !hlist_empty(>ip4_mc_router_list) ||
+  !hlist_empty(>ip6_mc_router_list);
+#else
return !hlist_empty(>ip4_mc_router_list);
+#endif
 }
 
 static inline bool
@@ -31,8 +36,13 @@ br_ip4_rports_get_timer(struct net_bridge_port *port, 
unsigned long *timer)
 static inline bool
 br_ip6_rports_get_timer(struct net_bridge_port *port, unsigned long *timer)
 {
+#if IS_ENABLED(CONFIG_IPV6)
+   *timer = br_timer_value(>ip6_mc_router_timer);
+   return !hlist_unhashed(>ip6_rlist);
+#else
*timer = 0;
return false;
+#endif
 }
 
 static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback 
*cb,
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 39854d5..b625fd6 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -63,6 +63,8 @@ static void br_multicast_port_group_rexmit(struct timer_list 
*t);
 static void
 br_multicast_rport_del_notify(struct net_bridge_port *p, bool deleted);
 #if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_add_router(struct net_bridge *br,
+   struct net_bridge_port *port);
 static void br_ip6_multicast_leave_group(struct net_bridge *br,
 struct net_bridge_port *port,
 const struct in6_addr *group,
@@ -1369,6 +1371,15 @@ static inline bool br_ip4_multicast_rport_del(struct 
net_bridge_port *p)
return br_multicast_rport_del(>ip4_rlist);
 }
 
+static inline bool br_ip6_multicast_rport_del(struct net_bridge_port *p)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+   return br_multicast_rport_del(>ip6_rlist);
+#else
+   return false;
+#endif
+}
+
 static void br_multicast_router_expired(struct net_bridge_port *port,
struct timer_list *t,
struct hlist_node *rlist)
@@ -1395,6 +1406,15 @@ static void br_ip4_multicast_router_expired(struct 
timer_list *t)
br_multicast_router_expired(port, t, >ip4_rlist);
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+static void br_ip6_multicast_router_expired(struct timer_list *t)
+{
+   struct net_bridge_port *port = from_timer(port, t, ip6_mc_router_timer);
+
+   br_multicast_router_expired(port, t, >ip6_rlist);
+}
+#endif
+
 static void br_mc_router_state_change(struct net_bridge *p,
  bool is_mc_router)
 {
@@ -1430,6 +1450,15 @@ static inline void 
br_ip4_multicast_local_router_expired(struct timer_list *t)
br_multicast_local_router_expired(br, t);
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+static inline void br_ip6_multicast_local_router_expired(struct timer_list *t)
+{
+   struct net_bridge *br = from_timer(br, t, ip6_mc_router_timer);
+
+   br_multicast_

[net-next v2 08/11] net: bridge: mcast: split router port del+notify for mcast router split

2021-05-09 Thread Linus Lüssing
In preparation for the upcoming split of multicast router state into
their IPv4 and IPv6 variants split router port deletion and notification
into two functions. When we disable a port for instance later we want to
only send one notification to switchdev and netlink for compatibility
and want to avoid sending one for IPv4 and one for IPv6. For that the
split is needed.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c | 40 ++-
 1 file changed, 31 insertions(+), 9 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 839d21b..39854d5 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -60,7 +60,8 @@ static void br_ip4_multicast_leave_group(struct net_bridge 
*br,
 const unsigned char *src);
 static void br_multicast_port_group_rexmit(struct timer_list *t);
 
-static void __del_port_router(struct net_bridge_port *p);
+static void
+br_multicast_rport_del_notify(struct net_bridge_port *p, bool deleted);
 #if IS_ENABLED(CONFIG_IPV6)
 static void br_ip6_multicast_leave_group(struct net_bridge *br,
 struct net_bridge_port *port,
@@ -1354,11 +1355,26 @@ static int br_ip6_multicast_add_group(struct net_bridge 
*br,
 }
 #endif
 
+static bool br_multicast_rport_del(struct hlist_node *rlist)
+{
+   if (hlist_unhashed(rlist))
+   return false;
+
+   hlist_del_init_rcu(rlist);
+   return true;
+}
+
+static inline bool br_ip4_multicast_rport_del(struct net_bridge_port *p)
+{
+   return br_multicast_rport_del(>ip4_rlist);
+}
+
 static void br_multicast_router_expired(struct net_bridge_port *port,
struct timer_list *t,
struct hlist_node *rlist)
 {
struct net_bridge *br = port->br;
+   bool del;
 
spin_lock(>multicast_lock);
if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
@@ -1366,7 +1382,8 @@ static void br_multicast_router_expired(struct 
net_bridge_port *port,
timer_pending(t))
goto out;
 
-   __del_port_router(port);
+   del = br_multicast_rport_del(rlist);
+   br_multicast_rport_del_notify(port, del);
 out:
spin_unlock(>multicast_lock);
 }
@@ -1706,19 +1723,20 @@ void br_multicast_disable_port(struct net_bridge_port 
*port)
struct net_bridge *br = port->br;
struct net_bridge_port_group *pg;
struct hlist_node *n;
+   bool del = false;
 
spin_lock(>multicast_lock);
hlist_for_each_entry_safe(pg, n, >mglist, mglist)
if (!(pg->flags & MDB_PG_FLAGS_PERMANENT))
br_multicast_find_del_pg(br, pg);
 
-   __del_port_router(port);
-
+   del |= br_ip4_multicast_rport_del(port);
del_timer(>ip4_mc_router_timer);
del_timer(>ip4_own_query.timer);
 #if IS_ENABLED(CONFIG_IPV6)
del_timer(>ip6_own_query.timer);
 #endif
+   br_multicast_rport_del_notify(port, del);
spin_unlock(>multicast_lock);
 }
 
@@ -3508,11 +3526,12 @@ int br_multicast_set_router(struct net_bridge *br, 
unsigned long val)
return err;
 }
 
-static void __del_port_router(struct net_bridge_port *p)
+static void
+br_multicast_rport_del_notify(struct net_bridge_port *p, bool deleted)
 {
-   if (hlist_unhashed(>ip4_rlist))
+   if (!deleted)
return;
-   hlist_del_init_rcu(>ip4_rlist);
+
br_rtr_notify(p->br->dev, p, RTM_DELMDB);
br_port_mc_router_state_change(p, false);
 
@@ -3526,6 +3545,7 @@ int br_multicast_set_port_router(struct net_bridge_port 
*p, unsigned long val)
struct net_bridge *br = p->br;
unsigned long now = jiffies;
int err = -EINVAL;
+   bool del = false;
 
spin_lock(>multicast_lock);
if (p->multicast_router == val) {
@@ -3539,12 +3559,14 @@ int br_multicast_set_port_router(struct net_bridge_port 
*p, unsigned long val)
switch (val) {
case MDB_RTR_TYPE_DISABLED:
p->multicast_router = MDB_RTR_TYPE_DISABLED;
-   __del_port_router(p);
+   del |= br_ip4_multicast_rport_del(p);
del_timer(>ip4_mc_router_timer);
+   br_multicast_rport_del_notify(p, del);
break;
case MDB_RTR_TYPE_TEMP_QUERY:
p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
-   __del_port_router(p);
+   del |= br_ip4_multicast_rport_del(p);
+   br_multicast_rport_del_notify(p, del);
break;
case MDB_RTR_TYPE_PERM:
p->multicast_router = MDB_RTR_TYPE_PERM;
-- 
2.31.0


[net-next v2 07/11] net: bridge: mcast: prepare add-router function for mcast router split

2021-05-09 Thread Linus Lüssing
In preparation for the upcoming split of multicast router state into
their IPv4 and IPv6 variants move the protocol specific router list
access to an ip4 wrapper function.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c | 59 +++
 1 file changed, 41 insertions(+), 18 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 6c844b2..839d21b 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -51,8 +51,8 @@ static const struct rhashtable_params br_sg_port_rht_params = 
{
 
 static void br_multicast_start_querier(struct net_bridge *br,
   struct bridge_mcast_own_query *query);
-static void br_multicast_add_router(struct net_bridge *br,
-   struct net_bridge_port *port);
+static void br_ip4_multicast_add_router(struct net_bridge *br,
+   struct net_bridge_port *port);
 static void br_ip4_multicast_leave_group(struct net_bridge *br,
 struct net_bridge_port *port,
 __be32 group,
@@ -1689,7 +1689,7 @@ static void __br_multicast_enable_port(struct 
net_bridge_port *port)
 #endif
if (port->multicast_router == MDB_RTR_TYPE_PERM &&
hlist_unhashed(>ip4_rlist))
-   br_multicast_add_router(br, port);
+   br_ip4_multicast_add_router(br, port);
 }
 
 void br_multicast_enable_port(struct net_bridge_port *port)
@@ -2659,28 +2659,51 @@ static void br_port_mc_router_state_change(struct 
net_bridge_port *p,
  *  and locked by br->multicast_lock and RCU
  */
 static void br_multicast_add_router(struct net_bridge *br,
-   struct net_bridge_port *port)
+   struct net_bridge_port *port,
+   struct hlist_node *slot,
+   struct hlist_node *rlist,
+   struct hlist_head *mc_router_list)
 {
-   struct net_bridge_port *p;
-   struct hlist_node *slot = NULL;
-
-   if (!hlist_unhashed(>ip4_rlist))
+   if (!hlist_unhashed(rlist))
return;
 
-   hlist_for_each_entry(p, >ip4_mc_router_list, ip4_rlist) {
-   if ((unsigned long) port >= (unsigned long) p)
-   break;
-   slot = >ip4_rlist;
-   }
-
if (slot)
-   hlist_add_behind_rcu(>ip4_rlist, slot);
+   hlist_add_behind_rcu(rlist, slot);
else
-   hlist_add_head_rcu(>ip4_rlist, >ip4_mc_router_list);
+   hlist_add_head_rcu(rlist, mc_router_list);
+
br_rtr_notify(br->dev, port, RTM_NEWMDB);
br_port_mc_router_state_change(port, true);
 }
 
+struct hlist_node *
+br_ip4_multicast_get_rport_slot(struct net_bridge *br, struct net_bridge_port 
*port)
+{
+   struct hlist_node *slot = NULL;
+   struct net_bridge_port *p;
+
+   hlist_for_each_entry(p, >ip4_mc_router_list, ip4_rlist) {
+   if ((unsigned long)port >= (unsigned long)p)
+   break;
+   slot = >ip4_rlist;
+   }
+
+   return slot;
+}
+
+/* Add port to router_list
+ *  list is maintained ordered by pointer value
+ *  and locked by br->multicast_lock and RCU
+ */
+static void br_ip4_multicast_add_router(struct net_bridge *br,
+   struct net_bridge_port *port)
+{
+   struct hlist_node *slot = br_ip4_multicast_get_rport_slot(br, port);
+
+   br_multicast_add_router(br, port, slot, >ip4_rlist,
+   >ip4_mc_router_list);
+}
+
 static void br_multicast_mark_router(struct net_bridge *br,
 struct net_bridge_port *port)
 {
@@ -2700,7 +2723,7 @@ static void br_multicast_mark_router(struct net_bridge 
*br,
port->multicast_router == MDB_RTR_TYPE_PERM)
return;
 
-   br_multicast_add_router(br, port);
+   br_ip4_multicast_add_router(br, port);
 
mod_timer(>ip4_mc_router_timer,
  now + br->multicast_querier_interval);
@@ -3526,7 +3549,7 @@ int br_multicast_set_port_router(struct net_bridge_port 
*p, unsigned long val)
case MDB_RTR_TYPE_PERM:
p->multicast_router = MDB_RTR_TYPE_PERM;
del_timer(>ip4_mc_router_timer);
-   br_multicast_add_router(br, p);
+   br_ip4_multicast_add_router(br, p);
break;
case MDB_RTR_TYPE_TEMP:
p->multicast_router = MDB_RTR_TYPE_TEMP;
-- 
2.31.0


[net-next v2 06/11] net: bridge: mcast: prepare expiry functions for mcast router split

2021-05-09 Thread Linus Lüssing
In preparation for the upcoming split of multicast router state into
their IPv4 and IPv6 variants move the protocol specific timer access to
an ip4 wrapper function.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c | 31 ++-
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 048b5b9..6c844b2 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1354,16 +1354,16 @@ static int br_ip6_multicast_add_group(struct net_bridge 
*br,
 }
 #endif
 
-static void br_multicast_router_expired(struct timer_list *t)
+static void br_multicast_router_expired(struct net_bridge_port *port,
+   struct timer_list *t,
+   struct hlist_node *rlist)
 {
-   struct net_bridge_port *port =
-   from_timer(port, t, ip4_mc_router_timer);
struct net_bridge *br = port->br;
 
spin_lock(>multicast_lock);
if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
port->multicast_router == MDB_RTR_TYPE_PERM ||
-   timer_pending(>ip4_mc_router_timer))
+   timer_pending(t))
goto out;
 
__del_port_router(port);
@@ -1371,6 +1371,13 @@ out:
spin_unlock(>multicast_lock);
 }
 
+static void br_ip4_multicast_router_expired(struct timer_list *t)
+{
+   struct net_bridge_port *port = from_timer(port, t, ip4_mc_router_timer);
+
+   br_multicast_router_expired(port, t, >ip4_rlist);
+}
+
 static void br_mc_router_state_change(struct net_bridge *p,
  bool is_mc_router)
 {
@@ -1384,10 +1391,9 @@ static void br_mc_router_state_change(struct net_bridge 
*p,
switchdev_port_attr_set(p->dev, , NULL);
 }
 
-static void br_multicast_local_router_expired(struct timer_list *t)
+static void br_multicast_local_router_expired(struct net_bridge *br,
+ struct timer_list *timer)
 {
-   struct net_bridge *br = from_timer(br, t, ip4_mc_router_timer);
-
spin_lock(>multicast_lock);
if (br->multicast_router == MDB_RTR_TYPE_DISABLED ||
br->multicast_router == MDB_RTR_TYPE_PERM ||
@@ -1400,6 +1406,13 @@ out:
spin_unlock(>multicast_lock);
 }
 
+static inline void br_ip4_multicast_local_router_expired(struct timer_list *t)
+{
+   struct net_bridge *br = from_timer(br, t, ip4_mc_router_timer);
+
+   br_multicast_local_router_expired(br, t);
+}
+
 static void br_multicast_querier_expired(struct net_bridge *br,
 struct bridge_mcast_own_query *query)
 {
@@ -1615,7 +1628,7 @@ int br_multicast_add_port(struct net_bridge_port *port)
port->multicast_eht_hosts_limit = BR_MCAST_DEFAULT_EHT_HOSTS_LIMIT;
 
timer_setup(>ip4_mc_router_timer,
-   br_multicast_router_expired, 0);
+   br_ip4_multicast_router_expired, 0);
timer_setup(>ip4_own_query.timer,
br_ip4_multicast_port_query_expired, 0);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -3319,7 +3332,7 @@ void br_multicast_init(struct net_bridge *br)
 
spin_lock_init(>multicast_lock);
timer_setup(>ip4_mc_router_timer,
-   br_multicast_local_router_expired, 0);
+   br_ip4_multicast_local_router_expired, 0);
timer_setup(>ip4_other_query.timer,
br_ip4_multicast_querier_expired, 0);
timer_setup(>ip4_own_query.timer,
-- 
2.31.0


[net-next v2 05/11] net: bridge: mcast: prepare is-router function for mcast router split

2021-05-09 Thread Linus Lüssing
In preparation for the upcoming split of multicast router state into
their IPv4 and IPv6 variants make br_multicast_is_router() protocol
family aware.

Note that for now br_ip6_multicast_is_router() uses the currently still
common ip4_mc_router_timer for now. It will be renamed to
ip6_mc_router_timer later when the split is performed.

While at it also renames the "1" and "2" constants in
br_multicast_is_router() to the MDB_RTR_TYPE_TEMP_QUERY and
MDB_RTR_TYPE_PERM enums.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_input.c |  2 +-
 net/bridge/br_multicast.c |  5 +++--
 net/bridge/br_private.h   | 36 
 3 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 8875e95..1f50630 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -132,7 +132,7 @@ int br_handle_frame_finish(struct net *net, struct sock 
*sk, struct sk_buff *skb
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(br, eth_hdr(skb), mdst)) {
if ((mdst && mdst->host_joined) ||
-   br_multicast_is_router(br)) {
+   br_multicast_is_router(br, skb)) {
local_rcv = true;
br->dev->stats.multicast++;
}
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 7edbbc9..048b5b9 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1391,7 +1391,8 @@ static void br_multicast_local_router_expired(struct 
timer_list *t)
spin_lock(>multicast_lock);
if (br->multicast_router == MDB_RTR_TYPE_DISABLED ||
br->multicast_router == MDB_RTR_TYPE_PERM ||
-   timer_pending(>ip4_mc_router_timer))
+   br_ip4_multicast_is_router(br) ||
+   br_ip6_multicast_is_router(br))
goto out;
 
br_mc_router_state_change(br, false);
@@ -3622,7 +3623,7 @@ bool br_multicast_router(const struct net_device *dev)
bool is_router;
 
spin_lock_bh(>multicast_lock);
-   is_router = br_multicast_is_router(br);
+   is_router = br_multicast_is_router(br, NULL);
spin_unlock_bh(>multicast_lock);
return is_router;
 }
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 26e91d2..ac5ca5b 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -864,11 +864,39 @@ static inline bool br_group_is_l2(const struct br_ip 
*group)
 #define mlock_dereference(X, br) \
rcu_dereference_protected(X, lockdep_is_held(>multicast_lock))
 
-static inline bool br_multicast_is_router(struct net_bridge *br)
+static inline bool br_ip4_multicast_is_router(struct net_bridge *br)
 {
-   return br->multicast_router == 2 ||
-  (br->multicast_router == 1 &&
-   timer_pending(>ip4_mc_router_timer));
+   return timer_pending(>ip4_mc_router_timer);
+}
+
+static inline bool br_ip6_multicast_is_router(struct net_bridge *br)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+   return timer_pending(>ip4_mc_router_timer);
+#else
+   return false;
+#endif
+}
+
+static inline bool
+br_multicast_is_router(struct net_bridge *br, struct sk_buff *skb)
+{
+   if (br->multicast_router == MDB_RTR_TYPE_PERM)
+   return true;
+
+   if (br->multicast_router == MDB_RTR_TYPE_TEMP_QUERY) {
+   if (skb) {
+   if (skb->protocol == htons(ETH_P_IP))
+   return br_ip4_multicast_is_router(br);
+   else if (skb->protocol == htons(ETH_P_IPV6))
+   return br_ip6_multicast_is_router(br);
+   } else {
+   return br_ip4_multicast_is_router(br) ||
+  br_ip6_multicast_is_router(br);
+   }
+   }
+
+   return false;
 }
 
 static inline bool
-- 
2.31.0


[net-next v2 04/11] net: bridge: mcast: prepare query reception for mcast router split

2021-05-09 Thread Linus Lüssing
In preparation for the upcoming split of multicast router state into
their IPv4 and IPv6 variants and as the br_multicast_mark_router() will
be split for that remove the select querier wrapper and instead add
ip4 and ip6 variants for br_multicast_query_received().

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_multicast.c | 53 ---
 1 file changed, 27 insertions(+), 26 deletions(-)

diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 6fe93a3..7edbbc9 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -2615,22 +2615,6 @@ update:
 }
 #endif
 
-static bool br_multicast_select_querier(struct net_bridge *br,
-   struct net_bridge_port *port,
-   struct br_ip *saddr)
-{
-   switch (saddr->proto) {
-   case htons(ETH_P_IP):
-   return br_ip4_multicast_select_querier(br, port, 
saddr->src.ip4);
-#if IS_ENABLED(CONFIG_IPV6)
-   case htons(ETH_P_IPV6):
-   return br_ip6_multicast_select_querier(br, port, 
>src.ip6);
-#endif
-   }
-
-   return false;
-}
-
 static void
 br_multicast_update_query_timer(struct net_bridge *br,
struct bridge_mcast_other_query *query,
@@ -2708,19 +2692,36 @@ static void br_multicast_mark_router(struct net_bridge 
*br,
  now + br->multicast_querier_interval);
 }
 
-static void br_multicast_query_received(struct net_bridge *br,
-   struct net_bridge_port *port,
-   struct bridge_mcast_other_query *query,
-   struct br_ip *saddr,
-   unsigned long max_delay)
+static void
+br_ip4_multicast_query_received(struct net_bridge *br,
+   struct net_bridge_port *port,
+   struct bridge_mcast_other_query *query,
+   struct br_ip *saddr,
+   unsigned long max_delay)
 {
-   if (!br_multicast_select_querier(br, port, saddr))
+   if (!br_ip4_multicast_select_querier(br, port, saddr->src.ip4))
return;
 
br_multicast_update_query_timer(br, query, max_delay);
br_multicast_mark_router(br, port);
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+static void
+br_ip6_multicast_query_received(struct net_bridge *br,
+   struct net_bridge_port *port,
+   struct bridge_mcast_other_query *query,
+   struct br_ip *saddr,
+   unsigned long max_delay)
+{
+   if (!br_ip6_multicast_select_querier(br, port, >src.ip6))
+   return;
+
+   br_multicast_update_query_timer(br, query, max_delay);
+   br_multicast_mark_router(br, port);
+}
+#endif
+
 static void br_ip4_multicast_query(struct net_bridge *br,
   struct net_bridge_port *port,
   struct sk_buff *skb,
@@ -2768,8 +2769,8 @@ static void br_ip4_multicast_query(struct net_bridge *br,
saddr.proto = htons(ETH_P_IP);
saddr.src.ip4 = iph->saddr;
 
-   br_multicast_query_received(br, port, >ip4_other_query,
-   , max_delay);
+   br_ip4_multicast_query_received(br, port, >ip4_other_query,
+   , max_delay);
goto out;
}
 
@@ -2856,8 +2857,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
saddr.proto = htons(ETH_P_IPV6);
saddr.src.ip6 = ipv6_hdr(skb)->saddr;
 
-   br_multicast_query_received(br, port, >ip6_other_query,
-   , max_delay);
+   br_ip6_multicast_query_received(br, port, >ip6_other_query,
+   , max_delay);
goto out;
} else if (!group) {
goto out;
-- 
2.31.0


[net-next v2 03/11] net: bridge: mcast: prepare mdb netlink for mcast router split

2021-05-09 Thread Linus Lüssing
In preparation for the upcoming split of multicast router state into
their IPv4 and IPv6 variants and to avoid IPv6 #ifdef clutter later add
some inline functions for the protocol specific parts in the mdb router
netlink code. Also the we need iterate over the port instead of router
list to be able put one router port entry with both the IPv4 and IPv6
multicast router info later.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_mdb.c | 39 ++-
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index d61def8..6937d3b 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -16,29 +16,58 @@
 
 #include "br_private.h"
 
+static inline bool br_rports_have_mc_router(struct net_bridge *br)
+{
+   return !hlist_empty(>ip4_mc_router_list);
+}
+
+static inline bool
+br_ip4_rports_get_timer(struct net_bridge_port *port, unsigned long *timer)
+{
+   *timer = br_timer_value(>ip4_mc_router_timer);
+   return !hlist_unhashed(>ip4_rlist);
+}
+
+static inline bool
+br_ip6_rports_get_timer(struct net_bridge_port *port, unsigned long *timer)
+{
+   *timer = 0;
+   return false;
+}
+
 static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback 
*cb,
   struct net_device *dev)
 {
struct net_bridge *br = netdev_priv(dev);
-   struct net_bridge_port *p;
+   bool have_ip4_mc_rtr, have_ip6_mc_rtr;
+   unsigned long ip4_timer, ip6_timer;
struct nlattr *nest, *port_nest;
+   struct net_bridge_port *p;
 
-   if (!br->multicast_router || hlist_empty(>ip4_mc_router_list))
+   if (!br->multicast_router)
+   return 0;
+
+   if (!br_rports_have_mc_router(br))
return 0;
 
nest = nla_nest_start_noflag(skb, MDBA_ROUTER);
if (nest == NULL)
return -EMSGSIZE;
 
-   hlist_for_each_entry_rcu(p, >ip4_mc_router_list, ip4_rlist) {
-   if (!p)
+   list_for_each_entry_rcu(p, >port_list, list) {
+   have_ip4_mc_rtr = br_ip4_rports_get_timer(p, _timer);
+   have_ip6_mc_rtr = br_ip6_rports_get_timer(p, _timer);
+
+   if (!have_ip4_mc_rtr && !have_ip6_mc_rtr)
continue;
+
port_nest = nla_nest_start_noflag(skb, MDBA_ROUTER_PORT);
if (!port_nest)
goto fail;
+
if (nla_put_nohdr(skb, sizeof(u32), >dev->ifindex) ||
nla_put_u32(skb, MDBA_ROUTER_PATTR_TIMER,
-   br_timer_value(>ip4_mc_router_timer)) ||
+   max(ip4_timer, ip6_timer)) ||
nla_put_u8(skb, MDBA_ROUTER_PATTR_TYPE,
   p->multicast_router)) {
nla_nest_cancel(skb, port_nest);
-- 
2.31.0


[net-next v2 02/11] net: bridge: mcast: add wrappers for router node retrieval

2021-05-09 Thread Linus Lüssing
In preparation for the upcoming split of multicast router state into
their IPv4 and IPv6 variants and to avoid IPv6 #ifdef clutter later add
two wrapper functions for router node retrieval in the payload
forwarding code.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_forward.c | 15 +--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 3b67184..b5ec4f9 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -264,6 +264,16 @@ static void maybe_deliver_addr(struct net_bridge_port *p, 
struct sk_buff *skb,
__br_forward(p, skb, local_orig);
 }
 
+static inline struct hlist_node *
+br_multicast_get_first_rport_node(struct net_bridge *b, struct sk_buff *skb) {
+   return rcu_dereference(hlist_first_rcu(>ip4_mc_router_list));
+}
+
+static inline struct net_bridge_port *
+br_multicast_rport_from_node(struct hlist_node *rp, struct sk_buff *skb) {
+   return hlist_entry_safe(rp, struct net_bridge_port, ip4_rlist);
+}
+
 /* called with rcu_read_lock */
 void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct sk_buff *skb,
@@ -276,7 +286,8 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
bool allow_mode_include = true;
struct hlist_node *rp;
 
-   rp = rcu_dereference(hlist_first_rcu(>router_list));
+   rp = br_multicast_get_first_rport_node(br, skb);
+
if (mdst) {
p = rcu_dereference(mdst->ports);
if (br_multicast_should_handle_mode(br, mdst->addr.proto) &&
@@ -290,7 +301,7 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct net_bridge_port *port, *lport, *rport;
 
lport = p ? p->key.port : NULL;
-   rport = hlist_entry_safe(rp, struct net_bridge_port, ip4_rlist);
+   rport = br_multicast_rport_from_node(rp, skb);
 
if ((unsigned long)lport > (unsigned long)rport) {
port = lport;
-- 
2.31.0


[net-next v2 01/11] net: bridge: mcast: rename multicast router lists and timers

2021-05-09 Thread Linus Lüssing
In preparation for the upcoming split of multicast router state into
their IPv4 and IPv6 variants, rename the affected variable to the IPv4
version first to avoid some renames in later commits.

Signed-off-by: Linus Lüssing 
---
 net/bridge/br_forward.c   |  2 +-
 net/bridge/br_mdb.c   |  6 ++---
 net/bridge/br_multicast.c | 48 +++
 net/bridge/br_private.h   | 10 
 4 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 6e9b049..3b67184 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -290,7 +290,7 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct net_bridge_port *port, *lport, *rport;
 
lport = p ? p->key.port : NULL;
-   rport = hlist_entry_safe(rp, struct net_bridge_port, rlist);
+   rport = hlist_entry_safe(rp, struct net_bridge_port, ip4_rlist);
 
if ((unsigned long)lport > (unsigned long)rport) {
port = lport;
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 95fa4af..d61def8 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -23,14 +23,14 @@ static int br_rports_fill_info(struct sk_buff *skb, struct 
netlink_callback *cb,
struct net_bridge_port *p;
struct nlattr *nest, *port_nest;
 
-   if (!br->multicast_router || hlist_empty(>router_list))
+   if (!br->multicast_router || hlist_empty(>ip4_mc_router_list))
return 0;
 
nest = nla_nest_start_noflag(skb, MDBA_ROUTER);
if (nest == NULL)
return -EMSGSIZE;
 
-   hlist_for_each_entry_rcu(p, >router_list, rlist) {
+   hlist_for_each_entry_rcu(p, >ip4_mc_router_list, ip4_rlist) {
if (!p)
continue;
port_nest = nla_nest_start_noflag(skb, MDBA_ROUTER_PORT);
@@ -38,7 +38,7 @@ static int br_rports_fill_info(struct sk_buff *skb, struct 
netlink_callback *cb,
goto fail;
if (nla_put_nohdr(skb, sizeof(u32), >dev->ifindex) ||
nla_put_u32(skb, MDBA_ROUTER_PATTR_TIMER,
-   br_timer_value(>multicast_router_timer)) ||
+   br_timer_value(>ip4_mc_router_timer)) ||
nla_put_u8(skb, MDBA_ROUTER_PATTR_TYPE,
   p->multicast_router)) {
nla_nest_cancel(skb, port_nest);
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 226bb05..6fe93a3 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1357,13 +1357,13 @@ static int br_ip6_multicast_add_group(struct net_bridge 
*br,
 static void br_multicast_router_expired(struct timer_list *t)
 {
struct net_bridge_port *port =
-   from_timer(port, t, multicast_router_timer);
+   from_timer(port, t, ip4_mc_router_timer);
struct net_bridge *br = port->br;
 
spin_lock(>multicast_lock);
if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
port->multicast_router == MDB_RTR_TYPE_PERM ||
-   timer_pending(>multicast_router_timer))
+   timer_pending(>ip4_mc_router_timer))
goto out;
 
__del_port_router(port);
@@ -1386,12 +1386,12 @@ static void br_mc_router_state_change(struct net_bridge 
*p,
 
 static void br_multicast_local_router_expired(struct timer_list *t)
 {
-   struct net_bridge *br = from_timer(br, t, multicast_router_timer);
+   struct net_bridge *br = from_timer(br, t, ip4_mc_router_timer);
 
spin_lock(>multicast_lock);
if (br->multicast_router == MDB_RTR_TYPE_DISABLED ||
br->multicast_router == MDB_RTR_TYPE_PERM ||
-   timer_pending(>multicast_router_timer))
+   timer_pending(>ip4_mc_router_timer))
goto out;
 
br_mc_router_state_change(br, false);
@@ -1613,7 +1613,7 @@ int br_multicast_add_port(struct net_bridge_port *port)
port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
port->multicast_eht_hosts_limit = BR_MCAST_DEFAULT_EHT_HOSTS_LIMIT;
 
-   timer_setup(>multicast_router_timer,
+   timer_setup(>ip4_mc_router_timer,
br_multicast_router_expired, 0);
timer_setup(>ip4_own_query.timer,
br_ip4_multicast_port_query_expired, 0);
@@ -1649,7 +1649,7 @@ void br_multicast_del_port(struct net_bridge_port *port)
hlist_move_list(>mcast_gc_list, _head);
spin_unlock_bh(>multicast_lock);
br_multicast_gc(_head);
-   del_timer_sync(>multicast_router_timer);
+   del_timer_sync(>ip4_mc_router_timer);
free_percpu(port->mcast_stats);
 }
 
@@ -1674,7 +1674,7 @@ static void __br_multicast_enable_port(struct 
net_brid

[PATCH net-next v2 00/11] net: bridge: split IPv4/v6 mc router state and export for batman-adv

2021-05-09 Thread Linus Lüssing
Hi,

The following patches are splitting the so far combined multicast router
state in the Linux bridge into two ones, one for IPv4 and one for IPv6,
for a more fine-grained detection of multicast routers. This avoids
sending IPv4 multicast packets to an IPv6-only multicast router and 
avoids sending IPv6 multicast packets to an IPv4-only multicast router.
This also allows batman-adv to make use of the now split information in
the final patch.

The first eight patches prepare the bridge code to avoid duplicate
code or IPv6-#ifdef clutter for the multicast router state split. And 
contain no functional changes yet.

The ninth patch then implements the IPv4+IPv6 multicast router state
split.

Patch number ten adds IPv4+IPv6 specific timers to the mdb netlink
router port dump, so that the timers validity can be checked individually
from userspace.

The final, eleventh patch exports this now per protocol family multicast
router state so that batman-adv can then later make full use of the 
Multicast Router Discovery (MRD) support in the Linux bridge. The 
batman-adv protocol format currently expects separate multicast router
states for IPv4 and IPv6, therefore it depends on the first patch.
batman-adv will then make use of this newly exported functions like
this[0].

Regards, Linus

[0]: 
https://git.open-mesh.org/batman-adv.git/shortlog/refs/heads/linus/multicast-routeable-mrd
 -> 
https://git.open-mesh.org/batman-adv.git/commit/d4bed3a92427445708baeb1f2d1841c5fb816fd4

Changelog v2: 

* split into multiple patches as suggested by Nikolay
* added helper functions to br_multicast_flood(), avoiding
  IPv6 #ifdef clutter
* fixed reverse xmas tree ordering in br_rports_fill_info() and 
  added helper functions to avoid IPv6 #ifdef clutter
* Added a common br_multicast_add_router() and a helper function
  to retrieve the correct slot to avoid duplicate code for an
  ip4 and ip6 variant
* replaced the "1" and "2" constants in br_multicast_is_router()
  with the appropriate enums
* added br_{ip4,ip6}_multicast_rport_del() wrappers to reduce
  IPv6 #ifdef clutter
* added return values to br_*multicast_rport_del() to only notify
  if the port was actually removed and did not race with a readdition
  somewhere else
* added empty, void br_ip6_multicast_mark_router() if compiled
  without IPv6, to reduce IPv6 #ifdef clutter



[PATCH v2] batman-adv: bcast: queue per interface, if needed

2021-04-27 Thread Linus Lüssing
Currently we schedule a broadcast packet like:

3x: [ [(re-)queue] --> for(hard-if): maybe-transmit ]

The intention of queueing a broadcast packet multiple times is to
increase robustness for wireless interfaces. However on interfaces
which we only broadcast on once the queueing induces an unnecessary
penalty. This patch restructures the queueing to be performed on a per
interface basis:

for(hard-if):
- transmit
- if wireless: [queue] --> transmit --> [requeue] --> transmit

Next to the performance benefits on non-wireless interfaces this
should also make it easier to apply alternative strategies for
transmissions on wireless interfaces in the future (for instance sending
via unicast transmissions on wireless interfaces, without queueing in
batman-adv, if appropriate).

Signed-off-by: Linus Lüssing 
---

Changelog v2:
* removed the other two patches from the patchset for now, only
  the broadcast queueing cleanup to start with

* fixed spelling of "unnecessary" in commit message (thanks Sven)
* removed now superflous kerneldoc for hard_iface in
  batadv_forw_packet_bcasts_left() (thanks Sven)
* removed delay check for queued (re)broadcasts in
  batadv_forw_bcast_packet_if(): the only case where a delay is set
  for this function is for a delayed, DAT fallback ARP Request from
  this node, then however num_bcasts will be >=1, too, and the fallback
  ARP Request will be scheduled anyway
---
 net/batman-adv/main.h   |   1 -
 net/batman-adv/routing.c|   9 +-
 net/batman-adv/send.c   | 392 ++--
 net/batman-adv/send.h   |  12 +-
 net/batman-adv/soft-interface.c |  12 +-
 5 files changed, 288 insertions(+), 138 deletions(-)

diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 8f0102b7..baa9fcbe 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -88,7 +88,6 @@
 /* number of packets to send for broadcasts on different interface types */
 #define BATADV_NUM_BCASTS_DEFAULT 1
 #define BATADV_NUM_BCASTS_WIRELESS 3
-#define BATADV_NUM_BCASTS_MAX 3
 
 /* length of the single packet used by the TP meter */
 #define BATADV_TP_PACKET_LEN ETH_DATA_LEN
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 40f5cffd..bb9e93e3 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -1182,9 +1182,9 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
struct batadv_bcast_packet *bcast_packet;
struct ethhdr *ethhdr;
int hdr_size = sizeof(*bcast_packet);
-   int ret = NET_RX_DROP;
s32 seq_diff;
u32 seqno;
+   int ret;
 
/* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, hdr_size)))
@@ -1210,7 +1210,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
if (batadv_is_my_mac(bat_priv, bcast_packet->orig))
goto free_skb;
 
-   if (bcast_packet->ttl < 2)
+   if (bcast_packet->ttl-- < 2)
goto free_skb;
 
orig_node = batadv_orig_hash_find(bat_priv, bcast_packet->orig);
@@ -1249,7 +1249,9 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
batadv_skb_set_priority(skb, sizeof(struct batadv_bcast_packet));
 
/* rebroadcast packet */
-   batadv_add_bcast_packet_to_list(bat_priv, skb, 1, false);
+   ret = batadv_forw_bcast_packet(bat_priv, skb, 0, false);
+   if (ret == NETDEV_TX_BUSY)
+   goto free_skb;
 
/* don't hand the broadcast up if it is from an originator
 * from the same backbone.
@@ -1275,6 +1277,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
spin_unlock_bh(_node->bcast_seqno_lock);
 free_skb:
kfree_skb(skb);
+   ret = NET_RX_DROP;
 out:
if (orig_node)
batadv_orig_node_put(orig_node);
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 157abe92..1db6b217 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -737,57 +737,52 @@ void batadv_forw_packet_ogmv1_queue(struct batadv_priv 
*bat_priv,
 }
 
 /**
- * batadv_add_bcast_packet_to_list() - queue broadcast packet for multiple 
sends
+ * batadv_forw_bcast_packet_to_list() - queue broadcast packet for 
transmissions
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: broadcast packet to add
  * @delay: number of jiffies to wait before sending
  * @own_packet: true if it is a self-generated broadcast packet
+ * @if_in: the interface where the packet was received on
+ * @if_out: the outgoing interface to queue on
  *
- * add a broadcast packet to the queue and setup timers. broadcast packets
+ * Adds a broadcast packet to the queue and sets up timers. Broadcast packets
  * are sent multiple times to increase probability for being received.
  *
- * The skb is not consumed, so the caller should make sure that the
- * skb is freed.
+ * This call clones the given skb, hence the caller needs to take into
+ * acc

[PATCH net-next 2/2] net: bridge: mcast: export multicast router presence adjacent to a port

2021-04-25 Thread Linus Lüssing
To properly support routable multicast addresses in batman-adv in a
group-aware way, a batman-adv node needs to know if it serves multicast
routers.

This adds a function to the bridge to export this so that batman-adv
can then make full use of the Multicast Router Discovery capability of
the bridge.

Signed-off-by: Linus Lüssing 
---
 include/linux/if_bridge.h |  8 ++
 net/bridge/br_multicast.c | 58 +++
 2 files changed, 66 insertions(+)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 2cc35038a8ca..12e9a32dbca0 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -67,6 +67,7 @@ int br_multicast_list_adjacent(struct net_device *dev,
   struct list_head *br_ip_list);
 bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto);
 bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto);
+bool br_multicast_has_router_adjacent(struct net_device *dev, int proto);
 bool br_multicast_enabled(const struct net_device *dev);
 bool br_multicast_router(const struct net_device *dev);
 int br_mdb_replay(struct net_device *br_dev, struct net_device *dev,
@@ -87,6 +88,13 @@ static inline bool br_multicast_has_querier_adjacent(struct 
net_device *dev,
 {
return false;
 }
+
+static inline bool br_multicast_has_router_adjacent(struct net_device *dev,
+   int proto)
+{
+   return true;
+}
+
 static inline bool br_multicast_enabled(const struct net_device *dev)
 {
return false;
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 0ebdbf09f44c..4afaf011f171 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -4013,6 +4013,64 @@ bool br_multicast_has_querier_adjacent(struct net_device 
*dev, int proto)
 }
 EXPORT_SYMBOL_GPL(br_multicast_has_querier_adjacent);
 
+/**
+ * br_multicast_has_router_adjacent - Checks for a router behind a bridge port
+ * @dev: The bridge port adjacent to which to check for a multicast router
+ * @proto: The protocol family to check for: IGMP -> ETH_P_IP, MLD -> 
ETH_P_IPV6
+ *
+ * Checks whether the given interface has a bridge on top and if so returns
+ * true if a multicast router is behind one of the other ports of this
+ * bridge. Otherwise returns false.
+ */
+bool br_multicast_has_router_adjacent(struct net_device *dev, int proto)
+{
+   struct net_bridge_port *port, *p;
+   bool ret = false;
+
+   rcu_read_lock();
+   if (!netif_is_bridge_port(dev))
+   goto unlock;
+
+   port = br_port_get_rcu(dev);
+   if (!port || !port->br)
+   goto unlock;
+
+   switch (proto) {
+   case ETH_P_IP:
+   hlist_for_each_entry_rcu(p, >br->ip4_mc_router_list,
+ip4_rlist) {
+   if (p == port)
+   continue;
+
+   ret = true;
+   goto unlock;
+   }
+   break;
+#if IS_ENABLED(CONFIG_IPV6)
+   case ETH_P_IPV6:
+   hlist_for_each_entry_rcu(p, >br->ip6_mc_router_list,
+ip6_rlist) {
+   if (p == port)
+   continue;
+
+   ret = true;
+   goto unlock;
+   }
+   break;
+#endif
+   default:
+   /* when compiled without IPv6 support, be conservative and
+* always assume presence of an IPv6 multicast router
+*/
+   ret = true;
+   }
+
+unlock:
+   rcu_read_unlock();
+   return ret;
+}
+EXPORT_SYMBOL_GPL(br_multicast_has_router_adjacent);
+
 static void br_mcast_stats_add(struct bridge_mcast_stats __percpu *stats,
   const struct sk_buff *skb, u8 type, u8 dir)
 {
-- 
2.31.0


[PATCH net-next 1/2] net: bridge: mcast: split multicast router state for IPv4 and IPv6

2021-04-25 Thread Linus Lüssing
A multicast router for IPv4 does not imply that the same host also is a
multicast router for IPv6 and vice versa.

To reduce multicast traffic when a host is only a multicast router for
one of these two protocol families, keep router state for IPv4 and IPv6
separately. Similar to how querier state is kept separately.

For backwards compatibility for netlink and switchdev notifications
these two will still only notify if a port switched from either no
IPv4/IPv6 multicast router to any IPv4/IPv6 multicast router or the
other way round. However a full netlink MDB router dump will now also
include a multicast router timeout for both IPv4 and IPv6.

Signed-off-by: Linus Lüssing 
---
 include/uapi/linux/if_bridge.h |   2 +
 net/bridge/br_forward.c|  22 ++-
 net/bridge/br_input.c  |   2 +-
 net/bridge/br_mdb.c|  38 +++-
 net/bridge/br_multicast.c  | 341 +
 net/bridge/br_private.h|  48 -
 6 files changed, 352 insertions(+), 101 deletions(-)

diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index 13d59c51ef5b..6b56a7549531 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -627,6 +627,8 @@ enum {
MDBA_ROUTER_PATTR_UNSPEC,
MDBA_ROUTER_PATTR_TIMER,
MDBA_ROUTER_PATTR_TYPE,
+   MDBA_ROUTER_PATTR_INET_TIMER,
+   MDBA_ROUTER_PATTR_INET6_TIMER,
__MDBA_ROUTER_PATTR_MAX
 };
 #define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1)
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 6e9b049ae521..897fafc83cd0 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -275,8 +275,19 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct net_bridge_port_group *p;
bool allow_mode_include = true;
struct hlist_node *rp;
+#if IS_ENABLED(CONFIG_IPV6)
+   bool is_ipv6 = false;
+
+   if (skb->protocol == htons(ETH_P_IPV6)) {
+   is_ipv6 = true;
+   rp = rcu_dereference(hlist_first_rcu(>ip6_mc_router_list));
+   } else {
+#else
+   if (1) {
+#endif
+   rp = rcu_dereference(hlist_first_rcu(>ip4_mc_router_list));
+   }
 
-   rp = rcu_dereference(hlist_first_rcu(>router_list));
if (mdst) {
p = rcu_dereference(mdst->ports);
if (br_multicast_should_handle_mode(br, mdst->addr.proto) &&
@@ -290,7 +301,14 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
struct net_bridge_port *port, *lport, *rport;
 
lport = p ? p->key.port : NULL;
-   rport = hlist_entry_safe(rp, struct net_bridge_port, rlist);
+#if IS_ENABLED(CONFIG_IPV6)
+   if (is_ipv6)
+   rport = hlist_entry_safe(rp, struct net_bridge_port,
+ip6_rlist);
+   else
+#endif
+   rport = hlist_entry_safe(rp, struct net_bridge_port,
+ip4_rlist);
 
if ((unsigned long)lport > (unsigned long)rport) {
port = lport;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 8875e953ac53..1f506309efa8 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -132,7 +132,7 @@ int br_handle_frame_finish(struct net *net, struct sock 
*sk, struct sk_buff *skb
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(br, eth_hdr(skb), mdst)) {
if ((mdst && mdst->host_joined) ||
-   br_multicast_is_router(br)) {
+   br_multicast_is_router(br, skb)) {
local_rcv = true;
br->dev->stats.multicast++;
}
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 95fa4af0e8dd..2fce1a895a70 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -22,25 +22,53 @@ static int br_rports_fill_info(struct sk_buff *skb, struct 
netlink_callback *cb,
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_port *p;
struct nlattr *nest, *port_nest;
+   bool have_ip4_mc_rtr, have_ip6_mc_rtr = false;
+   unsigned long ip4_timer, ip6_timer = 0;
 
-   if (!br->multicast_router || hlist_empty(>router_list))
+   if (!br->multicast_router)
return 0;
 
+#if IS_ENABLED(CONFIG_IPV6)
+   if (hlist_empty(>ip4_mc_router_list) &&
+   hlist_empty(>ip6_mc_router_list))
+   return 0;
+#else
+   if (hlist_empty(>ip4_mc_router_list))
+   return 0;
+#endif
+
nest = nla_nest_start_noflag(skb, MDBA_ROUTER);
if (nest == NULL)
return -EMSGSIZE;
 
-   hlist_for_each_entry_rcu(p, >router_list

[PATCH net-next 0/2] net: bridge: split IPv4/v6 mc router state and export for batman-adv

2021-04-25 Thread Linus Lüssing
Hi,

The following are two patches for the Linux bridge regarding multicast
routers. They are rebased on top of the following fix:
"net: bridge: mcast: fix broken length + header check for MRDv6 Adv." [0]
And should be applied afterwards.

The first one splits the so far combined multicast router state into two
ones, one for IPv4 and one for IPv6, for a more fine-grained detection of
multicast routers. This avoids sending IPv4 multicast packets to an
IPv6-only multicast router and avoids sending IPv6 multicast packets to
an IPv4-only multicast router. This is also in preparation for the
second patch:

The second patch exports this now per protocol family multicast router
state so that batman-adv can then later make full use of the
Multicast Router Discovery (MRD) support in the Linux bridge. The
batman-adv protocol format currently expects separate multicast router
states for IPv4 and IPv6, therefore it depends on the first patch.
batman-adv will then make use of this newly exported functions like
this[1].

Regards, Linus

[0]: 
https://patchwork.kernel.org/project/netdevbpf/patch/20210425152736.8421-1-linus.luess...@c0d3.blue/
[1]: 
https://git.open-mesh.org/batman-adv.git/shortlog/refs/heads/linus/multicast-routeable-mrd
 -> 
https://git.open-mesh.org/batman-adv.git/commit/d4bed3a92427445708baeb1f2d1841c5fb816fd4


[PATCH net-next 0/2] net: bridge: split IPv4/v6 mc router state and export for batman-adv

2021-04-25 Thread Linus Lüssing
Hi,

The following are two patches for the Linux bridge regarding multicast
routers. They are rebased on top of the following fix:
"net: bridge: mcast: fix broken length + header check for MRDv6 Adv." [0]
And should be applied afterwards.

The first one splits the so far combined multicast router state into two
ones, one for IPv4 and one for IPv6, for a more fine-grained detection of
multicast routers. This avoids sending IPv4 multicast packets to an
IPv6-only multicast router and avoids sending IPv6 multicast packets to
an IPv4-only multicast router. This is also in preparation for the
second patch:

The second patch exports this now per protocol family multicast router
state so that batman-adv can then later make full use of the
Multicast Router Discovery (MRD) support in the Linux bridge. The
batman-adv protocol format currently expects separate multicast router
states for IPv4 and IPv6, therefore it depends on the first patch.
batman-adv will then make use of this newly exported functions like
this[1].

Regards, Linus

[0]: 
https://patchwork.kernel.org/project/netdevbpf/patch/20210425152736.8421-1-linus.luess...@c0d3.blue/
[1]: 
https://git.open-mesh.org/batman-adv.git/shortlog/refs/heads/linus/multicast-routeable-mrd
 -> 
https://git.open-mesh.org/batman-adv.git/commit/d4bed3a92427445708baeb1f2d1841c5fb816fd4


Re: [RFC PATCH] batman-adv: convert ifmcaddr6 to RCU

2021-04-18 Thread Linus Lüssing
On Sun, Apr 18, 2021 at 10:16:07PM +0200, Linus Lüssing wrote:
> On Sun, Apr 18, 2021 at 10:14:22PM +0200, Linus Lüssing wrote:
> > [...]
> > diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
> > index 28166402..1d63c8cb 100644
> > --- a/net/batman-adv/multicast.c
> > +++ b/net/batman-adv/multicast.c
> > @@ -454,8 +454,9 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
> > return 0;
> > }
> >  
> > -   read_lock_bh(_dev->lock);
> > -   for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) {
> > +   for (pmc6 = rcu_dereference(in6_dev->mc_list);
> > +pmc6;
> > +pmc6 = rcu_dereference(pmc6->next)) {
> > if (IPV6_ADDR_MC_SCOPE(>mca_addr) <
> > IPV6_ADDR_SCOPE_LINKLOCAL)
> > continue;
> > @@ -484,7 +485,6 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
> > hlist_add_head(>list, mcast_list);
> > ret++;
> > }
> > -   read_unlock_bh(_dev->lock);
> > rcu_read_unlock();
> >  
> > return ret;
> > -- 
> 
> Ups, accidentally added this. Will remove that in the next
> version.

Ah, no, sorry, should be in there, changed my mind :D.

Sorry for the noise.


Re: [RFC PATCH] batman-adv: convert ifmcaddr6 to RCU

2021-04-18 Thread Linus Lüssing
On Sun, Apr 18, 2021 at 10:14:22PM +0200, Linus Lüssing wrote:
> [...]
> diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
> index 28166402..1d63c8cb 100644
> --- a/net/batman-adv/multicast.c
> +++ b/net/batman-adv/multicast.c
> @@ -454,8 +454,9 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
>   return 0;
>   }
>  
> - read_lock_bh(_dev->lock);
> - for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) {
> + for (pmc6 = rcu_dereference(in6_dev->mc_list);
> +  pmc6;
> +  pmc6 = rcu_dereference(pmc6->next)) {
>   if (IPV6_ADDR_MC_SCOPE(>mca_addr) <
>   IPV6_ADDR_SCOPE_LINKLOCAL)
>   continue;
> @@ -484,7 +485,6 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
>   hlist_add_head(>list, mcast_list);
>   ret++;
>   }
> - read_unlock_bh(_dev->lock);
>   rcu_read_unlock();
>  
>   return ret;
> -- 

Ups, accidentally added this. Will remove that in the next
version.


[RFC PATCH] batman-adv: convert ifmcaddr6 to RCU

2021-04-18 Thread Linus Lüssing
From: Taehee Yoo 

The ifmcaddr6 has been protected by inet6_dev->lock(rwlock) so that
the critical section is atomic context. In order to switch this context,
changing locking is needed. The ifmcaddr6 actually already protected by
RTNL So if it's converted to use RCU, its control path context can be
switched to sleepable.

Suggested-by: Cong Wang 
Signed-off-by: Taehee Yoo 
Signed-off-by: David S. Miller 
[linus.luess...@c0d3.blue: Add compat code]
Signed-off-by: Linus Lüssing 
---
@Sven: maybe something like this?

Seems to compile fine for me, without warnings and seems to run fine and
use the compat code for me.

I tried to create and add it to compat-include/net/if_inet6.h, as that
would fit better for the "struct ifmcaddr6", but couldn't get that
to work, lots of errors. And when adding it to compat.h the compat code
does not seem to be used at all.

Also let me know if the kernel version is correct or if it should be
5.14 instead?

 compat-include/net/addrconf.h | 85 +++
 net/batman-adv/multicast.c|  6 +--
 2 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/compat-include/net/addrconf.h b/compat-include/net/addrconf.h
index 30124124..080e1dda 100644
--- a/compat-include/net/addrconf.h
+++ b/compat-include/net/addrconf.h
@@ -25,4 +25,89 @@ static inline int batadv_ipv6_mc_check_mld(struct sk_buff 
*skb)
 
 #endif /* LINUX_VERSION_IS_LESS(5, 1, 0) */
 
+#if LINUX_VERSION_IS_LESS(5, 13, 0)
+
+static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr,
+ struct hlist_head *mcast_list);
+
+static inline int
+compat_batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
+struct hlist_head *mcast_list,
+struct batadv_mcast_mla_flags *flags,
+u8 *mcast_addr,
+   struct batadv_hw_addr *new,
+   struct inet6_dev *in6_dev)
+
+{
+   struct ifmcaddr6 *pmc6;
+   int ret = 0;
+
+   if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6)
+   return 0;
+
+   rcu_read_lock();
+
+   in6_dev = __in6_dev_get(dev);
+   if (!in6_dev) {
+   rcu_read_unlock();
+   return 0;
+   }
+
+   read_lock_bh(_dev->lock);
+   for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) {
+   if (IPV6_ADDR_MC_SCOPE(>mca_addr) <
+   IPV6_ADDR_SCOPE_LINKLOCAL)
+   continue;
+
+   if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
+   ipv6_addr_is_ll_all_nodes(>mca_addr))
+   continue;
+
+   if (!(flags->tvlv_flags & BATADV_MCAST_WANT_NO_RTR6) &&
+   IPV6_ADDR_MC_SCOPE(>mca_addr) >
+   IPV6_ADDR_SCOPE_LINKLOCAL)
+   continue;
+
+   ipv6_eth_mc_map(>mca_addr, mcast_addr);
+
+   if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
+   continue;
+
+   new = kmalloc(sizeof(*new), GFP_ATOMIC);
+   if (!new) {
+   ret = -ENOMEM;
+   break;
+   }
+
+   ether_addr_copy(new->addr, mcast_addr);
+   hlist_add_head(>list, mcast_list);
+   ret++;
+   }
+   read_unlock_bh(_dev->lock);
+   rcu_read_unlock();
+
+   return ret;
+}
+
+#define ifmcaddr6 \
+   net_device *orig_dev = dev; \
+   return compat_batadv_mcast_mla_softif_get_ipv6(orig_dev, \
+  mcast_list, \
+  flags, \
+  mcast_addr, \
+  new = NULL, \
+  in6_dev = NULL); 
\
+   } \
+   static inline int \
+   __unused_batadv_mcast_mla_softif_get_ipv6(struct net_device *dev, \
+struct hlist_head *mcast_list, \
+struct batadv_mcast_mla_flags 
*flags) \
+   { \
+   struct batadv_hw_addr *new; \
+   struct inet6_dev *in6_dev; \
+   u8 mcast_addr[ETH_ALEN]; \
+   struct ifmcaddr6
+
+#endif /* LINUX_VERSION_IS_LESS(5, 13, 0) */
+
 #endif /* _NET_BATMAN_ADV_COMPAT_NET_ADDRCONF_H_ */
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 28166402..1d63c8cb 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -454,8 +454,9 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
return 0;
}
 
-   read_lock_bh(_dev->lock);
-   for

Re: How to mesh over ethernet VLAN?

2021-04-14 Thread Linus Lüssing
On Fri, Apr 09, 2021 at 03:38:15PM +0200, Andi Depressivum wrote:
> Actual OpenWRT trunk on TP-Link C7 / C2600 devices. Can decrease to
> anything lower than 1500 but cannot raise above 1500.

Hm, yes, many/most ethernet devices don't support jumbo frames.

You could test with iperf3 and its --set-mss option if smaller,
unfragmented frames have a better performance.

A few more options to solve this are then:

* using the DHCP MTU option on the DHCP server (though many
  DHCP clients do not properly support this)
* use iptables MSS clamping (only works for TCP and routed
  traffic)
* on a gateway router, set a route to the internet with a lower
  MTU, which then results in "ICMP packet too big" messages back
  to the client with containing the desired MTU and the initial
  host should retry with a smaller packet size
  (only works for routed traffic)

Or if you have full control of all hosts in the network you can
also reduce the MTU on the hosts.

Also note batman-adv v2021.0 had some performance
improvements for frames fragmented by batman-adv:

https://www.open-mesh.org/news/100 ->
* 
https://git.open-mesh.org/batman-adv.git/commit/92064deda9b063ca2d5a53b307c6127a9453357c
* 
https://git.open-mesh.org/batman-adv.git/commit/0966d5424bb87e863037301488519ccdd69e4d26
* 
https://git.open-mesh.org/batman-adv.git/commit/3e3ff987876d3be70d928561acbefe5a48ab1654

Regards, Linus


Re: How to mesh over ethernet VLAN?

2021-04-09 Thread Linus Lüssing
On Tue, Apr 06, 2021 at 11:33:26PM +0200, Andi Depressivum wrote:
> That was my very first configuration approach but it's rather slow
> (about 200mbit/s over a gigabit link) compared to native VLANs. I've
> tried to set the MTU size to 1536 for the mesh interface but for some
> reason the MTU of the interface stays at 1500?!

The MTU of eth0.2 or bat0?

One of the performance penalties might occur when batman-adv needs
to use fragmentation. batman-adv is going to add its own header
on top of the 1500 byte frames received on bat0.

1536 on eth0.2 looks good though. Then 1500 bytes should fit
without fragmentation on bat0. You can check with "batctl
td" or Wireshark if you see batman-adv fragments on eth0.2.

If 1536 is somehow not applied to eth0.2, might be a driver issue
then. You can check wether you can manually alter an interface MTU
with "ip link dev eth0.2 set mtu 1536", for instance.

Regards, Linus


Re: Problems with Multiple Interfaces

2021-04-09 Thread Linus Lüssing
On Fri, Apr 09, 2021 at 12:17:36PM +0200, Simon Wunderlich wrote:
> On Thursday, April 8, 2021 7:56:29 AM CEST j...@careyhome.org wrote:
> > Hi Everybody,
> > 
> > I'm running BATMAN v 2019.2 with ath10k on OpenWRT.  The particular router
> > I'm using has two interfaces, 2.4 GHz and 5GHz.  With each router using
> > single interface (e.g. 2.4 GHz), it works fine.  When I add a second
> > interface (e.g. 5GHz), it sometimes hangs.

One more note: ath10k firmware refuses to provide an expected
throughput for the wifi link.

The fallback to an estimate which uses the raw tx bitrate was
added not that long ago in batman-adv v2020.0:

https://www.open-mesh.org/news/95

I'm wondering if you might have very low throughput values in
batman-adv and if that might lead to issues with interface
alternating.

Also, would be interesting to know if you have the same issues
when using BATMAN IV, which mainly uses a packetloss based metric.

Regards, Linus


IPv4/IPv6 separation in bridge code for multicast routers

2021-04-06 Thread Linus Lüssing
Hi,

I wanted to add the remaining pieces for batman-adv to support
IPv4 multicast groups in bridged setups, next to the IPv6 support
already in place. For which we'd need MRD support. So once more
I'd tap into the bridge for this information from batman-adv.

Then I realized again that the bridge keeps track of the
IGMP/MLD querier per protocol family but not for the multicast
router ports. For the latter we only have one list right now. For
batman-adv we have the multicast router flags and logic already
separate though.

I started separating the router list for IPv4 and IPv6 in the
bridge, but it seems there are already external users for the
protocol family unaware router list right now: netlink and switchdev.
Now I'm wondering:

A) For netlink:

Would it be fine to just add a MDBA_ROUTER_PATTR_FAMILY with
either the value PF_INET or PF_INET6? The downside would be that
a userspace application which does not know this new attribute
yet would potentially see or list a duplicate.

Another option would be to add two separate attributes:
MDBA_ROUTER_PATTR_{INET,INET6}. Which looks a bit more clumsy and
and inflexible to me. But would have a better compatiblity when
userspace requests a router ports dump. For events there'd still
be the same issue of duplicates though, as IPv4 and IPv6 routers
might appear or disappear asynchronously.

B) For switchdev:

I'm not that familiar with switchdev. Should it generally be
possible to separate the protocol family here? Or would it be
better to add a few more lines to the bridge code to
only call switchdev_port_attr_set() when transitioning between
v4-rtr, v6-rtr: (off, off) <=> (on, on) | (on, off) | (off, on)?
At least for a start, maybe?

C)

Or am I missing something in the MRD RFC (RFC4286) which implies
that a Multicast router Advertisement should be interpreted
across protocol families?


Any ideas what might be the best way to tackle this?

Regards, Linus


Re: How to mesh over ethernet VLAN?

2021-04-06 Thread Linus Lüssing
On Sun, Apr 04, 2021 at 07:52:35PM +0200, Andi Depressivum wrote:
> Hello everybody,
> 
> What's the correct setup to mesh also over an existing ethernet VLAN link?
> 
> My core network with all routers & servers is running on VLAN 3
> (eth0.3 in the routers). How do I have to setup batman-adv to a) mesh
> also over this existing link and b) propagate this VLAN also over
> wireless links. Bridging eth0.3 with bat0.3 and adding eth0.3 also as
> a hardif doesn't work, as it will remove eth0.3 from the bridge.

Right, that is not supported. That goes in the direction of
creating an encapsulating loop. It's best to avoid sharing a link for both
the payload frames and the mesh layer.

One option could be to add an extra VLAN, like VLAN 4, dedicated
for the mesh layer with the batman-adv frames, parallel to the
VLAN 3.

Or if most/all hosts are running batman-adv, so if architecturally
batman-adv is forming the backbone of your network, you could
run batman-adv over this VLAN 3 only. And then either run
batman-adv on the servers themselves or bridge the servers into the
batman-adv mesh on their adjacent mesh router(s).

Regards, Linus


Re: Batman adv selective broadcast mechanism

2021-03-28 Thread Linus Lüssing
Hi Oytun,

Are you able to recompile the kernel module and batctl? If so, I
could have a look at updating that patch for a more recent
batman-adv version.

Actually, I'm also kind of curious about your use-case. Sounds
like it's not 802.11 wifi you are using, right?

Regards, Linus


On Thu, Mar 25, 2021 at 12:58:15PM -, oytunya...@hotmail.com wrote:
> Hi Linus,
> 
> Thank you for the answer. Configuring batman-adv from /sys is deprecated 
> in the last version (batctl is the only way now). I am not sure how to apply 
> this patch. What do you suggest as a proper way of doing this?
> 
> Regards.
> Oytun


Re: Batman adv selective broadcast mechanism

2021-03-24 Thread Linus Lüssing
Hi,

On Wed, Mar 24, 2021 at 12:16:16PM -, oytunya...@hotmail.com wrote:
> Hi everybody,
> 
> As I check, batman-adv protocol, sends IP broadcast packets, to every 
> slave interface, including the slave interface from which the broadcast 
> packet is received. Is there any way for preventing the batman-adv from 
> sending IP broadcast packets to some of the slave interfaces (etc. the one 
> which the packet is received)?

When there is just a single neighbor on the interface a node
received the packet on that batman-adv avoids sending it
back automatically. E.g. this case here:

https://www.open-mesh.org/projects/batman-adv/wiki/Broadcast#-Single-Neighbor-Is-Previous-Sender

If there are multiple neighbors on the receiving interface then
batman-adv assumes that other neighbors might potentially not have
received the packet from the original sender. And will therefore
rebroadcast on the incoming interface, too.

If you are 100% sure that all other neighbors received it from
the original sender then there is this old patch which isn't
upstream though (including the discussion with why it was
rejetected for upstream):

https://patchwork.open-mesh.org/project/b.a.t.m.a.n./patch/1380030033-11533-1-git-send-email-linus.luess...@web.de/

Regards, Linus


[PATCH maint] batman-adv: Fix order of kernel doc in batadv_priv

2021-03-23 Thread Linus Lüssing
During the inlining process of kerneldoc some comments were placed at
the wrong struct members. Fixing this by reordering the comments.

Fixes: 6369b8e999af ("batman-adv: Use inline kernel-doc for enum/struct")
Signed-off-by: Linus Lüssing 
---

Note: checkpatch shows me a warning:

```
~/dev-priv/linux/linux/scripts/checkpatch.pl --strict 
./0001-batman-adv-Fix-order-of-kernel-doc-in-batadv_priv.patch
CHECK: spinlock_t definition without comment
#35: FILE: net/batman-adv/types.h:1665:
+   spinlock_t forw_bat_list_lock;

CHECK: spinlock_t definition without comment
#39: FILE: net/batman-adv/types.h:1668:
+   spinlock_t forw_bcast_list_lock;

total: 0 errors, 0 warnings, 2 checks, 25 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
  mechanically convert to the typical style using --fix or --fix-inplace.

./0001-batman-adv-Fix-order-of-kernel-doc-in-batadv_priv.patch has style 
problems, please review.
```

However it seems to be a false positive:

```
~/dev-priv/linux/linux/scripts/checkpatch.pl -f ./net/batman-adv/types.h
Traceback (most recent call last):
  File "scripts/spdxcheck.py", line 10, in 
import git
ImportError: No module named git
total: 0 errors, 0 warnings, 2410 lines checked

NOTE: If any of the errors are false positives, please report
  them to the maintainer, see CHECKPATCH in MAINTAINERS.

./net/batman-adv/types.h has no obvious style problems and is ready for 
submission.
```

Checkpatch version is: e0c755a45f6f from net-master


 net/batman-adv/types.h | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 2f96e96a..30c78e6e 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1658,19 +1658,19 @@ struct batadv_priv {
/** @tp_list: list of tp sessions */
struct hlist_head tp_list;
 
-   /** @tp_num: number of currently active tp sessions */
-   struct batadv_hashtable *orig_hash;
-
/** @orig_hash: hash table containing mesh participants (orig nodes) */
-   spinlock_t forw_bat_list_lock;
+   struct batadv_hashtable *orig_hash;
 
/** @forw_bat_list_lock: lock protecting forw_bat_list */
-   spinlock_t forw_bcast_list_lock;
+   spinlock_t forw_bat_list_lock;
 
/** @forw_bcast_list_lock: lock protecting forw_bcast_list */
-   spinlock_t tp_list_lock;
+   spinlock_t forw_bcast_list_lock;
 
/** @tp_list_lock: spinlock protecting @tp_list */
+   spinlock_t tp_list_lock;
+
+   /** @tp_num: number of currently active tp sessions */
atomic_t tp_num;
 
/** @orig_work: work queue callback item for orig node purging */
-- 
2.30.1


Re: batman-adv for kbit level speeds, external neighbor info

2021-03-16 Thread Linus Lüssing
On Tue, Mar 16, 2021 at 01:17:50PM -, oytunya...@hotmail.com wrote:
> Hi everybody,
> 
> I have some questions about batman-adv.
> Do you suggest, batman-adv, for speeds like 2.4kbit/s (very slow 
> networks)? I tried to use batctl throughput_override, for such a setup. It 
> seems at least 100kbit/s speed is valid for this utility.
> Is there any way, feeding neighbor information to batman-adv externally 
> (etc. using DLEP protocol, as an external link monitor)?
> Thank you in advance.

If you use throughput override on all devices, you could also
just shift the value equally on all devices. For instance just set
24 Mbit/s instead for a 2.4 kbit/s link.

BATMAN V algorithm itself at the moment does not care about the
actual accuracy of the unit. As long as the values are not too
small or too large. And as long as it's the same baseline on all
devices.

Regards, Linus


[PATCH v2] net: bridge: mcast: rename br_ip's u member to dst

2020-09-28 Thread Linus Lüssing
From: Nikolay Aleksandrov 

Since now we have src in br_ip, u no longer makes sense so rename
it to dst. No functional changes.

v2: fix build with CONFIG_BATMAN_ADV_MCAST

CC: Marek Lindner 
CC: Simon Wunderlich 
CC: Antonio Quartulli 
CC: Sven Eckelmann 
CC: b.a.t.m.a.n@lists.open-mesh.org
Signed-off-by: Nikolay Aleksandrov 
[linus.luess...@c0d3.blue: Add compat code]
Signed-off-by: Linus Lüssing 
---
Compat v2:
* added BUILD_BUG_ON size+offset checks as suggested by Sven (thanks!)

 compat-include/linux/if_bridge.h | 56 
 net/batman-adv/multicast.c   | 14 
 2 files changed, 63 insertions(+), 7 deletions(-)
 create mode 100644 compat-include/linux/if_bridge.h

diff --git a/compat-include/linux/if_bridge.h b/compat-include/linux/if_bridge.h
new file mode 100644
index ..45585003
--- /dev/null
+++ b/compat-include/linux/if_bridge.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2007-2020  B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner, Simon Wunderlich
+ *
+ * This file contains macros for maintaining compatibility with older versions
+ * of the Linux kernel.
+ */
+
+#ifndef _NET_BATMAN_ADV_COMPAT_LINUX_IF_BRIDGE_H_
+#define _NET_BATMAN_ADV_COMPAT_LINUX_IF_BRIDGE_H_
+
+#include 
+#include_next 
+
+#if LINUX_VERSION_IS_LESS(5, 10, 0)
+
+struct batadv_br_ip {
+   union {
+   __be32  ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+   struct in6_addr ip6;
+#endif
+   } dst;
+   __be16  proto;
+   __u16   vid;
+};
+
+struct batadv_br_ip_list {
+   struct list_head list;
+   struct batadv_br_ip addr;
+};
+
+/* "static" dropped to force compiler to evaluate it as part of multicast.c
+ * might need to be added again and then called in some kind of dummy
+ * compat.c in case this header is included in multiple files.
+ */
+inline void __batadv_br_ip_list_check(void)
+{
+   BUILD_BUG_ON(sizeof(struct batadv_br_ip_list) != sizeof(struct 
br_ip_list));
+   BUILD_BUG_ON(offsetof(struct batadv_br_ip_list, list) != 
offsetof(struct br_ip_list, list));
+   BUILD_BUG_ON(offsetof(struct batadv_br_ip_list, addr) != 
offsetof(struct br_ip_list, addr));
+
+   BUILD_BUG_ON(sizeof(struct batadv_br_ip) != sizeof(struct br_ip));
+   BUILD_BUG_ON(offsetof(struct batadv_br_ip, dst.ip4) != offsetof(struct 
br_ip, u.ip4));
+   BUILD_BUG_ON(offsetof(struct batadv_br_ip, dst.ip6) != offsetof(struct 
br_ip, u.ip6));
+   BUILD_BUG_ON(offsetof(struct batadv_br_ip, proto) != offsetof(struct 
br_ip, proto));
+   BUILD_BUG_ON(offsetof(struct batadv_br_ip, vid) != offsetof(struct 
br_ip, vid));
+}
+
+#define br_ip batadv_br_ip
+#define br_ip_list batadv_br_ip_list
+
+#endif /* LINUX_VERSION_IS_LESS(5, 10, 0) */
+
+#endif /* _NET_BATMAN_ADV_COMPAT_LINUX_IF_BRIDGE_H_ */
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 0746fe2c..9af99c39 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -221,7 +221,7 @@ static u8 batadv_mcast_mla_rtr_flags_bridge_get(struct 
batadv_priv *bat_priv,
 * address here, only IPv6 ones
 */
if (br_ip_entry->addr.proto == htons(ETH_P_IPV6) &&
-   ipv6_addr_is_ll_all_routers(_ip_entry->addr.u.ip6))
+   ipv6_addr_is_ll_all_routers(_ip_entry->addr.dst.ip6))
flags &= ~BATADV_MCAST_WANT_NO_RTR6;
 
list_del(_ip_entry->list);
@@ -562,10 +562,10 @@ batadv_mcast_mla_softif_get(struct net_device *dev,
 static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src)
 {
if (src->proto == htons(ETH_P_IP))
-   ip_eth_mc_map(src->u.ip4, dst);
+   ip_eth_mc_map(src->dst.ip4, dst);
 #if IS_ENABLED(CONFIG_IPV6)
else if (src->proto == htons(ETH_P_IPV6))
-   ipv6_eth_mc_map(>u.ip6, dst);
+   ipv6_eth_mc_map(>dst.ip6, dst);
 #endif
else
eth_zero_addr(dst);
@@ -609,11 +609,11 @@ static int batadv_mcast_mla_bridge_get(struct net_device 
*dev,
continue;
 
if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
-   ipv4_is_local_multicast(br_ip_entry->addr.u.ip4))
+   ipv4_is_local_multicast(br_ip_entry->addr.dst.ip4))
continue;
 
if (!(tvlv_flags & BATADV_MCAST_WANT_NO_RTR4) &&
-   !ipv4_is_local_multicast(br_ip_entry->addr.u.ip4))
+   !ipv4_is_local_multicast(br_ip_entry->addr.dst.ip4))
continue;
}
 
@@ -623,11 +623,11 @@ static int batadv_mcast_mla_bridge_get(struct net_device 
*dev,
continue;
 
if (tvlv_flags &

Re: [PATCH 2/2] batman-adv: mcast: rename br_ip's u member to dst

2020-09-27 Thread Linus Lüssing
On Sat, Sep 26, 2020 at 10:12:20AM +0200, Sven Eckelmann wrote:
> From: Nikolay Aleksandrov 
> 
> Since now we have src in br_ip, u no longer makes sense so rename
> it to dst. No functional changes.
> 
> Signed-off-by: Nikolay Aleksandrov 
> Signed-off-by: David S. Miller 
> [s...@narfation.org: Add compat code]
> Signed-off-by: Sven Eckelmann 
> ---

Hi Sven,

The version I've just posted [1] should hopefully work without needing
to readd the source code patching infrastructure.

Regards, Linus

[1]: 
https://patchwork.open-mesh.org/project/b.a.t.m.a.n./patch/20200927191234.22423-1-linus.luess...@c0d3.blue/


[PATCH] net: bridge: mcast: rename br_ip's u member to dst

2020-09-27 Thread Linus Lüssing
From: Nikolay Aleksandrov 

Since now we have src in br_ip, u no longer makes sense so rename
it to dst. No functional changes.

v2: fix build with CONFIG_BATMAN_ADV_MCAST

CC: Marek Lindner 
CC: Simon Wunderlich 
CC: Antonio Quartulli 
CC: Sven Eckelmann 
CC: b.a.t.m.a.n@lists.open-mesh.org
Signed-off-by: Nikolay Aleksandrov 
[linus.luess...@c0d3.blue: Add compat code]
Signed-off-by: Linus Lüssing 
---
 compat-include/linux/if_bridge.h | 39 
 net/batman-adv/multicast.c   | 14 ++--
 2 files changed, 46 insertions(+), 7 deletions(-)
 create mode 100644 compat-include/linux/if_bridge.h

diff --git a/compat-include/linux/if_bridge.h b/compat-include/linux/if_bridge.h
new file mode 100644
index ..c4f9bc08
--- /dev/null
+++ b/compat-include/linux/if_bridge.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2007-2020  B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner, Simon Wunderlich
+ *
+ * This file contains macros for maintaining compatibility with older versions
+ * of the Linux kernel.
+ */
+
+#ifndef _NET_BATMAN_ADV_COMPAT_LINUX_IF_BRIDGE_H_
+#define _NET_BATMAN_ADV_COMPAT_LINUX_IF_BRIDGE_H_
+
+#include 
+#include_next 
+
+#if LINUX_VERSION_IS_LESS(5, 10, 0)
+
+struct batadv_br_ip {
+   union {
+   __be32  ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+   struct in6_addr ip6;
+#endif
+   } dst;
+   __be16  proto;
+   __u16   vid;
+};
+
+struct batadv_br_ip_list {
+   struct list_head list;
+   struct batadv_br_ip addr;
+};
+
+#define br_ip batadv_br_ip
+#define br_ip_list batadv_br_ip_list
+
+#endif /* LINUX_VERSION_IS_LESS(5, 10, 0) */
+
+#endif /* _NET_BATMAN_ADV_COMPAT_LINUX_IF_BRIDGE_H_ */
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 0746fe2c..9af99c39 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -221,7 +221,7 @@ static u8 batadv_mcast_mla_rtr_flags_bridge_get(struct 
batadv_priv *bat_priv,
 * address here, only IPv6 ones
 */
if (br_ip_entry->addr.proto == htons(ETH_P_IPV6) &&
-   ipv6_addr_is_ll_all_routers(_ip_entry->addr.u.ip6))
+   ipv6_addr_is_ll_all_routers(_ip_entry->addr.dst.ip6))
flags &= ~BATADV_MCAST_WANT_NO_RTR6;
 
list_del(_ip_entry->list);
@@ -562,10 +562,10 @@ batadv_mcast_mla_softif_get(struct net_device *dev,
 static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src)
 {
if (src->proto == htons(ETH_P_IP))
-   ip_eth_mc_map(src->u.ip4, dst);
+   ip_eth_mc_map(src->dst.ip4, dst);
 #if IS_ENABLED(CONFIG_IPV6)
else if (src->proto == htons(ETH_P_IPV6))
-   ipv6_eth_mc_map(>u.ip6, dst);
+   ipv6_eth_mc_map(>dst.ip6, dst);
 #endif
else
eth_zero_addr(dst);
@@ -609,11 +609,11 @@ static int batadv_mcast_mla_bridge_get(struct net_device 
*dev,
continue;
 
if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
-   ipv4_is_local_multicast(br_ip_entry->addr.u.ip4))
+   ipv4_is_local_multicast(br_ip_entry->addr.dst.ip4))
continue;
 
if (!(tvlv_flags & BATADV_MCAST_WANT_NO_RTR4) &&
-   !ipv4_is_local_multicast(br_ip_entry->addr.u.ip4))
+   !ipv4_is_local_multicast(br_ip_entry->addr.dst.ip4))
continue;
}
 
@@ -623,11 +623,11 @@ static int batadv_mcast_mla_bridge_get(struct net_device 
*dev,
continue;
 
if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
-   ipv6_addr_is_ll_all_nodes(_ip_entry->addr.u.ip6))
+   
ipv6_addr_is_ll_all_nodes(_ip_entry->addr.dst.ip6))
continue;
 
if (!(tvlv_flags & BATADV_MCAST_WANT_NO_RTR6) &&
-   IPV6_ADDR_MC_SCOPE(_ip_entry->addr.u.ip6) >
+   IPV6_ADDR_MC_SCOPE(_ip_entry->addr.dst.ip6) >
IPV6_ADDR_SCOPE_LINKLOCAL)
continue;
}
-- 
2.28.0


  1   2   3   4   5   6   7   8   9   10   >