Skip to content

Commit 32e7274

Browse files
T-Xsimonwunderlich
authored andcommitted
batman-adv: Add multicast-to-unicast support for multiple targets
With this patch multicast packets with a limited number of destinations (current default: 16) will be split and transmitted by the originator as individual unicast transmissions. Wifi broadcasts with their low bitrate are still a costly undertaking. In a mesh network this cost multiplies with the overall size of the mesh network. Therefore using multiple unicast transmissions instead of broadcast flooding is almost always less burdensome for the mesh network. The maximum amount of unicast packets can be configured via the newly introduced multicast_fanout parameter. If this limit is exceeded distribution will fall back to classic broadcast flooding. The multicast-to-unicast conversion is performed on the initial multicast sender node and counts on a final destination node, mesh-wide basis (and not next hop, neighbor node basis). Signed-off-by: Linus Lüssing <[email protected]> Signed-off-by: Sven Eckelmann <[email protected]> Signed-off-by: Simon Wunderlich <[email protected]>
1 parent 099e6cc commit 32e7274

File tree

8 files changed

+252
-6
lines changed

8 files changed

+252
-6
lines changed

include/uapi/linux/batman_adv.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,13 @@ enum batadv_nl_attrs {
473473
*/
474474
BATADV_ATTR_THROUGHPUT_OVERRIDE,
475475

476+
/**
477+
* @BATADV_ATTR_MULTICAST_FANOUT: defines the maximum number of packet
478+
* copies that may be generated for a multicast-to-unicast conversion.
479+
* Once this limit is exceeded distribution will fall back to broadcast.
480+
*/
481+
BATADV_ATTR_MULTICAST_FANOUT,
482+
476483
/* add attributes above here, update the policy in netlink.c */
477484

478485
/**

net/batman-adv/multicast.c

Lines changed: 198 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "hash.h"
5555
#include "log.h"
5656
#include "netlink.h"
57+
#include "send.h"
5758
#include "soft-interface.h"
5859
#include "translation-table.h"
5960
#include "tvlv.h"
@@ -979,6 +980,7 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
979980
{
980981
int ret, tt_count, ip_count, unsnoop_count, total_count;
981982
bool is_unsnoopable = false;
983+
unsigned int mcast_fanout;
982984
struct ethhdr *ethhdr;
983985

984986
ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable);
@@ -1013,8 +1015,203 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
10131015
case 0:
10141016
return BATADV_FORW_NONE;
10151017
default:
1016-
return BATADV_FORW_ALL;
1018+
mcast_fanout = atomic_read(&bat_priv->multicast_fanout);
1019+
1020+
if (!unsnoop_count && total_count <= mcast_fanout)
1021+
return BATADV_FORW_SOME;
1022+
}
1023+
1024+
return BATADV_FORW_ALL;
1025+
}
1026+
1027+
/**
1028+
* batadv_mcast_forw_tt() - forwards a packet to multicast listeners
1029+
* @bat_priv: the bat priv with all the soft interface information
1030+
* @skb: the multicast packet to transmit
1031+
* @vid: the vlan identifier
1032+
*
1033+
* Sends copies of a frame with multicast destination to any multicast
1034+
* listener registered in the translation table. A transmission is performed
1035+
* via a batman-adv unicast packet for each such destination node.
1036+
*
1037+
* Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
1038+
* otherwise.
1039+
*/
1040+
static int
1041+
batadv_mcast_forw_tt(struct batadv_priv *bat_priv, struct sk_buff *skb,
1042+
unsigned short vid)
1043+
{
1044+
int ret = NET_XMIT_SUCCESS;
1045+
struct sk_buff *newskb;
1046+
1047+
struct batadv_tt_orig_list_entry *orig_entry;
1048+
1049+
struct batadv_tt_global_entry *tt_global;
1050+
const u8 *addr = eth_hdr(skb)->h_dest;
1051+
1052+
tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
1053+
if (!tt_global)
1054+
goto out;
1055+
1056+
rcu_read_lock();
1057+
hlist_for_each_entry_rcu(orig_entry, &tt_global->orig_list, list) {
1058+
newskb = skb_copy(skb, GFP_ATOMIC);
1059+
if (!newskb) {
1060+
ret = NET_XMIT_DROP;
1061+
break;
1062+
}
1063+
1064+
batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
1065+
orig_entry->orig_node, vid);
1066+
}
1067+
rcu_read_unlock();
1068+
1069+
batadv_tt_global_entry_put(tt_global);
1070+
1071+
out:
1072+
return ret;
1073+
}
1074+
1075+
/**
1076+
* batadv_mcast_forw_want_all_ipv4() - forward to nodes with want-all-ipv4
1077+
* @bat_priv: the bat priv with all the soft interface information
1078+
* @skb: the multicast packet to transmit
1079+
* @vid: the vlan identifier
1080+
*
1081+
* Sends copies of a frame with multicast destination to any node with a
1082+
* BATADV_MCAST_WANT_ALL_IPV4 flag set. A transmission is performed via a
1083+
* batman-adv unicast packet for each such destination node.
1084+
*
1085+
* Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
1086+
* otherwise.
1087+
*/
1088+
static int
1089+
batadv_mcast_forw_want_all_ipv4(struct batadv_priv *bat_priv,
1090+
struct sk_buff *skb, unsigned short vid)
1091+
{
1092+
struct batadv_orig_node *orig_node;
1093+
int ret = NET_XMIT_SUCCESS;
1094+
struct sk_buff *newskb;
1095+
1096+
rcu_read_lock();
1097+
hlist_for_each_entry_rcu(orig_node,
1098+
&bat_priv->mcast.want_all_ipv4_list,
1099+
mcast_want_all_ipv4_node) {
1100+
newskb = skb_copy(skb, GFP_ATOMIC);
1101+
if (!newskb) {
1102+
ret = NET_XMIT_DROP;
1103+
break;
1104+
}
1105+
1106+
batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
1107+
orig_node, vid);
1108+
}
1109+
rcu_read_unlock();
1110+
return ret;
1111+
}
1112+
1113+
/**
1114+
* batadv_mcast_forw_want_all_ipv6() - forward to nodes with want-all-ipv6
1115+
* @bat_priv: the bat priv with all the soft interface information
1116+
* @skb: The multicast packet to transmit
1117+
* @vid: the vlan identifier
1118+
*
1119+
* Sends copies of a frame with multicast destination to any node with a
1120+
* BATADV_MCAST_WANT_ALL_IPV6 flag set. A transmission is performed via a
1121+
* batman-adv unicast packet for each such destination node.
1122+
*
1123+
* Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
1124+
* otherwise.
1125+
*/
1126+
static int
1127+
batadv_mcast_forw_want_all_ipv6(struct batadv_priv *bat_priv,
1128+
struct sk_buff *skb, unsigned short vid)
1129+
{
1130+
struct batadv_orig_node *orig_node;
1131+
int ret = NET_XMIT_SUCCESS;
1132+
struct sk_buff *newskb;
1133+
1134+
rcu_read_lock();
1135+
hlist_for_each_entry_rcu(orig_node,
1136+
&bat_priv->mcast.want_all_ipv6_list,
1137+
mcast_want_all_ipv6_node) {
1138+
newskb = skb_copy(skb, GFP_ATOMIC);
1139+
if (!newskb) {
1140+
ret = NET_XMIT_DROP;
1141+
break;
1142+
}
1143+
1144+
batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
1145+
orig_node, vid);
10171146
}
1147+
rcu_read_unlock();
1148+
return ret;
1149+
}
1150+
1151+
/**
1152+
* batadv_mcast_forw_want_all() - forward packet to nodes in a want-all list
1153+
* @bat_priv: the bat priv with all the soft interface information
1154+
* @skb: the multicast packet to transmit
1155+
* @vid: the vlan identifier
1156+
*
1157+
* Sends copies of a frame with multicast destination to any node with a
1158+
* BATADV_MCAST_WANT_ALL_IPV4 or BATADV_MCAST_WANT_ALL_IPV6 flag set. A
1159+
* transmission is performed via a batman-adv unicast packet for each such
1160+
* destination node.
1161+
*
1162+
* Return: NET_XMIT_DROP on memory allocation failure or if the protocol family
1163+
* is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
1164+
*/
1165+
static int
1166+
batadv_mcast_forw_want_all(struct batadv_priv *bat_priv,
1167+
struct sk_buff *skb, unsigned short vid)
1168+
{
1169+
switch (ntohs(eth_hdr(skb)->h_proto)) {
1170+
case ETH_P_IP:
1171+
return batadv_mcast_forw_want_all_ipv4(bat_priv, skb, vid);
1172+
case ETH_P_IPV6:
1173+
return batadv_mcast_forw_want_all_ipv6(bat_priv, skb, vid);
1174+
default:
1175+
/* we shouldn't be here... */
1176+
return NET_XMIT_DROP;
1177+
}
1178+
}
1179+
1180+
/**
1181+
* batadv_mcast_forw_send() - send packet to any detected multicast recpient
1182+
* @bat_priv: the bat priv with all the soft interface information
1183+
* @skb: the multicast packet to transmit
1184+
* @vid: the vlan identifier
1185+
*
1186+
* Sends copies of a frame with multicast destination to any node that signaled
1187+
* interest in it, that is either via the translation table or the according
1188+
* want-all flags. A transmission is performed via a batman-adv unicast packet
1189+
* for each such destination node.
1190+
*
1191+
* The given skb is consumed/freed.
1192+
*
1193+
* Return: NET_XMIT_DROP on memory allocation failure or if the protocol family
1194+
* is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
1195+
*/
1196+
int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
1197+
unsigned short vid)
1198+
{
1199+
int ret;
1200+
1201+
ret = batadv_mcast_forw_tt(bat_priv, skb, vid);
1202+
if (ret != NET_XMIT_SUCCESS) {
1203+
kfree_skb(skb);
1204+
return ret;
1205+
}
1206+
1207+
ret = batadv_mcast_forw_want_all(bat_priv, skb, vid);
1208+
if (ret != NET_XMIT_SUCCESS) {
1209+
kfree_skb(skb);
1210+
return ret;
1211+
}
1212+
1213+
consume_skb(skb);
1214+
return ret;
10181215
}
10191216

