• ovs 数据包的处理过程


    Openvswitch的内核模块openvswitch.ko会在网卡上注册一个函数netdev_frame_hook,每当有网络包到达网卡的时候,这个函数就会被调用。

    static struct sk_buff *netdev_frame_hook(struct sk_buff *skb)
    {
       if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
          return skb;
     
       port_receive(skb);
       return NULL;
    }
    

    调用port_receive即是调用netdev_port_receive

    define port_receive(skb) netdev_port_receive(skb, NULL)

    void netdev_port_receive(struct sk_buff *skb, struct ip_tunnel_info *tun_info)
    {
       struct vport *vport;
     
       vport = ovs_netdev_get_vport(skb->dev);
    ……
       skb_push(skb, ETH_HLEN);
       ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
       ovs_vport_receive(vport, skb, tun_info);
       return;
    error:
       kfree_skb(skb);
    }
    

    在函数int ovs_vport_receive(struct vport *vport, struct sk_buff *skb, const struct ip_tunnel_info *tun_info)实现如下

    int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
                const struct ip_tunnel_info *tun_info)
    {
       struct sw_flow_key key;
       ......
       /* Extract flow from 'skb' into 'key'. */
       error = ovs_flow_key_extract(tun_info, skb, &key);
       if (unlikely(error)) {
          kfree_skb(skb);
          return error;
       }
       ovs_dp_process_packet(skb, &key);
       return 0;
    }
    

    在这个函数里面,首先声明了变量struct sw_flow_key key;可见这个key里面是一个大杂烩,数据包里面的几乎任何部分都可以作为key来查找flow表

    tunnel可以作为key
    在物理层,in_port即包进入的网口的ID
    在MAC层,源和目的MAC地址
    在IP层,源和目的IP地址
    在传输层,源和目的端口号
    IPV6
    所以,要在内核态匹配流表,首先需要调用ovs_flow_key_extract,从包的正文中提取key的值。

    接下来就是要调用ovs_dp_process_packet了。

    void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
    {
       const struct vport *p = OVS_CB(skb)->input_vport;
       struct datapath *dp = p->dp;
       struct sw_flow *flow;
       struct sw_flow_actions *sf_acts;
       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, key, skb_get_hash(skb),
                    &n_mask_hit);
       if (unlikely(!flow)) {
          struct dp_upcall_info upcall;
          int error;
     
          memset(&upcall, 0, sizeof(upcall));
          upcall.cmd = OVS_PACKET_CMD_MISS;
          upcall.portid = ovs_vport_find_upcall_portid(p, skb);
          upcall.mru = OVS_CB(skb)->mru;
          error = ovs_dp_upcall(dp, skb, key, &upcall);
          if (unlikely(error))
             kfree_skb(skb);
          else
             consume_skb(skb);
          stats_counter = &stats->n_missed;
          goto out;
       }
     
       ovs_flow_stats_update(flow, key->tp.flags, skb);
       sf_acts = rcu_dereference(flow->sf_acts);
       ovs_execute_actions(dp, skb, sf_acts, key);
     
       stats_counter = &stats->n_hit;
     
    out:
       /* Update datapath statistics. */
       u64_stats_update_begin(&stats->syncp);
       (*stats_counter)++;
       stats->n_mask_hit += n_mask_hit;
       u64_stats_update_end(&stats->syncp);
    }
    

    这个函数首先在内核里面的流表中查找符合key的flow,也即ovs_flow_tbl_lookup_stats,如果找到了,很好说明用户态的流表已经放入内核,则走fast path就可了。于是直接调用ovs_execute_actions,执行这个key对应的action。

    如果不能找到,则只好调用ovs_dp_upcall,让用户态去查找流表。会调用static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, const struct sw_flow_key *key, const struct dp_upcall_info *upcall_info)

    它会调用err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);通过netlink将消息发送给用户态。在用户态,有线程监听消息,一旦有消息,则触发udpif_upcall_handler。

    1. 从Device接收Packet交给事先注册的event handler进行处理
    2. 接收Packet后识别是否是unknown packet,是则交由upcall处理
    3. vswitchd对unknown packet找到flow rule进行处理
    4. 将Flow rule发送给datapath
      也就是说OVS处理数据包首先会看有没有事先订阅的事件,如果有直接转交给该对应的处理函数,然后匹配流表,最后按照传统网络协议栈进行处理。
  • 相关阅读:
    form表单回车提交
    Mac os x下配置nginx + php
    Mac下git命令自动补全
    关于javascript中的操作符&&和||的最终返回值
    ARM 裸机程序学习 01 点亮LED
    LINUX SHELL 中 2>&1 重定向的问题
    项目经理到底关心项目的什么?——有关外包项目成本的计算
    ARM 裸机程序学习 03 发送SOS信号(汇编 + C)
    ARM 裸机程序学习 02 按响BEEP
    备忘录 Linux及其内核杂项知识
  • 原文地址:https://www.cnblogs.com/janeysj/p/11194868.html
Copyright © 2020-2023  润新知