| From: Linus Lüssing <linus.luessing@c0d3.blue> |
| Date: Sat, 1 Jan 2022 06:27:13 +0100 |
| Subject: batman-adv: mcast: don't send link-local multicast to mcast routers |
| |
| 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 <linus.luessing@c0d3.blue> |
| Signed-off-by: Sven Eckelmann <sven@narfation.org> |
| Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/ee013870947b9175847aa46a0686ca01dd480af4 |
| |
| --- a/net/batman-adv/multicast.c |
| +++ b/net/batman-adv/multicast.c |
| @@ -1380,6 +1380,7 @@ batadv_mcast_forw_rtr_node_get(struct ba |
| * @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 |
| @@ -1387,17 +1388,16 @@ batadv_mcast_forw_rtr_node_get(struct ba |
| */ |
| 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, &is_unsnoopable, |
| - &is_routable); |
| + is_routable); |
| if (ret == -ENOMEM) |
| return BATADV_FORW_NONE; |
| else if (ret < 0) |
| @@ -1410,7 +1410,7 @@ batadv_mcast_forw_mode(struct batadv_pri |
| ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr); |
| unsnoop_count = !is_unsnoopable ? 0 : |
| atomic_read(&bat_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; |
| |
| @@ -1730,6 +1730,7 @@ batadv_mcast_forw_want_rtr(struct batadv |
| * @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 |
| @@ -1742,7 +1743,7 @@ batadv_mcast_forw_want_rtr(struct batadv |
| * 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; |
| |
| @@ -1758,12 +1759,16 @@ int batadv_mcast_forw_send(struct batadv |
| 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; |
| } |
| --- 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 b |
| struct batadv_orig_node *orig_node); |
| |
| int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb, |
| - unsigned short vid); |
| + unsigned short vid, int is_routable); |
| |
| void batadv_mcast_init(struct batadv_priv *bat_priv); |
| |
| @@ -68,7 +69,8 @@ void batadv_mcast_purge_orig(struct bata |
| |
| static inline 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) |
| { |
| return BATADV_FORW_ALL; |
| } |
| @@ -85,7 +87,7 @@ batadv_mcast_forw_send_orig(struct batad |
| |
| static inline int |
| batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb, |
| - unsigned short vid) |
| + unsigned short vid, int is_routable) |
| { |
| kfree_skb(skb); |
| return NET_XMIT_DROP; |
| --- a/net/batman-adv/soft-interface.c |
| +++ b/net/batman-adv/soft-interface.c |
| @@ -198,6 +198,7 @@ static netdev_tx_t batadv_interface_tx(s |
| int gw_mode; |
| enum batadv_forw_mode forw_mode = BATADV_FORW_SINGLE; |
| struct batadv_orig_node *mcast_single_orig = NULL; |
| + int mcast_is_routable = 0; |
| int network_offset = ETH_HLEN; |
| __be16 proto; |
| |
| @@ -300,7 +301,8 @@ static netdev_tx_t batadv_interface_tx(s |
| send: |
| if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) { |
| forw_mode = batadv_mcast_forw_mode(bat_priv, skb, |
| - &mcast_single_orig); |
| + &mcast_single_orig, |
| + &mcast_is_routable); |
| if (forw_mode == BATADV_FORW_NONE) |
| goto dropped; |
| |
| @@ -365,7 +367,8 @@ send: |
| ret = batadv_mcast_forw_send_orig(bat_priv, skb, vid, |
| mcast_single_orig); |
| } else if (forw_mode == BATADV_FORW_SOME) { |
| - ret = batadv_mcast_forw_send(bat_priv, skb, vid); |
| + ret = batadv_mcast_forw_send(bat_priv, skb, vid, |
| + mcast_is_routable); |
| } else { |
| if (batadv_dat_snoop_outgoing_arp_request(bat_priv, |
| skb)) |