X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=14779a60ff41bbc24d0ee5072f74cc8dfcdd20d9;hb=e9e28be359f64c03944c0a282c17e714fcb0afc4;hp=14d83cd9238b55e075e56e10308dfa7836adff7c;hpb=e3fdfed11b8c56aa6a8deffe11a552fed7e7adbc;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index 14d83cd9..14779a60 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -370,11 +370,6 @@ static int add_port(int dp_idx, struct odp_port __user *portp) if (copy_from_user(&port, portp, sizeof port)) goto out; port.devname[IFNAMSIZ - 1] = '\0'; - port_no = port.port; - - err = -EINVAL; - if (port_no < 0 || port_no >= DP_MAX_PORTS) - goto out; rtnl_lock(); dp = get_dp_locked(dp_idx); @@ -382,10 +377,13 @@ static int add_port(int dp_idx, struct odp_port __user *portp) if (!dp) goto out_unlock_rtnl; - err = -EEXIST; - if (dp->ports[port_no]) - goto out_unlock_dp; + for (port_no = 1; port_no < DP_MAX_PORTS; port_no++) + if (!dp->ports[port_no]) + goto got_port_no; + err = -EXFULL; + goto out_unlock_dp; +got_port_no: if (!(port.flags & ODP_PORT_INTERNAL)) { err = -ENODEV; dev = dev_get_by_name(&init_net, port.devname); @@ -411,6 +409,8 @@ static int add_port(int dp_idx, struct odp_port __user *portp) if (dp_add_if_hook) dp_add_if_hook(dp->ports[port_no]); + err = __put_user(port_no, &port.port); + out_put: dev_put(dev); out_unlock_dp: @@ -831,6 +831,7 @@ static void get_stats(struct sw_flow *flow, struct odp_flow_stats *stats) stats->n_bytes = flow->byte_count; stats->ip_tos = flow->ip_tos; stats->tcp_flags = flow->tcp_flags; + stats->error = 0; } static void clear_stats(struct sw_flow *flow) @@ -959,8 +960,6 @@ static int put_actions(const struct sw_flow *flow, struct odp_flow __user *ufp) if (!n_actions) return 0; - if (ufp->n_actions > INT_MAX / sizeof(union odp_action)) - return -EINVAL; sf_acts = rcu_dereference(flow->sf_acts); if (__put_user(sf_acts->n_actions, &ufp->n_actions) || @@ -986,9 +985,7 @@ static int answer_query(struct sw_flow *flow, struct odp_flow __user *ufp) return put_actions(flow, ufp); } -static int del_or_query_flow(struct datapath *dp, - struct odp_flow __user *ufp, - unsigned int cmd) +static int del_flow(struct datapath *dp, struct odp_flow __user *ufp) { struct dp_table *table = rcu_dereference(dp->table); struct odp_flow uf; @@ -1005,29 +1002,24 @@ static int del_or_query_flow(struct datapath *dp, if (!flow) goto error; - if (cmd == ODP_FLOW_DEL) { - /* XXX redundant lookup */ - error = dp_table_delete(table, flow); - if (error) - goto error; + /* XXX redundant lookup */ + error = dp_table_delete(table, flow); + if (error) + goto error; - /* XXX These statistics might lose a few packets, since other - * CPUs can be using this flow. We used to synchronize_rcu() - * to make sure that we get completely accurate stats, but that - * blows our performance, badly. */ - dp->n_flows--; - error = answer_query(flow, ufp); - flow_deferred_free(flow); - } else { - error = answer_query(flow, ufp); - } + /* XXX These statistics might lose a few packets, since other CPUs can + * be using this flow. We used to synchronize_rcu() to make sure that + * we get completely accurate stats, but that blows our performance, + * badly. */ + dp->n_flows--; + error = answer_query(flow, ufp); + flow_deferred_free(flow); error: return error; } -static int query_multiple_flows(struct datapath *dp, - const struct odp_flowvec *flowvec) +static int query_flows(struct datapath *dp, const struct odp_flowvec *flowvec) { struct dp_table *table = rcu_dereference(dp->table); int i; @@ -1043,7 +1035,7 @@ static int query_multiple_flows(struct datapath *dp, flow = dp_table_lookup(table, &uf.key); if (!flow) - error = __clear_user(&ufp->stats, sizeof ufp->stats); + error = __put_user(ENOENT, &ufp->stats.error); else error = answer_query(flow, ufp); if (error) @@ -1176,8 +1168,7 @@ error: return err; } -static int -get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp) +static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp) { struct odp_stats stats; int i; @@ -1269,7 +1260,7 @@ list_ports(struct datapath *dp, struct odp_portvec __user *pvp) break; } } - return put_user(idx, &pvp->n_ports); + return put_user(dp->n_ports, &pvp->n_ports); } /* RCU callback for freeing a dp_port_group */ @@ -1353,24 +1344,28 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, /* Handle commands with special locking requirements up front. */ switch (cmd) { case ODP_DP_CREATE: - return create_dp(dp_idx, (char __user *)argp); + err = create_dp(dp_idx, (char __user *)argp); + goto exit; case ODP_DP_DESTROY: - return destroy_dp(dp_idx); + err = destroy_dp(dp_idx); + goto exit; case ODP_PORT_ADD: - return add_port(dp_idx, (struct odp_port __user *)argp); + err = add_port(dp_idx, (struct odp_port __user *)argp); + goto exit; case ODP_PORT_DEL: err = get_user(port_no, (int __user *)argp); - if (err) - break; - return del_port(dp_idx, port_no); + if (!err) + err = del_port(dp_idx, port_no); + goto exit; } dp = get_dp_locked(dp_idx); + err = -ENODEV; if (!dp) - return -ENODEV; + goto exit; switch (cmd) { case ODP_DP_STATS: @@ -1432,13 +1427,11 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, break; case ODP_FLOW_DEL: - case ODP_FLOW_GET: - err = del_or_query_flow(dp, (struct odp_flow __user *)argp, - cmd); + err = del_flow(dp, (struct odp_flow __user *)argp); break; - case ODP_FLOW_GET_MULTIPLE: - err = do_flowvec_ioctl(dp, argp, query_multiple_flows); + case ODP_FLOW_GET: + err = do_flowvec_ioctl(dp, argp, query_flows); break; case ODP_FLOW_LIST: @@ -1454,6 +1447,7 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, break; } mutex_unlock(&dp->mutex); +exit: return err; }