openvswitch datapath 内核态流表创建过程(ovs_flow_cmd_new)

datapath流表更新的入口函数都定义在dp_flow_genl_ops中,流表创建的入口函数是ovs_flow_cmd_new函数,通过该函数,我们可以一窥流表相关信息的建立。

1、ovs_flow_cmd_new函数

  1 static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
  2 {
  3     struct net *net = sock_net(skb->sk);
  4     struct nlattr **a = info->attrs;
  5     struct ovs_header *ovs_header = info->userhdr;
  6     struct sw_flow *flow = NULL, *new_flow;
  7     struct sw_flow_mask mask;
  8     struct sk_buff *reply;
  9     struct datapath *dp;
 10     struct sw_flow_actions *acts;
 11     struct sw_flow_match match;
 12     u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
 13     int error;
 14     bool log = !a[OVS_FLOW_ATTR_PROBE];
 15 
 16     /* Must have key and actions. */
 17     error = -EINVAL;
 18     if (!a[OVS_FLOW_ATTR_KEY]) {
 19         OVS_NLERR(log, "Flow key attr not present in new flow.");
 20         goto error;
 21     }
 22     if (!a[OVS_FLOW_ATTR_ACTIONS]) {
 23         OVS_NLERR(log, "Flow actions attr not present in new flow.");
 24         goto error;
 25     }
 26 
 27     /* Most of the time we need to allocate a new flow, do it before
 28      * locking.
 29      */
 30     new_flow = ovs_flow_alloc();
 31     if (IS_ERR(new_flow)) {
 32         error = PTR_ERR(new_flow);
 33         goto error;
 34     }
 35 
 36     /* Extract key. */
 37     ovs_match_init(&match, &new_flow->key, false, &mask);
 38     error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
 39                   a[OVS_FLOW_ATTR_MASK], log);
 40     if (error)
 41         goto err_kfree_flow;
 42 
 43     /* Extract flow identifier. */
 44     error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
 45                        &new_flow->key, log);
 46     if (error)
 47         goto err_kfree_flow;
 48 
 49     /* unmasked key is needed to match when ufid is not used. */
 50     if (ovs_identifier_is_key(&new_flow->id))
 51         match.key = new_flow->id.unmasked_key;
 52 
 53     ovs_flow_mask_key(&new_flow->key, &new_flow->key, true, &mask);
 54 
 55     /* Validate actions. */
 56     error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
 57                      &new_flow->key, &acts, log);
 58     if (error) {
 59         OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
 60         goto err_kfree_flow;
 61     }
 62 
 63     reply = ovs_flow_cmd_alloc_info(acts, &new_flow->id, info, false,
 64                     ufid_flags);
 65     if (IS_ERR(reply)) {
 66         error = PTR_ERR(reply);
 67         goto err_kfree_acts;
 68     }
 69 
 70     ovs_lock();
 71     dp = get_dp(net, ovs_header->dp_ifindex);
 72     if (unlikely(!dp)) {
 73         error = -ENODEV;
 74         goto err_unlock_ovs;
 75     }
 76 
 77     /* Check if this is a duplicate flow */
 78     if (ovs_identifier_is_ufid(&new_flow->id))
 79         flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
 80     if (!flow)
 81         flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->key);
 82     if (likely(!flow)) {
 83         rcu_assign_pointer(new_flow->sf_acts, acts);
 84 
 85         /* Put flow in bucket. */
 86         error = ovs_flow_tbl_insert(&dp->table, new_flow, &mask);
 87         if (unlikely(error)) {
 88             acts = NULL;
 89             goto err_unlock_ovs;
 90         }
 91 
 92         if (unlikely(reply)) {
 93             error = ovs_flow_cmd_fill_info(new_flow,
 94                                ovs_header->dp_ifindex,
 95                                reply, info->snd_portid,
 96                                info->snd_seq, 0,
 97                                OVS_FLOW_CMD_NEW,
 98                                ufid_flags);
 99             BUG_ON(error < 0);
100         }
101         ovs_unlock();
102     } else {
103         struct sw_flow_actions *old_acts;
104 
105         /* Bail out if we're not allowed to modify an existing flow.
106          * We accept NLM_F_CREATE in place of the intended NLM_F_EXCL
107          * because Generic Netlink treats the latter as a dump
108          * request.  We also accept NLM_F_EXCL in case that bug ever
109          * gets fixed.
110          */
111         if (unlikely(info->nlhdr->nlmsg_flags & (NLM_F_CREATE
112                              | NLM_F_EXCL))) {
113             error = -EEXIST;
114             goto err_unlock_ovs;
115         }
116         /* The flow identifier has to be the same for flow updates.
117          * Look for any overlapping flow.
118          */
119         if (unlikely(!ovs_flow_cmp(flow, &match))) {
120             if (ovs_identifier_is_key(&flow->id))
121                 flow = ovs_flow_tbl_lookup_exact(&dp->table,
122                                  &match);
123             else /* UFID matches but key is different */
124                 flow = NULL;
125             if (!flow) {
126                 error = -ENOENT;
127                 goto err_unlock_ovs;
128             }
129         }
130         /* Update actions. */
131         old_acts = ovsl_dereference(flow->sf_acts);
132         rcu_assign_pointer(flow->sf_acts, acts);
133 
134         if (unlikely(reply)) {
135             error = ovs_flow_cmd_fill_info(flow,
136                                ovs_header->dp_ifindex,
137                                reply, info->snd_portid,
138                                info->snd_seq, 0,
139                                OVS_FLOW_CMD_NEW,
140                                ufid_flags);
141             BUG_ON(error < 0);
142         }
143         ovs_unlock();
144 
145         ovs_nla_free_flow_actions_rcu(old_acts);
146         ovs_flow_free(new_flow, false);
147     }
148 
149     if (reply)
150         ovs_notify(&dp_flow_genl_family, &ovs_dp_flow_multicast_group, reply, info);
151     return 0;
152 
153 err_unlock_ovs:
154     ovs_unlock();
155     kfree_skb(reply);
156 err_kfree_acts:
157     ovs_nla_free_flow_actions(acts);
158 err_kfree_flow:
159     ovs_flow_free(new_flow, false);
160 error:
161     return error;
162 }

