X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=b19123975ad1cca2fec2a958a734e3e048fb2840;hb=6adf1730c8e21a653faf1d614fdddb2cd7825670;hp=544f8cdffec29a164d389c11408214a5d3cdb58f;hpb=aa5a8fdca51153d25be8a90e3121cdeff011b684;p=sliver-openvswitch.git diff --git a/datapath/datapath.c b/datapath/datapath.c index 544f8cdff..b19123975 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -49,10 +49,15 @@ #include "datapath.h" #include "actions.h" #include "flow.h" -#include "loop_counter.h" #include "table.h" +#include "vlan.h" #include "vport-internal_dev.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \ + LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#error Kernels before 2.6.18 or after 3.0 are not supported by this version of Open vSwitch. +#endif + int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd); EXPORT_SYMBOL(dp_ioctl_hook); @@ -79,7 +84,7 @@ EXPORT_SYMBOL(dp_ioctl_hook); static LIST_HEAD(dps); static struct vport *new_vport(const struct vport_parms *); -static int queue_control_packets(struct datapath *, struct sk_buff *, +static int queue_userspace_packets(struct datapath *, struct sk_buff *, const struct dp_upcall_info *); /* Must be called with rcu_read_lock, genl_mutex, or RTNL lock. */ @@ -266,8 +271,6 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) struct datapath *dp = p->dp; struct dp_stats_percpu *stats; int stats_counter_off; - struct sw_flow_actions *acts; - struct loop_counter *loop; int error; OVS_CB(skb)->vport = p; @@ -275,24 +278,25 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) if (!OVS_CB(skb)->flow) { struct sw_flow_key key; struct tbl_node *flow_node; + int key_len; bool is_frag; /* Extract flow from 'skb' into 'key'. */ - error = flow_extract(skb, p->port_no, &key, &is_frag); + error = flow_extract(skb, p->port_no, &key, &key_len, &is_frag); if (unlikely(error)) { kfree_skb(skb); return; } if (is_frag && dp->drop_frags) { - kfree_skb(skb); + consume_skb(skb); stats_counter_off = offsetof(struct dp_stats_percpu, n_frags); goto out; } /* Look up flow. */ - flow_node = tbl_lookup(rcu_dereference(dp->table), &key, - flow_hash(&key), flow_cmp); + flow_node = tbl_lookup(rcu_dereference(dp->table), &key, key_len, + flow_hash(&key, key_len), flow_cmp); if (unlikely(!flow_node)) { struct dp_upcall_info upcall; @@ -312,32 +316,7 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) 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); - - /* Check whether we've looped too much. */ - loop = loop_get_counter(); - if (unlikely(++loop->count > MAX_LOOPS)) - 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); - - /* Check whether sub-actions looped too much. */ - if (unlikely(loop->looping)) - loop_suppress(dp, acts); - -out_loop: - /* Decrement loop counter. */ - if (!--loop->count) - loop->looping = false; - loop_put_counter(); + execute_actions(dp, skb); out: /* Update datapath statistics. */ @@ -358,7 +337,6 @@ static void copy_and_csum_skb(struct sk_buff *skb, void *to) get_skb_csum_pointers(skb, &csum_start, &csum_offset); csum_start -= skb_headroom(skb); - BUG_ON(csum_start >= skb_headlen(skb)); skb_copy_bits(skb, 0, to, csum_start); @@ -421,29 +399,28 @@ int dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_i WARN_ON_ONCE(skb_shared(skb)); - forward_ip_summed(skb); - - err = vswitch_skb_checksum_setup(skb); - if (err) - goto err_kfree_skb; + forward_ip_summed(skb, true); /* Break apart GSO packets into their component pieces. Otherwise * 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); - kfree_skb(skb); - skb = nskb; - if (IS_ERR(skb)) { - err = PTR_ERR(skb); + if (IS_ERR(nskb)) { + kfree_skb(skb); + err = PTR_ERR(nskb); goto err; } + consume_skb(skb); + skb = nskb; } - return queue_control_packets(dp, skb, upcall_info); + err = queue_userspace_packets(dp, skb, upcall_info); + if (err) + goto err; + + return 0; -err_kfree_skb: - kfree_skb(skb); err: local_bh_disable(); stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id()); @@ -461,19 +438,13 @@ err: * 'upcall_info'. There will be only one packet unless we broke up a GSO * packet. */ -static int queue_control_packets(struct datapath *dp, struct sk_buff *skb, +static int queue_userspace_packets(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_info *upcall_info) { u32 group = packet_mc_group(dp, upcall_info->cmd); struct sk_buff *nskb; - int port_no; int err; - if (OVS_CB(skb)->vport) - port_no = OVS_CB(skb)->vport->port_no; - else - port_no = ODPP_LOCAL; - do { struct odp_header *upcall; struct sk_buff *user_skb; /* to be queued to userspace */ @@ -483,8 +454,14 @@ static int queue_control_packets(struct datapath *dp, struct sk_buff *skb, nskb = skb->next; skb->next = NULL; + err = vlan_deaccel_tag(skb); + if (unlikely(err)) + goto err_kfree_skbs; + + if (nla_attr_size(skb->len) > USHRT_MAX) + goto err_kfree_skbs; + len = sizeof(struct odp_header); - len += nla_total_size(4); /* ODP_PACKET_ATTR_TYPE. */ len += nla_total_size(skb->len); len += nla_total_size(FLOW_BUFSIZE); if (upcall_info->userdata) @@ -530,7 +507,7 @@ static int queue_control_packets(struct datapath *dp, struct sk_buff *skb, if (err) goto err_kfree_skbs; - kfree_skb(skb); + consume_skb(skb); skb = nskb; } while (skb); return 0; @@ -575,7 +552,7 @@ static int validate_actions(const struct nlattr *attr) nla_for_each_nested(a, attr, rem) { static const u32 action_lens[ODP_ACTION_ATTR_MAX + 1] = { [ODP_ACTION_ATTR_OUTPUT] = 4, - [ODP_ACTION_ATTR_CONTROLLER] = 8, + [ODP_ACTION_ATTR_USERSPACE] = 8, [ODP_ACTION_ATTR_SET_DL_TCI] = 2, [ODP_ACTION_ATTR_STRIP_VLAN] = 0, [ODP_ACTION_ATTR_SET_DL_SRC] = ETH_ALEN, @@ -588,7 +565,6 @@ static int validate_actions(const struct nlattr *attr) [ODP_ACTION_ATTR_SET_TUNNEL] = 8, [ODP_ACTION_ATTR_SET_PRIORITY] = 4, [ODP_ACTION_ATTR_POP_PRIORITY] = 0, - [ODP_ACTION_ATTR_DROP_SPOOFED_ARP] = 0, }; int type = nla_type(a); @@ -599,7 +575,7 @@ static int validate_actions(const struct nlattr *attr) case ODP_ACTION_ATTR_UNSPEC: return -EINVAL; - case ODP_ACTION_ATTR_CONTROLLER: + case ODP_ACTION_ATTR_USERSPACE: case ODP_ACTION_ATTR_STRIP_VLAN: case ODP_ACTION_ATTR_SET_DL_SRC: case ODP_ACTION_ATTR_SET_DL_DST: @@ -610,7 +586,6 @@ static int validate_actions(const struct nlattr *attr) case ODP_ACTION_ATTR_SET_TUNNEL: case ODP_ACTION_ATTR_SET_PRIORITY: case ODP_ACTION_ATTR_POP_PRIORITY: - case ODP_ACTION_ATTR_DROP_SPOOFED_ARP: /* No validation needed. */ break; @@ -654,11 +629,13 @@ static int expand_table(struct datapath *dp) struct tbl *new_table; new_table = tbl_expand(old_table); - if (IS_ERR(new_table)) - return PTR_ERR(new_table); - - rcu_assign_pointer(dp->table, new_table); - tbl_deferred_destroy(old_table, NULL); + if (IS_ERR(new_table)) { + if (PTR_ERR(new_table) != -ENOSPC) + return PTR_ERR(new_table); + } else { + rcu_assign_pointer(dp->table, new_table); + tbl_deferred_destroy(old_table, NULL); + } return 0; } @@ -667,28 +644,34 @@ static int odp_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) { struct odp_header *odp_header = info->userhdr; struct nlattr **a = info->attrs; + struct sw_flow_actions *acts; struct sk_buff *packet; - struct sw_flow_key key; + struct sw_flow *flow; struct datapath *dp; struct ethhdr *eth; bool is_frag; + int len; int err; + int key_len; err = -EINVAL; - if (!a[ODP_PACKET_ATTR_PACKET] || !a[ODP_PACKET_ATTR_ACTIONS] || + if (!a[ODP_PACKET_ATTR_PACKET] || !a[ODP_PACKET_ATTR_KEY] || + !a[ODP_PACKET_ATTR_ACTIONS] || nla_len(a[ODP_PACKET_ATTR_PACKET]) < ETH_HLEN) - goto exit; + goto err; err = validate_actions(a[ODP_PACKET_ATTR_ACTIONS]); if (err) - goto exit; + goto err; - packet = skb_clone(skb, GFP_KERNEL); + len = nla_len(a[ODP_PACKET_ATTR_PACKET]); + packet = __dev_alloc_skb(NET_IP_ALIGN + len, GFP_KERNEL); err = -ENOMEM; if (!packet) - goto exit; - packet->data = nla_data(a[ODP_PACKET_ATTR_PACKET]); - packet->len = nla_len(a[ODP_PACKET_ATTR_PACKET]); + goto err; + skb_reserve(packet, NET_IP_ALIGN); + + memcpy(__skb_put(packet, len), nla_data(a[ODP_PACKET_ATTR_PACKET]), len); skb_reset_mac_header(packet); eth = eth_hdr(packet); @@ -701,25 +684,55 @@ static int odp_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) else packet->protocol = htons(ETH_P_802_2); - err = flow_extract(packet, -1, &key, &is_frag); + /* Build an sw_flow for sending this packet. */ + flow = flow_alloc(); + err = PTR_ERR(flow); + if (IS_ERR(flow)) + goto err_kfree_skb; + + err = flow_extract(packet, -1, &flow->key, &key_len, &is_frag); if (err) - goto exit; + goto err_flow_put; + flow->tbl_node.hash = flow_hash(&flow->key, key_len); + + err = flow_metadata_from_nlattrs(&flow->key.eth.in_port, + &flow->key.eth.tun_id, + a[ODP_PACKET_ATTR_KEY]); + if (err) + goto err_flow_put; + + acts = flow_actions_alloc(a[ODP_PACKET_ATTR_ACTIONS]); + err = PTR_ERR(acts); + if (IS_ERR(acts)) + goto err_flow_put; + rcu_assign_pointer(flow->sf_acts, acts); + + OVS_CB(packet)->flow = flow; rcu_read_lock(); dp = get_dp(odp_header->dp_ifindex); err = -ENODEV; - if (dp) - err = execute_actions(dp, packet, &key, - nla_data(a[ODP_PACKET_ATTR_ACTIONS]), - nla_len(a[ODP_PACKET_ATTR_ACTIONS])); + if (!dp) + goto err_unlock; + err = execute_actions(dp, packet); rcu_read_unlock(); -exit: + flow_put(flow); + return err; + +err_unlock: + rcu_read_unlock(); +err_flow_put: + flow_put(flow); +err_kfree_skb: + kfree_skb(packet); +err: return err; } static const struct nla_policy packet_policy[ODP_PACKET_ATTR_MAX + 1] = { [ODP_PACKET_ATTR_PACKET] = { .type = NLA_UNSPEC }, + [ODP_PACKET_ATTR_KEY] = { .type = NLA_NESTED }, [ODP_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, }; @@ -734,6 +747,9 @@ static struct genl_ops dp_packet_genl_ops[] = { static void get_dp_stats(struct datapath *dp, struct odp_stats *stats) { int i; + struct tbl *table = get_table_protected(dp); + + stats->n_flows = tbl_count(table); stats->n_frags = stats->n_hit = stats->n_missed = stats->n_lost = 0; for_each_possible_cpu(i) { @@ -774,6 +790,8 @@ int dp_min_mtu(const struct datapath *dp) continue; dev_mtu = vport_get_mtu(p); + if (!dev_mtu) + continue; if (!mtu || dev_mtu < mtu) mtu = dev_mtu; } @@ -828,7 +846,6 @@ static int odp_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, struct nlattr *nla; unsigned long used; u8 tcp_flags; - int nla_len; int err; sf_acts = rcu_dereference_protected(flow->sf_acts, @@ -856,7 +873,7 @@ static int odp_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, spin_unlock_bh(&flow->lock); if (used) - NLA_PUT_MSECS(skb, ODP_FLOW_ATTR_USED, used); + NLA_PUT_U64(skb, ODP_FLOW_ATTR_USED, flow_used_time(used)); if (stats.n_packets) NLA_PUT(skb, ODP_FLOW_ATTR_STATS, sizeof(struct odp_flow_stats), &stats); @@ -864,23 +881,20 @@ static int odp_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, if (tcp_flags) NLA_PUT_U8(skb, ODP_FLOW_ATTR_TCP_FLAGS, tcp_flags); - /* If ODP_FLOW_ATTR_ACTIONS doesn't fit, and this is the first flow to - * be dumped into 'skb', then expand the skb. This is unusual for - * Netlink but individual action lists can be longer than a page and - * thus entirely undumpable if we didn't do this. */ - nla_len = nla_total_size(sf_acts->actions_len); - if (nla_len > skb_tailroom(skb) && !skb_orig_len) { - int hdr_off = (unsigned char *)odp_header - skb->data; - - err = pskb_expand_head(skb, 0, nla_len - skb_tailroom(skb), GFP_KERNEL); - if (err) - goto error; - - odp_header = (struct odp_header *)(skb->data + hdr_off); - } - nla = nla_nest_start(skb, ODP_FLOW_ATTR_ACTIONS); - memcpy(__skb_put(skb, sf_acts->actions_len), sf_acts->actions, sf_acts->actions_len); - nla_nest_end(skb, nla); + /* If ODP_FLOW_ATTR_ACTIONS doesn't fit, skip dumping the actions if + * this is the first flow to be dumped into 'skb'. This is unusual for + * Netlink but individual action lists can be longer than + * NLMSG_GOODSIZE and thus entirely undumpable if we didn't do this. + * The userspace caller can always fetch the actions separately if it + * really wants them. (Most userspace callers in fact don't care.) + * + * This can only fail for dump operations because the skb is always + * properly sized for single flows. + */ + err = nla_put(skb, ODP_FLOW_ATTR_ACTIONS, sf_acts->actions_len, + sf_acts->actions); + if (err < 0 && skb_orig_len) + goto error; return genlmsg_end(skb, odp_header); @@ -934,12 +948,13 @@ static int odp_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) struct tbl *table; u32 hash; int error; + int key_len; /* Extract key. */ error = -EINVAL; if (!a[ODP_FLOW_ATTR_KEY]) goto error; - error = flow_from_nlattrs(&key, a[ODP_FLOW_ATTR_KEY]); + error = flow_from_nlattrs(&key, &key_len, a[ODP_FLOW_ATTR_KEY]); if (error) goto error; @@ -958,9 +973,9 @@ static int odp_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) if (!dp) goto error; - hash = flow_hash(&key); + hash = flow_hash(&key, key_len); table = get_table_protected(dp); - flow_node = tbl_lookup(table, &key, hash, flow_cmp); + flow_node = tbl_lookup(table, &key, key_len, hash, flow_cmp); if (!flow_node) { struct sw_flow_actions *acts; @@ -1070,10 +1085,11 @@ static int odp_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) struct datapath *dp; struct tbl *table; int err; + int key_len; if (!a[ODP_FLOW_ATTR_KEY]) return -EINVAL; - err = flow_from_nlattrs(&key, a[ODP_FLOW_ATTR_KEY]); + err = flow_from_nlattrs(&key, &key_len, a[ODP_FLOW_ATTR_KEY]); if (err) return err; @@ -1082,7 +1098,8 @@ static int odp_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) return -ENODEV; table = get_table_protected(dp); - flow_node = tbl_lookup(table, &key, flow_hash(&key), flow_cmp); + flow_node = tbl_lookup(table, &key, key_len, flow_hash(&key, key_len), + flow_cmp); if (!flow_node) return -ENOENT; @@ -1105,10 +1122,11 @@ static int odp_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) struct datapath *dp; struct tbl *table; int err; + int key_len; if (!a[ODP_FLOW_ATTR_KEY]) return flush_flows(odp_header->dp_ifindex); - err = flow_from_nlattrs(&key, a[ODP_FLOW_ATTR_KEY]); + err = flow_from_nlattrs(&key, &key_len, a[ODP_FLOW_ATTR_KEY]); if (err) return err; @@ -1117,7 +1135,8 @@ static int odp_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) return -ENODEV; table = get_table_protected(dp); - flow_node = tbl_lookup(table, &key, flow_hash(&key), flow_cmp); + flow_node = tbl_lookup(table, &key, key_len, flow_hash(&key, key_len), + flow_cmp); if (!flow_node) return -ENOENT; flow = flow_cast(flow_node); @@ -1293,7 +1312,7 @@ static int odp_dp_cmd_validate(struct nlattr *a[ODP_DP_ATTR_MAX + 1]) return -EINVAL; } - return VERIFY_NUL_STRING(a[ODP_DP_ATTR_NAME], IFNAMSIZ - 1); + return CHECK_NUL_STRING(a[ODP_DP_ATTR_NAME], IFNAMSIZ - 1); } /* Called with genl_mutex and optionally with RTNL lock also. */ @@ -1445,12 +1464,20 @@ static int odp_dp_cmd_del(struct sk_buff *skb, struct genl_info *info) list_del(&dp->list_node); dp_detach_port(get_vport_protected(dp, ODPP_LOCAL)); + /* rtnl_unlock() will wait until all the references to devices that + * are pending unregistration have been dropped. We do it here to + * ensure that any internal devices (which contain DP pointers) are + * fully destroyed before freeing the datapath. + */ + rtnl_unlock(); + call_rcu(&dp->rcu, destroy_dp_rcu); module_put(THIS_MODULE); genl_notify(reply, genl_info_net(info), info->snd_pid, dp_datapath_multicast_group.id, info->nlhdr, GFP_KERNEL); - err = 0; + + return 0; exit_unlock: rtnl_unlock(); @@ -1587,6 +1614,7 @@ static int odp_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, struct odp_header *odp_header; struct nlattr *nla; int ifindex, iflink; + int mtu; int err; odp_header = genlmsg_put(skb, pid, seq, &dp_vport_genl_family, @@ -1608,7 +1636,9 @@ static int odp_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, 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)); + mtu = vport_get_mtu(vport); + if (mtu) + NLA_PUT_U32(skb, ODP_VPORT_ATTR_MTU, mtu); err = vport_get_options(vport, skb); if (err == -EMSGSIZE) @@ -1652,7 +1682,7 @@ static struct sk_buff *odp_vport_cmd_build_info(struct vport *vport, u32 pid, static int odp_vport_cmd_validate(struct nlattr *a[ODP_VPORT_ATTR_MAX + 1]) { - return VERIFY_NUL_STRING(a[ODP_VPORT_ATTR_NAME], IFNAMSIZ - 1); + return CHECK_NUL_STRING(a[ODP_VPORT_ATTR_NAME], IFNAMSIZ - 1); } /* Called with RTNL lock or RCU read lock. */ @@ -1885,7 +1915,9 @@ static int odp_vport_cmd_get(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(reply)) goto exit_unlock; - err = genlmsg_reply(reply, info); + rcu_read_unlock(); + + return genlmsg_reply(reply, info); exit_unlock: rcu_read_unlock();