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的流表项中