Prepare Open vSwitch 1.1.2 release.
[sliver-openvswitch.git] / datapath / dp_sysfs_dp.c
index 8214c60..587b8bc 100644 (file)
@@ -6,6 +6,8 @@
  * kernel, by Linus Torvalds and others.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/version.h>
 
 /*
 #define DEV_ATTR(NAME) dev_attr_##NAME
 #endif
 
-struct datapath *sysfs_get_dp(struct net_device *netdev)
+static struct datapath *sysfs_get_dp(struct net_device *netdev)
 {
-       return vport_get_dp_port(internal_dev_get_vport(netdev))->dp;
+       struct vport *vport = internal_dev_get_vport(netdev);
+       return vport ? vport->dp : NULL;
 }
-
 /*
  * Common code for storing bridge parameters.
  */
@@ -53,9 +55,9 @@ static ssize_t store_bridge_parm(DEVICE_PARAMS,
                                 const char *buf, size_t len,
                                 void (*set)(struct datapath *, unsigned long))
 {
-       struct datapath *dp = sysfs_get_dp(to_net_dev(d));
        char *endp;
        unsigned long val;
+       ssize_t result = len;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
@@ -66,14 +68,24 @@ static ssize_t store_bridge_parm(DEVICE_PARAMS,
 
        /* xxx We use a default value of 0 for all fields.  If the caller is
         * xxx attempting to set the value to our default, just silently
-        * xxx ignore the request. 
+        * xxx ignore the request.
         */
        if (val != 0) {
-               printk("%s: xxx writing dp parms not supported yet!\n", 
-                      dp_name(dp));
+               struct datapath *dp;
+
+               rcu_read_lock();
+
+               dp = sysfs_get_dp(to_net_dev(d));
+               if (dp)
+                       printk("%s: xxx writing dp parms not supported yet!\n",
+                              dp_name(dp));
+               else
+                       result = -ENODEV;
+
+               rcu_read_unlock();
        }
 
-       return len;
+       return result;
 }
 
 
@@ -159,11 +171,20 @@ static ssize_t store_stp_state(DEVICE_PARAMS,
                               const char *buf,
                               size_t len)
 {
-       struct datapath *dp = sysfs_get_dp(to_net_dev(d));
+       struct datapath *dp;
+       ssize_t result = len;
+
+       rcu_read_lock();
+
+       dp = sysfs_get_dp(to_net_dev(d));
+       if (dp)
+               printk("%s: xxx attempt to set_stp_state()\n", dp_name(dp));
+       else
+               result = -ENODEV;
 
-       printk("%s: xxx attempt to set_stp_state()\n", dp_name(dp));
+       rcu_read_unlock();
 
-       return len;
+       return result;
 }
 static INTERNAL_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
                   store_stp_state);
@@ -193,12 +214,24 @@ static INTERNAL_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
 
 static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
 {
-       struct datapath *dp = sysfs_get_dp(to_net_dev(d));
-       const unsigned char *addr = vport_get_addr(dp->ports[ODPP_LOCAL]->vport);
+       struct vport *vport;
+       ssize_t result;
 
-       /* xxx Do we need a lock of some sort? */
-       return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
-                       0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+       rcu_read_lock();
+
+       vport = internal_dev_get_vport(to_net_dev(d));
+       if (vport) {
+               const unsigned char *addr;
+
+               addr = vport_get_addr(vport);
+               result = sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
+                                0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+       } else
+               result = -ENODEV;
+
+       rcu_read_unlock();
+
+       return result;
 }
 static INTERNAL_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
 
@@ -260,10 +293,20 @@ static ssize_t show_group_addr(DEVICE_PARAMS, char *buf)
 static ssize_t store_group_addr(DEVICE_PARAMS,
                                const char *buf, size_t len)
 {
-       struct datapath *dp = sysfs_get_dp(to_net_dev(d));
+       struct datapath *dp;
+       ssize_t result = len;
+
+       rcu_read_lock();
+
+       dp = sysfs_get_dp(to_net_dev(d));
+       if (dp)
+               printk("%s: xxx attempt to store_group_addr()\n", dp_name(dp));
+       else
+               result = -ENODEV;
+
+       rcu_read_unlock();
 
-       printk("%s: xxx attempt to store_group_addr()\n", dp_name(dp));
-       return len;
+       return result;
 }
 
 static INTERNAL_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
@@ -307,7 +350,8 @@ static struct attribute_group bridge_group = {
  */
 int dp_sysfs_add_dp(struct datapath *dp)
 {
-       struct kobject *kobj = vport_get_kobj(dp->ports[ODPP_LOCAL]->vport);
+       struct kobject *kobj =
+               vport_get_kobj(rtnl_dereference(dp->ports[ODPP_LOCAL]));
        int err;
 
        /* Create /sys/class/net/<devname>/bridge directory. */
@@ -336,7 +380,8 @@ int dp_sysfs_add_dp(struct datapath *dp)
 
 int dp_sysfs_del_dp(struct datapath *dp)
 {
-       struct kobject *kobj = vport_get_kobj(dp->ports[ODPP_LOCAL]->vport);
+       struct kobject *kobj =
+               vport_get_kobj(rtnl_dereference(dp->ports[ODPP_LOCAL]));
 
        kobject_del(&dp->ifobj);
        sysfs_remove_group(kobj, &bridge_group);
@@ -346,6 +391,6 @@ int dp_sysfs_del_dp(struct datapath *dp)
 #else /* !CONFIG_SYSFS */
 int dp_sysfs_add_dp(struct datapath *dp) { return 0; }
 int dp_sysfs_del_dp(struct datapath *dp) { return 0; }
-int dp_sysfs_add_if(struct dp_port *p) { return 0; }
-int dp_sysfs_del_if(struct dp_port *p) { return 0; }
+int dp_sysfs_add_if(struct vport *p) { return 0; }
+int dp_sysfs_del_if(struct vport *p) { return 0; }
 #endif /* !CONFIG_SYSFS */