Files
openwrt-R7800-nss/target/linux/ipq806x/patches-6.6/990-0201-linux-bridge-add-patch-for-IGMP-MLD-snooping.patch
SqTER-PL 5536c2039e Updated and refreshed patches.
Renamed patches to keep their original numbering from codelinaro.org
Fixed minor bugs and added support for the qca-nss-drv-l2tpv2 module
2025-08-04 18:52:30 +02:00

124 lines
4.7 KiB
Diff

From 84fa3efb7d8eeb1c3f2daf9a3034e2794b3294f9 Mon Sep 17 00:00:00 2001
From: Zhi Chen <zhichen@codeaurora.org>
Date: Mon, 13 Apr 2015 16:39:06 -0700
Subject: [PATCH 223/281] linux: bridge: add patch for IGMP/MLD snooping
Kernel patch for the IGMP/MLD snooping module, which is a replacement
and enhancement of Linux bridge multicast snooping. With the IGMP/MLD
snooping module, we can support IGMPv3/MLDv2 on Linux bridge.
Furthermore, with additional plugins, we can support switch port-based
snooping and WiFi conversion from multicast to unicast.
This patch exported a couple of bridge APIs and added two packet hooks
on the input/output path.
Change-Id: I3507f2b793155856b4dac8ad5937a9fc6d28551d
Signed-off-by: Zhi Chen <zhichen@codeaurora.org>
Signed-off-by: Murat Sezgin <msezgin@codeaurora.org>
---
include/linux/if_bridge.h | 6 ++++++
net/bridge/br_device.c | 5 +++++
net/bridge/br_input.c | 12 +++++++++++-
net/bridge/br_private.h | 5 +++++
4 files changed, 27 insertions(+), 1 deletion(-)
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -66,11 +66,13 @@ struct br_ip_list {
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
struct net_bridge;
+struct net_bridge_port;
void brioctl_set(int (*hook)(struct net *net, struct net_bridge *br,
unsigned int cmd, struct ifreq *ifr,
void __user *uarg));
int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd,
struct ifreq *ifr, void __user *uarg);
+
extern struct net_device *br_port_dev_get(struct net_device *dev,
unsigned char *addr,
struct sk_buff *skb);
@@ -230,4 +232,8 @@ extern br_port_dev_get_hook_t __rcu *br_
typedef void (br_notify_hook_t)(int group, int event, const void *ptr);
extern br_notify_hook_t __rcu *br_notify_hook;
+typedef int (br_multicast_handle_hook_t)(const struct net_bridge_port *src,
+ struct sk_buff *skb);
+extern br_multicast_handle_hook_t __rcu *br_multicast_handle_hook;
+
#endif
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -89,6 +89,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
if (is_broadcast_ether_addr(dest)) {
br_flood(br, skb, BR_PKT_BROADCAST, false, true, vid);
} else if (is_multicast_ether_addr(dest)) {
+ br_multicast_handle_hook_t *multicast_handle_hook =
+ rcu_dereference(br_multicast_handle_hook);
+ if (!__br_get(multicast_handle_hook, true, NULL, skb))
+ goto out;
+
if (unlikely(netpoll_tx_running(dev))) {
br_flood(br, skb, BR_PKT_MULTICAST, false, true, vid);
goto out;
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -30,7 +30,11 @@ br_netif_receive_skb(struct net *net, st
return netif_receive_skb(skb);
}
-static int br_pass_frame_up(struct sk_buff *skb, bool promisc)
+/* Hook for external Multicast handler */
+br_multicast_handle_hook_t __rcu *br_multicast_handle_hook __read_mostly;
+EXPORT_SYMBOL_GPL(br_multicast_handle_hook);
+
+int br_pass_frame_up(struct sk_buff *skb, bool promisc)
{
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
struct net_bridge *br = netdev_priv(brdev);
@@ -71,6 +75,7 @@ static int br_pass_frame_up(struct sk_bu
dev_net(indev), NULL, skb, indev, NULL,
br_netif_receive_skb);
}
+EXPORT_SYMBOL_GPL(br_pass_frame_up);
/* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
@@ -85,6 +90,7 @@ int br_handle_frame_finish(struct net *n
struct net_bridge_vlan *vlan;
struct net_bridge *br;
bool promisc;
+ br_multicast_handle_hook_t *multicast_handle_hook;
u16 vid = 0;
u8 state;
@@ -182,6 +188,10 @@ int br_handle_frame_finish(struct net *n
switch (pkt_type) {
case BR_PKT_MULTICAST:
+ multicast_handle_hook = rcu_dereference(br_multicast_handle_hook);
+ if (!__br_get(multicast_handle_hook, true, p, skb))
+ goto out;
+
mdst = br_mdb_get(brmctx, skb, vid);
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(brmctx, eth_hdr(skb), mdst)) {
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -908,6 +908,7 @@ void br_manage_promisc(struct net_bridge
int nbp_backup_change(struct net_bridge_port *p, struct net_device *backup_dev);
/* br_input.c */
+int br_pass_frame_up(struct sk_buff *skb, bool promisc);
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
rx_handler_func_t *br_get_rx_handler(const struct net_device *dev);
@@ -2282,4 +2283,8 @@ void br_do_suppress_nd(struct sk_buff *s
u16 vid, struct net_bridge_port *p, struct nd_msg *msg);
struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m);
bool br_is_neigh_suppress_enabled(const struct net_bridge_port *p, u16 vid);
+
+#define __br_get(__hook, __default, __args ...) \
+ (__hook ? (__hook(__args)) : (__default))
+
#endif