X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=0f59e9ae5bda676c7375d1134eadf2ffcd9af979;hb=bc4a05c639ee3789d009bb6143345cf121b2d4d4;hp=3f108c09d0d34bfa5fb62053e270f243fc69812c;hpb=51d4d59822785c1044cd96e6c73427347e0154c2;p=sliver-openvswitch.git diff --git a/datapath/datapath.c b/datapath/datapath.c index 3f108c09d..0f59e9ae5 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -69,7 +69,7 @@ EXPORT_SYMBOL(dp_ioctl_hook); static struct datapath __rcu *dps[ODP_MAX]; static DEFINE_MUTEX(dp_mutex); -static int new_vport(struct datapath *, struct odp_port *, int port_no); +static struct vport *new_vport(const struct vport_parms *); /* Must be called with rcu_read_lock or dp_mutex. */ struct datapath *get_dp(int dp_idx) @@ -208,8 +208,9 @@ static struct kobj_type dp_ktype = { static int create_dp(int dp_idx, const char __user *devnamep) { - struct odp_port internal_dev_port; + struct vport_parms parms; char devname[IFNAMSIZ]; + struct vport *vport; struct datapath *dp; int err; int i; @@ -264,11 +265,14 @@ static int create_dp(int dp_idx, const char __user *devnamep) goto err_free_dp; /* Set up our datapath device. */ - BUILD_BUG_ON(sizeof(internal_dev_port.devname) != sizeof(devname)); - strcpy(internal_dev_port.devname, devname); - strcpy(internal_dev_port.type, "internal"); - err = new_vport(dp, &internal_dev_port, ODPP_LOCAL); - if (err) { + parms.name = devname; + parms.type = ODP_VPORT_TYPE_INTERNAL; + parms.options = NULL; + parms.dp = dp; + parms.port_no = ODPP_LOCAL; + vport = new_vport(&parms); + if (IS_ERR(vport)) { + err = PTR_ERR(vport); if (err == -EBUSY) err = -EEXIST; @@ -355,74 +359,23 @@ out: } /* Called with RTNL lock and dp->mutex. */ -static int new_vport(struct datapath *dp, struct odp_port *odp_port, int port_no) +static struct vport *new_vport(const struct vport_parms *parms) { - struct vport_parms parms; struct vport *vport; - parms.name = odp_port->devname; - parms.type = odp_port->type; - parms.config = odp_port->config; - parms.dp = dp; - parms.port_no = port_no; - vport_lock(); - vport = vport_add(&parms); - vport_unlock(); - - if (IS_ERR(vport)) - return PTR_ERR(vport); - - rcu_assign_pointer(dp->ports[port_no], vport); - list_add_rcu(&vport->node, &dp->port_list); - dp->n_ports++; - - dp_ifinfo_notify(RTM_NEWLINK, vport); - - return 0; -} - -static int attach_port(int dp_idx, struct odp_port __user *portp) -{ - struct datapath *dp; - struct odp_port port; - int port_no; - int err; - - err = -EFAULT; - if (copy_from_user(&port, portp, sizeof(port))) - goto out; - port.devname[IFNAMSIZ - 1] = '\0'; - port.type[VPORT_TYPE_SIZE - 1] = '\0'; - - rtnl_lock(); - dp = get_dp_locked(dp_idx); - err = -ENODEV; - if (!dp) - goto out_unlock_rtnl; - - for (port_no = 1; port_no < DP_MAX_PORTS; port_no++) - if (!dp->ports[port_no]) - goto got_port_no; - err = -EFBIG; - goto out_unlock_dp; + vport = vport_add(parms); + if (!IS_ERR(vport)) { + struct datapath *dp = parms->dp; -got_port_no: - err = new_vport(dp, &port, port_no); - if (err) - goto out_unlock_dp; - - set_internal_devs_mtu(dp); - dp_sysfs_add_if(get_vport_protected(dp, port_no)); + rcu_assign_pointer(dp->ports[parms->port_no], vport); + list_add_rcu(&vport->node, &dp->port_list); - err = put_user(port_no, &portp->port); + dp_ifinfo_notify(RTM_NEWLINK, vport); + } + vport_unlock(); -out_unlock_dp: - mutex_unlock(&dp->mutex); -out_unlock_rtnl: - rtnl_unlock(); -out: - return err; + return vport; } int dp_detach_port(struct vport *p) @@ -436,7 +389,6 @@ int dp_detach_port(struct vport *p) dp_ifinfo_notify(RTM_DELLINK, p); /* First drop references to device. */ - p->dp->n_ports--; list_del_rcu(&p->node); rcu_assign_pointer(p->dp->ports[p->port_no], NULL); @@ -448,37 +400,6 @@ int dp_detach_port(struct vport *p) return err; } -static int detach_port(int dp_idx, int port_no) -{ - struct vport *p; - struct datapath *dp; - int err; - - err = -EINVAL; - if (port_no < 0 || port_no >= DP_MAX_PORTS || port_no == ODPP_LOCAL) - goto out; - - rtnl_lock(); - dp = get_dp_locked(dp_idx); - err = -ENODEV; - if (!dp) - goto out_unlock_rtnl; - - p = get_vport_protected(dp, port_no); - err = -ENOENT; - if (!p) - goto out_unlock_dp; - - err = dp_detach_port(p); - -out_unlock_dp: - mutex_unlock(&dp->mutex); -out_unlock_rtnl: - rtnl_unlock(); -out: - return err; -} - /* Must be called with rcu_read_lock. */ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) { @@ -858,7 +779,6 @@ static void get_stats(struct sw_flow *flow, struct odp_flow_stats *stats) stats->n_bytes = flow->byte_count; stats->reserved = 0; stats->tcp_flags = flow->tcp_flags; - stats->error = 0; } static void clear_stats(struct sw_flow *flow) @@ -1096,55 +1016,25 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp) return error; } -static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec) +static int query_flow(struct datapath *dp, struct odp_flow __user *uflow) { struct tbl *table = get_table_protected(dp); - u32 i; - - for (i = 0; i < flowvec->n_flows; i++) { - struct odp_flow __user *ufp = (struct odp_flow __user __force *)&flowvec->flows[i]; - struct sw_flow_key key; - struct odp_flow uf; - struct tbl_node *flow_node; - int error; - - if (copy_from_user(&uf, ufp, sizeof(uf))) - return -EFAULT; - - error = flow_copy_from_user(&key, (const struct nlattr __force __user *)uf.key, uf.key_len); - if (error) - return error; - - flow_node = tbl_lookup(table, &uf.key, flow_hash(&key), flow_cmp); - if (!flow_node) - error = put_user(ENOENT, &ufp->stats.error); - else - error = answer_query(dp, flow_cast(flow_node), uf.flags, ufp); - if (error) - return -EFAULT; - } - return flowvec->n_flows; -} - -static int do_flowvec_ioctl(struct datapath *dp, unsigned long argp, - int (*function)(struct datapath *, - const struct odp_flowvec *)) -{ - struct odp_flowvec __user *uflowvec; - struct odp_flowvec flowvec; - int retval; + struct tbl_node *flow_node; + struct sw_flow_key key; + struct odp_flow flow; + int error; - uflowvec = (struct odp_flowvec __user *)argp; - if (copy_from_user(&flowvec, uflowvec, sizeof(flowvec))) + if (copy_from_user(&flow, uflow, sizeof(flow))) return -EFAULT; - if (flowvec.n_flows > INT_MAX / sizeof(struct odp_flow)) - return -EINVAL; + error = flow_copy_from_user(&key, (const struct nlattr __force __user *)flow.key, flow.key_len); + if (error) + return error; - retval = function(dp, &flowvec); - return (retval < 0 ? retval - : retval == flowvec.n_flows ? 0 - : put_user(retval, &uflowvec->n_flows)); + flow_node = tbl_lookup(table, &flow.key, flow_hash(&key), flow_cmp); + if (!flow_node) + return -ENOENT; + return answer_query(dp, flow_cast(flow_node), flow.flags, uflow); } static struct sw_flow *do_dump_flow(struct datapath *dp, u32 __user *state) @@ -1276,15 +1166,9 @@ static int execute_packet(struct datapath *dp, const struct odp_execute __user * static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp) { - struct tbl *table = get_table_protected(dp); struct odp_stats stats; int i; - stats.n_flows = tbl_count(table); - stats.cur_capacity = tbl_n_buckets(table); - stats.max_capacity = TBL_MAX_BUCKETS; - stats.n_ports = dp->n_ports; - stats.max_ports = DP_MAX_PORTS; stats.n_frags = stats.n_hit = stats.n_missed = stats.n_lost = 0; for_each_possible_cpu(i) { const struct dp_stats_percpu *percpu_stats; @@ -1303,8 +1187,6 @@ static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp) stats.n_missed += local_stats.n_missed; stats.n_lost += local_stats.n_lost; } - stats.max_miss_queue = DP_MAX_QUEUE_LEN; - stats.max_action_queue = DP_MAX_QUEUE_LEN; return copy_to_user(statsp, &stats, sizeof(stats)) ? -EFAULT : 0; } @@ -1349,95 +1231,408 @@ void set_internal_devs_mtu(const struct datapath *dp) } } -static void compose_odp_port(const struct vport *vport, struct odp_port *odp_port) +static int get_listen_mask(const struct file *f) +{ + return (long)f->private_data; +} + +static void set_listen_mask(struct file *f, int listen_mask) +{ + f->private_data = (void*)(long)listen_mask; +} + +static const struct nla_policy vport_policy[ODP_VPORT_ATTR_MAX + 1] = { + [ODP_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, + [ODP_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 }, + [ODP_VPORT_ATTR_TYPE] = { .type = NLA_U32 }, + [ODP_VPORT_ATTR_STATS] = { .len = sizeof(struct rtnl_link_stats64) }, + [ODP_VPORT_ATTR_ADDRESS] = { .len = ETH_ALEN }, + [ODP_VPORT_ATTR_MTU] = { .type = NLA_U32 }, + [ODP_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, +}; + +static int copy_vport_to_user(void __user *dst, struct vport *vport, uint32_t total_len) { + struct odp_vport *odp_vport; + struct sk_buff *skb; + struct nlattr *nla; + int ifindex, iflink; + int err; + + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + err = -ENOMEM; + if (!skb) + goto exit; + rcu_read_lock(); - 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; + odp_vport = (struct odp_vport*)__skb_put(skb, sizeof(struct odp_vport)); + odp_vport->dp_idx = vport->dp->dp_idx; + odp_vport->total_len = total_len; + + NLA_PUT_U32(skb, ODP_VPORT_ATTR_PORT_NO, vport->port_no); + NLA_PUT_U32(skb, ODP_VPORT_ATTR_TYPE, vport_get_type(vport)); + NLA_PUT_STRING(skb, ODP_VPORT_ATTR_NAME, vport_get_name(vport)); + + nla = nla_reserve(skb, ODP_VPORT_ATTR_STATS, sizeof(struct rtnl_link_stats64)); + if (!nla) + goto nla_put_failure; + if (vport_get_stats(vport, nla_data(nla))) + __skb_trim(skb, skb->len - nla->nla_len); + + NLA_PUT(skb, ODP_VPORT_ATTR_ADDRESS, ETH_ALEN, vport_get_addr(vport)); + + NLA_PUT_U32(skb, ODP_VPORT_ATTR_MTU, vport_get_mtu(vport)); + + err = vport_get_options(vport, skb); + + ifindex = vport_get_ifindex(vport); + if (ifindex > 0) + NLA_PUT_U32(skb, ODP_VPORT_ATTR_IFINDEX, ifindex); + + iflink = vport_get_iflink(vport); + if (iflink > 0) + NLA_PUT_U32(skb, ODP_VPORT_ATTR_IFLINK, iflink); + + err = -EMSGSIZE; + if (skb->len > total_len) + goto exit_unlock; + + odp_vport->len = skb->len; + err = copy_to_user(dst, skb->data, skb->len) ? -EFAULT : 0; + goto exit_unlock; + +nla_put_failure: + err = -EMSGSIZE; +exit_unlock: rcu_read_unlock(); + kfree_skb(skb); +exit: + return err; } -static int query_port(int dp_idx, struct odp_port __user *uport) +static struct sk_buff *copy_vport_from_user(struct odp_vport __user *uodp_vport, + struct nlattr *a[ODP_VPORT_ATTR_MAX + 1]) { - struct odp_port port; + struct odp_vport *odp_vport; + struct sk_buff *skb; + u32 len; + int err; - if (copy_from_user(&port, uport, sizeof(port))) - return -EFAULT; + if (get_user(len, &uodp_vport->len)) + return ERR_PTR(-EFAULT); + if (len < sizeof(struct odp_vport)) + return ERR_PTR(-EINVAL); - if (port.devname[0]) { - struct vport *vport; + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return ERR_PTR(-ENOMEM); - port.devname[IFNAMSIZ - 1] = '\0'; + err = -EFAULT; + if (copy_from_user(__skb_put(skb, len), uodp_vport, len)) + goto error_free_skb; - vport_lock(); - vport = vport_locate(port.devname); - if (vport) - compose_odp_port(vport, &port); - vport_unlock(); + odp_vport = (struct odp_vport *)skb->data; + err = -EINVAL; + if (odp_vport->len != len) + goto error_free_skb; - if (!vport) - return -ENODEV; - } else { - struct vport *vport; - struct datapath *dp; + err = nla_parse(a, ODP_VPORT_ATTR_MAX, (struct nlattr *)(skb->data + sizeof(struct odp_vport)), + skb->len - sizeof(struct odp_vport), vport_policy); + if (err) + goto error_free_skb; + + err = VERIFY_NUL_STRING(a[ODP_VPORT_ATTR_NAME], IFNAMSIZ - 1); + if (err) + goto error_free_skb; + + return skb; + +error_free_skb: + kfree_skb(skb); + return ERR_PTR(err); +} - if (port.port >= DP_MAX_PORTS) - return -EINVAL; + +/* Called without any locks (or with RTNL lock). + * Returns holding vport->dp->mutex. + */ +static struct vport *lookup_vport(struct odp_vport *odp_vport, + struct nlattr *a[ODP_VPORT_ATTR_MAX + 1]) +{ + struct datapath *dp; + struct vport *vport; + + if (a[ODP_VPORT_ATTR_NAME]) { + int dp_idx, port_no; + + retry: + vport_lock(); + vport = vport_locate(nla_data(a[ODP_VPORT_ATTR_NAME])); + if (!vport) { + vport_unlock(); + return ERR_PTR(-ENODEV); + } + dp_idx = vport->dp->dp_idx; + port_no = vport->port_no; + vport_unlock(); dp = get_dp_locked(dp_idx); if (!dp) - return -ENODEV; + goto retry; - vport = get_vport_protected(dp, port.port); - if (vport) - compose_odp_port(vport, &port); - mutex_unlock(&dp->mutex); + vport = get_vport_protected(dp, port_no); + if (!vport || + strcmp(vport_get_name(vport), nla_data(a[ODP_VPORT_ATTR_NAME]))) { + mutex_unlock(&dp->mutex); + goto retry; + } - if (!vport) - return -ENOENT; - } + return vport; + } else if (a[ODP_VPORT_ATTR_PORT_NO]) { + u32 port_no = nla_get_u32(a[ODP_VPORT_ATTR_PORT_NO]); + + if (port_no >= DP_MAX_PORTS) + return ERR_PTR(-EINVAL); - return copy_to_user(uport, &port, sizeof(struct odp_port)); + dp = get_dp_locked(odp_vport->dp_idx); + if (!dp) + return ERR_PTR(-ENODEV); + + vport = get_vport_protected(dp, port_no); + if (!vport) { + mutex_unlock(&dp->mutex); + return ERR_PTR(-ENOENT); + } + return vport; + } else + return ERR_PTR(-EINVAL); } -static int do_dump_port(struct datapath *dp, struct odp_vport_dump *dump) +static int change_vport(struct vport *vport, struct nlattr *a[ODP_VPORT_ATTR_MAX + 1]) { + int err = 0; + if (a[ODP_VPORT_ATTR_STATS]) + err = vport_set_stats(vport, nla_data(a[ODP_VPORT_ATTR_STATS])); + if (!err && a[ODP_VPORT_ATTR_ADDRESS]) + err = vport_set_addr(vport, nla_data(a[ODP_VPORT_ATTR_ADDRESS])); + if (!err && a[ODP_VPORT_ATTR_MTU]) + err = vport_set_mtu(vport, nla_get_u32(a[ODP_VPORT_ATTR_MTU])); + return err; +} + +static int attach_vport(struct odp_vport __user *uodp_vport) +{ + struct nlattr *a[ODP_VPORT_ATTR_MAX + 1]; + struct odp_vport *odp_vport; + struct vport_parms parms; + struct vport *vport; + struct sk_buff *skb; + struct datapath *dp; u32 port_no; + int err; - 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; + skb = copy_vport_from_user(uodp_vport, a); + err = PTR_ERR(skb); + if (IS_ERR(skb)) + goto exit; + odp_vport = (struct odp_vport *)skb->data; + + err = -EINVAL; + if (!a[ODP_VPORT_ATTR_NAME] || !a[ODP_VPORT_ATTR_TYPE]) + goto exit_kfree_skb; + + rtnl_lock(); + + dp = get_dp_locked(odp_vport->dp_idx); + err = -ENODEV; + if (!dp) + goto exit_unlock_rtnl; + + if (a[ODP_VPORT_ATTR_PORT_NO]) { + port_no = nla_get_u32(a[ODP_VPORT_ATTR_PORT_NO]); - compose_odp_port(vport, &odp_port); - return copy_to_user((struct odp_port __force __user*)dump->port, &odp_port, sizeof(struct odp_port)); + err = -EFBIG; + if (port_no >= DP_MAX_PORTS) + goto exit_unlock_dp; + + vport = get_vport_protected(dp, port_no); + err = -EBUSY; + if (vport) + goto exit_unlock_dp; + } else { + for (port_no = 1; ; port_no++) { + if (port_no >= DP_MAX_PORTS) { + err = -EFBIG; + goto exit_unlock_dp; + } + vport = get_vport_protected(dp, port_no); + if (!vport) + break; } } - return put_user('\0', (char __force __user*)&dump->port->devname[0]); + parms.name = nla_data(a[ODP_VPORT_ATTR_NAME]); + parms.type = nla_get_u32(a[ODP_VPORT_ATTR_TYPE]); + parms.options = a[ODP_VPORT_ATTR_OPTIONS]; + parms.dp = dp; + parms.port_no = port_no; + + vport = new_vport(&parms); + err = PTR_ERR(vport); + if (IS_ERR(vport)) + goto exit_unlock_dp; + + set_internal_devs_mtu(dp); + dp_sysfs_add_if(vport); + + err = change_vport(vport, a); + if (err) { + dp_detach_port(vport); + goto exit_unlock_dp; + } + + err = copy_vport_to_user(uodp_vport, vport, odp_vport->total_len); + +exit_unlock_dp: + mutex_unlock(&dp->mutex); +exit_unlock_rtnl: + rtnl_unlock(); +exit_kfree_skb: + kfree_skb(skb); +exit: + return err; } -static int dump_port(struct datapath *dp, struct odp_vport_dump __user *udump) +static int set_vport(unsigned int cmd, struct odp_vport __user *uodp_vport) { - struct odp_vport_dump dump; + struct nlattr *a[ODP_VPORT_ATTR_MAX + 1]; + struct vport *vport; + struct sk_buff *skb; + int err; - if (copy_from_user(&dump, udump, sizeof(dump))) - return -EFAULT; + skb = copy_vport_from_user(uodp_vport, a); + err = PTR_ERR(skb); + if (IS_ERR(skb)) + goto exit; - return do_dump_port(dp, &dump); + rtnl_lock(); + vport = lookup_vport((struct odp_vport *)skb->data, a); + err = PTR_ERR(vport); + if (IS_ERR(vport)) + goto exit_free; + + err = 0; + if (a[ODP_VPORT_ATTR_OPTIONS]) + err = vport_set_options(vport, a[ODP_VPORT_ATTR_OPTIONS]); + if (!err) + err = change_vport(vport, a); + + mutex_unlock(&vport->dp->mutex); +exit_free: + kfree_skb(skb); + rtnl_unlock(); +exit: + return err; } -static int get_listen_mask(const struct file *f) +static int del_vport(unsigned int cmd, struct odp_vport __user *uodp_vport) { - return (long)f->private_data; + struct nlattr *a[ODP_VPORT_ATTR_MAX + 1]; + struct datapath *dp; + struct vport *vport; + struct sk_buff *skb; + int err; + + skb = copy_vport_from_user(uodp_vport, a); + err = PTR_ERR(skb); + if (IS_ERR(skb)) + goto exit; + + rtnl_lock(); + vport = lookup_vport((struct odp_vport *)skb->data, a); + err = PTR_ERR(vport); + if (IS_ERR(vport)) + goto exit_free; + dp = vport->dp; + + err = -EINVAL; + if (vport->port_no == ODPP_LOCAL) + goto exit_free; + + err = dp_detach_port(vport); + mutex_unlock(&dp->mutex); +exit_free: + kfree_skb(skb); + rtnl_unlock(); +exit: + return err; } -static void set_listen_mask(struct file *f, int listen_mask) +static int get_vport(struct odp_vport __user *uodp_vport) { - f->private_data = (void*)(long)listen_mask; + struct nlattr *a[ODP_VPORT_ATTR_MAX + 1]; + struct odp_vport *odp_vport; + struct vport *vport; + struct sk_buff *skb; + int err; + + skb = copy_vport_from_user(uodp_vport, a); + err = PTR_ERR(skb); + if (IS_ERR(skb)) + goto exit; + odp_vport = (struct odp_vport *)skb->data; + + vport = lookup_vport(odp_vport, a); + err = PTR_ERR(vport); + if (IS_ERR(vport)) + goto exit_free; + + err = copy_vport_to_user(uodp_vport, vport, odp_vport->total_len); + mutex_unlock(&vport->dp->mutex); +exit_free: + kfree_skb(skb); +exit: + return err; +} + +static int dump_vport(struct odp_vport __user *uodp_vport) +{ + struct nlattr *a[ODP_VPORT_ATTR_MAX + 1]; + struct odp_vport *odp_vport; + struct sk_buff *skb; + struct datapath *dp; + u32 port_no; + int err; + + skb = copy_vport_from_user(uodp_vport, a); + err = PTR_ERR(skb); + if (IS_ERR(skb)) + goto exit; + odp_vport = (struct odp_vport *)skb->data; + + dp = get_dp_locked(odp_vport->dp_idx); + err = -ENODEV; + if (!dp) + goto exit_free; + + port_no = 0; + if (a[ODP_VPORT_ATTR_PORT_NO]) + port_no = nla_get_u32(a[ODP_VPORT_ATTR_PORT_NO]); + for (; port_no < DP_MAX_PORTS; port_no++) { + struct vport *vport = get_vport_protected(dp, port_no); + if (vport) { + err = copy_vport_to_user(uodp_vport, vport, odp_vport->total_len); + goto exit_unlock_dp; + } + } + err = -ENODEV; + +exit_unlock_dp: + mutex_unlock(&dp->mutex); +exit_free: + kfree_skb(skb); +exit: + return err; } static long openvswitch_ioctl(struct file *f, unsigned int cmd, @@ -1445,7 +1640,7 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, { int dp_idx = iminor(f->f_dentry->d_inode); struct datapath *dp; - int drop_frags, listeners, port_no; + int drop_frags, listeners; unsigned int sflow_probability; int err; @@ -1459,46 +1654,24 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, err = destroy_dp(dp_idx); goto exit; - case ODP_VPORT_ATTACH: - err = attach_port(dp_idx, (struct odp_port __user *)argp); - goto exit; - - case ODP_VPORT_DETACH: - err = get_user(port_no, (int __user *)argp); - if (!err) - 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; - - case ODP_VPORT_STATS_GET: - err = vport_user_stats_get((struct odp_vport_stats_req __user *)argp); - goto exit; - - case ODP_VPORT_STATS_SET: - err = vport_user_stats_set((struct odp_vport_stats_req __user *)argp); + case ODP_VPORT_NEW: + err = attach_vport((struct odp_vport __user *)argp); goto exit; - case ODP_VPORT_ETHER_GET: - err = vport_user_ether_get((struct odp_vport_ether __user *)argp); + case ODP_VPORT_GET: + err = get_vport((struct odp_vport __user *)argp); goto exit; - case ODP_VPORT_ETHER_SET: - err = vport_user_ether_set((struct odp_vport_ether __user *)argp); + case ODP_VPORT_DEL: + err = del_vport(cmd, (struct odp_vport __user *)argp); goto exit; - case ODP_VPORT_MTU_GET: - err = vport_user_mtu_get((struct odp_vport_mtu __user *)argp); + case ODP_VPORT_SET: + err = set_vport(cmd, (struct odp_vport __user *)argp); goto exit; - case ODP_VPORT_MTU_SET: - err = vport_user_mtu_set((struct odp_vport_mtu __user *)argp); + case ODP_VPORT_DUMP: + err = dump_vport((struct odp_vport __user *)argp); goto exit; } @@ -1552,10 +1725,6 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, dp->sflow_probability = sflow_probability; break; - case ODP_VPORT_DUMP: - err = dump_port(dp, (struct odp_vport_dump __user *)argp); - break; - case ODP_FLOW_FLUSH: err = flush_flows(dp); break; @@ -1569,7 +1738,7 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, break; case ODP_FLOW_GET: - err = do_flowvec_ioctl(dp, argp, do_query_flows); + err = query_flow(dp, (struct odp_flow __user *)argp); break; case ODP_FLOW_DUMP: @@ -1600,20 +1769,6 @@ static int dp_has_packet_of_interest(struct datapath *dp, int listeners) } #ifdef CONFIG_COMPAT -static int compat_dump_port(struct datapath *dp, struct compat_odp_vport_dump __user *compat) -{ - struct odp_vport_dump dump; - compat_uptr_t port; - - 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; - - 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) { compat_uptr_t key, actions; @@ -1684,37 +1839,25 @@ static int compat_del_flow(struct datapath *dp, struct compat_odp_flow __user *u return error; } -static int compat_query_flows(struct datapath *dp, - struct compat_odp_flow __user *flows, - u32 n_flows) +static int compat_query_flow(struct datapath *dp, struct compat_odp_flow __user *uflow) { struct tbl *table = get_table_protected(dp); - u32 i; - - for (i = 0; i < n_flows; i++) { - struct compat_odp_flow __user *ufp = &flows[i]; - struct odp_flow uf; - struct tbl_node *flow_node; - struct sw_flow_key key; - int error; + struct tbl_node *flow_node; + struct sw_flow_key key; + struct odp_flow flow; + int error; - if (compat_get_flow(&uf, ufp)) - return -EFAULT; + if (compat_get_flow(&flow, uflow)) + return -EFAULT; - error = flow_copy_from_user(&key, (const struct nlattr __force __user *) uf.key, uf.key_len); - if (error) - return error; + error = flow_copy_from_user(&key, (const struct nlattr __force __user *)flow.key, flow.key_len); + if (error) + return error; - flow_node = tbl_lookup(table, &key, flow_hash(&key), flow_cmp); - if (!flow_node) - error = put_user(ENOENT, &ufp->stats.error); - else - error = compat_answer_query(dp, flow_cast(flow_node), - uf.flags, ufp); - if (error) - return -EFAULT; - } - return n_flows; + flow_node = tbl_lookup(table, &key, flow_hash(&key), flow_cmp); + if (!flow_node) + return -ENOENT; + return compat_answer_query(dp, flow_cast(flow_node), flow.flags, uflow); } static int compat_dump_flow(struct datapath *dp, struct compat_odp_flow_dump __user *udumpp) @@ -1750,35 +1893,6 @@ static int compat_dump_flow(struct datapath *dp, struct compat_odp_flow_dump __u return compat_answer_query(dp, flow, 0, uflowp); } -static int compat_flowvec_ioctl(struct datapath *dp, unsigned long argp, - int (*function)(struct datapath *, - struct compat_odp_flow __user *, - u32 n_flows)) -{ - struct compat_odp_flowvec __user *uflowvec; - struct compat_odp_flow __user *flows; - struct compat_odp_flowvec flowvec; - int retval; - - uflowvec = compat_ptr(argp); - if (!access_ok(VERIFY_WRITE, uflowvec, sizeof(*uflowvec)) || - copy_from_user(&flowvec, uflowvec, sizeof(flowvec))) - return -EFAULT; - - if (flowvec.n_flows > INT_MAX / sizeof(struct compat_odp_flow)) - return -EINVAL; - - flows = compat_ptr(flowvec.flows); - if (!access_ok(VERIFY_WRITE, flows, - flowvec.n_flows * sizeof(struct compat_odp_flow))) - return -EFAULT; - - retval = function(dp, flows, flowvec.n_flows); - return (retval < 0 ? retval - : retval == flowvec.n_flows ? 0 - : put_user(retval, &uflowvec->n_flows)); -} - static int compat_execute(struct datapath *dp, const struct compat_odp_execute __user *uexecute) { struct odp_execute execute; @@ -1811,15 +1925,11 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned return openvswitch_ioctl(f, cmd, argp); case ODP_DP_CREATE: - case ODP_VPORT_ATTACH: - case ODP_VPORT_DETACH: - case ODP_VPORT_MOD: - case ODP_VPORT_MTU_SET: - case ODP_VPORT_MTU_GET: - case ODP_VPORT_ETHER_SET: - case ODP_VPORT_ETHER_GET: - case ODP_VPORT_STATS_SET: - case ODP_VPORT_STATS_GET: + case ODP_VPORT_NEW: + case ODP_VPORT_DEL: + case ODP_VPORT_GET: + case ODP_VPORT_SET: + case ODP_VPORT_DUMP: case ODP_DP_STATS: case ODP_GET_DROP_FRAGS: case ODP_SET_DROP_FRAGS: @@ -1827,7 +1937,6 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned case ODP_GET_LISTEN_MASK: case ODP_SET_SFLOW_PROBABILITY: case ODP_GET_SFLOW_PROBABILITY: - case ODP_VPORT_QUERY: /* Ioctls that just need their pointer argument extended. */ return openvswitch_ioctl(f, cmd, (unsigned long)compat_ptr(argp)); } @@ -1838,10 +1947,6 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned goto exit; switch (cmd) { - case ODP_VPORT_DUMP32: - err = compat_dump_port(dp, compat_ptr(argp)); - break; - case ODP_FLOW_PUT32: err = compat_put_flow(dp, compat_ptr(argp)); break; @@ -1851,7 +1956,7 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned break; case ODP_FLOW_GET32: - err = compat_flowvec_ioctl(dp, argp, compat_query_flows); + err = compat_query_flow(dp, compat_ptr(argp)); break; case ODP_FLOW_DUMP32: