概括
现在的OVS使用microflow+megaflow缓存查询流表,ovs整体流程是从ovs_vport_receive(datapath/vport.c)开始,然后进入ovs_dp_process_packet(datapath/datapath.c),这个时候调用ovs_flow_tbl_lookup_stats(datapath/flow_table.c)开始查,查microflow获得mask_array里的索引索找到mask,通过mask去找megaflow里的掩码元素,再去定位哈希桶,如果没找到就upcall去用户态:
查找 microflow 缓存:根据数据报文 SKB 的 hash 值,定位到 mask_cache_entry 数组中的某个元素,并得到该元素缓存的掩码数组索引值;
查找 megaflow 缓存:根据步骤 1 中查找到的掩码数组索引值,定位到掩码数组中的某个元素,并得到该元素的掩码,然后根据掩码定位到具体的哈希桶,并遍历该哈希桶中的所有节点,直到找到匹配的 flow。
说的是流表过程,所以就从ovs_flow_tbl_lookup_stats开始。
正文
查找 microflow 缓存
OVS 内核态流表查找的入口函数是定义在 datapath/flow_table.c 文件中的,在ovs_dp_process_packet里调用: flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb), &n_mask_hit);
structsw_flow*ovs_flow_tbl_lookup_stats(structflow_table*tbl,
conststructsw_flow_key*key,
u32skb_hash,
u32*n_mask_hit)
{
structmask_array*ma=rcu_dereference(tbl->mask_array);
structtable_instance*ti=rcu_dereference(tbl->ti);
structmask_cache_entry*entries, *ce;
structsw_flow*flow;
u32hash;
intseg;
*n_mask_hit=0;
if (unlikely(!skb_hash)) {
u32mask_index=0;
returnflow_lookup(tbl, ti, ma, key, n_mask_hit, &mask_index);
}
/* Pre and post recirulation flows usually have the same skb_hash
* value. To avoid hash collisions, rehash the 'skb_hash' with
* 'recirc_id'. */
if (key->recirc_id)
skb_hash=jhash_1word(skb_hash, key->recirc_id);
ce=NULL;
hash=skb_hash;
entries=this_cpu_ptr(tbl->mask_cache);
/* Find the cache entry 'ce' to operate on. */
for (seg=0; seg<MC_HASH_SEGS; seg++) {
intindex=hash& (MC_HASH_ENTRIES-1);
structmask_cache_entry*e;
e=&entries[index];
if (e->skb_hash==skb_hash) {
flow=flow_lookup(tbl, ti, ma, key, n_mask_hit,
&e->mask_index);
if (!flow)
e->skb_hash=0;
returnflow;
}