Skip to content

Commit

Permalink
batman-adv: Modified forwarding behaviour for multicast packets
Browse files Browse the repository at this point in the history
With this patch a multicast packet is not always simply flooded anymore,
the behaviour for the following cases is changed to reduce
unnecessary overhead:

If all nodes within the horizon of a certain node have signalized
multicast listener announcement capability then an IPv6 multicast packet
with a destination of IPv6 link-local scope (excluding ff02::1) coming
from the upstream of this node...

* ...is dropped if there is no according multicast listener in the
  translation table,
* ...is forwarded via unicast if there is a single node with interested
  multicast listeners
* ...and otherwise still gets flooded.

Signed-off-by: Linus Lüssing <linus.luessing@web.de>
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
  • Loading branch information
Linus Lüssing authored and Antonio Quartulli committed Mar 22, 2014
1 parent 60432d7 commit 1d8ab8d
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 26 deletions.
9 changes: 9 additions & 0 deletions Documentation/ABI/testing/sysfs-class-net-mesh
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ Description:
is used to classify clients as "isolated" by the
Extended Isolation feature.

What: /sys/class/net/<mesh_iface>/mesh/multicast_mode
Date: Feb 2014
Contact: Linus Lüssing <linus.luessing@web.de>
Description:
Indicates whether multicast optimizations are enabled
or disabled. If set to zero then all nodes in the
mesh are going to use classic flooding for any
multicast packet with no optimizations.

What: /sys/class/net/<mesh_iface>/mesh/network_coding
Date: Nov 2012
Contact: Martin Hundeboll <martin@hundeboll.net>
Expand Down
126 changes: 126 additions & 0 deletions net/batman-adv/multicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "originator.h"
#include "hard-interface.h"
#include "translation-table.h"
#include "multicast.h"

/**
* batadv_mcast_mla_softif_get - get softif multicast listeners
Expand Down Expand Up @@ -246,6 +247,131 @@ void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
batadv_mcast_mla_list_free(&mcast_list);
}

/**
* batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential
* @bat_priv: the bat priv with all the soft interface information
* @skb: the IPv6 packet to check
*
* Checks whether the given IPv6 packet has the potential to be forwarded with a
* mode more optimal than classic flooding.
*
* If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out
* of memory.
*/
static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
struct ipv6hdr *ip6hdr;

/* We might fail due to out-of-memory -> drop it */
if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr)))
return -ENOMEM;

ip6hdr = ipv6_hdr(skb);

/* TODO: Implement Multicast Router Discovery (RFC4286),
* then allow scope > link local, too
*/
if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) != IPV6_ADDR_SCOPE_LINKLOCAL)
return -EINVAL;

/* link-local-all-nodes multicast listeners behind a bridge are
* not snoopable (see RFC4541, section 3, paragraph 3)
*/
if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr))
return -EINVAL;

return 0;
}

/**
* batadv_mcast_forw_mode_check - check for optimized forwarding potential
* @bat_priv: the bat priv with all the soft interface information
* @skb: the multicast frame to check
*
* Checks whether the given multicast ethernet frame has the potential to be
* forwarded with a mode more optimal than classic flooding.
*
* If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out
* of memory.
*/
static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
struct ethhdr *ethhdr = eth_hdr(skb);

if (!atomic_read(&bat_priv->multicast_mode))
return -EINVAL;

if (atomic_read(&bat_priv->mcast.num_disabled))
return -EINVAL;

switch (ntohs(ethhdr->h_proto)) {
case ETH_P_IPV6:
return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb);
default:
return -EINVAL;
}
}

/**
* 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
*
* Returns 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, ethhdr->h_source,
ethhdr->h_dest, BATADV_NO_FLAGS);
}

/**
* 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
* @orig: an originator to be set to forward the skb to
*
* Returns the forwarding mode as enum batadv_forw_mode and in case of
* BATADV_FORW_SINGLE set the orig to the single originator the skb
* should be forwarded to.
*/
enum batadv_forw_mode
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
struct batadv_orig_node **orig)
{
struct ethhdr *ethhdr;
int ret, tt_count;

ret = batadv_mcast_forw_mode_check(bat_priv, skb);
if (ret == -ENOMEM)
return BATADV_FORW_NONE;
else if (ret < 0)
return BATADV_FORW_ALL;

ethhdr = eth_hdr(skb);

tt_count = batadv_tt_global_hash_count(bat_priv, ethhdr->h_dest,
BATADV_NO_FLAGS);

switch (tt_count) {
case 1:
*orig = batadv_mcast_forw_tt_node_get(bat_priv, ethhdr);
if (*orig)
return BATADV_FORW_SINGLE;

/* fall through */
case 0:
return BATADV_FORW_NONE;
default:
return BATADV_FORW_ALL;
}
}

