datapath: Make it possible to query vports by name regardless of datapath.
[sliver-openvswitch.git] / datapath / datapath.c
index 3837e92..3f108c0 100644 (file)
@@ -1349,85 +1349,85 @@ 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_list_ports(struct datapath *dp, struct odp_port __user *uports,
-                        int n_ports)
+static int do_dump_port(struct datapath *dp, struct odp_vport_dump *dump)
 {
-       int idx = 0;
-       if (n_ports) {
-               struct vport *p;
-
-               list_for_each_entry_rcu (p, &dp->port_list, node) {
-                       if (put_port(p, &uports[idx]))
-                               return -EFAULT;
-                       if (idx++ >= n_ports)
-                               break;
+       u32 port_no;
+
+       for (port_no = dump->port_no; port_no < DP_MAX_PORTS; port_no++) {
+               struct vport *vport = get_vport_protected(dp, port_no);
+               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 idx;
+
+       return put_user('\0', (char __force __user*)&dump->port->devname[0]);
 }
 
-static int list_ports(struct datapath *dp, struct odp_portvec __user *upv)
+static int dump_port(struct datapath *dp, struct odp_vport_dump __user *udump)
 {
-       struct odp_portvec pv;
-       int retval;
+       struct odp_vport_dump dump;
 
-       if (copy_from_user(&pv, upv, sizeof(pv)))
+       if (copy_from_user(&dump, udump, sizeof(dump)))
                return -EFAULT;
 
-       retval = do_list_ports(dp, (struct odp_port __user __force *)pv.ports,
-                              pv.n_ports);
-       if (retval < 0)
-               return retval;
-
-       return put_user(retval, &upv->n_ports);
+       return do_dump_port(dp, &dump);
 }
 
 static int get_listen_mask(const struct file *f)
@@ -1469,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;
@@ -1548,12 +1552,8 @@ 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_LIST:
-               err = list_ports(dp, (struct odp_portvec __user *)argp);
+       case ODP_VPORT_DUMP:
+               err = dump_port(dp, (struct odp_vport_dump __user *)argp);
                break;
 
        case ODP_FLOW_FLUSH:
@@ -1600,19 +1600,18 @@ static int dp_has_packet_of_interest(struct datapath *dp, int listeners)
 }
 
 #ifdef CONFIG_COMPAT
-static int compat_list_ports(struct datapath *dp, struct compat_odp_portvec __user *upv)
+static int compat_dump_port(struct datapath *dp, struct compat_odp_vport_dump __user *compat)
 {
-       struct compat_odp_portvec pv;
-       int retval;
+       struct odp_vport_dump dump;
+       compat_uptr_t port;
 
-       if (copy_from_user(&pv, upv, sizeof(pv)))
+       if (!access_ok(VERIFY_READ, compat, sizeof(struct compat_odp_vport_dump)) ||
+           __get_user(port, &compat->port) ||
+           __get_user(dump.port_no, &compat->port_no))
                return -EFAULT;
 
-       retval = do_list_ports(dp, compat_ptr(pv.ports), pv.n_ports);
-       if (retval < 0)
-               return retval;
-
-       return put_user(retval, &upv->n_ports);
+       dump.port = (struct odp_port __force *)compat_ptr(port);
+       return do_dump_port(dp, &dump);
 }
 
 static int compat_get_flow(struct odp_flow *flow, const struct compat_odp_flow __user *compat)
@@ -1839,8 +1838,8 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned
                goto exit;
 
        switch (cmd) {
-       case ODP_VPORT_LIST32:
-               err = compat_list_ports(dp, compat_ptr(argp));
+       case ODP_VPORT_DUMP32:
+               err = compat_dump_port(dp, compat_ptr(argp));
                break;
 
        case ODP_FLOW_PUT32: