bridge: Add a default_pvid sysfs attribute
authorVlad Yasevich <vyasevich@gmail.com>
Fri, 3 Oct 2014 15:29:16 +0000 (11:29 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 6 Oct 2014 01:21:36 +0000 (21:21 -0400)
This patch allows the user to set and retrieve default_pvid
value.  A new value can only be stored when vlan filtering
is disabled.

Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/br_private.h
net/bridge/br_sysfs_br.c
net/bridge/br_vlan.c

index fe7463c2af9a32bd65d12278bd3be16961828f5e..5a347eb1d139348c007dc9c5b15e480ca4c254cc 100644 (file)
@@ -299,6 +299,7 @@ struct net_bridge
 #ifdef CONFIG_BRIDGE_VLAN_FILTERING
        u8                              vlan_enabled;
        __be16                          vlan_proto;
+       u16                             default_pvid;
        struct net_port_vlans __rcu     *vlan_info;
 #endif
 };
@@ -605,6 +606,7 @@ void br_recalculate_fwd_mask(struct net_bridge *br);
 int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
 int br_vlan_set_proto(struct net_bridge *br, unsigned long val);
 void br_vlan_init(struct net_bridge *br);
+int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val);
 int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags);
 int nbp_vlan_delete(struct net_bridge_port *port, u16 vid);
 void nbp_vlan_flush(struct net_bridge_port *port);
index cb431c6016ee18935ddc20cb818391a98646c49e..4c97fc50fb704265bd2f51d96527cf3227a65118 100644 (file)
@@ -725,6 +725,22 @@ static ssize_t vlan_protocol_store(struct device *d,
        return store_bridge_parm(d, buf, len, br_vlan_set_proto);
 }
 static DEVICE_ATTR_RW(vlan_protocol);
+
+static ssize_t default_pvid_show(struct device *d,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct net_bridge *br = to_bridge(d);
+       return sprintf(buf, "%d\n", br->default_pvid);
+}
+
+static ssize_t default_pvid_store(struct device *d,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       return store_bridge_parm(d, buf, len, br_vlan_set_default_pvid);
+}
+static DEVICE_ATTR_RW(default_pvid);
 #endif
 
 static struct attribute *bridge_attrs[] = {
@@ -771,6 +787,7 @@ static struct attribute *bridge_attrs[] = {
 #ifdef CONFIG_BRIDGE_VLAN_FILTERING
        &dev_attr_vlan_filtering.attr,
        &dev_attr_vlan_protocol.attr,
+       &dev_attr_default_pvid.attr,
 #endif
        NULL
 };
index 3ba57fcdcd13fec638aa17e539e4baf0d3e010eb..dfa7c9a7e1935114fcd90e446c5710b16f5c4b83 100644 (file)
@@ -499,9 +499,38 @@ err_filt:
        goto unlock;
 }
 
+int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val)
+{
+       u16 pvid = val;
+       int err = 0;
+
+       if (!val || val >= VLAN_VID_MASK)
+               return -EINVAL;
+
+       if (!rtnl_trylock())
+               return restart_syscall();
+
+       if (pvid == br->default_pvid)
+               goto unlock;
+
+       /* Only allow default pvid change when filtering is disabled */
+       if (br->vlan_enabled) {
+               pr_info_once("Please disable vlan filtering to change default_pvid\n");
+               err = -EPERM;
+               goto unlock;
+       }
+
+       br->default_pvid = pvid;
+
+unlock:
+       rtnl_unlock();
+       return err;
+}
+
 void br_vlan_init(struct net_bridge *br)
 {
        br->vlan_proto = htons(ETH_P_8021Q);
+       br->default_pvid = 1;
 }
 
 /* Must be protected by RTNL.