bridge: vlan: Allow setting VLAN neighbor suppression state
authorIdo Schimmel <idosch@nvidia.com>
Wed, 19 Apr 2023 15:34:58 +0000 (18:34 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 21 Apr 2023 07:25:50 +0000 (08:25 +0100)
Add a new VLAN attribute that allows user space to set the neighbor
suppression state of the port VLAN. Example:

 # bridge -d -j -p vlan show dev swp1 vid 10 | jq '.[]["vlans"][]["neigh_suppress"]'
 false
 # bridge vlan set vid 10 dev swp1 neigh_suppress on
 # bridge -d -j -p vlan show dev swp1 vid 10 | jq '.[]["vlans"][]["neigh_suppress"]'
 true
 # bridge vlan set vid 10 dev swp1 neigh_suppress off
 # bridge -d -j -p vlan show dev swp1 vid 10 | jq '.[]["vlans"][]["neigh_suppress"]'
 false

 # bridge vlan set vid 10 dev br0 neigh_suppress on
 Error: bridge: Can't set neigh_suppress for non-port vlans.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/if_bridge.h
net/bridge/br_vlan.c
net/bridge/br_vlan_options.c

index c9d624f528c598a292b2a66e25167bdd7b473c2f..f95326fce6bbaa867d98d02bf82b1393964a85bf 100644 (file)
@@ -525,6 +525,7 @@ enum {
        BRIDGE_VLANDB_ENTRY_MCAST_ROUTER,
        BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS,
        BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS,
+       BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS,
        __BRIDGE_VLANDB_ENTRY_MAX,
 };
 #define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)
index 8a3dbc09ba388a65a933299ae1a883685dafb9a0..15f44d026e75a8818f958703c5ec054eaafc4d94 100644 (file)
@@ -2134,6 +2134,7 @@ static const struct nla_policy br_vlan_db_policy[BRIDGE_VLANDB_ENTRY_MAX + 1] =
        [BRIDGE_VLANDB_ENTRY_MCAST_ROUTER]      = { .type = NLA_U8 },
        [BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS]    = { .type = NLA_REJECT },
        [BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS]  = { .type = NLA_U32 },
+       [BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS]    = NLA_POLICY_MAX(NLA_U8, 1),
 };
 
 static int br_vlan_rtm_process_one(struct net_device *dev,
index e378c2f3a9e2c0b4e37ab31c7b8e650875f43ebc..8fa89b04ee942d3ad3a4de37377a60f9fb47eb77 100644 (file)
@@ -52,7 +52,9 @@ bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v,
                       const struct net_bridge_port *p)
 {
        if (nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_STATE, br_vlan_get_state(v)) ||
-           !__vlan_tun_put(skb, v))
+           !__vlan_tun_put(skb, v) ||
+           nla_put_u8(skb, BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS,
+                      !!(v->priv_flags & BR_VLFLAG_NEIGH_SUPPRESS_ENABLED)))
                return false;
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
@@ -80,6 +82,7 @@ size_t br_vlan_opts_nl_size(void)
               + nla_total_size(sizeof(u32)) /* BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS */
               + nla_total_size(sizeof(u32)) /* BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS */
 #endif
+              + nla_total_size(sizeof(u8)) /* BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS */
               + 0;
 }
 
@@ -239,6 +242,21 @@ static int br_vlan_process_one_opts(const struct net_bridge *br,
        }
 #endif
 
+       if (tb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS]) {
+               bool enabled = v->priv_flags & BR_VLFLAG_NEIGH_SUPPRESS_ENABLED;
+               bool val = nla_get_u8(tb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS]);
+
+               if (!p) {
+                       NL_SET_ERR_MSG_MOD(extack, "Can't set neigh_suppress for non-port vlans");
+                       return -EINVAL;
+               }
+
+               if (val != enabled) {
+                       v->priv_flags ^= BR_VLFLAG_NEIGH_SUPPRESS_ENABLED;
+                       *changed = true;
+               }
+       }
+
        return 0;
 }