代码改变世界

四 OVS--流表匹配

2017-03-21 19:59  yrpapa  阅读(939)  评论(0)    收藏  举报

一 datapath的数据结构

struct flex_array {
    union {
        struct {
            int element_size;
            int total_nr_elements;
            int elems_per_part;
            struct reciprocal_value reciprocal_elems;
            struct flex_array_part *parts[];
        };
        /*
         * This little trick makes sure that
         * sizeof(flex_array) == PAGE_SIZE
         */
        char padding[FLEX_ARRAY_BASE_SIZE]; // 联合体空间
    };  
};


struct table_instance {
    struct flex_array *buckets;
    unsigned int n_buckets;
    struct rcu_head rcu;
    int node_ver;
    u32 hash_seed;
    bool keep_flows;
};

struct flow_table {
    struct table_instance __rcu *ti;
    struct table_instance __rcu *ufid_ti;
    struct mask_cache_entry __percpu *mask_cache;
    struct mask_array __rcu *mask_array;
    unsigned long last_rehash;
    unsigned int count;
    unsigned int ufid_count;
};

 流表项--flex_array中的每一个bucket记录了一个sw_flow结构的node的头指针

struct sw_flow {
    struct rcu_head rcu;
    struct {
        struct hlist_node node[2];
        u32 hash;
    } flow_table, ufid_table;
    int stats_last_writer;      /* NUMA-node id of the last writer on
                     * 'stats[0]'.
                     */
    struct sw_flow_key key;
    struct sw_flow_id id; 
    struct sw_flow_mask *mask;
    struct sw_flow_actions __rcu *sf_acts;
    struct flow_stats __rcu *stats[]; /* One for each NUMA node.  First one
                       * is allocated at flow creation time,
                       * the rest are allocated on demand
                       * while holding the 'stats[0].lock'.
                       */
};

 

 

二 虚拟端口收到数据包后,进行流表的匹配,分析一下过程

struct sw_flow *ovs_flow_tbl_lookup_stats(struct flow_table *tbl,
                      const struct sw_flow_key *key,
                      u32 skb_hash,
                      u32 *n_mask_hit)
{   
    struct mask_array *ma = rcu_dereference(tbl->mask_array);
    struct table_instance *ti = rcu_dereference(tbl->ti);
    struct mask_cache_entry *entries, *ce;
    struct sw_flow *flow;
    u32 hash;
    int seg;

    *n_mask_hit = 0;
    if (unlikely(!skb_hash)) {
        u32 mask_index = 0;
     /* hash值为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; // 缓存mask_array 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++) { int index = hash & (MC_HASH_ENTRIES - 1); struct mask_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; 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); if (flow) ce->skb_hash = skb_hash; return flow; }

 

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) {
        mask = rcu_dereference_ovsl(ma->masks[*index]);
        if (mask) {
            flow = masked_flow_lookup(ti, key, mask, n_mask_hit); // 通过mask查找流表项所在的bucket
            if (flow)
                return flow;
        }
    }
   /* 迭代查找最大值范围内的所有mask */
    for (i = 0; i < ma->max; i++)  {

        if (i == *index)
            continue;

        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;
            return flow;
        }
    }
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);
    hash = flow_hash(&masked_key, &mask->range);
    head = find_bucket(ti, hash);
    (*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 &&
            flow_cmp_masked_key(flow, &masked_key, &mask->range))
            return flow;
    }
    return NULL;
}
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)));
}
static bool flow_cmp_masked_key(const struct sw_flow *flow,
                const struct sw_flow_key *key,
                const struct sw_flow_key_range *range)
{
    return cmp_key(&flow->key, key, range->start, range->end);
}

 参考 http://www.sdnlab.com/18668.html