先整理粗稿,后面再细化。
当调用ovs-vsctl add-port br-test eth0的时候调用netdev_create(datapath/vport-netdev.c),并通调用netdev_rx_handler_register注册设备收备报文后的处理方法:netdev_frame_hook。这样就能将接收报文将交给ovs处理,不走内核协议栈。
netdev_port_receive->ovs_vport_receive
void ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
struct ovs_key_ipv4_tunnel *tun_key)
{
struct pcpu_sw_netstats *stats;
stats = this_cpu_ptr(vport->percpu_stats);
u64_stats_update_begin(&stats->syncp);
//报文计数增加
stats->rx_packets++;
stats->rx_bytes += skb->len;
u64_stats_update_end(&stats->syncp);
OVS_CB(skb)->tun_key = tun_key;
ovs_dp_process_received_packet(vport, skb);
}
ovs_dp_process_received_packet-> ovs_dp_process_packet_with_key
void ovs_dp_process_packet_with_key(struct sk_buff *skb,
struct sw_flow_key *pkt_key,
bool recirc)
{
const struct vport *p = OVS_CB(skb)->input_vport;
struct datapath *dp = p->dp;
struct sw_flow *flow;
struct dp_stats_percpu *stats;
u64 *stats_counter;
u32 n_mask_hit;
stats = this_cpu_ptr(dp->stats_percpu);
/* Look up flow. */
//查找内核态流表
flow = ovs_flow_tbl_lookup_stats(&dp->table, pkt_key, skb_get_hash(skb),
&n_mask_hit);
//未查询到内核态流表,使用netlink机制调用upcall将报文送到用户态处理并生成内核态流表
if (unlikely(!flow)) {
struct dp_upcall_info upcall;
upcall.cmd = OVS_PACKET_CMD_MISS;
upcall.key = pkt_key;
upcall.userdata = NULL;
upcall.portid = ovs_vport_find_upcall_portid(p, skb);
ovs_dp_upcall(dp, skb, &upcall);
consume_skb(skb);
stats_counter = &stats->n_missed;
goto out;
}
OVS_CB(skb)->pkt_key = pkt_key;
OVS_CB(skb)->flow = flow;
//匹配到内核态流表后执行对应的actions,对报文做处理。
ovs_flow_stats_update(OVS_CB(skb)->flow, pkt_key->tp.flags, skb);
ovs_execute_actions(dp, skb, recirc);
stats_counter = &stats->n_hit;
out:
/* Update datapath statistics. */
u64_stats_update_begin(&stats->sync);
(*stats_counter)++;
stats->n_mask_hit += n_mask_hit;
u64_stats_update_end(&stats->sync);
}
综上所述,在接收报文后会有如下的函数调用。
netdev_frame_hook-> netdev_port_receive ->ovs_skb_postpush_rcsum(?)-> ovs_vport_receive(数据统计变化) -> ovs_dp_process_received_packet->ovs_dp_process_packet_with_key->ovs_flow_tbl_lookup_stats(查找内核态,若失败则调用upcall查询用户态)->ovs_execute_actions