Commit c5caf4ef authored by Linus Lüssing's avatar Linus Lüssing Committed by Antonio Quartulli
Browse files

batman-adv: Multicast Listener Announcements via Translation Table



With this patch a node which has no bridge interface on top of its soft
interface announces its local multicast listeners via the translation
table.

Signed-off-by: default avatarLinus Lüssing <linus.luessing@web.de>
Signed-off-by: default avatarMarek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: default avatarAntonio Quartulli <antonio@meshcoding.com>
parent c5d3a652
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,15 @@ config BATMAN_ADV_NC
	  If you think that your network does not need this feature you
	  If you think that your network does not need this feature you
	  can safely disable it and save some space.
	  can safely disable it and save some space.


config BATMAN_ADV_MCAST
	bool "Multicast optimisation"
	depends on BATMAN_ADV
	default n
	help
	  This option enables the multicast optimisation which aims to
	  reduce the air overhead while improving the reliability of
	  multicast messages.

config BATMAN_ADV_DEBUG
config BATMAN_ADV_DEBUG
	bool "B.A.T.M.A.N. debugging"
	bool "B.A.T.M.A.N. debugging"
	depends on BATMAN_ADV
	depends on BATMAN_ADV
+1 −0
Original line number Original line Diff line number Diff line
@@ -36,3 +36,4 @@ batman-adv-y += send.o
batman-adv-y += soft-interface.o
batman-adv-y += soft-interface.o
batman-adv-y += sysfs.o
batman-adv-y += sysfs.o
batman-adv-y += translation-table.o
batman-adv-y += translation-table.o
batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast.o
+6 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@
#include "gateway_client.h"
#include "gateway_client.h"
#include "bridge_loop_avoidance.h"
#include "bridge_loop_avoidance.h"
#include "distributed-arp-table.h"
#include "distributed-arp-table.h"
#include "multicast.h"
#include "gateway_common.h"
#include "gateway_common.h"
#include "hash.h"
#include "hash.h"
#include "bat_algo.h"
#include "bat_algo.h"
@@ -120,6 +121,9 @@ int batadv_mesh_init(struct net_device *soft_iface)
	INIT_LIST_HEAD(&bat_priv->tt.changes_list);
	INIT_LIST_HEAD(&bat_priv->tt.changes_list);
	INIT_LIST_HEAD(&bat_priv->tt.req_list);
	INIT_LIST_HEAD(&bat_priv->tt.req_list);
	INIT_LIST_HEAD(&bat_priv->tt.roam_list);
	INIT_LIST_HEAD(&bat_priv->tt.roam_list);
#ifdef CONFIG_BATMAN_ADV_MCAST
	INIT_HLIST_HEAD(&bat_priv->mcast.mla_list);
#endif
	INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
	INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
	INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
	INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
	INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
	INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
@@ -169,6 +173,8 @@ void batadv_mesh_free(struct net_device *soft_iface)
	batadv_dat_free(bat_priv);
	batadv_dat_free(bat_priv);
	batadv_bla_free(bat_priv);
	batadv_bla_free(bat_priv);


	batadv_mcast_free(bat_priv);

	/* Free the TT and the originator tables only after having terminated
	/* Free the TT and the originator tables only after having terminated
	 * all the other depending components which may use these structures for
	 * all the other depending components which may use these structures for
	 * their purposes.
	 * their purposes.
+1 −0
Original line number Original line Diff line number Diff line
@@ -176,6 +176,7 @@ enum batadv_uev_type {
#include <linux/percpu.h>
#include <linux/percpu.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <net/sock.h>		/* struct sock */
#include <net/sock.h>		/* struct sock */
#include <net/addrconf.h>	/* ipv6 address stuff */
#include <net/rtnetlink.h>
#include <net/rtnetlink.h>
#include <linux/jiffies.h>
#include <linux/jiffies.h>
#include <linux/seq_file.h>
#include <linux/seq_file.h>
+218 −0
Original line number Original line Diff line number Diff line
/* Copyright (C) 2014 B.A.T.M.A.N. contributors:
 *
 * Linus Lüssing
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include "main.h"
#include "multicast.h"
#include "originator.h"
#include "hard-interface.h"
#include "translation-table.h"

/**
 * batadv_mcast_mla_softif_get - get softif multicast listeners
 * @dev: the device to collect multicast addresses from
 * @mcast_list: a list to put found addresses into
 *
 * Collect multicast addresses of the local multicast listeners
 * on the given soft interface, dev, in the given mcast_list.
 *
 * Returns -ENOMEM on memory allocation error or the number of
 * items added to the mcast_list otherwise.
 */
static int batadv_mcast_mla_softif_get(struct net_device *dev,
				       struct hlist_head *mcast_list)
{
	struct netdev_hw_addr *mc_list_entry;
	struct batadv_hw_addr *new;
	int ret = 0;

