Move struct ovs_key_ipv4_tunnel to the top of sw_flow_key. Add a new struct ovs_flow_hash, which contains both the key_len and the offset to use when hashing. This allows the outer tunnel to be hashed and used when looking up flows.
Signed-off-by: Kyle Mestery <kmest...@cisco.com> --- datapath/actions.c | 1 + datapath/datapath.c | 33 +++++++++++++++++--------- datapath/datapath.h | 1 + datapath/flow.c | 68 ++++++++++++++++++++++++++++++++++------------------- datapath/flow.h | 21 +++++++++++------ datapath/tunnel.c | 5 ++-- 6 files changed, 85 insertions(+), 44 deletions(-) diff --git a/datapath/actions.c b/datapath/actions.c index fa8c10d..e430dfc 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -289,6 +289,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, upcall.cmd = OVS_PACKET_CMD_ACTION; upcall.key = &OVS_CB(skb)->flow->key; + upcall.tun_key = &OVS_CB(skb)->flow->key.tun.tun_key; upcall.userdata = NULL; upcall.pid = 0; diff --git a/datapath/datapath.c b/datapath/datapath.c index d8a198e..b9f95dc 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -313,10 +313,12 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) if (!OVS_CB(skb)->flow) { struct sw_flow_key key; + struct sw_flow_hash flowhash; int key_len; /* Extract flow from 'skb' into 'key'. */ - error = ovs_flow_extract(skb, p->port_no, &key, &key_len); + error = ovs_flow_extract(skb, p->port_no, &key, &key_len, + &flowhash); if (unlikely(error)) { kfree_skb(skb); return; @@ -324,12 +326,13 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) /* Look up flow. */ flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table), - &key, key_len); + &flowhash); if (unlikely(!flow)) { struct dp_upcall_info upcall; upcall.cmd = OVS_PACKET_CMD_MISS; upcall.key = &key; + upcall.tun_key = &key.tun.tun_key; upcall.userdata = NULL; upcall.pid = p->upcall_pid; ovs_dp_upcall(dp, skb, &upcall); @@ -747,6 +750,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) struct ovs_header *ovs_header = info->userhdr; struct nlattr **a = info->attrs; struct sw_flow_actions *acts; + struct sw_flow_hash flowhash; struct sk_buff *packet; struct sw_flow *flow; struct datapath *dp; @@ -787,7 +791,7 @@ 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_extract(packet, -1, &flow->key, &key_len, &flowhash); if (err) goto err_flow_put; @@ -802,7 +806,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) if (err) goto err_flow_put; - flow->hash = ovs_flow_hash(&flow->key, key_len); + flow->hash = ovs_flow_hash(&flowhash); acts = ovs_flow_actions_alloc(a[OVS_PACKET_ATTR_ACTIONS]); err = PTR_ERR(acts); @@ -1017,6 +1021,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) struct ovs_header *ovs_header = info->userhdr; struct sw_flow_key key; struct sw_flow *flow; + struct sw_flow_hash flowhash; struct sk_buff *reply; struct datapath *dp; struct flow_table *table; @@ -1027,7 +1032,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) 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_from_nlattrs(&key, &key_len, &flowhash, + a[OVS_FLOW_ATTR_KEY]); if (error) goto error; @@ -1047,7 +1053,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) goto error; table = genl_dereference(dp->table); - flow = ovs_flow_tbl_lookup(table, &key, key_len); + flow = ovs_flow_tbl_lookup(table, &flowhash); if (!flow) { struct sw_flow_actions *acts; @@ -1085,7 +1091,8 @@ 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. */ - flow->hash = ovs_flow_hash(&key, key_len); + flow->hash = ovs_flow_hash(&flowhash); + flow->flowhash = flowhash; ovs_flow_tbl_insert(table, flow); reply = ovs_flow_cmd_build_info(flow, dp, info->snd_pid, @@ -1157,6 +1164,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) struct nlattr **a = info->attrs; struct ovs_header *ovs_header = info->userhdr; struct sw_flow_key key; + struct sw_flow_hash flowhash; struct sk_buff *reply; struct sw_flow *flow; struct datapath *dp; @@ -1166,7 +1174,8 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) if (!a[OVS_FLOW_ATTR_KEY]) return -EINVAL; - err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); + err = ovs_flow_from_nlattrs(&key, &key_len, &flowhash, + a[OVS_FLOW_ATTR_KEY]); if (err) return err; @@ -1175,7 +1184,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, &flowhash); if (!flow) return -ENOENT; @@ -1192,6 +1201,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) struct nlattr **a = info->attrs; struct ovs_header *ovs_header = info->userhdr; struct sw_flow_key key; + struct sw_flow_hash flowhash; struct sk_buff *reply; struct sw_flow *flow; struct datapath *dp; @@ -1206,12 +1216,13 @@ 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_from_nlattrs(&key, &key_len, &flowhash, + 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, &flowhash); if (!flow) return -ENOENT; diff --git a/datapath/datapath.h b/datapath/datapath.h index c5df12d..074aa85 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -132,6 +132,7 @@ struct ovs_skb_cb { struct dp_upcall_info { u8 cmd; const struct sw_flow_key *key; + const struct ovs_key_ipv4_tunnel *tun_key; const struct nlattr *userdata; u32 pid; }; diff --git a/datapath/flow.c b/datapath/flow.c index 376f4be..c15b22c 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -620,17 +620,22 @@ out: * 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 *key_lenp, struct sw_flow_hash *flowhash) { int error = 0; int key_len = SW_FLOW_KEY_OFFSET(eth); struct ethhdr *eth; memset(key, 0, sizeof(*key)); + memset(flowhash, 0, sizeof(*flowhash)); key->phy.priority = skb->priority; - if (OVS_CB(skb)->tun_key) - key->tun.tun_key = *OVS_CB(skb)->tun_key; + if (OVS_CB(skb)->tun_key) { + key->tun.tun_key = OVS_CB(skb)->flow->key.tun.tun_key; + flowhash->offset = (u32 *)&key->tun; + } else { + flowhash->offset = (u32 *)&key->phy; + } key->phy.in_port = in_port; skb_reset_mac_header(skb); @@ -783,32 +788,32 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, } out: - *key_lenp = key_len; + *key_lenp = flowhash->key_len = key_len; return error; } -u32 ovs_flow_hash(const struct sw_flow_key *key, int key_len) +u32 ovs_flow_hash(const struct sw_flow_hash *flowhash) { - return jhash2((u32 *)key, DIV_ROUND_UP(key_len, sizeof(u32)), 0); + return jhash2((u32 *)flowhash->offset, DIV_ROUND_UP(flowhash->key_len, + sizeof(u32)), 0); } struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table, - struct sw_flow_key *key, int key_len) + struct sw_flow_hash *flowhash) { struct sw_flow *flow; struct hlist_node *n; struct hlist_head *head; u32 hash; - hash = ovs_flow_hash(key, key_len); + hash = ovs_flow_hash(flowhash); head = find_bucket(table, hash); hlist_for_each_entry_rcu(flow, n, head, hash_node[table->node_ver]) { if (flow->hash == hash && - !memcmp(&flow->key, key, key_len)) { + !memcmp(&flow->flowhash.offset, flowhash->offset, flowhash->key_len)) return flow; - } } return NULL; } @@ -994,7 +999,7 @@ static int parse_flow_nlattrs(const struct nlattr *attr, * sequence. */ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, - const struct nlattr *attr) + struct sw_flow_hash *flowhash, const struct nlattr *attr) { const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; const struct ovs_key_ethernet *eth_key; @@ -1003,6 +1008,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, int err; memset(swkey, 0, sizeof(struct sw_flow_key)); + memset(flowhash, 0, sizeof(*flowhash)); key_len = SW_FLOW_KEY_OFFSET(eth); err = parse_flow_nlattrs(attr, a, &attrs); @@ -1024,30 +1030,35 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, swkey->phy.in_port = DP_MAX_PORTS; } - /* OVS_KEY_ATTR_TUN_ID and OVS_KEY_ATTR_IPV4_TUNEL must both arrive + /* OVS_KEY_ATTR_TUN_ID and OVS_KEY_ATTR_IPV4_TUNNEL must both arrive * together. */ - if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID) && - attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) { - struct ovs_key_ipv4_tunnel *tun_key; + if ((attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) && + (attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL))) { + struct ovs_key_ipv4_tunnel *tunnel_key; __be64 tun_id = 0; - tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]); + tunnel_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]); tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]); - if (tun_id != tun_key->tun_id) + if (tun_id != tunnel_key->tun_id) return -EINVAL; - swkey->tun.tun_key = *tun_key; + swkey->tun.tun_key = *tunnel_key; + flowhash->offset = (u32 *)&swkey->tun; attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID); attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL); } else if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) { swkey->tun.tun_key.tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]); + flowhash->offset = (u32 *)&swkey->tun; attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID); } else if (attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) { struct ovs_key_ipv4_tunnel *tun_key; tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]); swkey->tun.tun_key = *tun_key; + flowhash->offset = (u32 *)&swkey->tun; attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL); + } else { + flowhash->offset = (u32 *)&swkey->phy; } /* Data attributes. */ @@ -1168,7 +1179,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, if (attrs) return -EINVAL; - *key_lenp = key_len; + *key_lenp = flowhash->key_len = key_len; return 0; } @@ -1252,14 +1263,23 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->tun.tun_key.tun_id)) goto nla_put_failure; - if (swkey->tun.tun_key.ipv4_dst) { - struct ovs_key_ipv4_tunnel *tun_key; + if (swkey->tun.tun_key.ipv4_dst && + swkey->tun.tun_key.tun_id != cpu_to_be64(0)) { + struct ovs_key_ipv4_tunnel *tunnel_key; nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4_TUNNEL, - sizeof(*tun_key)); + sizeof(*tunnel_key)); if (!nla) goto nla_put_failure; - tun_key = nla_data(nla); - *tun_key = swkey->tun.tun_key; + if (!nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, + swkey->tun.tun_key.tun_id)) + goto nla_put_failure; + tunnel_key = nla_data(nla); + tunnel_key->tun_id = swkey->tun.tun_key.tun_id; + tunnel_key->tun_flags = swkey->tun.tun_key.tun_flags; + tunnel_key->ipv4_src = swkey->tun.tun_key.ipv4_src; + tunnel_key->ipv4_dst = swkey->tun.tun_key.ipv4_dst; + tunnel_key->ipv4_tos = swkey->tun.tun_key.ipv4_tos; + tunnel_key->ipv4_ttl = swkey->tun.tun_key.ipv4_ttl; } if (swkey->phy.in_port != DP_MAX_PORTS && diff --git a/datapath/flow.h b/datapath/flow.h index 4430b32..a6f6b79 100644 --- a/datapath/flow.h +++ b/datapath/flow.h @@ -40,14 +40,19 @@ struct sw_flow_actions { struct nlattr actions[]; }; +struct sw_flow_hash { + int key_len; + u32 *offset; +}; + struct sw_flow_key { struct { + struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */ + } tun; + struct { u32 priority; /* Packet QoS priority. */ u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ } phy; - struct { - struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */ - } tun; struct { u8 src[ETH_ALEN]; /* Ethernet source address. */ u8 dst[ETH_ALEN]; /* Ethernet destination address. */ @@ -102,6 +107,7 @@ struct sw_flow { u32 hash; struct sw_flow_key key; + struct sw_flow_hash flowhash; struct sw_flow_actions __rcu *sf_acts; atomic_t refcnt; @@ -141,7 +147,7 @@ void ovs_flow_hold(struct sw_flow *); void ovs_flow_put(struct sw_flow *); int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *, - int *key_lenp); + int *key_lenp, struct sw_flow_hash *flowhash); void ovs_flow_used(struct sw_flow *, struct sk_buff *); u64 ovs_flow_used_time(unsigned long flow_jiffies); @@ -169,7 +175,8 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies); 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 *); + struct sw_flow_hash *flowhash, + const struct nlattr *attrs); int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, struct ovs_key_ipv4_tunnel *tun_key, const struct nlattr *); @@ -197,7 +204,7 @@ 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_hash *flowhash); 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); @@ -205,7 +212,7 @@ 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); void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); -u32 ovs_flow_hash(const struct sw_flow_key *key, int key_len); +u32 ovs_flow_hash(const struct sw_flow_hash *flowhash); struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx); extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1]; diff --git a/datapath/tunnel.c b/datapath/tunnel.c index 739f098..9e0fd22 100644 --- a/datapath/tunnel.c +++ b/datapath/tunnel.c @@ -953,6 +953,7 @@ static struct tnl_cache *build_cache(struct vport *vport, if (ovs_is_internal_dev(rt_dst(rt).dev)) { struct sw_flow_key flow_key; + struct sw_flow_hash flowhash; struct vport *dst_vport; struct sk_buff *skb; int err; @@ -971,14 +972,14 @@ static struct tnl_cache *build_cache(struct vport *vport, memcpy(skb->data, get_cached_header(cache), cache->len); err = ovs_flow_extract(skb, dst_vport->port_no, &flow_key, - &flow_key_len); + &flow_key_len, &flowhash); consume_skb(skb); if (err) goto done; flow = ovs_flow_tbl_lookup(rcu_dereference(dst_vport->dp->table), - &flow_key, flow_key_len); + &flowhash); if (flow) { cache->flow = flow; ovs_flow_hold(flow); -- 1.7.11.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev