Commit 278ed676 authored by David S. Miller's avatar David S. Miller

Merge branch 'br-next'

Nikolay Aleksandrov says:

====================
net: bridge: add per-port unknown multicast flood control

The first patch prepares the forwarding path by having the exact packet
type passed down so we can later filter based on it and the per-port
unknown mcast flood flag introduced in the second patch. It is similar to
how the per-port unknown unicast flood flag works.
Nice side-effects of patch 01 are the slight reduction of tests in the
fast-path and a few minor checkpatch fixes.

v3: don't change br_auto_mask as that will change user-visible behaviour
v2: make pkt_type an enum as per Stephen's comment
====================
Acked-by: default avatarStephen Hemminger <stephen@networkplumber.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d297653d b6cb5ac8
...@@ -45,6 +45,7 @@ struct br_ip_list { ...@@ -45,6 +45,7 @@ struct br_ip_list {
#define BR_PROXYARP BIT(8) #define BR_PROXYARP BIT(8)
#define BR_LEARNING_SYNC BIT(9) #define BR_LEARNING_SYNC BIT(9)
#define BR_PROXYARP_WIFI BIT(10) #define BR_PROXYARP_WIFI BIT(10)
#define BR_MCAST_FLOOD BIT(11)
#define BR_DEFAULT_AGEING_TIME (300 * HZ) #define BR_DEFAULT_AGEING_TIME (300 * HZ)
......
...@@ -318,6 +318,7 @@ enum { ...@@ -318,6 +318,7 @@ enum {
IFLA_BRPORT_FLUSH, IFLA_BRPORT_FLUSH,
IFLA_BRPORT_MULTICAST_ROUTER, IFLA_BRPORT_MULTICAST_ROUTER,
IFLA_BRPORT_PAD, IFLA_BRPORT_PAD,
IFLA_BRPORT_MCAST_FLOOD,
__IFLA_BRPORT_MAX __IFLA_BRPORT_MAX
}; };
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
......
...@@ -62,10 +62,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -62,10 +62,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
goto out; goto out;
if (is_broadcast_ether_addr(dest)) { if (is_broadcast_ether_addr(dest)) {
br_flood(br, skb, false, false, true); br_flood(br, skb, BR_PKT_BROADCAST, false, true);
} else if (is_multicast_ether_addr(dest)) { } else if (is_multicast_ether_addr(dest)) {
if (unlikely(netpoll_tx_running(dev))) { if (unlikely(netpoll_tx_running(dev))) {
br_flood(br, skb, false, false, true); br_flood(br, skb, BR_PKT_MULTICAST, false, true);
goto out; goto out;
} }
if (br_multicast_rcv(br, NULL, skb, vid)) { if (br_multicast_rcv(br, NULL, skb, vid)) {
...@@ -78,11 +78,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -78,11 +78,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
br_multicast_querier_exists(br, eth_hdr(skb))) br_multicast_querier_exists(br, eth_hdr(skb)))
br_multicast_flood(mdst, skb, false, true); br_multicast_flood(mdst, skb, false, true);
else else
br_flood(br, skb, false, false, true); br_flood(br, skb, BR_PKT_MULTICAST, false, true);
} else if ((dst = __br_fdb_get(br, dest, vid)) != NULL) { } else if ((dst = __br_fdb_get(br, dest, vid)) != NULL) {
br_forward(dst->dst, skb, false, true); br_forward(dst->dst, skb, false, true);
} else { } else {
br_flood(br, skb, true, false, true); br_flood(br, skb, BR_PKT_UNICAST, false, true);
} }
out: out:
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -176,7 +176,7 @@ static struct net_bridge_port *maybe_deliver( ...@@ -176,7 +176,7 @@ static struct net_bridge_port *maybe_deliver(
/* called under rcu_read_lock */ /* called under rcu_read_lock */
void br_flood(struct net_bridge *br, struct sk_buff *skb, void br_flood(struct net_bridge *br, struct sk_buff *skb,
bool unicast, bool local_rcv, bool local_orig) enum br_pkt_type pkt_type, bool local_rcv, bool local_orig)
{ {
u8 igmp_type = br_multicast_igmp_type(skb); u8 igmp_type = br_multicast_igmp_type(skb);
struct net_bridge_port *prev = NULL; struct net_bridge_port *prev = NULL;
...@@ -184,7 +184,10 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb, ...@@ -184,7 +184,10 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb,
list_for_each_entry_rcu(p, &br->port_list, list) { list_for_each_entry_rcu(p, &br->port_list, list) {
/* Do not flood unicast traffic to ports that turn it off */ /* Do not flood unicast traffic to ports that turn it off */
if (unicast && !(p->flags & BR_FLOOD)) if (pkt_type == BR_PKT_UNICAST && !(p->flags & BR_FLOOD))
continue;
if (pkt_type == BR_PKT_MULTICAST &&
!(p->flags & BR_MCAST_FLOOD))
continue; continue;
/* Do not flood to ports that enable proxy ARP */ /* Do not flood to ports that enable proxy ARP */
......
...@@ -362,7 +362,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, ...@@ -362,7 +362,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
p->path_cost = port_cost(dev); p->path_cost = port_cost(dev);
p->priority = 0x8000 >> BR_PORT_BITS; p->priority = 0x8000 >> BR_PORT_BITS;
p->port_no = index; p->port_no = index;
p->flags = BR_LEARNING | BR_FLOOD; p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD;
br_init_port(p); br_init_port(p);
br_set_state(p, BR_STATE_DISABLED); br_set_state(p, BR_STATE_DISABLED);
br_stp_port_timer_init(p); br_stp_port_timer_init(p);
......
...@@ -131,11 +131,12 @@ static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br, ...@@ -131,11 +131,12 @@ static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
/* note: already called with rcu_read_lock */ /* note: already called with rcu_read_lock */
int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb) int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{ {
bool local_rcv = false, mcast_hit = false, unicast = true;
struct net_bridge_port *p = br_port_get_rcu(skb->dev); struct net_bridge_port *p = br_port_get_rcu(skb->dev);
const unsigned char *dest = eth_hdr(skb)->h_dest; const unsigned char *dest = eth_hdr(skb)->h_dest;
enum br_pkt_type pkt_type = BR_PKT_UNICAST;
struct net_bridge_fdb_entry *dst = NULL; struct net_bridge_fdb_entry *dst = NULL;
struct net_bridge_mdb_entry *mdst; struct net_bridge_mdb_entry *mdst;
bool local_rcv, mcast_hit = false;
struct net_bridge *br; struct net_bridge *br;
u16 vid = 0; u16 vid = 0;
...@@ -152,24 +153,29 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb ...@@ -152,24 +153,29 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
if (p->flags & BR_LEARNING) if (p->flags & BR_LEARNING)
br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false); br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);
if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) && local_rcv = !!(br->dev->flags & IFF_PROMISC);
br_multicast_rcv(br, p, skb, vid)) if (is_multicast_ether_addr(dest)) {
goto drop; /* by definition the broadcast is also a multicast address */
if (is_broadcast_ether_addr(dest)) {
pkt_type = BR_PKT_BROADCAST;
local_rcv = true;
} else {
pkt_type = BR_PKT_MULTICAST;
if (br_multicast_rcv(br, p, skb, vid))
goto drop;
}
}
if (p->state == BR_STATE_LEARNING) if (p->state == BR_STATE_LEARNING)
goto drop; goto drop;
BR_INPUT_SKB_CB(skb)->brdev = br->dev; BR_INPUT_SKB_CB(skb)->brdev = br->dev;
local_rcv = !!(br->dev->flags & IFF_PROMISC);
if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP)) if (IS_ENABLED(CONFIG_INET) && skb->protocol == htons(ETH_P_ARP))
br_do_proxy_arp(skb, br, vid, p); br_do_proxy_arp(skb, br, vid, p);
if (is_broadcast_ether_addr(dest)) { switch (pkt_type) {
local_rcv = true; case BR_PKT_MULTICAST:
unicast = false;
} else if (is_multicast_ether_addr(dest)) {
mdst = br_mdb_get(br, skb, vid); mdst = br_mdb_get(br, skb, vid);
if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
br_multicast_querier_exists(br, eth_hdr(skb))) { br_multicast_querier_exists(br, eth_hdr(skb))) {
...@@ -183,18 +189,22 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb ...@@ -183,18 +189,22 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
local_rcv = true; local_rcv = true;
br->dev->stats.multicast++; br->dev->stats.multicast++;
} }
unicast = false; break;
} else if ((dst = __br_fdb_get(br, dest, vid)) && dst->is_local) { case BR_PKT_UNICAST:
/* Do not forward the packet since it's local. */ dst = __br_fdb_get(br, dest, vid);
return br_pass_frame_up(skb); default:
break;
} }
if (dst) { if (dst) {
if (dst->is_local)
return br_pass_frame_up(skb);
dst->used = jiffies; dst->used = jiffies;
br_forward(dst->dst, skb, local_rcv, false); br_forward(dst->dst, skb, local_rcv, false);
} else { } else {
if (!mcast_hit) if (!mcast_hit)
br_flood(br, skb, unicast, local_rcv, false); br_flood(br, skb, pkt_type, local_rcv, false);
else else
br_multicast_flood(mdst, skb, local_rcv, false); br_multicast_flood(mdst, skb, local_rcv, false);
} }
......
...@@ -169,10 +169,15 @@ static int br_port_fill_attrs(struct sk_buff *skb, ...@@ -169,10 +169,15 @@ static int br_port_fill_attrs(struct sk_buff *skb,
nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) || nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) ||
nla_put_u8(skb, IFLA_BRPORT_MODE, mode) || nla_put_u8(skb, IFLA_BRPORT_MODE, mode) ||
nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) || nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) ||
nla_put_u8(skb, IFLA_BRPORT_PROTECT, !!(p->flags & BR_ROOT_BLOCK)) || nla_put_u8(skb, IFLA_BRPORT_PROTECT,
nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, !!(p->flags & BR_MULTICAST_FAST_LEAVE)) || !!(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_LEARNING, !!(p->flags & BR_LEARNING)) || nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, !!(p->flags & BR_FLOOD)) || nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD,
!!(p->flags & BR_FLOOD)) ||
nla_put_u8(skb, IFLA_BRPORT_MCAST_FLOOD,
!!(p->flags & BR_MCAST_FLOOD)) ||
nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)) || nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)) ||
nla_put_u8(skb, IFLA_BRPORT_PROXYARP_WIFI, nla_put_u8(skb, IFLA_BRPORT_PROXYARP_WIFI,
!!(p->flags & BR_PROXYARP_WIFI)) || !!(p->flags & BR_PROXYARP_WIFI)) ||
...@@ -630,6 +635,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) ...@@ -630,6 +635,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK); br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK);
br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); 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_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_PROXYARP, BR_PROXYARP); br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI); br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
......
...@@ -517,12 +517,17 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, ...@@ -517,12 +517,17 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p,
const unsigned char *addr, u16 vid); const unsigned char *addr, u16 vid);
/* br_forward.c */ /* br_forward.c */
enum br_pkt_type {
BR_PKT_UNICAST,
BR_PKT_MULTICAST,
BR_PKT_BROADCAST
};
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb); int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb);
void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, void br_forward(const struct net_bridge_port *to, struct sk_buff *skb,
bool local_rcv, bool local_orig); bool local_rcv, bool local_orig);
int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb); int br_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb);
void br_flood(struct net_bridge *br, struct sk_buff *skb, void br_flood(struct net_bridge *br, struct sk_buff *skb,
bool unicast, bool local_rcv, bool local_orig); enum br_pkt_type pkt_type, bool local_rcv, bool local_orig);
/* br_if.c */ /* br_if.c */
void br_port_carrier_check(struct net_bridge_port *p); void br_port_carrier_check(struct net_bridge_port *p);
......
...@@ -171,6 +171,7 @@ BRPORT_ATTR_FLAG(learning, BR_LEARNING); ...@@ -171,6 +171,7 @@ BRPORT_ATTR_FLAG(learning, BR_LEARNING);
BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD); BRPORT_ATTR_FLAG(unicast_flood, BR_FLOOD);
BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP); BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI); BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI);
BRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD);
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment