vport: Extract common functions for virtual devices.
[sliver-openvswitch.git] / datapath / vport.c
index 5656672..f1c78b1 100644 (file)
 #include <linux/mutex.h>
 #include <linux/percpu.h>
 #include <linux/rtnetlink.h>
+#include <linux/compat.h>
 
 #include "vport.h"
+#include "vport-internal_dev.h"
 
 extern struct vport_ops netdev_vport_ops;
 extern struct vport_ops internal_vport_ops;
@@ -228,6 +230,24 @@ vport_add(const struct odp_vport_add __user *uvport_config)
        return do_vport_add(&vport_config);
 }
 
+#ifdef CONFIG_COMPAT
+int
+compat_vport_add(struct compat_odp_vport_add *ucompat)
+{
+       struct compat_odp_vport_add compat;
+       struct odp_vport_add vport_config;
+
+       if (copy_from_user(&compat, ucompat, sizeof(struct compat_odp_vport_add)))
+               return -EFAULT;
+
+       memcpy(vport_config.port_type, compat.port_type, VPORT_TYPE_SIZE);
+       memcpy(vport_config.devname, compat.devname, IFNAMSIZ);
+       vport_config.config = compat_ptr(compat.config);
+
+       return do_vport_add(&vport_config);
+}
+#endif
+
 /**
  *     vport_mod - modify existing vport device (for userspace callers)
  *
@@ -273,6 +293,23 @@ vport_mod(const struct odp_vport_mod __user *uvport_config)
        return do_vport_mod(&vport_config);
 }
 
+#ifdef CONFIG_COMPAT
+int
+compat_vport_mod(struct compat_odp_vport_mod *ucompat)
+{
+       struct compat_odp_vport_mod compat;
+       struct odp_vport_mod vport_config;
+
+       if (copy_from_user(&compat, ucompat, sizeof(struct compat_odp_vport_mod)))
+               return -EFAULT;
+
+       memcpy(vport_config.devname, compat.devname, IFNAMSIZ);
+       vport_config.config = compat_ptr(compat.config);
+
+       return do_vport_mod(&vport_config);
+}
+#endif
+
 /**
  *     vport_del - delete existing vport device (for userspace callers)
  *
@@ -364,9 +401,12 @@ vport_stats_get(struct odp_vport_stats_req __user *ustats_req)
                goto out;
        }
 
-       if (vport->ops->get_stats)
+       if (vport->ops->get_stats) {
+               rcu_read_lock();
                err = vport->ops->get_stats(vport, &stats_req.stats);
-       else if (vport->ops->flags & VPORT_F_GEN_STATS) {
+               rcu_read_unlock();
+
+       } else if (vport->ops->flags & VPORT_F_GEN_STATS) {
                int i;
 
                memset(&stats_req.stats, 0, sizeof(struct odp_vport_stats));
@@ -439,7 +479,9 @@ vport_ether_get(struct odp_vport_ether __user *uvport_ether)
                goto out;
        }
 
+       rcu_read_lock();
        memcpy(vport_ether.ether_addr, vport_get_addr(vport), ETH_ALEN);
+       rcu_read_unlock();
 
 out:
        vport_unlock();
@@ -596,11 +638,17 @@ vport_locate(const char *name)
                dump_stack();
        }
 
+       rcu_read_lock();
+
        hlist_for_each_entry(vport, node, bucket, hash_node)
                if (!strcmp(name, vport_get_name(vport)))
-                       return vport;
+                       goto out;
+
+       vport = NULL;
 
-       return NULL;
+out:
+       rcu_read_unlock();
+       return vport;
 }
 
 static void
@@ -835,9 +883,20 @@ vport_set_mtu(struct vport *vport, int mtu)
        if (mtu < 68)
                return -EINVAL;
 
-       if (vport->ops->set_mtu)
-               return vport->ops->set_mtu(vport, mtu);
-       else
+       if (vport->ops->set_mtu) {
+               int ret;
+
+               ret = vport->ops->set_mtu(vport, mtu);
+
+               if (!ret && !is_internal_vport(vport)) {
+                       struct dp_port *dp_port = vport_get_dp_port(vport);
+
+                       if (dp_port)
+                               set_internal_devs_mtu(dp_port->dp);
+               }
+
+               return ret;
+       } else
                return -EOPNOTSUPP;
 }
 
@@ -1051,10 +1110,9 @@ vport_get_mtu(const struct vport *vport)
  * @vport: vport that received the packet
  * @skb: skb that was received
  *
- * Must be called with rcu_read_lock and bottom halves disabled.  The packet
- * cannot be shared and skb->data should point to the Ethernet header.  The
- * caller must have already called compute_ip_summed() to initialize the
- * checksumming fields.
+ * Must be called with rcu_read_lock.  The packet cannot be shared and
+ * skb->data should point to the Ethernet header.  The caller must have already
+ * called compute_ip_summed() to initialize the checksumming fields.
  */
 void
 vport_receive(struct vport *vport, struct sk_buff *skb)
@@ -1170,25 +1228,3 @@ vport_record_error(struct vport *vport, enum vport_err_type err_type)
                spin_unlock_bh(&vport->err_stats.lock);
        }
 }
-
-/**
- *     vport_gen_ether_addr - generate an Ethernet address
- *
- * @addr: location to store generated address
- *
- * Generates a random Ethernet address for use when creating a device that
- * has no natural address.
- */
-void
-vport_gen_ether_addr(u8 *addr)
-{
-       random_ether_addr(addr);
-
-       /* Set the OUI to the Nicira one. */
-       addr[0] = 0x00;
-       addr[1] = 0x23;
-       addr[2] = 0x20;
-
-       /* Set the top bit to indicate random address. */
-       addr[3] |= 0x80;
-}