X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=e545cda0518a0aaae3b46bd3f8bc766a79da296c;hb=e86c8696eb0bc62f4a4ae45df5715cee73533408;hp=e62eaea130e0ce892bdf257862424e75844aeca8;hpb=312b427dab326ffacfc64daaa57ed4d31595302b;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index e62eaea1..e545cda0 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -277,18 +277,19 @@ static void do_destroy_dp(struct datapath *dp, struct list_head *dp_devs) struct net_bridge_port *p, *n; int i; + list_for_each_entry_safe (p, n, &dp->port_list, node) + if (p->port_no != ODPP_LOCAL) + dp_del_port(p, dp_devs); + if (dp_del_dp_hook) dp_del_dp_hook(dp); - /* Drop references to DP. */ - list_for_each_entry_safe (p, n, &dp->port_list, node) - dp_del_port(p, dp_devs); - rcu_assign_pointer(dps[dp->dp_idx], NULL); - /* Wait until no longer in use, then destroy it. */ - synchronize_rcu(); + dp_del_port(dp->ports[ODPP_LOCAL], dp_devs); + dp_table_destroy(dp->table, 1); + for (i = 0; i < DP_N_QUEUES; i++) skb_queue_purge(&dp->queues[i]); for (i = 0; i < DP_MAX_GROUPS; i++) @@ -369,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); @@ -381,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); @@ -410,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: @@ -830,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) @@ -958,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) || @@ -985,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; @@ -1004,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; @@ -1042,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) @@ -1175,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; @@ -1352,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: @@ -1431,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: @@ -1453,6 +1447,7 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd, break; } mutex_unlock(&dp->mutex); +exit: return err; } @@ -1469,6 +1464,7 @@ static int dp_has_packet_of_interest(struct datapath *dp, int listeners) ssize_t openvswitch_read(struct file *f, char __user *buf, size_t nbytes, loff_t *ppos) { + /* XXX is there sufficient synchronization here? */ int listeners = (int) f->private_data; int dp_idx = iminor(f->f_dentry->d_inode); struct datapath *dp = get_dp(dp_idx); @@ -1523,6 +1519,7 @@ error: static unsigned int openvswitch_poll(struct file *file, poll_table *wait) { + /* XXX is there sufficient synchronization here? */ int dp_idx = iminor(file->f_dentry->d_inode); struct datapath *dp = get_dp(dp_idx); unsigned int mask;