diff options
Diffstat (limited to 'target/linux/generic/backport-4.9/021-bridge-multicast-to-unicast.patch')
-rw-r--r-- | target/linux/generic/backport-4.9/021-bridge-multicast-to-unicast.patch | 499 |
1 files changed, 0 insertions, 499 deletions
diff --git a/target/linux/generic/backport-4.9/021-bridge-multicast-to-unicast.patch b/target/linux/generic/backport-4.9/021-bridge-multicast-to-unicast.patch deleted file mode 100644 index 42daacf50d..0000000000 --- a/target/linux/generic/backport-4.9/021-bridge-multicast-to-unicast.patch +++ /dev/null @@ -1,499 +0,0 @@ -From: Felix Fietkau <nbd@nbd.name> -Date: Thu, 19 Jan 2017 03:45:10 +0100 -Subject: [PATCH] bridge: multicast to unicast -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Implements an optional, per bridge port flag and feature to deliver -multicast packets to any host on the according port via unicast -individually. This is done by copying the packet per host and -changing the multicast destination MAC to a unicast one accordingly. - -multicast-to-unicast works on top of the multicast snooping feature of -the bridge. Which means unicast copies are only delivered to hosts which -are interested in it and signalized this via IGMP/MLD reports -previously. - -This feature is intended for interface types which have a more reliable -and/or efficient way to deliver unicast packets than broadcast ones -(e.g. wifi). - -However, it should only be enabled on interfaces where no IGMPv2/MLDv1 -report suppression takes place. This feature is disabled by default. - -The initial patch and idea is from Felix Fietkau. - -Signed-off-by: Felix Fietkau <nbd@nbd.name> -[linus.luessing@c0d3.blue: various bug + style fixes, commit message] -Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue> ---- - ---- a/include/linux/if_bridge.h -+++ b/include/linux/if_bridge.h -@@ -46,6 +46,7 @@ struct br_ip_list { - #define BR_LEARNING_SYNC BIT(9) - #define BR_PROXYARP_WIFI BIT(10) - #define BR_MCAST_FLOOD BIT(11) -+#define BR_MULTICAST_TO_UNICAST BIT(12) - - #define BR_DEFAULT_AGEING_TIME (300 * HZ) - ---- a/include/uapi/linux/if_link.h -+++ b/include/uapi/linux/if_link.h -@@ -319,6 +319,7 @@ enum { - IFLA_BRPORT_MULTICAST_ROUTER, - IFLA_BRPORT_PAD, - IFLA_BRPORT_MCAST_FLOOD, -+ IFLA_BRPORT_MCAST_TO_UCAST, - __IFLA_BRPORT_MAX - }; - #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) ---- a/net/bridge/br_forward.c -+++ b/net/bridge/br_forward.c -@@ -173,6 +173,29 @@ out: - return p; - } - -+static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb, -+ const unsigned char *addr, bool local_orig) -+{ -+ struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; -+ const unsigned char *src = eth_hdr(skb)->h_source; -+ -+ if (!should_deliver(p, skb)) -+ return; -+ -+ /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */ -+ if (skb->dev == p->dev && ether_addr_equal(src, addr)) -+ return; -+ -+ skb = skb_copy(skb, GFP_ATOMIC); -+ if (!skb) { -+ dev->stats.tx_dropped++; -+ return; -+ } -+ -+ memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN); -+ __br_forward(p, skb, local_orig); -+} -+ - /* called under rcu_read_lock */ - void br_flood(struct net_bridge *br, struct sk_buff *skb, - enum br_pkt_type pkt_type, bool local_rcv, bool local_orig) -@@ -241,10 +264,20 @@ void br_multicast_flood(struct net_bridg - rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) : - NULL; - -- port = (unsigned long)lport > (unsigned long)rport ? -- lport : rport; -+ if ((unsigned long)lport > (unsigned long)rport) { -+ port = lport; -+ -+ if (p->flags & MDB_PG_FLAGS_MCAST_TO_UCAST) { -+ maybe_deliver_addr(lport, skb, p->eth_addr, -+ local_orig); -+ goto delivered; -+ } -+ } else { -+ port = rport; -+ } - - prev = maybe_deliver(prev, port, skb, local_orig); -+delivered: - if (IS_ERR(prev)) - goto out; - if (prev == port) ---- a/net/bridge/br_mdb.c -+++ b/net/bridge/br_mdb.c -@@ -532,7 +532,7 @@ static int br_mdb_add_group(struct net_b - break; - } - -- p = br_multicast_new_port_group(port, group, *pp, state); -+ p = br_multicast_new_port_group(port, group, *pp, state, NULL); - if (unlikely(!p)) - return -ENOMEM; - rcu_assign_pointer(*pp, p); ---- a/net/bridge/br_multicast.c -+++ b/net/bridge/br_multicast.c -@@ -42,12 +42,14 @@ static void br_multicast_add_router(stru - static void br_ip4_multicast_leave_group(struct net_bridge *br, - struct net_bridge_port *port, - __be32 group, -- __u16 vid); -+ __u16 vid, -+ const unsigned char *src); -+ - #if IS_ENABLED(CONFIG_IPV6) - static void br_ip6_multicast_leave_group(struct net_bridge *br, - struct net_bridge_port *port, - const struct in6_addr *group, -- __u16 vid); -+ __u16 vid, const unsigned char *src); - #endif - unsigned int br_mdb_rehash_seq; - -@@ -658,7 +660,8 @@ struct net_bridge_port_group *br_multica - struct net_bridge_port *port, - struct br_ip *group, - struct net_bridge_port_group __rcu *next, -- unsigned char flags) -+ unsigned char flags, -+ const unsigned char *src) - { - struct net_bridge_port_group *p; - -@@ -673,12 +676,39 @@ struct net_bridge_port_group *br_multica - hlist_add_head(&p->mglist, &port->mglist); - setup_timer(&p->timer, br_multicast_port_group_expired, - (unsigned long)p); -+ -+ if ((port->flags & BR_MULTICAST_TO_UNICAST) && src) { -+ memcpy(p->eth_addr, src, ETH_ALEN); -+ p->flags |= MDB_PG_FLAGS_MCAST_TO_UCAST; -+ } -+ - return p; - } - -+static bool br_port_group_equal(struct net_bridge_port_group *p, -+ struct net_bridge_port *port, -+ const unsigned char *src) -+{ -+ if (p->port != port) -+ return false; -+ -+ if (!(p->flags & MDB_PG_FLAGS_MCAST_TO_UCAST) != -+ !(port->flags & BR_MULTICAST_TO_UNICAST)) -+ return false; -+ -+ if (!(p->flags & MDB_PG_FLAGS_MCAST_TO_UCAST)) -+ return true; -+ -+ if (!src) -+ return false; -+ -+ return ether_addr_equal(src, p->eth_addr); -+} -+ - static int br_multicast_add_group(struct net_bridge *br, - struct net_bridge_port *port, -- struct br_ip *group) -+ struct br_ip *group, -+ const unsigned char *src) - { - struct net_bridge_mdb_entry *mp; - struct net_bridge_port_group *p; -@@ -705,13 +735,13 @@ static int br_multicast_add_group(struct - for (pp = &mp->ports; - (p = mlock_dereference(*pp, br)) != NULL; - pp = &p->next) { -- if (p->port == port) -+ if (br_port_group_equal(p, port, src)) - goto found; - if ((unsigned long)p->port < (unsigned long)port) - break; - } - -- p = br_multicast_new_port_group(port, group, *pp, 0); -+ p = br_multicast_new_port_group(port, group, *pp, 0, src); - if (unlikely(!p)) - goto err; - rcu_assign_pointer(*pp, p); -@@ -730,7 +760,8 @@ err: - static int br_ip4_multicast_add_group(struct net_bridge *br, - struct net_bridge_port *port, - __be32 group, -- __u16 vid) -+ __u16 vid, -+ const unsigned char *src) - { - struct br_ip br_group; - -@@ -741,14 +772,15 @@ static int br_ip4_multicast_add_group(st - br_group.proto = htons(ETH_P_IP); - br_group.vid = vid; - -- return br_multicast_add_group(br, port, &br_group); -+ return br_multicast_add_group(br, port, &br_group, src); - } - - #if IS_ENABLED(CONFIG_IPV6) - static int br_ip6_multicast_add_group(struct net_bridge *br, - struct net_bridge_port *port, - const struct in6_addr *group, -- __u16 vid) -+ __u16 vid, -+ const unsigned char *src) - { - struct br_ip br_group; - -@@ -759,7 +791,7 @@ static int br_ip6_multicast_add_group(st - br_group.proto = htons(ETH_P_IPV6); - br_group.vid = vid; - -- return br_multicast_add_group(br, port, &br_group); -+ return br_multicast_add_group(br, port, &br_group, src); - } - #endif - -@@ -1028,6 +1060,7 @@ static int br_ip4_multicast_igmp3_report - struct sk_buff *skb, - u16 vid) - { -+ const unsigned char *src; - struct igmpv3_report *ih; - struct igmpv3_grec *grec; - int i; -@@ -1070,12 +1103,14 @@ static int br_ip4_multicast_igmp3_report - continue; - } - -+ src = eth_hdr(skb)->h_source; - if ((type == IGMPV3_CHANGE_TO_INCLUDE || - type == IGMPV3_MODE_IS_INCLUDE) && - nsrcs == 0) { -- br_ip4_multicast_leave_group(br, port, group, vid); -+ br_ip4_multicast_leave_group(br, port, group, vid, src); - } else { -- err = br_ip4_multicast_add_group(br, port, group, vid); -+ err = br_ip4_multicast_add_group(br, port, group, vid, -+ src); - if (err) - break; - } -@@ -1090,6 +1125,7 @@ static int br_ip6_multicast_mld2_report( - struct sk_buff *skb, - u16 vid) - { -+ const unsigned char *src = eth_hdr(skb)->h_source; - struct icmp6hdr *icmp6h; - struct mld2_grec *grec; - int i; -@@ -1144,10 +1180,11 @@ static int br_ip6_multicast_mld2_report( - grec->grec_type == MLD2_MODE_IS_INCLUDE) && - nsrcs == 0) { - br_ip6_multicast_leave_group(br, port, &grec->grec_mca, -- vid); -+ vid, src); - } else { - err = br_ip6_multicast_add_group(br, port, -- &grec->grec_mca, vid); -+ &grec->grec_mca, vid, -+ src); - if (err) - break; - } -@@ -1462,7 +1499,8 @@ br_multicast_leave_group(struct net_brid - struct net_bridge_port *port, - struct br_ip *group, - struct bridge_mcast_other_query *other_query, -- struct bridge_mcast_own_query *own_query) -+ struct bridge_mcast_own_query *own_query, -+ const unsigned char *src) - { - struct net_bridge_mdb_htable *mdb; - struct net_bridge_mdb_entry *mp; -@@ -1486,7 +1524,7 @@ br_multicast_leave_group(struct net_brid - for (pp = &mp->ports; - (p = mlock_dereference(*pp, br)) != NULL; - pp = &p->next) { -- if (p->port != port) -+ if (!br_port_group_equal(p, port, src)) - continue; - - if (p->flags & MDB_PG_FLAGS_PERMANENT) -@@ -1520,7 +1558,7 @@ br_multicast_leave_group(struct net_brid - for (p = mlock_dereference(mp->ports, br); - p != NULL; - p = mlock_dereference(p->next, br)) { -- if (p->port != port) -+ if (!br_port_group_equal(p, port, src)) - continue; - - if (!hlist_unhashed(&p->mglist) && -@@ -1571,7 +1609,8 @@ out: - static void br_ip4_multicast_leave_group(struct net_bridge *br, - struct net_bridge_port *port, - __be32 group, -- __u16 vid) -+ __u16 vid, -+ const unsigned char *src) - { - struct br_ip br_group; - struct bridge_mcast_own_query *own_query; -@@ -1586,14 +1625,15 @@ static void br_ip4_multicast_leave_group - br_group.vid = vid; - - br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query, -- own_query); -+ own_query, src); - } - - #if IS_ENABLED(CONFIG_IPV6) - static void br_ip6_multicast_leave_group(struct net_bridge *br, - struct net_bridge_port *port, - const struct in6_addr *group, -- __u16 vid) -+ __u16 vid, -+ const unsigned char *src) - { - struct br_ip br_group; - struct bridge_mcast_own_query *own_query; -@@ -1608,7 +1648,7 @@ static void br_ip6_multicast_leave_group - br_group.vid = vid; - - br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query, -- own_query); -+ own_query, src); - } - #endif - -@@ -1651,6 +1691,7 @@ static int br_multicast_ipv4_rcv(struct - u16 vid) - { - struct sk_buff *skb_trimmed = NULL; -+ const unsigned char *src; - struct igmphdr *ih; - int err; - -@@ -1666,13 +1707,14 @@ static int br_multicast_ipv4_rcv(struct - } - - ih = igmp_hdr(skb); -+ src = eth_hdr(skb)->h_source; - BR_INPUT_SKB_CB(skb)->igmp = ih->type; - - switch (ih->type) { - case IGMP_HOST_MEMBERSHIP_REPORT: - case IGMPV2_HOST_MEMBERSHIP_REPORT: - BR_INPUT_SKB_CB(skb)->mrouters_only = 1; -- err = br_ip4_multicast_add_group(br, port, ih->group, vid); -+ err = br_ip4_multicast_add_group(br, port, ih->group, vid, src); - break; - case IGMPV3_HOST_MEMBERSHIP_REPORT: - err = br_ip4_multicast_igmp3_report(br, port, skb_trimmed, vid); -@@ -1681,7 +1723,7 @@ static int br_multicast_ipv4_rcv(struct - err = br_ip4_multicast_query(br, port, skb_trimmed, vid); - break; - case IGMP_HOST_LEAVE_MESSAGE: -- br_ip4_multicast_leave_group(br, port, ih->group, vid); -+ br_ip4_multicast_leave_group(br, port, ih->group, vid, src); - break; - } - -@@ -1701,6 +1743,7 @@ static int br_multicast_ipv6_rcv(struct - u16 vid) - { - struct sk_buff *skb_trimmed = NULL; -+ const unsigned char *src; - struct mld_msg *mld; - int err; - -@@ -1720,8 +1763,10 @@ static int br_multicast_ipv6_rcv(struct - - switch (mld->mld_type) { - case ICMPV6_MGM_REPORT: -+ src = eth_hdr(skb)->h_source; - BR_INPUT_SKB_CB(skb)->mrouters_only = 1; -- err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid); -+ err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid, -+ src); - break; - case ICMPV6_MLD2_REPORT: - err = br_ip6_multicast_mld2_report(br, port, skb_trimmed, vid); -@@ -1730,7 +1775,8 @@ static int br_multicast_ipv6_rcv(struct - err = br_ip6_multicast_query(br, port, skb_trimmed, vid); - break; - case ICMPV6_MGM_REDUCTION: -- br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid); -+ src = eth_hdr(skb)->h_source; -+ br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src); - break; - } - ---- a/net/bridge/br_netlink.c -+++ b/net/bridge/br_netlink.c -@@ -123,6 +123,7 @@ static inline size_t br_port_info_size(v - + nla_total_size(1) /* IFLA_BRPORT_GUARD */ - + nla_total_size(1) /* IFLA_BRPORT_PROTECT */ - + nla_total_size(1) /* IFLA_BRPORT_FAST_LEAVE */ -+ + nla_total_size(1) /* IFLA_BRPORT_MCAST_TO_UCAST */ - + nla_total_size(1) /* IFLA_BRPORT_LEARNING */ - + nla_total_size(1) /* IFLA_BRPORT_UNICAST_FLOOD */ - + nla_total_size(1) /* IFLA_BRPORT_PROXYARP */ -@@ -173,6 +174,8 @@ static int br_port_fill_attrs(struct sk_ - !!(p->flags & BR_ROOT_BLOCK)) || - nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, - !!(p->flags & BR_MULTICAST_FAST_LEAVE)) || -+ nla_put_u8(skb, IFLA_BRPORT_MCAST_TO_UCAST, -+ !!(p->flags & BR_MULTICAST_TO_UNICAST)) || - nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) || - nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, - !!(p->flags & BR_FLOOD)) || -@@ -586,6 +589,7 @@ static const struct nla_policy br_port_p - [IFLA_BRPORT_PROXYARP] = { .type = NLA_U8 }, - [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 }, - [IFLA_BRPORT_MULTICAST_ROUTER] = { .type = NLA_U8 }, -+ [IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 }, - }; - - /* Change the state of the port and notify spanning tree */ -@@ -636,6 +640,7 @@ static int br_setport(struct net_bridge_ - br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); - br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); - br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD); -+ br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST, BR_MULTICAST_TO_UNICAST); - br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP); - br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI); - ---- a/net/bridge/br_private.h -+++ b/net/bridge/br_private.h -@@ -166,8 +166,9 @@ struct net_bridge_fdb_entry - struct rcu_head rcu; - }; - --#define MDB_PG_FLAGS_PERMANENT BIT(0) --#define MDB_PG_FLAGS_OFFLOAD BIT(1) -+#define MDB_PG_FLAGS_PERMANENT BIT(0) -+#define MDB_PG_FLAGS_OFFLOAD BIT(1) -+#define MDB_PG_FLAGS_MCAST_TO_UCAST BIT(2) - - struct net_bridge_port_group { - struct net_bridge_port *port; -@@ -177,6 +178,7 @@ struct net_bridge_port_group { - struct timer_list timer; - struct br_ip addr; - unsigned char flags; -+ unsigned char eth_addr[ETH_ALEN]; - }; - - struct net_bridge_mdb_entry -@@ -591,7 +593,7 @@ void br_multicast_free_pg(struct rcu_hea - struct net_bridge_port_group * - br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group, - struct net_bridge_port_group __rcu *next, -- unsigned char flags); -+ unsigned char flags, const unsigned char *src); - void br_mdb_init(void); - void br_mdb_uninit(void); - void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, ---- a/net/bridge/br_sysfs_if.c -+++ b/net/bridge/br_sysfs_if.c -@@ -188,6 +188,7 @@ static BRPORT_ATTR(multicast_router, S_I - store_multicast_router); - - BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE); -+BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST); - #endif - - static const struct brport_attribute *brport_attrs[] = { -@@ -214,6 +215,7 @@ static const struct brport_attribute *br - #ifdef CONFIG_BRIDGE_IGMP_SNOOPING - &brport_attr_multicast_router, - &brport_attr_multicast_fast_leave, -+ &brport_attr_multicast_to_unicast, - #endif - &brport_attr_proxyarp, - &brport_attr_proxyarp_wifi, |