【OVS2.5.0源码分析】datapath之流表创建过程

来源:互联网 发布:天天炫斗刷钻石软件 编辑:程序博客网 时间:2024/05/21 22:28

上一篇分析了流表查找过程,支撑流表查询的相关信息是什么时候建立,是怎么建立的将在本篇分析。 datapath流表更新的入口函数都定义在dp_flow_genl_ops中,流表创建的入口函数是ovs_flow_cmd_new函数,通过该函数,我们可以一窥流表相关信息的建立。

1、ovs_flow_cmd_new函数

static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info){struct net *net = sock_net(skb->sk);struct nlattr **a = info->attrs;struct ovs_header *ovs_header = info->userhdr;struct sw_flow *flow = NULL, *new_flow;struct sw_flow_mask mask;struct sk_buff *reply;struct datapath *dp;struct sw_flow_key key;struct sw_flow_actions *acts;struct sw_flow_match match;u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);int error;bool log = !a[OVS_FLOW_ATTR_PROBE];/* Must have key and actions. */error = -EINVAL;if (!a[OVS_FLOW_ATTR_KEY]) {OVS_NLERR(log, "Flow key attr not present in new flow.");goto error;}if (!a[OVS_FLOW_ATTR_ACTIONS]) {OVS_NLERR(log, "Flow actions attr not present in new flow.");goto error;}/* Most of the time we need to allocate a new flow, do it before * locking. */new_flow = ovs_flow_alloc();if (IS_ERR(new_flow)) {error = PTR_ERR(new_flow);goto error;}/* Extract key. */ovs_match_init(&match, &key, &mask);error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],         //完成key和match的信息设置  a[OVS_FLOW_ATTR_MASK], log);if (error)goto err_kfree_flow;ovs_flow_mask_key(&new_flow->key, &key, true, &mask);          //根据key和mask,生成masked key/* Extract flow identifier. */error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],       &key, log);if (error)goto err_kfree_flow;/* Validate actions. */error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],          &new_flow->key, &acts, log);if (error) {OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");goto err_kfree_flow;}reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false,ufid_flags);if (IS_ERR(reply)) {error = PTR_ERR(reply);goto err_kfree_acts;}ovs_lock();dp = get_dp(net, ovs_header->dp_ifindex);  if (unlikely(!dp)) {error = -ENODEV;goto err_unlock_ovs;}/* Check if this is a duplicate flow */if (ovs_identifier_is_ufid(&new_flow->id))flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);if (!flow)flow = ovs_flow_tbl_lookup(&dp->table, &key);     //查找流表,正常情况是查不到的if (likely(!flow)) {rcu_assign_pointer(new_flow->sf_acts, acts);/* Put flow in bucket. */error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask);      //插入流表if (unlikely(error)) {acts = NULL;goto err_unlock_ovs;}if (unlikely(reply)) {error = ovs_flow_cmd_fill_info(new_flow,       ovs_header->dp_ifindex,       reply, info->snd_portid,       info->snd_seq, 0,       OVS_FLOW_CMD_NEW,       ufid_flags);BUG_ON(error < 0);}ovs_unlock();} else {struct sw_flow_actions *old_acts;/* Bail out if we're not allowed to modify an existing flow. * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL * because Generic Netlink treats the latter as a dump * request.  We also accept NLM_F_EXCL in case that bug ever * gets fixed. */if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL))) {error = -EEXIST;goto err_unlock_ovs;}/* The flow identifier has to be the same for flow updates. * Look for any overlapping flow. */if (unlikely(!ovs_flow_cmp(flow, &match))) {if (ovs_identifier_is_key(&flow->id))flow = ovs_flow_tbl_lookup_exact(&dp->table, &match);else /* UFID matches but key is different */flow = NULL;if (!flow) {error = -ENOENT;goto err_unlock_ovs;}}/* Update actions. */old_acts = ovsl_dereference(flow->sf_acts);rcu_assign_pointer(flow->sf_acts, acts);if (unlikely(reply)) {error = ovs_flow_cmd_fill_info(flow,       ovs_header->dp_ifindex,       reply, info->snd_portid,       info->snd_seq, 0,       OVS_FLOW_CMD_NEW,       ufid_flags);BUG_ON(error < 0);}ovs_unlock();ovs_nla_free_flow_actions_rcu(old_acts);ovs_flow_free(new_flow, false);}if (reply)ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info);return 0;err_unlock_ovs:ovs_unlock();kfree_skb(reply);err_kfree_acts:ovs_nla_free_flow_actions(acts);err_kfree_flow:ovs_flow_free(new_flow, false);error:return error;}
2、ovs_flow_tbl_insert函数

/* Must be called with OVS mutex held. */int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,const struct sw_flow_mask *mask){int err;err = flow_mask_insert(table, flow, mask);    //插入maskif (err)return err;flow_key_insert(table, flow);                 //插入flowif (ovs_identifier_is_ufid(&flow->id))flow_ufid_insert(table, flow);return 0;}
3、flow_mask_insert函数
static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,    const struct sw_flow_mask *new){struct sw_flow_mask *mask;mask = flow_mask_find(tbl, new);if (!mask) {struct mask_array *ma;int i;/* Allocate a new mask if none exsits. */mask = mask_alloc();        //新创建maskif (!mask)return -ENOMEM;mask->key = new->key;        //mask复制mask->range = new->range;    //mask复制/* Add mask to mask-list. */ma = ovsl_dereference(tbl->mask_array);if (ma->count >= ma->max) {int err;err = tbl_mask_array_realloc(tbl, ma->max +  MASK_ARRAY_SIZE_MIN);if (err) {kfree(mask);return err;}ma = ovsl_dereference(tbl->mask_array);}for (i = 0; i < ma->max; i++) {struct sw_flow_mask *t;t = ovsl_dereference(ma->masks[i]);if (!t) {rcu_assign_pointer(ma->masks[i], mask);    //maks保存到mask_array中,流表查找中的mask_array构造完成ma->count++;break;}}} else {BUG_ON(!mask->ref_count);mask->ref_count++;}flow->mask = mask;     //flow的mask指针指向新的maskreturn 0;}
4、flow_key_insert函数

static void flow_key_insert(struct flow_table *table, struct sw_flow *flow){struct table_instance *new_ti = NULL;struct table_instance *ti;flow->flow_table.hash = flow_hash(&flow->key, &flow->mask->range);   //计算hash值ti = ovsl_dereference(table->ti);table_instance_insert(ti, flow);//flow插入到ti中table->count++;/* Expand table, if necessary, to make room. */if (table->count > ti->n_buckets)new_ti = table_instance_expand(ti, false);else if (time_after(jiffies, table->last_rehash + REHASH_INTERVAL))new_ti = table_instance_rehash(ti, ti->n_buckets, false);     //为什么要刷新,还不是很清晰,希望等整体分析完成后能够解答if (new_ti) {rcu_assign_pointer(table->ti, new_ti);call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);table->last_rehash = jiffies;}}
5、table_instance_insert函数

static void table_instance_insert(struct table_instance *ti,  struct sw_flow *flow){struct hlist_head *head;head = find_bucket(ti, flow->flow_table.hash);   //通过hash值找到flow list headhlist_add_head_rcu(&flow->flow_table.node[ti->node_ver], head);   //flow插入到队列前头}

到这,datapath中流表查询的数据已经建立完成。

0 0
原创粉丝点击