datapath: Make it possible to query vports by name regardless of datapath.
authorBen Pfaff <blp@nicira.com>
Wed, 29 Dec 2010 23:04:36 +0000 (15:04 -0800)
committerBen Pfaff <blp@nicira.com>
Fri, 28 Jan 2011 05:08:36 +0000 (21:08 -0800)
Until now it has only been possible to query a vport if you know what
datapath it is on.  This doesn't really make sense, so this commit removes
that restriction.  It is a little bigger than one might naturally expect
because locking changes are required.

This also allows us to get rid of the ETHTOOL_GDRVINFO kluge that has
bothered me for a long time.  The next commit does that.

Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
datapath/datapath.c
include/openvswitch/datapath-protocol.h
lib/dpif-linux.c

index 26f0444..3f108c0 100644 (file)
@@ -1349,52 +1349,58 @@ void set_internal_devs_mtu(const struct datapath *dp)
        }
 }
 
-static int put_port(const struct vport *p, struct odp_port __user *uop)
+static void compose_odp_port(const struct vport *vport, struct odp_port *odp_port)
 {
-       struct odp_port op;
-
-       memset(&op, 0, sizeof(op));
-
        rcu_read_lock();
-       strncpy(op.devname, vport_get_name(p), sizeof(op.devname));
-       strncpy(op.type, vport_get_type(p), sizeof(op.type));
-       vport_get_config(p, op.config);
+       strncpy(odp_port->devname, vport_get_name(vport), sizeof(odp_port->devname));
+       strncpy(odp_port->type, vport_get_type(vport), sizeof(odp_port->type));
+       vport_get_config(vport, odp_port->config);
+       odp_port->port = vport->port_no;
+       odp_port->dp_idx = vport->dp->dp_idx;
        rcu_read_unlock();
-
-       op.port = p->port_no;
-
-       return copy_to_user(uop, &op, sizeof(op)) ? -EFAULT : 0;
 }
 
-static int query_port(struct datapath *dp, struct odp_port __user *uport)
+static int query_port(int dp_idx, struct odp_port __user *uport)
 {
        struct odp_port port;
-       struct vport *vport;
 
        if (copy_from_user(&port, uport, sizeof(port)))
                return -EFAULT;
 
        if (port.devname[0]) {
+               struct vport *vport;
+
                port.devname[IFNAMSIZ - 1] = '\0';
 
                vport_lock();
                vport = vport_locate(port.devname);
+               if (vport)
+                       compose_odp_port(vport, &port);
                vport_unlock();
 
                if (!vport)
                        return -ENODEV;
-               if (vport->dp != dp)
-                       return -ENOENT;
        } else {
+               struct vport *vport;
+               struct datapath *dp;
+
                if (port.port >= DP_MAX_PORTS)
                        return -EINVAL;
 
+               dp = get_dp_locked(dp_idx);
+               if (!dp)
+                       return -ENODEV;
+
                vport = get_vport_protected(dp, port.port);
+               if (vport)
+                       compose_odp_port(vport, &port);
+               mutex_unlock(&dp->mutex);
+
                if (!vport)
                        return -ENOENT;
        }
 
-       return put_port(vport, uport);
+       return copy_to_user(uport, &port, sizeof(struct odp_port));
 }
 
 static int do_dump_port(struct datapath *dp, struct odp_vport_dump *dump)
@@ -1403,8 +1409,12 @@ static int do_dump_port(struct datapath *dp, struct odp_vport_dump *dump)
 
        for (port_no = dump->port_no; port_no < DP_MAX_PORTS; port_no++) {
                struct vport *vport = get_vport_protected(dp, port_no);
-               if (vport)
-                       return put_port(vport, (struct odp_port __force __user*)dump->port);
+               if (vport) {
+                       struct odp_port odp_port;
+
+                       compose_odp_port(vport, &odp_port);
+                       return copy_to_user((struct odp_port __force __user*)dump->port, &odp_port, sizeof(struct odp_port));
+               }
        }
 
        return put_user('\0', (char __force __user*)&dump->port->devname[0]);
@@ -1459,6 +1469,10 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
                        err = detach_port(dp_idx, port_no);
                goto exit;
 
+       case ODP_VPORT_QUERY:
+               err = query_port(dp_idx, (struct odp_port __user *)argp);
+               goto exit;
+
        case ODP_VPORT_MOD:
                err = vport_user_mod((struct odp_port __user *)argp);
                goto exit;
@@ -1538,10 +1552,6 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
                        dp->sflow_probability = sflow_probability;
                break;
 
-       case ODP_VPORT_QUERY:
-               err = query_port(dp, (struct odp_port __user *)argp);
-               break;
-
        case ODP_VPORT_DUMP:
                err = dump_port(dp, (struct odp_vport_dump __user *)argp);
                break;
index dd717c0..25f8e13 100644 (file)
@@ -182,7 +182,7 @@ struct odp_port {
     char devname[16];           /* IFNAMSIZ */
     char type[VPORT_TYPE_SIZE];
     uint16_t port;
-    uint16_t reserved1;
+    uint16_t dp_idx;
     uint32_t reserved2;
     __aligned_u64 config[VPORT_CONFIG_SIZE / 8]; /* type-specific */
 };
index ac0444d..530784c 100644 (file)
@@ -309,12 +309,20 @@ dpif_linux_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
 }
 
 static int
-dpif_linux_port_query_by_name(const struct dpif *dpif, const char *devname,
+dpif_linux_port_query_by_name(const struct dpif *dpif_, const char *devname,
                               struct odp_port *port)
 {
+    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+    int error;
+
     memset(port, 0, sizeof *port);
     strncpy(port->devname, devname, sizeof port->devname);
-    return dpif_linux_port_query__(dpif, port);
+    error = dpif_linux_port_query__(dpif_, port);
+    if (!error && port->dp_idx != dpif->minor) {
+        /* A vport named 'devname' exists but in some other datapath.  */
+        error = ENOENT;
+    }
+    return error;
 }
 
 static int