10201217
/**

net/batman-adv/multicast.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ enum batadv_forw_mode {
2323
*/
2424
BATADV_FORW_ALL,
2525

26+
/**
27+
* @BATADV_FORW_SOME: forward the packet to some nodes (currently via
28+
* a multicast-to-unicast conversion and the BATMAN unicast routing
29+
* protocol)
30+
*/
31+
BATADV_FORW_SOME,
32+
2633
/**
2734
* @BATADV_FORW_SINGLE: forward the packet to a single node (currently
2835
* via the BATMAN unicast routing protocol)
@@ -39,6 +46,9 @@ enum batadv_forw_mode
3946
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
4047
struct batadv_orig_node **mcast_single_orig);
4148

49+
int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
50+
unsigned short vid);
51+
4252
void batadv_mcast_init(struct batadv_priv *bat_priv);
4353

4454
int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset);
@@ -61,6 +71,14 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
6171
return BATADV_FORW_ALL;
6272
}
6373

74+
static inline int
75+
batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
76+
unsigned short vid)
77+
{
78+
kfree_skb(skb);
79+
return NET_XMIT_DROP;
80+
}
81+
6482
static inline int batadv_mcast_init(struct batadv_priv *bat_priv)
6583
{
6684
return 0;

net/batman-adv/netlink.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = {
145145
[BATADV_ATTR_HOP_PENALTY] = { .type = NLA_U8 },
146146
[BATADV_ATTR_LOG_LEVEL] = { .type = NLA_U32 },
147147
[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED] = { .type = NLA_U8 },
148+
[BATADV_ATTR_MULTICAST_FANOUT] = { .type = NLA_U32 },
148149
[BATADV_ATTR_NETWORK_CODING_ENABLED] = { .type = NLA_U8 },
149150
[BATADV_ATTR_ORIG_INTERVAL] = { .type = NLA_U32 },
150151
[BATADV_ATTR_ELP_INTERVAL] = { .type = NLA_U32 },
@@ -341,6 +342,10 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg,
341342
if (nla_put_u8(msg, BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED,
342343
!atomic_read(&bat_priv->multicast_mode)))
343344
goto nla_put_failure;
345+
346+
if (nla_put_u32(msg, BATADV_ATTR_MULTICAST_FANOUT,
347+
atomic_read(&bat_priv->multicast_fanout)))
348+
goto nla_put_failure;
344349
#endif /* CONFIG_BATMAN_ADV_MCAST */
345350