2、ovs_flow_tbl_insert函数

 1 /* Must be called with OVS mutex held. */
 2 int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
 3             const struct sw_flow_mask *mask)
 4 {
 5     int err;
 6 
 7     err = flow_mask_insert(table, flow, mask);
 8     if (err)
 9         return err;
10     flow_key_insert(table, flow);
11     if (ovs_identifier_is_ufid(&flow->id))
12         flow_ufid_insert(table, flow);
13 
14     return 0;
15 }

3、flow_mask_insert函数

 1 /* Add 'mask' into the mask list, if it is not already there. */
 2 static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,
 3                 const struct sw_flow_mask *new)
 4 {
 5     struct sw_flow_mask *mask;
 6 
 7     mask = flow_mask_find(tbl, new);
 8     if (!mask) {
 9         struct mask_array *ma;
10         int i;
11 
12         /* Allocate a new mask if none exsits. */
13         mask = mask_alloc();
14         if (!mask)
15             return -ENOMEM;
16 
17         mask->key = new->key;
18         mask->range = new->range;
19 
20         /* Add mask to mask-list. */
21         ma = ovsl_dereference(tbl->mask_array);
22         if (ma->count >= ma->max) {
23             int err;
24 
25             err = tbl_mask_array_realloc(tbl, ma->max +
26                               MASK_ARRAY_SIZE_MIN);
27             if (err) {
28                 kfree(mask);
29                 return err;
30             }
31             ma = ovsl_dereference(tbl->mask_array);
32         }
33 
34         for (i = 0; i < ma->max; i++) {
35             struct sw_flow_mask *t;
36 
37             t = ovsl_dereference(ma->masks[i]);
38             if (!t) {
39                 rcu_assign_pointer(ma->masks[i], mask);
40                 ma->count++;
41                 break;
42             }
43         }
44 
45     } else {
46         BUG_ON(!mask->ref_count);
47         mask->ref_count++;
48     }
49 
50     flow->mask = mask;
51     return 0;
52 }

