From 51d4d59822785c1044cd96e6c73427347e0154c2 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 29 Dec 2010 15:04:36 -0800 Subject: [PATCH] datapath: Make it possible to query vports by name regardless of datapath. 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 Acked-by: Jesse Gross --- datapath/datapath.c | 56 +++++++++++++++---------- include/openvswitch/datapath-protocol.h | 2 +- lib/dpif-linux.c | 12 +++++- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index 26f04440..3f108c09 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -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; diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h index dd717c09..25f8e132 100644 --- a/include/openvswitch/datapath-protocol.h +++ b/include/openvswitch/datapath-protocol.h @@ -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 */ }; diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index ac0444d8..530784ce 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -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 -- 2.30.2