346351
#ifdef CONFIG_BATMAN_ADV_NC
@@ -580,6 +585,12 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info)
580585

581586
atomic_set(&bat_priv->multicast_mode, !nla_get_u8(attr));
582587
}
588+
589+
if (info->attrs[BATADV_ATTR_MULTICAST_FANOUT]) {
590+
attr = info->attrs[BATADV_ATTR_MULTICAST_FANOUT];
591+
592+
atomic_set(&bat_priv->multicast_fanout, nla_get_u32(attr));
593+
}
583594
#endif /* CONFIG_BATMAN_ADV_MCAST */
584595

585596
#ifdef CONFIG_BATMAN_ADV_NC

net/batman-adv/soft-interface.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
197197
unsigned short vid;
198198
u32 seqno;
199199
int gw_mode;
200-
enum batadv_forw_mode forw_mode;
200+
enum batadv_forw_mode forw_mode = BATADV_FORW_SINGLE;
201201
struct batadv_orig_node *mcast_single_orig = NULL;
202202
int network_offset = ETH_HLEN;
203203
__be16 proto;
@@ -305,7 +305,8 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
305305
if (forw_mode == BATADV_FORW_NONE)
306306
goto dropped;
307307

308-
if (forw_mode == BATADV_FORW_SINGLE)
308+
if (forw_mode == BATADV_FORW_SINGLE ||
309+
forw_mode == BATADV_FORW_SOME)
309310
do_bcast = false;
310311
}
311312
}
@@ -365,6 +366,8 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
365366
ret = batadv_send_skb_unicast(bat_priv, skb,
366367
BATADV_UNICAST, 0,
367368
mcast_single_orig, vid);
369+
} else if (forw_mode == BATADV_FORW_SOME) {
370+
ret = batadv_mcast_forw_send(bat_priv, skb, vid);
368371
} else {
369372
if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
370373
skb))
@@ -806,6 +809,7 @@ static int batadv_softif_init_late(struct net_device *dev)
806809
bat_priv->mcast.querier_ipv6.shadowing = false;
807810
bat_priv->mcast.flags = BATADV_NO_FLAGS;
808811
atomic_set(&bat_priv->multicast_mode, 1);
812+
atomic_set(&bat_priv->multicast_fanout, 16);
809813
atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0);
810814
atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0);
811815
atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0);

