bridge: add new BR_NEIGH_SUPPRESS port flag to suppress arp and nd flood
authorRoopa Prabhu <roopa@cumulusnetworks.com>
Sat, 7 Oct 2017 05:12:37 +0000 (22:12 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 9 Oct 2017 04:12:04 +0000 (21:12 -0700)
This patch adds a new bridge port flag BR_NEIGH_SUPPRESS to
suppress arp and nd flood on bridge ports. It implements
rfc7432, section 10.
https://tools.ietf.org/html/rfc7432#section-10
for ethernet VPN deployments. It is similar to the existing
BR_PROXYARP* flags but has a few semantic differences to conform
to EVPN standard. Unlike the existing flags, this new flag suppresses
flood of all neigh discovery packets (arp and nd) to tunnel ports.
Supports both vlan filtering and non-vlan filtering bridges.

In case of EVPN, it is mainly used to avoid flooding
of arp and nd packets to tunnel ports like vxlan.

This patch adds netlink and sysfs support to set this bridge port
flag.

Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/if_bridge.h
include/uapi/linux/if_link.h
net/bridge/Makefile
net/bridge/br_arp_nd_proxy.c [new file with mode: 0644]
net/bridge/br_forward.c
net/bridge/br_if.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_sysfs_if.c

index 3cd18ac0697f8293e42fbabd699b50d96a9abd02..316ee113a2201e197de15fc42d16c893e107ec03 100644 (file)
@@ -49,6 +49,7 @@ struct br_ip_list {
 #define BR_MULTICAST_TO_UNICAST        BIT(12)
 #define BR_VLAN_TUNNEL         BIT(13)
 #define BR_BCAST_FLOOD         BIT(14)
+#define BR_NEIGH_SUPPRESS      BIT(15)
 
 #define BR_DEFAULT_AGEING_TIME (300 * HZ)
 
index cd580fc0e58ffb71b44920219a47724ec91f380e..b037e0ab19751ec95608846a50697d5e62b10c44 100644 (file)
@@ -327,6 +327,7 @@ enum {
        IFLA_BRPORT_VLAN_TUNNEL,
        IFLA_BRPORT_BCAST_FLOOD,
        IFLA_BRPORT_GROUP_FWD_MASK,
+       IFLA_BRPORT_NEIGH_SUPPRESS,
        __IFLA_BRPORT_MAX
 };
 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
index 40b1ede527caedde81bbfea79d807a1af912e29e..4aee55fdcc92fa0ace5bc84e0bb943586e4762bd 100644 (file)
@@ -7,7 +7,7 @@ obj-$(CONFIG_BRIDGE) += bridge.o
 bridge-y       := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
                        br_ioctl.o br_stp.o br_stp_bpdu.o \
                        br_stp_if.o br_stp_timer.o br_netlink.o \
-                       br_netlink_tunnel.o
+                       br_netlink_tunnel.o br_arp_nd_proxy.o
 
 bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
 
diff --git a/net/bridge/br_arp_nd_proxy.c b/net/bridge/br_arp_nd_proxy.c
new file mode 100644 (file)
index 0000000..f889ad5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  Handle bridge arp/nd proxy/suppress
+ *
+ *  Copyright (C) 2017 Cumulus Networks
+ *  Copyright (c) 2017 Roopa Prabhu <roopa@cumulusnetworks.com>
+ *
+ *  Authors:
+ *     Roopa Prabhu <roopa@cumulusnetworks.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include "br_private.h"
+
+void br_recalculate_neigh_suppress_enabled(struct net_bridge *br)
+{
+       struct net_bridge_port *p;
+       bool neigh_suppress = false;
+
+       list_for_each_entry(p, &br->port_list, list) {
+               if (p->flags & BR_NEIGH_SUPPRESS) {
+                       neigh_suppress = true;
+                       break;
+               }
+       }
+
+       br->neigh_suppress_enabled = neigh_suppress;
+}
index 48fb17417fac3397e74cb712388076ed1ee87865..b4eed113d2ec89181e1451244b3a42afeed0e2c8 100644 (file)
@@ -204,7 +204,7 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb,
                /* Do not flood to ports that enable proxy ARP */
                if (p->flags & BR_PROXYARP)
                        continue;
-               if ((p->flags & BR_PROXYARP_WIFI) &&
+               if ((p->flags & (BR_PROXYARP_WIFI | BR_NEIGH_SUPPRESS)) &&
                    BR_INPUT_SKB_CB(skb)->proxyarp_replied)
                        continue;
 
index 59a74a414e20403636d7d16629f13352da591b00..ae38547bbf9145fbddd69c948713d3ed4049e707 100644 (file)
@@ -310,6 +310,8 @@ void br_dev_delete(struct net_device *dev, struct list_head *head)
                del_nbp(p);
        }
 
+       br_recalculate_neigh_suppress_enabled(br);
+
        br_fdb_delete_by_port(br, NULL, 0, 1);
 
        cancel_delayed_work_sync(&br->gc_work);
@@ -660,4 +662,7 @@ void br_port_flags_change(struct net_bridge_port *p, unsigned long mask)
 
        if (mask & BR_AUTO_MASK)
                nbp_update_port_count(br);
+
+       if (mask & BR_NEIGH_SUPPRESS)
+               br_recalculate_neigh_suppress_enabled(br);
 }
index dea88a255d2639bc2601aefd5d51cd82147c5f90..f0e82682e0716af7fa8b3b01e49f527629d9b3d9 100644 (file)
@@ -138,6 +138,7 @@ static inline size_t br_port_info_size(void)
                + nla_total_size(1)     /* IFLA_BRPORT_PROXYARP */
                + nla_total_size(1)     /* IFLA_BRPORT_PROXYARP_WIFI */
                + nla_total_size(1)     /* IFLA_BRPORT_VLAN_TUNNEL */
+               + nla_total_size(1)     /* IFLA_BRPORT_NEIGH_SUPPRESS */
                + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */
                + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */
                + nla_total_size(sizeof(u16))   /* IFLA_BRPORT_DESIGNATED_PORT */
@@ -210,7 +211,9 @@ static int br_port_fill_attrs(struct sk_buff *skb,
            nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) ||
            nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags &
                                                        BR_VLAN_TUNNEL)) ||