/**
* batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container
* @bat_priv: the bat priv with all the soft interface information
Expand Down
25 changes: 25 additions & 0 deletions net/batman-adv/multicast.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,28 @@
#ifndef _NET_BATMAN_ADV_MULTICAST_H_
#define _NET_BATMAN_ADV_MULTICAST_H_

/**
* batadv_forw_mode - the way a packet should be forwarded as
* @BATADV_FORW_ALL: forward the packet to all nodes (currently via classic
* flooding)
* @BATADV_FORW_SINGLE: forward the packet to a single node (currently via the
* BATMAN unicast routing protocol)
* @BATADV_FORW_NONE: don't forward, drop it
*/
enum batadv_forw_mode {
BATADV_FORW_ALL,
BATADV_FORW_SINGLE,
BATADV_FORW_NONE,
};

#ifdef CONFIG_BATMAN_ADV_MCAST

void batadv_mcast_mla_update(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 **mcast_single_orig);

void batadv_mcast_init(struct batadv_priv *bat_priv);

void batadv_mcast_free(struct batadv_priv *bat_priv);
Expand All @@ -35,6 +53,13 @@ static inline void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
return;
}

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)
{
return BATADV_FORW_ALL;
}

static inline int batadv_mcast_init(struct batadv_priv *bat_priv)
{
return 0;
Expand Down
10 changes: 5 additions & 5 deletions net/batman-adv/send.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,11 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
*
* Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype,
struct batadv_orig_node *orig_node,
unsigned short vid)
int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype,
struct batadv_orig_node *orig_node,
unsigned short vid)
{
struct ethhdr *ethhdr;
struct batadv_unicast_packet *unicast_packet;
Expand Down
5 changes: 5 additions & 0 deletions net/batman-adv/send.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig_node,
int packet_subtype);
int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype,
struct batadv_orig_node *orig_node,
unsigned short vid);
int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype, uint8_t *dst_hint,
Expand Down
20 changes: 19 additions & 1 deletion net/batman-adv/soft-interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include "multicast.h"
#include "bridge_loop_avoidance.h"
#include "network-coding.h"

Expand Down Expand Up @@ -170,6 +171,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
unsigned short vid;
uint32_t seqno;
int gw_mode;
enum batadv_forw_mode forw_mode;
struct batadv_orig_node *mcast_single_orig = NULL;

if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
goto dropped;
Expand Down Expand Up @@ -247,9 +250,19 @@ static int batadv_interface_tx(struct sk_buff *skb,
* directed to a DHCP server
*/
goto dropped;
}

send:
if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
forw_mode = batadv_mcast_forw_mode(bat_priv, skb,
&mcast_single_orig);
if (forw_mode == BATADV_FORW_NONE)
goto dropped;

if (forw_mode == BATADV_FORW_SINGLE)
do_bcast = false;
}
}

batadv_skb_set_priority(skb, 0);

/* ethernet packet should be broadcasted */
Expand Down Expand Up @@ -301,6 +314,10 @@ static int batadv_interface_tx(struct sk_buff *skb,
if (ret)
goto dropped;
ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
} else if (mcast_single_orig) {
ret = batadv_send_skb_unicast(bat_priv, skb,
BATADV_UNICAST, 0,
mcast_single_orig, vid);
} else {
if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
skb))
Expand Down Expand Up @@ -691,6 +708,7 @@ static int batadv_softif_init_late(struct net_device *dev)
#endif
#ifdef CONFIG_BATMAN_ADV_MCAST
bat_priv->mcast.flags = BATADV_NO_FLAGS;
atomic_set(&bat_priv->multicast_mode, 1);
atomic_set(&bat_priv->mcast.num_disabled, 0);
#endif
atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF);
Expand Down
6 changes: 6 additions & 0 deletions net/batman-adv/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,9 @@ BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE,
batadv_post_gw_reselect);
static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
batadv_store_gw_bwidth);
#ifdef CONFIG_BATMAN_ADV_MCAST
BATADV_ATTR_SIF_BOOL(multicast_mode, S_IRUGO | S_IWUSR, NULL);
#endif
#ifdef CONFIG_BATMAN_ADV_DEBUG
BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL);
#endif
Expand All @@ -557,6 +560,9 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
#endif
#ifdef CONFIG_BATMAN_ADV_DAT
&batadv_attr_distributed_arp_table,
#endif
#ifdef CONFIG_BATMAN_ADV_MCAST
&batadv_attr_multicast_mode,
#endif
&batadv_attr_fragmentation,
&batadv_attr_routing_algo,
Expand Down
Loading

0 comments on commit 1d8ab8d

Please sign in to comment.