4、flow_key_insert函数

 1 /* Must be called with OVS mutex held. */
 2 static void flow_key_insert(struct flow_table *table, struct sw_flow *flow)
 3 {
 4     struct table_instance *new_ti = NULL;
 5     struct table_instance *ti;
 6 
 7     flow->flow_table.hash = flow_hash(&flow->key, &flow->mask->range);
 8     ti = ovsl_dereference(table->ti);
 9     table_instance_insert(ti, flow);
10     table->count++;
11 
12     /* Expand table, if necessary, to make room. */
13     if (table->count > ti->n_buckets)
14         new_ti = table_instance_expand(ti, false);
15     else if (time_after(jiffies, table->last_rehash + REHASH_INTERVAL))
16         new_ti = table_instance_rehash(ti, ti->n_buckets, false);
17 
18     if (new_ti) {
19         rcu_assign_pointer(table->ti, new_ti);
20         call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
21         table->last_rehash = jiffies;
22     }
23 }

5、table_instance_insert函数

1 static void table_instance_insert(struct table_instance *ti,
2                   struct sw_flow *flow)
3 {
4     struct hlist_head *head;
5 
6     head = find_bucket(ti, flow->flow_table.hash);
7     hlist_add_head_rcu(&flow->flow_table.node[ti->node_ver], head);
8 }

 6、ovs_nla_copy_actions函数

 1 /* 'key' must be the masked key. */
 2 int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
 3              const struct sw_flow_key *key,
 4              struct sw_flow_actions **sfa, bool log)
 5 {
 6     int err;
 7 
 8     *sfa = nla_alloc_flow_actions(min(nla_len(attr), MAX_ACTIONS_BUFSIZE));
 9     if (IS_ERR(*sfa))
10         return PTR_ERR(*sfa);
11 
12     (*sfa)->orig_len = nla_len(attr);
13     err = __ovs_nla_copy_actions(net, attr, key, sfa, key->eth.type,
14                      key->eth.vlan.tci, log);
15     if (err)
16         ovs_nla_free_flow_actions(*sfa);
17 
18     return err;
19 }

