X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=b95c8f25539fc5d98f44707804c78f44fc629a3c;hb=4faaba2b90979e1106b8c9b0430481f2cc62364d;hp=ffe3bd86943d2f0e0030ce8f593e431539a04b14;hpb=b9298d3f825703063c9538aa37407da43e1e4781;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index ffe3bd86..b95c8f25 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -67,7 +67,7 @@ EXPORT_SYMBOL(dp_ioctl_hook); * It is safe to access the datapath and vport structures with just * dp_mutex. */ -static struct datapath *dps[ODP_MAX]; +static struct datapath __rcu *dps[ODP_MAX]; static DEFINE_MUTEX(dp_mutex); static int new_vport(struct datapath *, struct odp_port *, int port_no); @@ -77,7 +77,8 @@ struct datapath *get_dp(int dp_idx) { if (dp_idx < 0 || dp_idx >= ODP_MAX) return NULL; - return rcu_dereference(dps[dp_idx]); + return rcu_dereference_check(dps[dp_idx], rcu_read_lock_held() || + lockdep_is_held(&dp_mutex)); } EXPORT_SYMBOL_GPL(get_dp); @@ -93,10 +94,15 @@ static struct datapath *get_dp_locked(int dp_idx) return dp; } +static struct tbl *get_table_protected(struct datapath *dp) +{ + return rcu_dereference_protected(dp->table, lockdep_is_held(&dp->mutex)); +} + /* Must be called with rcu_read_lock or RTNL lock. */ const char *dp_name(const struct datapath *dp) { - return vport_get_name(dp->ports[ODPP_LOCAL]); + return vport_get_name(rcu_dereference_rtnl(dp->ports[ODPP_LOCAL])); } static inline size_t br_nlmsg_size(void) @@ -139,7 +145,8 @@ static int dp_fill_ifinfo(struct sk_buff *skb, hdr->ifi_change = 0; NLA_PUT_STRING(skb, IFLA_IFNAME, vport_get_name(port)); - NLA_PUT_U32(skb, IFLA_MASTER, vport_get_ifindex(dp->ports[ODPP_LOCAL])); + NLA_PUT_U32(skb, IFLA_MASTER, + vport_get_ifindex(rtnl_dereference(dp->ports[ODPP_LOCAL]))); NLA_PUT_U32(skb, IFLA_MTU, vport_get_mtu(port)); #ifdef IFLA_OPERSTATE NLA_PUT_U8(skb, IFLA_OPERSTATE, @@ -263,8 +270,10 @@ static int create_dp(int dp_idx, const char __user *devnamep) dp->drop_frags = 0; dp->stats_percpu = alloc_percpu(struct dp_stats_percpu); - if (!dp->stats_percpu) + if (!dp->stats_percpu) { + err = -ENOMEM; goto err_destroy_local_port; + } rcu_assign_pointer(dps[dp_idx], dp); dp_sysfs_add_dp(dp); @@ -493,7 +502,8 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) flow_node = tbl_lookup(rcu_dereference(dp->table), &key, flow_hash(&key), flow_cmp); if (unlikely(!flow_node)) { - dp_output_control(dp, skb, _ODPL_MISS_NR, OVS_CB(skb)->tun_id); + dp_output_control(dp, skb, _ODPL_MISS_NR, + (__force u64)OVS_CB(skb)->tun_id); stats_counter_off = offsetof(struct dp_stats_percpu, n_missed); goto out; } @@ -501,6 +511,7 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) OVS_CB(skb)->flow = flow_cast(flow_node); } + stats_counter_off = offsetof(struct dp_stats_percpu, n_hit); flow_used(OVS_CB(skb)->flow, skb); acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts); @@ -511,13 +522,13 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) loop->looping = true; if (unlikely(loop->looping)) { loop_suppress(dp, acts); + kfree_skb(skb); goto out_loop; } /* Execute actions. */ execute_actions(dp, skb, &OVS_CB(skb)->flow->key, acts->actions, acts->actions_len); - stats_counter_off = offsetof(struct dp_stats_percpu, n_hit); /* Check whether sub-actions looped too much. */ if (unlikely(loop->looping)) @@ -609,16 +620,12 @@ int dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no, * userspace may try to stuff a 64kB packet into a 1500-byte MTU. */ if (skb_is_gso(skb)) { struct sk_buff *nskb = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM); - if (nskb) { - kfree_skb(skb); - skb = nskb; - if (unlikely(IS_ERR(skb))) { - err = PTR_ERR(skb); - goto err; - } - } else { - /* XXX This case might not be possible. It's hard to - * tell from the skb_gso_segment() code and comment. */ + + kfree_skb(skb); + skb = nskb; + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto err; } } @@ -643,7 +650,7 @@ err: static int flush_flows(struct datapath *dp) { - struct tbl *old_table = rcu_dereference(dp->table); + struct tbl *old_table = get_table_protected(dp); struct tbl *new_table; new_table = tbl_create(0); @@ -740,7 +747,9 @@ static struct sw_flow_actions *get_actions(const struct odp_flow *flow) goto error; error = -EFAULT; - if (copy_from_user(actions->actions, flow->actions, flow->actions_len)) + if (copy_from_user(actions->actions, + (struct nlattr __user *)flow->actions, + flow->actions_len)) goto error_free_actions; error = validate_actions(actions->actions, actions->actions_len); if (error) @@ -788,7 +797,7 @@ static void clear_stats(struct sw_flow *flow) static int expand_table(struct datapath *dp) { - struct tbl *old_table = rcu_dereference(dp->table); + struct tbl *old_table = get_table_protected(dp); struct tbl *new_table; new_table = tbl_expand(old_table); @@ -808,9 +817,11 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf, struct sw_flow *flow; struct tbl *table; int error; + u32 hash; - table = rcu_dereference(dp->table); - flow_node = tbl_lookup(table, &uf->flow.key, flow_hash(&uf->flow.key), flow_cmp); + hash = flow_hash(&uf->flow.key); + table = get_table_protected(dp); + flow_node = tbl_lookup(table, &uf->flow.key, hash, flow_cmp); if (!flow_node) { /* No such flow. */ struct sw_flow_actions *acts; @@ -824,7 +835,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf, error = expand_table(dp); if (error) goto error; - table = rcu_dereference(dp->table); + table = get_table_protected(dp); } /* Allocate flow. */ @@ -844,7 +855,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf, rcu_assign_pointer(flow->sf_acts, acts); /* Put flow in bucket. */ - error = tbl_insert(table, &flow->tbl_node, flow_hash(&flow->key)); + error = tbl_insert(table, &flow->tbl_node, hash); if (error) goto error_free_flow_acts; @@ -865,7 +876,9 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf, error = PTR_ERR(new_acts); if (IS_ERR(new_acts)) goto error; - old_acts = rcu_dereference(flow->sf_acts); + + old_acts = rcu_dereference_protected(flow->sf_acts, + lockdep_is_held(&dp->mutex)); if (old_acts->actions_len != new_acts->actions_len || memcmp(old_acts->actions, new_acts->actions, old_acts->actions_len)) { @@ -914,7 +927,8 @@ static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp) return 0; } -static int do_answer_query(struct sw_flow *flow, u32 query_flags, +static int do_answer_query(struct datapath *dp, struct sw_flow *flow, + u32 query_flags, struct odp_flow_stats __user *ustats, struct nlattr __user *actions, u32 __user *actions_lenp) @@ -937,7 +951,8 @@ static int do_answer_query(struct sw_flow *flow, u32 query_flags, if (!actions_len) return 0; - sf_acts = rcu_dereference(flow->sf_acts); + sf_acts = rcu_dereference_protected(flow->sf_acts, + lockdep_is_held(&dp->mutex)); if (put_user(sf_acts->actions_len, actions_lenp) || (actions && copy_to_user(actions, sf_acts->actions, min(sf_acts->actions_len, actions_len)))) @@ -946,21 +961,21 @@ static int do_answer_query(struct sw_flow *flow, u32 query_flags, return 0; } -static int answer_query(struct sw_flow *flow, u32 query_flags, - struct odp_flow __user *ufp) +static int answer_query(struct datapath *dp, struct sw_flow *flow, + u32 query_flags, struct odp_flow __user *ufp) { - struct nlattr *actions; + struct nlattr __user *actions; - if (get_user(actions, &ufp->actions)) + if (get_user(actions, (struct nlattr __user * __user *)&ufp->actions)) return -EFAULT; - return do_answer_query(flow, query_flags, + return do_answer_query(dp, flow, query_flags, &ufp->stats, actions, &ufp->actions_len); } static struct sw_flow *do_del_flow(struct datapath *dp, struct odp_flow_key *key) { - struct tbl *table = rcu_dereference(dp->table); + struct tbl *table = get_table_protected(dp); struct tbl_node *flow_node; int error; @@ -992,18 +1007,18 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp) if (IS_ERR(flow)) return PTR_ERR(flow); - error = answer_query(flow, 0, ufp); + error = answer_query(dp, flow, 0, ufp); flow_deferred_free(flow); return error; } static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec) { - struct tbl *table = rcu_dereference(dp->table); + struct tbl *table = get_table_protected(dp); u32 i; for (i = 0; i < flowvec->n_flows; i++) { - struct odp_flow __user *ufp = &flowvec->flows[i]; + struct odp_flow __user *ufp = (struct odp_flow __user *)&flowvec->flows[i]; struct odp_flow uf; struct tbl_node *flow_node; int error; @@ -1015,7 +1030,7 @@ static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec if (!flow_node) error = put_user(ENOENT, &ufp->stats.error); else - error = answer_query(flow_cast(flow_node), uf.flags, ufp); + error = answer_query(dp, flow_cast(flow_node), uf.flags, ufp); if (error) return -EFAULT; } @@ -1023,6 +1038,7 @@ static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec } struct list_flows_cbdata { + struct datapath *dp; struct odp_flow __user *uflows; u32 n_flows; u32 listed_flows; @@ -1037,7 +1053,7 @@ static int list_flow(struct tbl_node *node, void *cbdata_) if (copy_to_user(&ufp->key, &flow->key, sizeof flow->key)) return -EFAULT; - error = answer_query(flow, 0, ufp); + error = answer_query(cbdata->dp, flow, 0, ufp); if (error) return error; @@ -1054,11 +1070,12 @@ static int do_list_flows(struct datapath *dp, const struct odp_flowvec *flowvec) if (!flowvec->n_flows) return 0; - cbdata.uflows = flowvec->flows; + cbdata.dp = dp; + cbdata.uflows = (struct odp_flow __user *)flowvec->flows; cbdata.n_flows = flowvec->n_flows; cbdata.listed_flows = 0; - error = tbl_foreach(rcu_dereference(dp->table), list_flow, &cbdata); + error = tbl_foreach(get_table_protected(dp), list_flow, &cbdata); return error ? error : cbdata.listed_flows; } @@ -1103,7 +1120,8 @@ static int do_execute(struct datapath *dp, const struct odp_execute *execute) } err = -EFAULT; - if (copy_from_user(actions->actions, execute->actions, execute->actions_len)) + if (copy_from_user(actions->actions, + (struct nlattr __user *)execute->actions, execute->actions_len)) goto error_free_actions; err = validate_actions(actions->actions, execute->actions_len); @@ -1116,7 +1134,8 @@ static int do_execute(struct datapath *dp, const struct odp_execute *execute) goto error_free_actions; err = -EFAULT; - if (copy_from_user(skb_put(skb, execute->length), execute->data, + if (copy_from_user(skb_put(skb, execute->length), + (const void __user *)execute->data, execute->length)) goto error_free_skb; @@ -1162,7 +1181,7 @@ 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 = rcu_dereference(dp->table); + struct tbl *table = get_table_protected(dp); struct odp_stats stats; int i; @@ -1320,7 +1339,8 @@ static int list_ports(struct datapath *dp, struct odp_portvec __user *upv) if (copy_from_user(&pv, upv, sizeof pv)) return -EFAULT; - retval = do_list_ports(dp, pv.ports, pv.n_ports); + retval = do_list_ports(dp, (struct odp_port __user *)pv.ports, + pv.n_ports); if (retval < 0) return retval; @@ -1524,7 +1544,7 @@ static int compat_get_flow(struct odp_flow *flow, const struct compat_odp_flow _ __get_user(flow->flags, &compat->flags)) return -EFAULT; - flow->actions = compat_ptr(actions); + flow->actions = (struct nlattr __force *)compat_ptr(actions); return 0; } @@ -1549,7 +1569,8 @@ static int compat_put_flow(struct datapath *dp, struct compat_odp_flow_put __use return 0; } -static int compat_answer_query(struct sw_flow *flow, u32 query_flags, +static int compat_answer_query(struct datapath *dp, struct sw_flow *flow, + u32 query_flags, struct compat_odp_flow __user *ufp) { compat_uptr_t actions; @@ -1557,7 +1578,7 @@ static int compat_answer_query(struct sw_flow *flow, u32 query_flags, if (get_user(actions, &ufp->actions)) return -EFAULT; - return do_answer_query(flow, query_flags, &ufp->stats, + return do_answer_query(dp, flow, query_flags, &ufp->stats, compat_ptr(actions), &ufp->actions_len); } @@ -1574,14 +1595,16 @@ static int compat_del_flow(struct datapath *dp, struct compat_odp_flow __user *u if (IS_ERR(flow)) return PTR_ERR(flow); - error = compat_answer_query(flow, 0, ufp); + error = compat_answer_query(dp, flow, 0, ufp); flow_deferred_free(flow); return error; } -static int compat_query_flows(struct datapath *dp, struct compat_odp_flow *flows, u32 n_flows) +static int compat_query_flows(struct datapath *dp, + struct compat_odp_flow __user *flows, + u32 n_flows) { - struct tbl *table = rcu_dereference(dp->table); + struct tbl *table = get_table_protected(dp); u32 i; for (i = 0; i < n_flows; i++) { @@ -1597,7 +1620,8 @@ static int compat_query_flows(struct datapath *dp, struct compat_odp_flow *flows if (!flow_node) error = put_user(ENOENT, &ufp->stats.error); else - error = compat_answer_query(flow_cast(flow_node), uf.flags, ufp); + error = compat_answer_query(dp, flow_cast(flow_node), + uf.flags, ufp); if (error) return -EFAULT; } @@ -1605,6 +1629,7 @@ static int compat_query_flows(struct datapath *dp, struct compat_odp_flow *flows } struct compat_list_flows_cbdata { + struct datapath *dp; struct compat_odp_flow __user *uflows; u32 n_flows; u32 listed_flows; @@ -1619,7 +1644,7 @@ static int compat_list_flow(struct tbl_node *node, void *cbdata_) if (copy_to_user(&ufp->key, &flow->key, sizeof flow->key)) return -EFAULT; - error = compat_answer_query(flow, 0, ufp); + error = compat_answer_query(cbdata->dp, flow, 0, ufp); if (error) return error; @@ -1628,7 +1653,8 @@ static int compat_list_flow(struct tbl_node *node, void *cbdata_) return 0; } -static int compat_list_flows(struct datapath *dp, struct compat_odp_flow *flows, u32 n_flows) +static int compat_list_flows(struct datapath *dp, + struct compat_odp_flow __user *flows, u32 n_flows) { struct compat_list_flows_cbdata cbdata; int error; @@ -1636,17 +1662,18 @@ static int compat_list_flows(struct datapath *dp, struct compat_odp_flow *flows, if (!n_flows) return 0; + cbdata.dp = dp; cbdata.uflows = flows; cbdata.n_flows = n_flows; cbdata.listed_flows = 0; - error = tbl_foreach(rcu_dereference(dp->table), compat_list_flow, &cbdata); + error = tbl_foreach(get_table_protected(dp), compat_list_flow, &cbdata); return error ? error : cbdata.listed_flows; } static int compat_flowvec_ioctl(struct datapath *dp, unsigned long argp, int (*function)(struct datapath *, - struct compat_odp_flow *, + struct compat_odp_flow __user *, u32 n_flows)) { struct compat_odp_flowvec __user *uflowvec; @@ -1686,8 +1713,8 @@ static int compat_execute(struct datapath *dp, const struct compat_odp_execute _ __get_user(execute.length, &uexecute->length)) return -EFAULT; - execute.actions = compat_ptr(actions); - execute.data = compat_ptr(data); + execute.actions = (struct nlattr __force *)compat_ptr(actions); + execute.data = (const void __force *)compat_ptr(data); return do_execute(dp, &execute); } @@ -1913,6 +1940,8 @@ success: u16 csum_start, csum_offset; get_skb_csum_pointers(skb, &csum_start, &csum_offset); + csum_start -= skb_headroom(skb); + BUG_ON(csum_start >= skb_headlen(skb)); retval = skb_copy_and_csum_datagram(skb, csum_start, buf + csum_start, copy_bytes - csum_start, &csum); @@ -1922,7 +1951,8 @@ success: copy_bytes = csum_start; csump = (__sum16 __user *)(buf + csum_start + csum_offset); - BUG_ON((char *)csump + sizeof(__sum16) > buf + nbytes); + BUG_ON((char __user *)csump + sizeof(__sum16) > + buf + nbytes); put_user(csum_fold(csum), csump); } } else @@ -1930,7 +1960,7 @@ success: } if (!retval) { - struct iovec __user iov; + struct iovec iov; iov.iov_base = buf; iov.iov_len = copy_bytes;