Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

batman-adv: Modified forwarding behaviour for multicast packets

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>

authored by

Linus Lüssing and committed by
Antonio Quartulli
1d8ab8d3 60432d75

+275 -26
+9
Documentation/ABI/testing/sysfs-class-net-mesh
··· 76 76 is used to classify clients as "isolated" by the 77 77 Extended Isolation feature. 78 78 79 + What: /sys/class/net/<mesh_iface>/mesh/multicast_mode 80 + Date: Feb 2014 81 + Contact: Linus Lüssing <linus.luessing@web.de> 82 + Description: 83 + Indicates whether multicast optimizations are enabled 84 + or disabled. If set to zero then all nodes in the 85 + mesh are going to use classic flooding for any 86 + multicast packet with no optimizations. 87 + 79 88 What: /sys/class/net/<mesh_iface>/mesh/network_coding 80 89 Date: Nov 2012 81 90 Contact: Martin Hundeboll <martin@hundeboll.net>
+126
net/batman-adv/multicast.c
··· 20 20 #include "originator.h" 21 21 #include "hard-interface.h" 22 22 #include "translation-table.h" 23 + #include "multicast.h" 23 24 24 25 /** 25 26 * batadv_mcast_mla_softif_get - get softif multicast listeners ··· 245 244 246 245 out: 247 246 batadv_mcast_mla_list_free(&mcast_list); 247 + } 248 + 249 + /** 250 + * batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential 251 + * @bat_priv: the bat priv with all the soft interface information 252 + * @skb: the IPv6 packet to check 253 + * 254 + * Checks whether the given IPv6 packet has the potential to be forwarded with a 255 + * mode more optimal than classic flooding. 256 + * 257 + * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out 258 + * of memory. 259 + */ 260 + static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv, 261 + struct sk_buff *skb) 262 + { 263 + struct ipv6hdr *ip6hdr; 264 + 265 + /* We might fail due to out-of-memory -> drop it */ 266 + if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr))) 267 + return -ENOMEM; 268 + 269 + ip6hdr = ipv6_hdr(skb); 270 + 271 + /* TODO: Implement Multicast Router Discovery (RFC4286), 272 + * then allow scope > link local, too 273 + */ 274 + if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) != IPV6_ADDR_SCOPE_LINKLOCAL) 275 + return -EINVAL; 276 + 277 + /* link-local-all-nodes multicast listeners behind a bridge are 278 + * not snoopable (see RFC4541, section 3, paragraph 3) 279 + */ 280 + if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr)) 281 + return -EINVAL; 282 + 283 + return 0; 284 + } 285 + 286 + /** 287 + * batadv_mcast_forw_mode_check - check for optimized forwarding potential 288 + * @bat_priv: the bat priv with all the soft interface information 289 + * @skb: the multicast frame to check 290 + * 291 + * Checks whether the given multicast ethernet frame has the potential to be 292 + * forwarded with a mode more optimal than classic flooding. 293 + * 294 + * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out 295 + * of memory. 296 + */ 297 + static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv, 298 + struct sk_buff *skb) 299 + { 300 + struct ethhdr *ethhdr = eth_hdr(skb); 301 + 302 + if (!atomic_read(&bat_priv->multicast_mode)) 303 + return -EINVAL; 304 + 305 + if (atomic_read(&bat_priv->mcast.num_disabled)) 306 + return -EINVAL; 307 + 308 + switch (ntohs(ethhdr->h_proto)) { 309 + case ETH_P_IPV6: 310 + return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb); 311 + default: 312 + return -EINVAL; 313 + } 314 + } 315 + 316 + /** 317 + * batadv_mcast_forw_tt_node_get - get a multicast tt node 318 + * @bat_priv: the bat priv with all the soft interface information 319 + * @ethhdr: the ether header containing the multicast destination 320 + * 321 + * Returns an orig_node matching the multicast address provided by ethhdr 322 + * via a translation table lookup. This increases the returned nodes refcount. 323 + */ 324 + static struct batadv_orig_node * 325 + batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv, 326 + struct ethhdr *ethhdr) 327 + { 328 + return batadv_transtable_search(bat_priv, ethhdr->h_source, 329 + ethhdr->h_dest, BATADV_NO_FLAGS); 330 + } 331 + 332 + /** 333 + * batadv_mcast_forw_mode - check on how to forward a multicast packet 334 + * @bat_priv: the bat priv with all the soft interface information 335 + * @skb: The multicast packet to check 336 + * @orig: an originator to be set to forward the skb to 337 + * 338 + * Returns the forwarding mode as enum batadv_forw_mode and in case of 339 + * BATADV_FORW_SINGLE set the orig to the single originator the skb 340 + * should be forwarded to. 341 + */ 342 + enum batadv_forw_mode 343 + batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, 344 + struct batadv_orig_node **orig) 345 + { 346 + struct ethhdr *ethhdr; 347 + int ret, tt_count; 348 + 349 + ret = batadv_mcast_forw_mode_check(bat_priv, skb); 350 + if (ret == -ENOMEM) 351 + return BATADV_FORW_NONE; 352 + else if (ret < 0) 353 + return BATADV_FORW_ALL; 354 + 355 + ethhdr = eth_hdr(skb); 356 + 357 + tt_count = batadv_tt_global_hash_count(bat_priv, ethhdr->h_dest, 358 + BATADV_NO_FLAGS); 359 + 360 + switch (tt_count) { 361 + case 1: 362 + *orig = batadv_mcast_forw_tt_node_get(bat_priv, ethhdr); 363 + if (*orig) 364 + return BATADV_FORW_SINGLE; 365 + 366 + /* fall through */ 367 + case 0: 368 + return BATADV_FORW_NONE; 369 + default: 370 + return BATADV_FORW_ALL; 371 + } 248 372 } 249 373 250 374 /**
+25
net/batman-adv/multicast.h
··· 18 18 #ifndef _NET_BATMAN_ADV_MULTICAST_H_ 19 19 #define _NET_BATMAN_ADV_MULTICAST_H_ 20 20 21 + /** 22 + * batadv_forw_mode - the way a packet should be forwarded as 23 + * @BATADV_FORW_ALL: forward the packet to all nodes (currently via classic 24 + * flooding) 25 + * @BATADV_FORW_SINGLE: forward the packet to a single node (currently via the 26 + * BATMAN unicast routing protocol) 27 + * @BATADV_FORW_NONE: don't forward, drop it 28 + */ 29 + enum batadv_forw_mode { 30 + BATADV_FORW_ALL, 31 + BATADV_FORW_SINGLE, 32 + BATADV_FORW_NONE, 33 + }; 34 + 21 35 #ifdef CONFIG_BATMAN_ADV_MCAST 22 36 23 37 void batadv_mcast_mla_update(struct batadv_priv *bat_priv); 38 + 39 + enum batadv_forw_mode 40 + batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, 41 + struct batadv_orig_node **mcast_single_orig); 24 42 25 43 void batadv_mcast_init(struct batadv_priv *bat_priv); 26 44 ··· 51 33 static inline void batadv_mcast_mla_update(struct batadv_priv *bat_priv) 52 34 { 53 35 return; 36 + } 37 + 38 + static inline enum batadv_forw_mode 39 + batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, 40 + struct batadv_orig_node **mcast_single_orig) 41 + { 42 + return BATADV_FORW_ALL; 54 43 } 55 44 56 45 static inline int batadv_mcast_init(struct batadv_priv *bat_priv)
+5 -5
net/batman-adv/send.c
··· 248 248 * 249 249 * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. 250 250 */ 251 - static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, 252 - struct sk_buff *skb, int packet_type, 253 - int packet_subtype, 254 - struct batadv_orig_node *orig_node, 255 - unsigned short vid) 251 + int batadv_send_skb_unicast(struct batadv_priv *bat_priv, 252 + struct sk_buff *skb, int packet_type, 253 + int packet_subtype, 254 + struct batadv_orig_node *orig_node, 255 + unsigned short vid) 256 256 { 257 257 struct ethhdr *ethhdr; 258 258 struct batadv_unicast_packet *unicast_packet;
+5
net/batman-adv/send.h
··· 36 36 struct sk_buff *skb, 37 37 struct batadv_orig_node *orig_node, 38 38 int packet_subtype); 39 + int batadv_send_skb_unicast(struct batadv_priv *bat_priv, 40 + struct sk_buff *skb, int packet_type, 41 + int packet_subtype, 42 + struct batadv_orig_node *orig_node, 43 + unsigned short vid); 39 44 int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, 40 45 struct sk_buff *skb, int packet_type, 41 46 int packet_subtype, uint8_t *dst_hint,
+19 -1
net/batman-adv/soft-interface.c
··· 32 32 #include <linux/ethtool.h> 33 33 #include <linux/etherdevice.h> 34 34 #include <linux/if_vlan.h> 35 + #include "multicast.h" 35 36 #include "bridge_loop_avoidance.h" 36 37 #include "network-coding.h" 37 38 ··· 171 170 unsigned short vid; 172 171 uint32_t seqno; 173 172 int gw_mode; 173 + enum batadv_forw_mode forw_mode; 174 + struct batadv_orig_node *mcast_single_orig = NULL; 174 175 175 176 if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) 176 177 goto dropped; ··· 250 247 * directed to a DHCP server 251 248 */ 252 249 goto dropped; 253 - } 254 250 255 251 send: 252 + if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) { 253 + forw_mode = batadv_mcast_forw_mode(bat_priv, skb, 254 + &mcast_single_orig); 255 + if (forw_mode == BATADV_FORW_NONE) 256 + goto dropped; 257 + 258 + if (forw_mode == BATADV_FORW_SINGLE) 259 + do_bcast = false; 260 + } 261 + } 262 + 256 263 batadv_skb_set_priority(skb, 0); 257 264 258 265 /* ethernet packet should be broadcasted */ ··· 314 301 if (ret) 315 302 goto dropped; 316 303 ret = batadv_send_skb_via_gw(bat_priv, skb, vid); 304 + } else if (mcast_single_orig) { 305 + ret = batadv_send_skb_unicast(bat_priv, skb, 306 + BATADV_UNICAST, 0, 307 + mcast_single_orig, vid); 317 308 } else { 318 309 if (batadv_dat_snoop_outgoing_arp_request(bat_priv, 319 310 skb)) ··· 708 691 #endif 709 692 #ifdef CONFIG_BATMAN_ADV_MCAST 710 693 bat_priv->mcast.flags = BATADV_NO_FLAGS; 694 + atomic_set(&bat_priv->multicast_mode, 1); 711 695 atomic_set(&bat_priv->mcast.num_disabled, 0); 712 696 #endif 713 697 atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF);
+6
net/batman-adv/sysfs.c
··· 539 539 batadv_post_gw_reselect); 540 540 static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth, 541 541 batadv_store_gw_bwidth); 542 + #ifdef CONFIG_BATMAN_ADV_MCAST 543 + BATADV_ATTR_SIF_BOOL(multicast_mode, S_IRUGO | S_IWUSR, NULL); 544 + #endif 542 545 #ifdef CONFIG_BATMAN_ADV_DEBUG 543 546 BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL); 544 547 #endif ··· 560 557 #endif 561 558 #ifdef CONFIG_BATMAN_ADV_DAT 562 559 &batadv_attr_distributed_arp_table, 560 + #endif 561 + #ifdef CONFIG_BATMAN_ADV_MCAST 562 + &batadv_attr_multicast_mode, 563 563 #endif 564 564 &batadv_attr_fragmentation, 565 565 &batadv_attr_routing_algo,
+71 -20
net/batman-adv/translation-table.c
··· 193 193 } 194 194 } 195 195 196 + /** 197 + * batadv_tt_global_hash_count - count the number of orig entries 198 + * @hash: hash table containing the tt entries 199 + * @addr: the mac address of the client to count entries for 200 + * @vid: VLAN identifier 201 + * 202 + * Return the number of originators advertising the given address/data 203 + * (excluding ourself). 204 + */ 205 + int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, 206 + const uint8_t *addr, unsigned short vid) 207 + { 208 + struct batadv_tt_global_entry *tt_global_entry; 209 + int count; 210 + 211 + tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); 212 + if (!tt_global_entry) 213 + return 0; 214 + 215 + count = atomic_read(&tt_global_entry->orig_list_count); 216 + batadv_tt_global_entry_free_ref(tt_global_entry); 217 + 218 + return count; 219 + } 220 + 196 221 static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) 197 222 { 198 223 struct batadv_tt_orig_list_entry *orig_entry; ··· 1250 1225 hlist_add_head_rcu(&orig_entry->list, 1251 1226 &tt_global->orig_list); 1252 1227 spin_unlock_bh(&tt_global->list_lock); 1228 + atomic_inc(&tt_global->orig_list_count); 1229 + 1253 1230 out: 1254 1231 if (orig_entry) 1255 1232 batadv_tt_orig_list_entry_free_ref(orig_entry); ··· 1325 1298 common->added_at = jiffies; 1326 1299 1327 1300 INIT_HLIST_HEAD(&tt_global_entry->orig_list); 1301 + atomic_set(&tt_global_entry->orig_list_count, 0); 1328 1302 spin_lock_init(&tt_global_entry->list_lock); 1329 1303 1330 1304 hash_added = batadv_hash_add(bat_priv->tt.global_hash, ··· 1591 1563 return 0; 1592 1564 } 1593 1565 1566 + /** 1567 + * batadv_tt_global_del_orig_entry - remove and free an orig_entry 1568 + * @tt_global_entry: the global entry to remove the orig_entry from 1569 + * @orig_entry: the orig entry to remove and free 1570 + * 1571 + * Remove an orig_entry from its list in the given tt_global_entry and 1572 + * free this orig_entry afterwards. 1573 + */ 1574 + static void 1575 + batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, 1576 + struct batadv_tt_orig_list_entry *orig_entry) 1577 + { 1578 + batadv_tt_global_size_dec(orig_entry->orig_node, 1579 + tt_global_entry->common.vid); 1580 + atomic_dec(&tt_global_entry->orig_list_count); 1581 + hlist_del_rcu(&orig_entry->list); 1582 + batadv_tt_orig_list_entry_free_ref(orig_entry); 1583 + } 1584 + 1594 1585 /* deletes the orig list of a tt_global_entry */ 1595 1586 static void 1596 1587 batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) ··· 1620 1573 1621 1574 spin_lock_bh(&tt_global_entry->list_lock); 1622 1575 head = &tt_global_entry->orig_list; 1623 - hlist_for_each_entry_safe(orig_entry, safe, head, list) { 1624 - hlist_del_rcu(&orig_entry->list); 1625 - batadv_tt_global_size_dec(orig_entry->orig_node, 1626 - tt_global_entry->common.vid); 1627 - batadv_tt_orig_list_entry_free_ref(orig_entry); 1628 - } 1576 + hlist_for_each_entry_safe(orig_entry, safe, head, list) 1577 + batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); 1629 1578 spin_unlock_bh(&tt_global_entry->list_lock); 1630 1579 } 1631 1580 1581 + /** 1582 + * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry 1583 + * @bat_priv: the bat priv with all the soft interface information 1584 + * @tt_global_entry: the global entry to remove the orig_node from 1585 + * @orig_node: the originator announcing the client 1586 + * @message: message to append to the log on deletion 1587 + * 1588 + * Remove the given orig_node and its according orig_entry from the given 1589 + * global tt entry. 1590 + */ 1632 1591 static void 1633 - batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, 1634 - struct batadv_tt_global_entry *tt_global_entry, 1635 - struct batadv_orig_node *orig_node, 1636 - const char *message) 1592 + batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, 1593 + struct batadv_tt_global_entry *tt_global_entry, 1594 + struct batadv_orig_node *orig_node, 1595 + const char *message) 1637 1596 { 1638 1597 struct hlist_head *head; 1639 1598 struct hlist_node *safe; ··· 1656 1603 orig_node->orig, 1657 1604 tt_global_entry->common.addr, 1658 1605 BATADV_PRINT_VID(vid), message); 1659 - hlist_del_rcu(&orig_entry->list); 1660 - batadv_tt_global_size_dec(orig_node, 1661 - tt_global_entry->common.vid); 1662 - batadv_tt_orig_list_entry_free_ref(orig_entry); 1606 + batadv_tt_global_del_orig_entry(tt_global_entry, 1607 + orig_entry); 1663 1608 } 1664 1609 } 1665 1610 spin_unlock_bh(&tt_global_entry->list_lock); ··· 1699 1648 /* there is another entry, we can simply delete this 1700 1649 * one and can still use the other one. 1701 1650 */ 1702 - batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 1703 - orig_node, message); 1651 + batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 1652 + orig_node, message); 1704 1653 } 1705 1654 1706 1655 /** ··· 1726 1675 goto out; 1727 1676 1728 1677 if (!roaming) { 1729 - batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, 1730 - orig_node, message); 1678 + batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, 1679 + orig_node, message); 1731 1680 1732 1681 if (hlist_empty(&tt_global_entry->orig_list)) 1733 1682 batadv_tt_global_free(bat_priv, tt_global_entry, ··· 1810 1759 struct batadv_tt_global_entry, 1811 1760 common); 1812 1761 1813 - batadv_tt_global_del_orig_entry(bat_priv, tt_global, 1814 - orig_node, message); 1762 + batadv_tt_global_del_orig_node(bat_priv, tt_global, 1763 + orig_node, message); 1815 1764 1816 1765 if (hlist_empty(&tt_global->orig_list)) { 1817 1766 vid = tt_global->common.vid;
+2
net/batman-adv/translation-table.h
··· 29 29 void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, 30 30 struct batadv_orig_node *orig_node, 31 31 int32_t match_vid, const char *message); 32 + int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, 33 + const uint8_t *addr, unsigned short vid); 32 34 struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, 33 35 const uint8_t *src, 34 36 const uint8_t *addr,
+7
net/batman-adv/types.h
··· 696 696 * enabled 697 697 * @distributed_arp_table: bool indicating whether distributed ARP table is 698 698 * enabled 699 + * @multicast_mode: Enable or disable multicast optimizations on this node's 700 + * sender/originating side 699 701 * @gw_mode: gateway operation: off, client or server (see batadv_gw_modes) 700 702 * @gw_sel_class: gateway selection class (applies if gw_mode client) 701 703 * @orig_interval: OGM broadcast interval in milliseconds ··· 747 745 #endif 748 746 #ifdef CONFIG_BATMAN_ADV_DAT 749 747 atomic_t distributed_arp_table; 748 + #endif 749 + #ifdef CONFIG_BATMAN_ADV_MCAST 750 + atomic_t multicast_mode; 750 751 #endif 751 752 atomic_t gw_mode; 752 753 atomic_t gw_sel_class; ··· 914 909 * struct batadv_tt_global_entry - translation table global entry data 915 910 * @common: general translation table data 916 911 * @orig_list: list of orig nodes announcing this non-mesh client 912 + * @orig_list_count: number of items in the orig_list 917 913 * @list_lock: lock protecting orig_list 918 914 * @roam_at: time at which TT_GLOBAL_ROAM was set 919 915 */ 920 916 struct batadv_tt_global_entry { 921 917 struct batadv_tt_common_entry common; 922 918 struct hlist_head orig_list; 919 + atomic_t orig_list_count; 923 920 spinlock_t list_lock; /* protects orig_list */ 924 921 unsigned long roam_at; 925 922 };