	netif_addr_lock_bh(dev);
	netdev_for_each_mc_addr(mc_list_entry, dev) {
		new = kmalloc(sizeof(*new), GFP_ATOMIC);
		if (!new) {
			ret = -ENOMEM;
			break;
		}

		ether_addr_copy(new->addr, mc_list_entry->addr);
		hlist_add_head(&new->list, mcast_list);
		ret++;
	}
	netif_addr_unlock_bh(dev);

	return ret;
}

/**
 * batadv_mcast_mla_is_duplicate - check whether an address is in a list
 * @mcast_addr: the multicast address to check
 * @mcast_list: the list with multicast addresses to search in
 *
 * Returns true if the given address is already in the given list.
 * Otherwise returns false.
 */
static bool batadv_mcast_mla_is_duplicate(uint8_t *mcast_addr,
					  struct hlist_head *mcast_list)
{
	struct batadv_hw_addr *mcast_entry;

	hlist_for_each_entry(mcast_entry, mcast_list, list)
		if (batadv_compare_eth(mcast_entry->addr, mcast_addr))
			return true;

	return false;
}

/**
 * batadv_mcast_mla_list_free - free a list of multicast addresses
 * @mcast_list: the list to free
 *
 * Removes and frees all items in the given mcast_list.
 */
static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list)
{
	struct batadv_hw_addr *mcast_entry;
	struct hlist_node *tmp;

	hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
		hlist_del(&mcast_entry->list);
		kfree(mcast_entry);
	}
}

/**
 * batadv_mcast_mla_tt_retract - clean up multicast listener announcements
 * @bat_priv: the bat priv with all the soft interface information
 * @mcast_list: a list of addresses which should _not_ be removed
 *
 * Retracts the announcement of any multicast listener from the
 * translation table except the ones listed in the given mcast_list.
 *
 * If mcast_list is NULL then all are retracted.
 */
static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
					struct hlist_head *mcast_list)
{
	struct batadv_hw_addr *mcast_entry;
	struct hlist_node *tmp;

	hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list,
				  list) {
		if (mcast_list &&
		    batadv_mcast_mla_is_duplicate(mcast_entry->addr,
						  mcast_list))
			continue;

		batadv_tt_local_remove(bat_priv, mcast_entry->addr,
				       BATADV_NO_FLAGS,
				       "mcast TT outdated", false);

		hlist_del(&mcast_entry->list);
		kfree(mcast_entry);
	}
}

/**
 * batadv_mcast_mla_tt_add - add multicast listener announcements
 * @bat_priv: the bat priv with all the soft interface information
 * @mcast_list: a list of addresses which are going to get added
 *
 * Adds multicast listener announcements from the given mcast_list to the
 * translation table if they have not been added yet.
 */
static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
				    struct hlist_head *mcast_list)
{
	struct batadv_hw_addr *mcast_entry;
	struct hlist_node *tmp;

	if (!mcast_list)
		return;

	hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
		if (batadv_mcast_mla_is_duplicate(mcast_entry->addr,
						  &bat_priv->mcast.mla_list))
			continue;

		if (!batadv_tt_local_add(bat_priv->soft_iface,
					 mcast_entry->addr, BATADV_NO_FLAGS,
					 BATADV_NULL_IFINDEX, BATADV_NO_MARK))
			continue;

		hlist_del(&mcast_entry->list);
		hlist_add_head(&mcast_entry->list, &bat_priv->mcast.mla_list);
	}
}

/**
 * batadv_mcast_has_bridge - check whether the soft-iface is bridged
 * @bat_priv: the bat priv with all the soft interface information
 *
 * Checks whether there is a bridge on top of our soft interface. Returns
 * true if so, false otherwise.
 */
static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv)
{
	struct net_device *upper = bat_priv->soft_iface;

	rcu_read_lock();
	do {
		upper = netdev_master_upper_dev_get_rcu(upper);
	} while (upper && !(upper->priv_flags & IFF_EBRIDGE));
	rcu_read_unlock();

	return upper;
}

/**
 * batadv_mcast_mla_update - update the own MLAs
 * @bat_priv: the bat priv with all the soft interface information
 *
 * Update the own multicast listener announcements in the translation
 * table.
 */
void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
{
	struct net_device *soft_iface = bat_priv->soft_iface;
	struct hlist_head mcast_list = HLIST_HEAD_INIT;
	int ret;

	/* Avoid attaching MLAs, if there is a bridge on top of our soft
	 * interface, we don't support that yet (TODO)
	 */
	if (batadv_mcast_has_bridge(bat_priv))
		goto update;

	ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list);
	if (ret < 0)
		goto out;

update:
	batadv_mcast_mla_tt_retract(bat_priv, &mcast_list);
	batadv_mcast_mla_tt_add(bat_priv, &mcast_list);

out:
	batadv_mcast_mla_list_free(&mcast_list);
}

/**
 * batadv_mcast_free - free the multicast optimizations structures
 * @bat_priv: the bat priv with all the soft interface information
 */
void batadv_mcast_free(struct batadv_priv *bat_priv)
{
	batadv_mcast_mla_tt_retract(bat_priv, NULL);
}
Loading