Commit 90039133 authored by Linus Lüssing's avatar Linus Lüssing Committed by Simon Wunderlich
Browse files

batman-adv: mcast: implement multicast packet generation



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: default avatarLinus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: default avatarSimon Wunderlich <sw@simonwunderlich.de>
parent 07afe1ba
Loading
Loading
Loading
Loading
+74 −5
Original line number Diff line number Diff line
@@ -1169,17 +1169,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(&bat_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(&bat_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;
@@ -1209,10 +1254,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(&bat_priv->multicast_fanout))
		return BATADV_FORW_UCASTS;

	return BATADV_FORW_BCAST;
	return batadv_mcast_forw_mode_by_count(bat_priv, skb, vid, *is_routable,
					       total_count);
}

/**
@@ -1772,6 +1815,31 @@ static void batadv_mcast_want_rtr6_update(struct batadv_priv *bat_priv,
	}
}

/**
 * batadv_mcast_have_mc_ptype_update() - update multicast packet type counter
 * @bat_priv: the bat priv with all the soft interface information
 * @orig: the orig_node which multicast state might have changed of
 * @mcast_flags: flags indicating the new multicast state
 *
 * If the BATADV_MCAST_HAVE_MC_PTYPE_CAPA flag of this originator, orig, has
 * toggled then this method updates the counter accordingly.
 */
static void batadv_mcast_have_mc_ptype_update(struct batadv_priv *bat_priv,
					      struct batadv_orig_node *orig,
					      u8 mcast_flags)
{
	lockdep_assert_held(&orig->mcast_handler_lock);

	/* switched from flag set to unset */
	if (!(mcast_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA) &&
	    orig->mcast_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA)
		atomic_inc(&bat_priv->mcast.num_no_mc_ptype_capa);
	/* switched from flag unset to set */
	else if (mcast_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA &&
		 !(orig->mcast_flags & BATADV_MCAST_HAVE_MC_PTYPE_CAPA))
		atomic_dec(&bat_priv->mcast.num_no_mc_ptype_capa);
}

/**
 * batadv_mcast_tvlv_flags_get() - get multicast flags from an OGM TVLV
 * @enabled: whether the originator has multicast TVLV support enabled
@@ -1840,6 +1908,7 @@ static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
	batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags);
	batadv_mcast_want_rtr4_update(bat_priv, orig, mcast_flags);
	batadv_mcast_want_rtr6_update(bat_priv, orig, mcast_flags);
	batadv_mcast_have_mc_ptype_update(bat_priv, orig, mcast_flags);

	orig->mcast_flags = mcast_flags;
	spin_unlock_bh(&orig->mcast_handler_lock);
+23 −2
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@

#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/types.h>

/**
 * enum batadv_forw_mode - the way a packet should be forwarded as
@@ -28,6 +29,12 @@ enum batadv_forw_mode {
	 */
	BATADV_FORW_UCASTS,

	/**
	 * @BATADV_FORW_MCAST: forward the packet to some nodes via a
	 *  batman-adv multicast packet
	 */
	BATADV_FORW_MCAST,

	/** @BATADV_FORW_NONE: don't forward, drop it */
	BATADV_FORW_NONE,
};
@@ -36,7 +43,7 @@ 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 batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
			   unsigned short vid, int is_routable);
@@ -57,11 +64,18 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node);
int batadv_mcast_forw_tracker_tvlv_handler(struct batadv_priv *bat_priv,
					   struct sk_buff *skb);

unsigned int batadv_mcast_forw_packet_hdrlen(unsigned int num_dests);

bool batadv_mcast_forw_push(struct batadv_priv *bat_priv, struct sk_buff *skb,
			    unsigned short vid, int is_routable, int count);

int batadv_mcast_forw_mcsend(struct batadv_priv *bat_priv, struct sk_buff *skb);

#else

static inline 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)
{
	return BATADV_FORW_BCAST;
}
@@ -99,6 +113,13 @@ static inline void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node)
{
}

static inline int batadv_mcast_forw_mcsend(struct batadv_priv *bat_priv,
					   struct sk_buff *skb)
{
	kfree_skb(skb);
	return NET_XMIT_DROP;
}

#endif /* CONFIG_BATMAN_ADV_MCAST */

#endif /* _NET_BATMAN_ADV_MULTICAST_H_ */
+732 −0

File changed.

Preview size limit exceeded, changes collapsed.

+5 −1
Original line number Diff line number Diff line
@@ -301,12 +301,13 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,

send:
		if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
			forw_mode = batadv_mcast_forw_mode(bat_priv, skb,
			forw_mode = batadv_mcast_forw_mode(bat_priv, skb, vid,
							   &mcast_is_routable);
			switch (forw_mode) {
			case BATADV_FORW_BCAST:
				break;
			case BATADV_FORW_UCASTS:
			case BATADV_FORW_MCAST:
				do_bcast = false;
				break;
			case BATADV_FORW_NONE:
@@ -365,6 +366,8 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
		} else if (forw_mode == BATADV_FORW_UCASTS) {
			ret = batadv_mcast_forw_send(bat_priv, skb, vid,
						     mcast_is_routable);
		} else if (forw_mode == BATADV_FORW_MCAST) {
			ret = batadv_mcast_forw_mcsend(bat_priv, skb);
		} else {
			if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
								  skb))
@@ -762,6 +765,7 @@ static int batadv_softif_init_late(struct net_device *dev)
	atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0);
	atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0);
	atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0);
	atomic_set(&bat_priv->mcast.num_no_mc_ptype_capa, 0);
#endif
	atomic_set(&bat_priv->gw.mode, BATADV_GW_MODE_OFF);
	atomic_set(&bat_priv->gw.bandwidth_down, 100);
+6 −0
Original line number Diff line number Diff line
@@ -1342,6 +1342,12 @@ struct batadv_priv_mcast {
	/** @num_want_all_rtr6: counter for items in want_all_rtr6_list */
	atomic_t num_want_all_rtr6;

	/**
	 * @num_no_mc_ptype_capa: counter for number of nodes without the
	 *  BATADV_MCAST_HAVE_MC_PTYPE_CAPA flag
	 */
	atomic_t num_no_mc_ptype_capa;

	/**
	 * @want_lists_lock: lock for protecting modifications to mcasts
	 *  want_all_{unsnoopables,ipv4,ipv6}_list (traversals are rcu-locked)