• OpenvSwitch 解读


    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接收处理

      继续上面所说的,当接收包将会发生如下代码流:

      1. netif_receive_skb 
        netif_receive_skb(struct sk_buff *skb)从网络中接收数据,它是主要的接收数据处理函数,总是成功,这个buffer在拥塞处理或协议层的时候可能被丢弃。这个函数只能从软中断环境(softirq context)中调用,并且中断允许。返回值NET_RX_SUCCESS表示没有拥塞,NET_RX_DROP包丢弃。
      2. netdev_frame_hook() 
        其调用netdev_port_receive()
      3. netdev_port_receive() 
        函数netdev_port_receive()首先检查是否skb被共享,若是则得到一个packet的拷贝。 其调用ovs_vport_receive()。检查包的校验和,然后交付给我们的vport通用层来处理。
      4. ovs_vport_receive() 
        将收到的packet传给datapath处理。 其调用ovs_dp_process_received_packet()
      5. 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 }
  • 相关阅读:
    规划分类
    java 命名空间
    何为"IOE"、"去IOE"
    vSphere 6.7 新特性 — 基于虚拟化的安全 (VBS)
    RHCE
    VCPU的解释
    VMware vSphere学习整理
    Vmware
    Linux启动
    Linux相关笔记
  • 原文地址:https://www.cnblogs.com/wangjq19920210/p/10196413.html
Copyright © 2020-2023  润新知