Store key_len and hash fields at the end of struct sw_flow_key, past the area being hashed. Rename functions operating on keys from "_flow_" to "_flow_key_". Shift the responsibility for key hashing from lookup and insert to key construction side, which helps avaiding unnecessary hash computations.
Signed-off-by: Jarno Rajahalme <jarno.rajaha...@nsn.com> --- datapath/datapath.c | 42 ++++++------ datapath/flow.c | 165 ++++++++++++++++++++++++------------------------ datapath/flow.h | 24 ++++--- datapath/vport-vxlan.c | 2 +- 4 files changed, 118 insertions(+), 115 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index 87c96ae..2e01740 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -209,18 +209,16 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) if (!OVS_CB(skb)->flow) { struct sw_flow_key key; - int key_len; /* Extract flow from 'skb' into 'key'. */ - error = ovs_flow_extract(skb, p->port_no, &key, &key_len); + error = ovs_flow_key_extract(skb, p->port_no, &key); if (unlikely(error)) { kfree_skb(skb); return; } /* Look up flow. */ - flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table), - &key, key_len); + flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table), &key); if (unlikely(!flow)) { struct dp_upcall_info upcall; @@ -318,12 +316,14 @@ static int queue_gso_packets(struct net *net, int dp_ifindex, break; if (skb == segs && gso_type & SKB_GSO_UDP) { - /* The initial flow key extracted by ovs_flow_extract() - * in this case is for a first fragment, so we need to - * properly mark later fragments. + /* The initial flow key extracted by + * ovs_flow_key_extract() in this case is for a first + * fragment, so we need to properly mark later + * fragments. */ later_key = *upcall_info->key; later_key.ip.frag = OVS_FRAG_TYPE_LATER; + ovs_flow_key_hash_set(&later_key); /* Update hash */ later_info = *upcall_info; later_info.key = &later_key; @@ -358,7 +358,7 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex, nskb = skb_clone(skb, GFP_ATOMIC); if (!nskb) return -ENOMEM; - + err = vlan_deaccel_tag(nskb); if (err) return err; @@ -388,7 +388,7 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex, upcall->dp_ifindex = dp_ifindex; nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); - ovs_flow_to_nlattrs(upcall_info->key, user_skb); + ovs_flow_key_to_nlattrs(upcall_info->key, user_skb); nla_nest_end(user_skb, nla); if (upcall_info->userdata) @@ -815,7 +815,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) struct ethhdr *eth; int len; int err; - int key_len; err = -EINVAL; if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] || @@ -849,11 +848,11 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(flow)) goto err_kfree_skb; - err = ovs_flow_extract(packet, -1, &flow->key, &key_len); + err = ovs_flow_key_extract(packet, -1, &flow->key); if (err) goto err_flow_free; - err = ovs_flow_metadata_from_nlattrs(flow, key_len, a[OVS_PACKET_ATTR_KEY]); + err = ovs_flow_key_metadata_from_nlattrs(&flow->key, a[OVS_PACKET_ATTR_KEY]); if (err) goto err_flow_free; acts = ovs_flow_actions_alloc(nla_len(a[OVS_PACKET_ATTR_ACTIONS])); @@ -1073,7 +1072,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY); if (!nla) goto nla_put_failure; - err = ovs_flow_to_nlattrs(&flow->key, skb); + err = ovs_flow_key_to_nlattrs(&flow->key, skb); if (err) goto error; nla_nest_end(skb, nla); @@ -1182,13 +1181,12 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) struct flow_table *table; struct sw_flow_actions *acts = NULL; int error; - int key_len; /* Extract key. */ error = -EINVAL; if (!a[OVS_FLOW_ATTR_KEY]) goto error; - error = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); + error = ovs_flow_key_from_nlattrs(&key, a[OVS_FLOW_ATTR_KEY]); if (error) goto error; @@ -1213,7 +1211,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) goto err_kfree; table = genl_dereference(dp->table); - flow = ovs_flow_tbl_lookup(table, &key, key_len); + flow = ovs_flow_tbl_lookup(table, &key); if (!flow) { /* Bail out if we're not allowed to create a new flow. */ error = -ENOENT; @@ -1243,7 +1241,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) rcu_assign_pointer(flow->sf_acts, acts); /* Put flow in bucket. */ - ovs_flow_tbl_insert(table, flow, &key, key_len); + ovs_flow_tbl_insert(table, flow, &key); reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, info->snd_seq, @@ -1305,11 +1303,10 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) struct datapath *dp; struct flow_table *table; int err; - int key_len; if (!a[OVS_FLOW_ATTR_KEY]) return -EINVAL; - err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); + err = ovs_flow_key_from_nlattrs(&key, a[OVS_FLOW_ATTR_KEY]); if (err) return err; @@ -1318,7 +1315,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) return -ENODEV; table = genl_dereference(dp->table); - flow = ovs_flow_tbl_lookup(table, &key, key_len); + flow = ovs_flow_tbl_lookup(table, &key); if (!flow) return -ENOENT; @@ -1340,7 +1337,6 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) struct datapath *dp; struct flow_table *table; int err; - int key_len; dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); if (!dp) @@ -1349,12 +1345,12 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) if (!a[OVS_FLOW_ATTR_KEY]) return flush_flows(dp); - err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); + err = ovs_flow_key_from_nlattrs(&key, a[OVS_FLOW_ATTR_KEY]); if (err) return err; table = genl_dereference(dp->table); - flow = ovs_flow_tbl_lookup(table, &key, key_len); + flow = ovs_flow_tbl_lookup(table, &key); if (!flow) return -ENOENT; diff --git a/datapath/flow.c b/datapath/flow.c index fad9e19..4c85e81 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -126,8 +126,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies) (offsetof(struct sw_flow_key, field) + \ FIELD_SIZEOF(struct sw_flow_key, field)) -static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key, - int *key_lenp) +static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) { unsigned int nh_ofs = skb_network_offset(skb); unsigned int nh_len; @@ -137,7 +136,7 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key, __be16 frag_off; int err; - *key_lenp = SW_FLOW_KEY_OFFSET(ipv6.label); + key->key_len = SW_FLOW_KEY_OFFSET(ipv6.label); err = check_header(skb, nh_ofs + sizeof(*nh)); if (unlikely(err)) @@ -351,14 +350,13 @@ struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *la (*bucket)++; *last = 0; } - return NULL; } static void __flow_tbl_insert(struct flow_table *table, struct sw_flow *flow) { struct hlist_head *head; - head = find_bucket(table, flow->hash); + head = find_bucket(table, flow->key.hash); hlist_add_head_rcu(&flow->hash_node[table->node_ver], head); table->count++; } @@ -504,18 +502,17 @@ static __be16 parse_ethertype(struct sk_buff *skb) } static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key, - int *key_lenp, int nh_len) + int nh_len) { struct icmp6hdr *icmp = icmp6_hdr(skb); int error = 0; - int key_len; /* The ICMPv6 type and code fields use the 16-bit transport port * fields, so we need to store them in 16-bit network byte order. */ key->ipv6.tp.src = htons(icmp->icmp6_type); key->ipv6.tp.dst = htons(icmp->icmp6_code); - key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); + key->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); if (icmp->icmp6_code == 0 && (icmp->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION || @@ -524,7 +521,7 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key, struct nd_msg *nd; int offset; - key_len = SW_FLOW_KEY_OFFSET(ipv6.nd); + key->key_len = SW_FLOW_KEY_OFFSET(ipv6.nd); /* In order to process neighbor discovery options, we need the * entire packet. @@ -538,7 +535,7 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key, nd = (struct nd_msg *)skb_transport_header(skb); key->ipv6.nd.target = nd->target; - key_len = SW_FLOW_KEY_OFFSET(ipv6.nd); + key->key_len = SW_FLOW_KEY_OFFSET(ipv6.nd); icmp_len -= sizeof(*nd); offset = 0; @@ -581,22 +578,24 @@ invalid: memset(key->ipv6.nd.tll, 0, sizeof(key->ipv6.nd.tll)); out: - *key_lenp = key_len; return error; } /** - * ovs_flow_extract - extracts a flow key from an Ethernet frame. + * ovs_flow_key_extract - extracts a flow key from an Ethernet frame. * @skb: sk_buff that contains the frame, with skb->data pointing to the * Ethernet header * @in_port: port number on which @skb was received. * @key: output flow key - * @key_lenp: length of output flow key * * The caller must ensure that skb->len >= ETH_HLEN. * * Returns 0 if successful, otherwise a negative errno value. * + * Initializes @key metadata fields and hash value only if @in_port != -1. + * If @in_port is -1 ovs_flow_key_metadata_from_nlattrs() must be called + * after this to initialize the metadata and hash fields. + * * Initializes @skb header pointers as follows: * * - skb->mac_header: the Ethernet header. @@ -609,20 +608,14 @@ out: * of a correct length, otherwise the same as skb->network_header. * For other key->dl_type values it is left untouched. */ -int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, - int *key_lenp) +int ovs_flow_key_extract(struct sk_buff *skb, u16 in_port, + struct sw_flow_key *key) { int error = 0; - int key_len = SW_FLOW_KEY_OFFSET(eth); struct ethhdr *eth; memset(key, 0, sizeof(*key)); - - key->phy.priority = skb->priority; - if (OVS_CB(skb)->tun_key) - memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key)); - key->phy.in_port = in_port; - key->phy.skb_mark = skb_get_mark(skb); + key->key_len = SW_FLOW_KEY_OFFSET(eth); skb_reset_mac_header(skb); @@ -653,7 +646,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, struct iphdr *nh; __be16 offset; - key_len = SW_FLOW_KEY_OFFSET(ipv4.addr); + key->key_len = SW_FLOW_KEY_OFFSET(ipv4.addr); error = check_iphdr(skb); if (unlikely(error)) { @@ -683,21 +676,21 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, /* Transport layer. */ if (key->ip.proto == IPPROTO_TCP) { - key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); + key->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); if (tcphdr_ok(skb)) { struct tcphdr *tcp = tcp_hdr(skb); key->ipv4.tp.src = tcp->source; key->ipv4.tp.dst = tcp->dest; } } else if (key->ip.proto == IPPROTO_UDP) { - key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); + key->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); if (udphdr_ok(skb)) { struct udphdr *udp = udp_hdr(skb); key->ipv4.tp.src = udp->source; key->ipv4.tp.dst = udp->dest; } } else if (key->ip.proto == IPPROTO_ICMP) { - key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); + key->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); if (icmphdr_ok(skb)) { struct icmphdr *icmp = icmp_hdr(skb); /* The ICMP type and code fields use the 16-bit @@ -726,12 +719,12 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst)); memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN); memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN); - key_len = SW_FLOW_KEY_OFFSET(ipv4.arp); + key->key_len = SW_FLOW_KEY_OFFSET(ipv4.arp); } } else if (key->eth.type == htons(ETH_P_IPV6)) { int nh_len; /* IPv6 Header + Extensions */ - nh_len = parse_ipv6hdr(skb, key, &key_len); + nh_len = parse_ipv6hdr(skb, key); if (unlikely(nh_len < 0)) { if (nh_len == -EINVAL) skb->transport_header = skb->network_header; @@ -747,23 +740,23 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, /* Transport layer. */ if (key->ip.proto == NEXTHDR_TCP) { - key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); + key->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); if (tcphdr_ok(skb)) { struct tcphdr *tcp = tcp_hdr(skb); key->ipv6.tp.src = tcp->source; key->ipv6.tp.dst = tcp->dest; } } else if (key->ip.proto == NEXTHDR_UDP) { - key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); + key->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); if (udphdr_ok(skb)) { struct udphdr *udp = udp_hdr(skb); key->ipv6.tp.src = udp->source; key->ipv6.tp.dst = udp->dest; } } else if (key->ip.proto == NEXTHDR_ICMP) { - key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); + key->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); if (icmp6hdr_ok(skb)) { - error = parse_icmpv6(skb, key, &key_len, nh_len); + error = parse_icmpv6(skb, key, nh_len); if (error < 0) goto out; } @@ -771,14 +764,24 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, } out: - *key_lenp = key_len; + if (in_port != -1 && !error) { + key->phy.priority = skb->priority; + if (OVS_CB(skb)->tun_key) + memcpy(&key->tun_key, OVS_CB(skb)->tun_key, + sizeof(key->tun_key)); + key->phy.in_port = in_port; + key->phy.skb_mark = skb_get_mark(skb); + + ovs_flow_key_hash_set(key); + } + return error; } -static u32 ovs_flow_hash(const struct sw_flow_key *key, int key_start, int key_len) +static u32 ovs_flow_hash(const struct sw_flow_key *key, int key_start) { return jhash2((u32 *)((u8 *)key + key_start), - DIV_ROUND_UP(key_len - key_start, sizeof(u32)), 0); + DIV_ROUND_UP(key->key_len - key_start, sizeof(u32)), 0); } static int flow_key_start(struct sw_flow_key *key) @@ -789,35 +792,38 @@ static int flow_key_start(struct sw_flow_key *key) return offsetof(struct sw_flow_key, phy); } +void ovs_flow_key_hash_set(struct sw_flow_key *key) +{ + key->hash = ovs_flow_hash(key, flow_key_start(key)); +} + struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table, - struct sw_flow_key *key, int key_len) + struct sw_flow_key *key) { struct sw_flow *flow; struct hlist_node *n; struct hlist_head *head; u8 *_key; int key_start; - u32 hash; key_start = flow_key_start(key); - hash = ovs_flow_hash(key, key_start, key_len); _key = (u8 *) key + key_start; - head = find_bucket(table, hash); + head = find_bucket(table, key->hash); hlist_for_each_entry_rcu(flow, n, head, hash_node[table->node_ver]) { - if (flow->hash == hash && - !memcmp((u8 *)&flow->key + key_start, _key, key_len - key_start)) { + if (flow->key.hash == key->hash && + !memcmp((u8 *)&flow->key + key_start, _key, key->key_len - key_start)) { return flow; } } + return NULL; } void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, - struct sw_flow_key *key, int key_len) + struct sw_flow_key *key) { - flow->hash = ovs_flow_hash(key, flow_key_start(key), key_len); memcpy(&flow->key, key, sizeof(flow->key)); __flow_tbl_insert(table, flow); } @@ -852,7 +858,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_TUN_ID] = sizeof(__be64), }; -static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, +static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *a[], u64 *attrs) { const struct ovs_key_icmp *icmp_key; @@ -865,7 +871,7 @@ static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, return -EINVAL; *attrs &= ~(1 << OVS_KEY_ATTR_TCP); - *key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]); swkey->ipv4.tp.src = tcp_key->tcp_src; swkey->ipv4.tp.dst = tcp_key->tcp_dst; @@ -876,7 +882,7 @@ static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, return -EINVAL; *attrs &= ~(1 << OVS_KEY_ATTR_UDP); - *key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); udp_key = nla_data(a[OVS_KEY_ATTR_UDP]); swkey->ipv4.tp.src = udp_key->udp_src; swkey->ipv4.tp.dst = udp_key->udp_dst; @@ -887,7 +893,7 @@ static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, return -EINVAL; *attrs &= ~(1 << OVS_KEY_ATTR_ICMP); - *key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); icmp_key = nla_data(a[OVS_KEY_ATTR_ICMP]); swkey->ipv4.tp.src = htons(icmp_key->icmp_type); swkey->ipv4.tp.dst = htons(icmp_key->icmp_code); @@ -897,7 +903,7 @@ static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, return 0; } -static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, +static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *a[], u64 *attrs) { const struct ovs_key_icmpv6 *icmpv6_key; @@ -910,7 +916,7 @@ static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, return -EINVAL; *attrs &= ~(1 << OVS_KEY_ATTR_TCP); - *key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]); swkey->ipv6.tp.src = tcp_key->tcp_src; swkey->ipv6.tp.dst = tcp_key->tcp_dst; @@ -921,7 +927,7 @@ static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, return -EINVAL; *attrs &= ~(1 << OVS_KEY_ATTR_UDP); - *key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); udp_key = nla_data(a[OVS_KEY_ATTR_UDP]); swkey->ipv6.tp.src = udp_key->udp_src; swkey->ipv6.tp.dst = udp_key->udp_dst; @@ -932,7 +938,7 @@ static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, return -EINVAL; *attrs &= ~(1 << OVS_KEY_ATTR_ICMPV6); - *key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); icmpv6_key = nla_data(a[OVS_KEY_ATTR_ICMPV6]); swkey->ipv6.tp.src = htons(icmpv6_key->icmpv6_type); swkey->ipv6.tp.dst = htons(icmpv6_key->icmpv6_code); @@ -945,7 +951,7 @@ static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, return -EINVAL; *attrs &= ~(1 << OVS_KEY_ATTR_ND); - *key_len = SW_FLOW_KEY_OFFSET(ipv6.nd); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.nd); nd_key = nla_data(a[OVS_KEY_ATTR_ND]); memcpy(&swkey->ipv6.nd.target, nd_key->nd_target, sizeof(swkey->ipv6.nd.target)); @@ -1087,23 +1093,21 @@ int ipv4_tun_to_nlattr(struct sk_buff *skb, } /** - * ovs_flow_from_nlattrs - parses Netlink attributes into a flow key. + * ovs_flow_key_from_nlattrs - parses Netlink attributes into a flow key. * @swkey: receives the extracted flow key. - * @key_lenp: number of bytes used in @swkey. * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute * sequence. */ -int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, - const struct nlattr *attr) +int ovs_flow_key_from_nlattrs(struct sw_flow_key *swkey, + const struct nlattr *attr) { const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; const struct ovs_key_ethernet *eth_key; - int key_len; u64 attrs; int err; memset(swkey, 0, sizeof(struct sw_flow_key)); - key_len = SW_FLOW_KEY_OFFSET(eth); + swkey->key_len = SW_FLOW_KEY_OFFSET(eth); err = parse_flow_nlattrs(attr, a, &attrs); if (err) @@ -1192,7 +1196,6 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, return -EINVAL; swkey->eth.type = htons(ETH_P_8021Q); - *key_lenp = key_len; return 0; } else { return -EINVAL; @@ -1215,7 +1218,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, return -EINVAL; attrs &= ~(1 << OVS_KEY_ATTR_IPV4); - key_len = SW_FLOW_KEY_OFFSET(ipv4.addr); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.addr); ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]); if (ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) return -EINVAL; @@ -1227,7 +1230,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, swkey->ipv4.addr.dst = ipv4_key->ipv4_dst; if (swkey->ip.frag != OVS_FRAG_TYPE_LATER) { - err = ipv4_flow_from_nlattrs(swkey, &key_len, a, &attrs); + err = ipv4_flow_from_nlattrs(swkey, a, &attrs); if (err) return err; } @@ -1238,7 +1241,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, return -EINVAL; attrs &= ~(1 << OVS_KEY_ATTR_IPV6); - key_len = SW_FLOW_KEY_OFFSET(ipv6.label); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.label); ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]); if (ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) return -EINVAL; @@ -1253,7 +1256,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, sizeof(swkey->ipv6.addr.dst)); if (swkey->ip.frag != OVS_FRAG_TYPE_LATER) { - err = ipv6_flow_from_nlattrs(swkey, &key_len, a, &attrs); + err = ipv6_flow_from_nlattrs(swkey, a, &attrs); if (err) return err; } @@ -1265,7 +1268,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, return -EINVAL; attrs &= ~(1 << OVS_KEY_ATTR_ARP); - key_len = SW_FLOW_KEY_OFFSET(ipv4.arp); + swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.arp); arp_key = nla_data(a[OVS_KEY_ATTR_ARP]); swkey->ipv4.addr.src = arp_key->arp_sip; swkey->ipv4.addr.dst = arp_key->arp_tip; @@ -1278,16 +1281,17 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, if (attrs) return -EINVAL; - *key_lenp = key_len; + + swkey->hash = ovs_flow_hash(swkey, flow_key_start(swkey)); return 0; } /** - * ovs_flow_metadata_from_nlattrs - parses Netlink attributes into a flow key. - * @in_port: receives the extracted input port. - * @tun_id: receives the extracted tunnel ID. - * @key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute + * ovs_flow_key_metadata_from_nlattrs - parses Netlink attributes into a flow + * key. + * @sw_flow_key: receives the extracted metadata. + * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute * sequence. * * This parses a series of Netlink attributes that form a flow key, which must @@ -1296,17 +1300,17 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, * extracted from the packet itself. */ -int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const struct nlattr *attr) +int ovs_flow_key_metadata_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *attr) { - struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key; + struct ovs_key_ipv4_tunnel *tun_key = &swkey->tun_key; const struct nlattr *nla; int rem; __be64 tun_id = 0; - flow->key.phy.in_port = DP_MAX_PORTS; - flow->key.phy.priority = 0; - flow->key.phy.skb_mark = 0; - memset(tun_key, 0, sizeof(flow->key.tun_key)); + swkey->phy.in_port = DP_MAX_PORTS; + swkey->phy.priority = 0; + swkey->phy.skb_mark = 0; + memset(tun_key, 0, sizeof(swkey->tun_key)); nla_for_each_nested(nla, attr, rem) { int type = nla_type(nla); @@ -1319,7 +1323,7 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru switch (type) { case OVS_KEY_ATTR_PRIORITY: - flow->key.phy.priority = nla_get_u32(nla); + swkey->phy.priority = nla_get_u32(nla); break; case OVS_KEY_ATTR_TUN_ID: @@ -1359,7 +1363,7 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru case OVS_KEY_ATTR_IN_PORT: if (nla_get_u32(nla) >= DP_MAX_PORTS) return -EINVAL; - flow->key.phy.in_port = nla_get_u32(nla); + swkey->phy.in_port = nla_get_u32(nla); break; case OVS_KEY_ATTR_SKB_MARK: @@ -1367,7 +1371,7 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru if (nla_get_u32(nla) != 0) return -EINVAL; #endif - flow->key.phy.skb_mark = nla_get_u32(nla); + swkey->phy.skb_mark = nla_get_u32(nla); break; } } @@ -1375,13 +1379,12 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru if (rem) return -EINVAL; - flow->hash = ovs_flow_hash(&flow->key, - flow_key_start(&flow->key), key_len); + swkey->hash = ovs_flow_hash(swkey, flow_key_start(swkey)); return 0; } -int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) +int ovs_flow_key_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) { struct ovs_key_ethernet *eth_key; struct nlattr *nla, *encap; diff --git a/datapath/flow.h b/datapath/flow.h index 6949640..dc9c000 100644 --- a/datapath/flow.h +++ b/datapath/flow.h @@ -112,12 +112,15 @@ struct sw_flow_key { } nd; } ipv6; }; + + /* Following fields are never included in key hash */ + int key_len; + u32 hash; /* Valid if key_len != 0 */ }; struct sw_flow { struct rcu_head rcu; struct hlist_node hash_node[2]; - u32 hash; struct sw_flow_key key; struct sw_flow_actions __rcu *sf_acts; @@ -143,6 +146,9 @@ struct arp_eth_header { unsigned char ar_tip[4]; /* target IP address */ } __packed; +int ovs_flow_key_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *); +void ovs_flow_key_hash_set(struct sw_flow_key *key); + int ovs_flow_init(void); void ovs_flow_exit(void); @@ -153,8 +159,6 @@ void ovs_flow_free(struct sw_flow *); struct sw_flow_actions *ovs_flow_actions_alloc(int actions_len); void ovs_flow_deferred_free_acts(struct sw_flow_actions *); -int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *, - int *key_lenp); void ovs_flow_used(struct sw_flow *, struct sk_buff *); u64 ovs_flow_used_time(unsigned long flow_jiffies); @@ -188,11 +192,11 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies); */ #define FLOW_BUFSIZE 220 -int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); -int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, - const struct nlattr *); -int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, - const struct nlattr *attr); +int ovs_flow_key_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); +int ovs_flow_key_from_nlattrs(struct sw_flow_key *, + const struct nlattr *); +int ovs_flow_key_metadata_from_nlattrs(struct sw_flow_key *, + const struct nlattr *); #define MAX_ACTIONS_BUFSIZE (16 * 1024) #define TBL_MIN_BUCKETS 1024 @@ -217,14 +221,14 @@ static inline int ovs_flow_tbl_need_to_expand(struct flow_table *table) } struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table, - struct sw_flow_key *key, int len); + struct sw_flow_key *key); void ovs_flow_tbl_destroy(struct flow_table *table); void ovs_flow_tbl_deferred_destroy(struct flow_table *table); struct flow_table *ovs_flow_tbl_alloc(int new_size); struct flow_table *ovs_flow_tbl_expand(struct flow_table *table); struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table); void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, - struct sw_flow_key *key, int key_len); + struct sw_flow_key *key); void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx); diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c index 413452e..6e5141f 100644 --- a/datapath/vport-vxlan.c +++ b/datapath/vport-vxlan.c @@ -98,7 +98,7 @@ static u16 get_src_port(struct sk_buff *skb) int low; int high; unsigned int range; - u32 hash = OVS_CB(skb)->flow->hash; + u32 hash = OVS_CB(skb)->flow->key.hash; inet_get_local_port_range(&low, &high); range = (high - low) + 1; -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev