OpenvSwitch 解读
报文匹配流程参考下图
调用流程(内核):
ovs_vport_receive->ovs_dp_process_received_packet->ovs_flow_tbl_lookup->ovs_dp_upcall->queue_userspace_packet
调用流程(用户态):
handle_miss_upcalls->handle_flow_miss->rule_dpif_lookup->rule_dpif_lookup__->classifier_lookup->find_match
packet接收处理
继续上面所说的,当接收包将会发生如下代码流:
netif_receive_skb
netif_receive_skb(struct sk_buff *skb)
从网络中接收数据,它是主要的接收数据处理函数,总是成功,这个buffer在拥塞处理或协议层的时候可能被丢弃。这个函数只能从软中断环境(softirq context)中调用,并且中断允许。返回值NET_RX_SUCCESS
表示没有拥塞,NET_RX_DROP
包丢弃。netdev_frame_hook()
其调用netdev_port_receive()
netdev_port_receive()
函数netdev_port_receive()
首先检查是否skb被共享,若是则得到一个packet的拷贝。 其调用ovs_vport_receive()
。检查包的校验和,然后交付给我们的vport通用层来处理。ovs_vport_receive()
将收到的packet传给datapath处理。 其调用ovs_dp_process_received_packet()
。ovs_dp_process_received_packet()
在ovs_dp_process_received_packet()
(datapath/datapath.c)中进行复杂的包处理过程,进行流查表,查表后执行对应的行为。当查找失败时候,使用ovs_dp_upcall()
发送 upcall到用户空间(ovs-vswitchd)。此后处理过程交给 ovsd 处理。其将产生以下代码流:ovs_dp_process_received_packet()
=>ovs_dp_upcall()
=>queue_userspace_packet()
本步骤具体内容可以参考我的另外一篇博客:ovs中流表在内核空间与用户空间的匹配过程
1 /* Must be called with rcu_read_lock. */ 2 void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key) 3 { 4 const struct vport *p = OVS_CB(skb)->input_vport; 5 struct datapath *dp = p->dp; 6 struct sw_flow *flow; 7 struct sw_flow_actions *sf_acts; 8 struct dp_stats_percpu *stats; 9 u64 *stats_counter; 10 u32 n_mask_hit; 11 12 stats = this_cpu_ptr(dp->stats_percpu); 13 14 /* Look up flow. */ 15 flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb), 16 &n_mask_hit); 17 if (unlikely(!flow)) { 18 struct dp_upcall_info upcall; 19 int error; 20 21 memset(&upcall, 0, sizeof(upcall)); 22 upcall.cmd = OVS_PACKET_CMD_MISS; 23 upcall.portid = ovs_vport_find_upcall_portid(p, skb); 24 upcall.mru = OVS_CB(skb)->mru; 25 error = ovs_dp_upcall(dp, skb, key, &upcall, 0); 26 if (unlikely(error)) 27 kfree_skb(skb); 28 else 29 consume_skb(skb); 30 stats_counter = &stats->n_missed; 31 goto out; 32 } 33 34 ovs_flow_stats_update(flow, key->tp.flags, skb); 35 sf_acts = rcu_dereference(flow->sf_acts); 36 ovs_execute_actions(dp, skb, sf_acts, key); 37 38 stats_counter = &stats->n_hit; 39 40 out: 41 /* Update datapath statistics. */ 42 u64_stats_update_begin(&stats->syncp); 43 (*stats_counter)++; 44 stats->n_mask_hit += n_mask_hit; 45 u64_stats_update_end(&stats->syncp); 46 }