【OVS2.5.0源码分析】datapath之流表查询
来源:互联网 发布:淘宝怎么买弹簧刀 编辑:程序博客网 时间:2024/05/22 07:03
流表查询是datapath报文处理过程中,最为关键的一个步骤,一个skb报文进入如何能够快速地进行匹配流表? 本篇分析ovs是如何查询流表的。
1、ovs_flow_tbl_lookup_stats函数
struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl, const struct sw_flow_key *key, //由ovs_flow_key_extract函数根据skb生成 u32 skb_hash,<span style="white-space:pre"></span> //skb中携带的信息 u32 *n_mask_hit){struct mask_array *ma = rcu_dereference(tbl->mask_array);struct table_instance *ti = rcu_dereference(tbl->ti); //得到table实例struct mask_cache_entry *entries, *ce;struct sw_flow *flow;u32 hash;int seg;*n_mask_hit = 0;if (unlikely(!skb_hash)) {//如果报文没有hash值,则mask_index为0,全遍历所有的mask。u32 mask_index = 0;return flow_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++) {//32位的hash值被分成4段,每段8字节,作为cache的索引int index = hash & (MC_HASH_ENTRIES - 1);struct mask_cache_entry *e;e = &entries[index]; //entry最大为256项if (e->skb_hash == skb_hash) { //如果在cache entry找到报文hash相同项,则根据该entry指定的mask查表flow = flow_lookup(tbl, ti, ma, key, n_mask_hit, &e->mask_index);if (!flow)e->skb_hash = 0;return flow;}if (!ce || e->skb_hash < ce->skb_hash)ce = e; /* A better replacement cache candidate. */hash >>= MC_HASH_SHIFT;}/* Cache miss, do full lookup. */flow = flow_lookup(tbl, ti, ma, key, n_mask_hit, &ce->mask_index); //没有命中,ce作为新的cache项,将被刷新,下一次可以直接命中if (flow)ce->skb_hash = skb_hash;return flow;}2、flow_lookup函数
</pre><pre name="code" class="cpp">static struct sw_flow *flow_lookup(struct flow_table *tbl, struct table_instance *ti, const struct mask_array *ma, const struct sw_flow_key *key, u32 *n_mask_hit, u32 *index){struct sw_flow_mask *mask;struct sw_flow *flow;int i;if (*index < ma->max) { //如果index的值小于mask的entry数量,说明index是有效值,基于该值获取sw_flow_mask值mask = rcu_dereference_ovsl(ma->masks[*index]);if (mask) {flow = masked_flow_lookup(ti, key, mask, n_mask_hit);if (flow)return flow;}}for (i = 0; i < ma->max; i++) {if (i == *index)//前面已查询过,所以跳过该maskcontinue;mask = rcu_dereference_ovsl(ma->masks[i]);if (!mask)continue;flow = masked_flow_lookup(ti, key, mask, n_mask_hit);if (flow) { /* Found */*index = i;//更新index指向的值,下次可以直接命中;此处说明cache没有命中,下一次可以直接命中return flow;}}return NULL;}3、masked_flow_lookup函数
static struct sw_flow *masked_flow_lookup(struct table_instance *ti, const struct sw_flow_key *unmasked, const struct sw_flow_mask *mask, u32 *n_mask_hit){struct sw_flow *flow;struct hlist_head *head;u32 hash;struct sw_flow_key masked_key; ovs_flow_mask_key(&masked_key, unmasked, false, mask); //根据mask,计算masked后的key,用以支持通配符hash = flow_hash(&masked_key, &mask->range); //根据masked key和mask.range 计算hash值head = find_bucket(ti, hash); //根据hash值,找到sw_flow的链表头(*n_mask_hit)++;hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver]) { //遍历链表if (flow->mask == mask && flow->flow_table.hash == hash && //mask相同、hash相同并且key相同,则匹配到流表 flow_cmp_masked_key(flow, &masked_key, &mask->range))return flow;}return NULL;}ovs_flow_mask_key 函数
void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, bool full, const struct sw_flow_mask *mask){int start = full ? 0 : mask->range.start;int len = full ? sizeof *dst : range_n_bytes(&mask->range);const long *m = (const long *)((const u8 *)&mask->key + start);const long *s = (const long *)((const u8 *)src + start);long *d = (long *)((u8 *)dst + start);int i;/* If 'full' is true then all of 'dst' is fully initialized. Otherwise, * if 'full' is false the memory outside of the 'mask->range' is left * uninitialized. This can be used as an optimization when further * operations on 'dst' only use contents within 'mask->range'. */for (i = 0; i < len; i += sizeof(long))*d++ = *s++ & *m++; //目标key = 源key & mask, 起始位置和长度由mask的range成员对象指定}find_bucket 函数
static struct hlist_head *find_bucket(struct table_instance *ti, u32 hash){hash = jhash_1word(hash, ti->hash_seed);return flex_array_get(ti->buckets,(hash & (ti->n_buckets - 1))); //hash的低N位作为index}
到此流表查找过程已经比较清晰了,tbl->mask_cache是用来加速报文处理的,相同流的skb其hash值也是相同的,可以快速找到mask对象,然后通过hash计算找到bucket进行匹配。 下图想用来阐述skb在流表查询中依赖了哪些数据,通过哪些数据完成了flow的查找。
PS: 一个框(橙色)如果有多个箭头输入,表示要获取该框的内容,依赖哪些信息。
0 0
- 【OVS2.5.0源码分析】datapath之流表查询
- 【OVS2.5.0源码分析】datapath之流表创建过程
- 【OVS2.5.0源码分析】datapath之netlink
- 【OVS2.5.0源码分析】datapath之主流程分析
- 【OVS2.5.0源码分析】datapath之action分析(1)
- 【OVS2.5.0源码分析】datapath之action分析(2)
- 【OVS2.5.0源码分析】datapath之action分析(3)
- 【OVS2.5.0源码分析】datapath之action分析(4)
- 【OVS2.5.0源码分析】datapath之action分析(5)
- 【OVS2.5.0源码分析】datapath之action分析(6)
- 【OVS2.5.0源码分析】datapath之action分析(7)
- 【OVS2.5.0源码分析】datapath之action分析(8)
- 【OVS2.5源码解读】datapath主流程分析
- 【OVS2.5.0源码分析】ofpbuf数据结构分析
- 【OVS2.5.0源码分析】nlattr数据结构分析
- 【OVS2.5源码解读】datapath的netlink机制
- 【OVS2.5.0源码分析】enqueue action精确流表生成过程分析
- 【OVS2.5.0源码分析】normal action精确流表生成和刷新过程分析
- 关于Tomcat版本更换时,安装不成功的问题解决方法
- 选择排序和堆排序
- Android开发中遇到的大坑
- tomcat的gzip压缩配置及优化效果对比
- VMware rhel6.5 虚拟机克隆后更改网卡
- 【OVS2.5.0源码分析】datapath之流表查询
- runtime学习
- 数据结构之链表:实现单链表的k逆序(2)
- Codeforces Round #369 (Div. 2)
- Word break
- 博客--第一篇
- 如何减少频繁分配内存(malloc或者new)造成的内存碎片?
- Mac OS增删环境变量
- HDU 2074 叠筐