net/batman-adv/translation-table.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
193193
* Return: a pointer to the corresponding tt_global_entry struct if the client
194194
* is found, NULL otherwise.
195195
*/
196-
static struct batadv_tt_global_entry *
196+
struct batadv_tt_global_entry *
197197
batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
198198
unsigned short vid)
199199
{
@@ -288,8 +288,7 @@ static void batadv_tt_global_entry_release(struct kref *ref)
288288
* possibly release it
289289
* @tt_global_entry: tt_global_entry to be free'd
290290
*/
291-
static void
292-
batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry)
291+
void batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry)
293292
{
294293
kref_put(&tt_global_entry->common.refcount,
295294
batadv_tt_global_entry_release);

net/batman-adv/translation-table.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb);
2929
void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
3030
struct batadv_orig_node *orig_node,
3131
s32 match_vid, const char *message);
32+
struct batadv_tt_global_entry *
33+
batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
34+
unsigned short vid);
35+
void batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry);
3236
int batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
3337
const u8 *addr, unsigned short vid);
3438
struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,

net/batman-adv/types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,6 +1553,12 @@ struct batadv_priv {
15531553
* node's sender/originating side
15541554
*/
15551555
atomic_t multicast_mode;
1556+
1557+
/**
1558+
* @multicast_fanout: Maximum number of packet copies to generate for a
1559+
* multicast-to-unicast conversion
1560+
*/
1561+
atomic_t multicast_fanout;
15561562
#endif
15571563

15581564
/** @orig_interval: OGM broadcast interval in milliseconds */

0 commit comments

Comments
 (0)