-           nla_put_u16(skb, IFLA_BRPORT_GROUP_FWD_MASK, p->group_fwd_mask))
+           nla_put_u16(skb, IFLA_BRPORT_GROUP_FWD_MASK, p->group_fwd_mask) ||
+           nla_put_u8(skb, IFLA_BRPORT_NEIGH_SUPPRESS,
+                      !!(p->flags & BR_NEIGH_SUPPRESS)))
                return -EMSGSIZE;
 
        timerval = br_timer_value(&p->message_age_timer);
@@ -785,6 +788,11 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
                p->group_fwd_mask = fwd_mask;
        }
 
+       err = br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS,
+                              BR_NEIGH_SUPPRESS);
+       if (err)
+               return err;
+
        br_port_flags_change(p, old_flags ^ p->flags);
        return 0;
 }
index ab4df24f7bba52b78a5ee3f945366ad5e37652d4..00fa371b1fb2d1f61868ba2fe882790161908449 100644 (file)
@@ -404,6 +404,7 @@ struct net_bridge {
 #ifdef CONFIG_NET_SWITCHDEV
        int offload_fwd_mark;
 #endif
+       bool                            neigh_suppress_enabled;
 };
 
 struct br_input_skb_cb {
@@ -1139,4 +1140,5 @@ static inline void br_switchdev_frame_unmark(struct sk_buff *skb)
 }
 #endif /* CONFIG_NET_SWITCHDEV */
 
+void br_recalculate_neigh_suppress_enabled(struct net_bridge *br);
 #endif
index 9110d5e56085c27a5b023b5a22fd06ab6e6f20a4..0a1fa9ccd8b78a314de2fcc9ff0cbcc4f4d54fe0 100644 (file)
@@ -191,6 +191,7 @@ BRPORT_ATTR_FLAG(proxyarp, BR_PROXYARP);
 BRPORT_ATTR_FLAG(proxyarp_wifi, BR_PROXYARP_WIFI);
 BRPORT_ATTR_FLAG(multicast_flood, BR_MCAST_FLOOD);
 BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD);
+BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
@@ -241,6 +242,7 @@ static const struct brport_attribute *brport_attrs[] = {
        &brport_attr_multicast_flood,
        &brport_attr_broadcast_flood,
        &brport_attr_group_fwd_mask,
+       &brport_attr_neigh_suppress,
        NULL
 };