7、__ovs_nla_copy_actions函数

  1 static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
  2                   const struct sw_flow_key *key,
  3                   struct sw_flow_actions **sfa,
  4                   __be16 eth_type, __be16 vlan_tci, bool log)
  5 {
  6     u8 mac_proto = ovs_key_mac_proto(key);
  7     const struct nlattr *a;
  8     int rem, err;
  9 
 10     nla_for_each_nested(a, attr, rem) {
 11         /* Expected argument lengths, (u32)-1 for variable length. */
 12         static const u32 action_lens[OVS_ACTION_ATTR_MAX + 1] = {
 13             [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32),
 14             [OVS_ACTION_ATTR_RECIRC] = sizeof(u32),
 15             [OVS_ACTION_ATTR_USERSPACE] = (u32)-1,
 16             [OVS_ACTION_ATTR_PUSH_MPLS] = sizeof(struct ovs_action_push_mpls),
 17             [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16),
 18             [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan),
 19             [OVS_ACTION_ATTR_POP_VLAN] = 0,
 20             [OVS_ACTION_ATTR_SET] = (u32)-1,
 21             [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1,
 22             [OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
 23             [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash),
 24             [OVS_ACTION_ATTR_CT] = (u32)-1,
 25             [OVS_ACTION_ATTR_CT_CLEAR] = 0,
 26             [OVS_ACTION_ATTR_TRUNC] = sizeof(struct ovs_action_trunc),
 27             [OVS_ACTION_ATTR_PUSH_ETH] = sizeof(struct ovs_action_push_eth),
 28             [OVS_ACTION_ATTR_POP_ETH] = 0,
 29             [OVS_ACTION_ATTR_PUSH_NSH] = (u32)-1,
 30             [OVS_ACTION_ATTR_POP_NSH] = 0,
 31         };
 32         const struct ovs_action_push_vlan *vlan;
 33         int type = nla_type(a);
 34         bool skip_copy;
 35 
 36         if (type > OVS_ACTION_ATTR_MAX ||
 37             (action_lens[type] != nla_len(a) &&
 38              action_lens[type] != (u32)-1))
 39             return -EINVAL;
 40 
 41         skip_copy = false;
 42         switch (type) {
 43         case OVS_ACTION_ATTR_UNSPEC:
 44             return -EINVAL;
 45 
 46         case OVS_ACTION_ATTR_USERSPACE:
 47             err = validate_userspace(a);
 48             if (err)
 49                 return err;
 50             break;
 51 
 52         case OVS_ACTION_ATTR_OUTPUT:
 53             if (nla_get_u32(a) >= DP_MAX_PORTS)
 54                 return -EINVAL;
 55             break;
 56 
 57         case OVS_ACTION_ATTR_TRUNC: {
 58             const struct ovs_action_trunc *trunc = nla_data(a);
 59 
 60             if (trunc->max_len < ETH_HLEN)
 61                 return -EINVAL;
 62             break;
 63         }
 64 
 65         case OVS_ACTION_ATTR_HASH: {
 66             const struct ovs_action_hash *act_hash = nla_data(a);
 67 
 68             switch (act_hash->hash_alg) {
 69             case OVS_HASH_ALG_L4:
 70                 break;
 71             default:
 72                 return  -EINVAL;
 73             }
 74 
 75             break;
 76         }
 77 
 78         case OVS_ACTION_ATTR_POP_VLAN:
 79             if (mac_proto != MAC_PROTO_ETHERNET)
 80                 return -EINVAL;
 81             vlan_tci = htons(0);
 82             break;
 83 
 84         case OVS_ACTION_ATTR_PUSH_VLAN:
 85             if (mac_proto != MAC_PROTO_ETHERNET)
 86                 return -EINVAL;
 87             vlan = nla_data(a);
 88             if (!eth_type_vlan(vlan->vlan_tpid))
 89                 return -EINVAL;
 90             if (!(vlan->vlan_tci & htons(VLAN_TAG_PRESENT)))
 91                 return -EINVAL;
 92             vlan_tci = vlan->vlan_tci;
 93             break;
 94 
 95         case OVS_ACTION_ATTR_RECIRC:
 96             break;
 97 
 98         case OVS_ACTION_ATTR_PUSH_MPLS: {
 99             const struct ovs_action_push_mpls *mpls = nla_data(a);
100 
101             if (!eth_p_mpls(mpls->mpls_ethertype))
102                 return -EINVAL;
103             /* Prohibit push MPLS other than to a white list
104              * for packets that have a known tag order.
105              */
106             if (vlan_tci & htons(VLAN_TAG_PRESENT) ||
107                 (eth_type != htons(ETH_P_IP) &&
108                  eth_type != htons(ETH_P_IPV6) &&
109                  eth_type != htons(ETH_P_ARP) &&
110                  eth_type != htons(ETH_P_RARP) &&
111                  !eth_p_mpls(eth_type)))
112                 return -EINVAL;
113             eth_type = mpls->mpls_ethertype;
114             break;
115         }
116 
117         case OVS_ACTION_ATTR_POP_MPLS:
118             if (vlan_tci & htons(VLAN_TAG_PRESENT) ||
119                 !eth_p_mpls(eth_type))
120                 return -EINVAL;
121 
122             /* Disallow subsequent L2.5+ set and mpls_pop actions
123              * as there is no check here to ensure that the new
124              * eth_type is valid and thus set actions could
125              * write off the end of the packet or otherwise
126              * corrupt it.
127              *
128              * Support for these actions is planned using packet
129              * recirculation.
130              */
131             eth_type = htons(0);
132             break;
133 
134         case OVS_ACTION_ATTR_SET:
135             err = validate_set(a, key, sfa,
136                        &skip_copy, mac_proto, eth_type,
137                        false, log);
138             if (err)
139                 return err;
140             break;
141 
142         case OVS_ACTION_ATTR_SET_MASKED:
143             err = validate_set(a, key, sfa,
144                        &skip_copy, mac_proto, eth_type,
145                        true, log);
146             if (err)
147                 return err;
148             break;
149 
150         case OVS_ACTION_ATTR_SAMPLE: {
151             bool last = nla_is_last(a, rem);
152 
153             err = validate_and_copy_sample(net, a, key, sfa,
154                                eth_type, vlan_tci,
155                                log, last);
156             if (err)
157                 return err;
158             skip_copy = true;
159             break;
160         }
161 
162         case OVS_ACTION_ATTR_CT:
163             err = ovs_ct_copy_action(net, a, key, sfa, log);
164             if (err)
165                 return err;
166             skip_copy = true;
167             break;
168 
169         case OVS_ACTION_ATTR_CT_CLEAR:
170             break;
171 
172         case OVS_ACTION_ATTR_PUSH_ETH:
173             /* Disallow pushing an Ethernet header if one
174              * is already present */
175             if (mac_proto != MAC_PROTO_NONE)
176                 return -EINVAL;
177             mac_proto = MAC_PROTO_NONE;
178             break;
179 
180         case OVS_ACTION_ATTR_POP_ETH:
181             if (mac_proto != MAC_PROTO_ETHERNET)
182                 return -EINVAL;
183             if (vlan_tci & htons(VLAN_TAG_PRESENT))
184                 return -EINVAL;
185             mac_proto = MAC_PROTO_ETHERNET;
186             break;
187 
188         case OVS_ACTION_ATTR_PUSH_NSH:
189             if (mac_proto != MAC_PROTO_ETHERNET) {
190                 u8 next_proto;
191 
192                 next_proto = tun_p_from_eth_p(eth_type);
193                 if (!next_proto)
194                     return -EINVAL;
195             }
196             mac_proto = MAC_PROTO_NONE;
197             if (!validate_nsh(nla_data(a), false, true, true))
198                 return -EINVAL;
199             break;
200 
201         case OVS_ACTION_ATTR_POP_NSH: {
202             __be16 inner_proto;
203 
204             if (eth_type != htons(ETH_P_NSH))
205                 return -EINVAL;
206             inner_proto = tun_p_to_eth_p(key->nsh.base.np);
207             if (!inner_proto)
208                 return -EINVAL;
209             if (key->nsh.base.np == TUN_P_ETHERNET)
210                 mac_proto = MAC_PROTO_ETHERNET;
211             else
212                 mac_proto = MAC_PROTO_NONE;
213             break;
214         }
215 
216         default:
217             OVS_NLERR(log, "Unknown Action type %d", type);
218             return -EINVAL;
219         }
220         if (!skip_copy) {
221             err = copy_action(a, sfa, log);
222             if (err)
223                 return err;
224         }
225     }
226 
227     if (rem > 0)
228         return -EINVAL;
229 
230     return 0;
231 }

调试信息:

场景一:

流表:
ovs-ofctl add-flow aaa 'table=0, in_port=veth2 actions=push_mpls:0x8847,set_mpls_label:800,resubmit(,10)' -O openflow15
ovs-ofctl add-flow aaa 'table=10, mpls, mpls_label=800 actions=pop_mpls:0x0800,mod_dl_src=fe:22:33:44:55:66,mod_dl_dst=11:22:33:44:55:66,output:veth3' -O openflow15

调试信息:
3月 20 16:18:30 localhost.localdomain kernel: ovs_flow_cmd_new ... ...

3月 20 16:18:30 localhost.localdomain kernel: nla_for_each_nested, type=3, key_len=12
3月 20 16:18:30 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=-1
3月 20 16:18:30 localhost.localdomain kernel: type: 3, key_len=12
3月 20 16:18:30 localhost.localdomain kernel: OVS_ACTION_ATTR_SET
3月 20 16:18:30 localhost.localdomain kernel: type: 1, key_len=-1
3月 20 16:18:30 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:18:30 localhost.localdomain kernel: nla_for_each_nested, type=3, key_len=12
3月 20 16:18:30 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=-1
3月 20 16:18:30 localhost.localdomain kernel: type: 3, key_len=12
3月 20 16:18:30 localhost.localdomain kernel: OVS_ACTION_ATTR_SET
3月 20 16:18:30 localhost.localdomain kernel: type: 1, key_len=-1
3月 20 16:18:30 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:18:30 localhost.localdomain kernel: do_execute_actions, type: 20
3月 20 16:18:30 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_SET_TO_MASKED
3月 20 16:18:30 localhost.localdomain kernel: do_execute_actions, type: 1
3月 20 16:18:30 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_OUTPUT
3月 20 16:18:30 localhost.localdomain kernel: not find ovs flows ... ...
3月 20 16:18:30 localhost.localdomain kernel: queue_userspace_packet ... ...
3月 20 16:18:30 localhost.localdomain kernel: ovs_flow_cmd_new ... ...

场景二:

流表:
ovs-ofctl add-flow aaa 'table=0, in_port=veth2 actions=push_mpls:0x8847,set_mpls_label:800,output:veth3' -O openflow15
ovs-ofctl add-flow aaa 'table=0, in_port=veth4, mpls, mpls_label=800 actions=pop_mpls:0x0800,mod_dl_src=fe:22:33:44:55:66,mod_dl_dst=11:22:33:44:55:66,output:veth5' -O openflow15

调试信息:
3月 20 16:30:27 localhost.localdomain kernel: ovs_flow_cmd_new ... ...
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=9, key_len=12796
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=-1
3月 20 16:30:27 localhost.localdomain kernel: type: 9, key_len=12796
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_PUSH_MPLS
3月 20 16:30:27 localhost.localdomain kernel: type: 1, key_len=-1
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=9, key_len=12796
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=-1
3月 20 16:30:27 localhost.localdomain kernel: type: 9, key_len=12796
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_PUSH_MPLS
3月 20 16:30:27 localhost.localdomain kernel: type: 1, key_len=-1
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 9
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_PUSH_MPLS
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 1
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: not find ovs flows ... ...
3月 20 16:30:27 localhost.localdomain kernel: queue_userspace_packet ... ...
3月 20 16:30:27 localhost.localdomain kernel: ovs_flow_cmd_new ... ...
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=3, key_len=12
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=10, key_len=4
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=1
3月 20 16:30:27 localhost.localdomain kernel: type: 3, key_len=12
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_SET
3月 20 16:30:27 localhost.localdomain kernel: type: 10, key_len=4
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_POP_MPLS
3月 20 16:30:27 localhost.localdomain kernel: type: 1, key_len=1
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=3, key_len=12
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=10, key_len=4
3月 20 16:30:27 localhost.localdomain kernel: nla_for_each_nested, type=1, key_len=1
3月 20 16:30:27 localhost.localdomain kernel: type: 3, key_len=12
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_SET
3月 20 16:30:27 localhost.localdomain kernel: type: 10, key_len=4
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_POP_MPLS
3月 20 16:30:27 localhost.localdomain kernel: type: 1, key_len=1
3月 20 16:30:27 localhost.localdomain kernel: OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 20
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_SET_TO_MASKED
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 10
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_POP_MPLS
3月 20 16:30:27 localhost.localdomain kernel: do_execute_actions, type: 1
3月 20 16:30:27 localhost.localdomain kernel: kernel OVS_ACTION_ATTR_OUTPUT
3月 20 16:30:27 localhost.localdomain kernel: not find ovs flows ... ...
3月 20 16:30:27 localhost.localdomain kernel: queue_userspace_packet ... ...

总结:

以上以mpls封装解封装为例(或push_vlan,pop_vlan,push_nsh,pop_nsh,push_eth,pop_eth等)

从场景一和场景二得出结论:

流表从in到out中间的过程,如果同时存在push和pop动作,ovs会跳过push和pop动作的处理,不会copy到kernel的流表项中

原文地址:https://www.cnblogs.com/wangjq19920210/p/10564531.html