OVS源码分析-datapath流程

简介: 点击关注阿里云科技快讯,关注最新大新闻!还有机会获得精美礼品!! 首先每个packet都会被datapath/vport.c : line 481的ovs_vport_receive函数接受。

chatu

首先每个packet都会被datapath/vport.c : line 481ovs_vport_receive函数接受。这个是第一步。

int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
              const struct ip_tunnel_info *tun_info)
{
    struct sw_flow_key key;  //  packet包头信息的提取,便于后面进行流表的匹配
    int error;
    OVS_CB(skb)->input_vport = vport;  //  在skb_buff数据结构里,有个struct cb 用来存放临时信息的。
    OVS_CB(skb)->mru = 0;
    OVS_CB(skb)->cutlen = 0;
    if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
        u32 mark;
        mark = skb->mark;
        skb_scrub_packet(skb, true);
        skb->mark = mark;
        tun_info = NULL;
    }
    ovs_skb_init_inner_protocol(skb);
    skb_clear_ovs_gso_cb(skb);
    /* 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;
}

然后由datapath/datapath.c中的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;  //  获取此packet是从哪个vport进来的。
    struct datapath *dp = p->dp;  //  从struct vport 中获取vport所属的datapath
    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. */
    // 在datapath中查找匹配的流表项。
    flow = ovs_flow_tbl_lookup_stats(&dp->table, key, skb_get_hash(skb),
                     &n_mask_hit);
    //  如果查找失败,没有匹配的流表,则进行upcall,上报到用户态。                  
    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, 0);
        if (unlikely(error))
            kfree_skb(skb);
        else
            consume_skb(skb);
        stats_counter = &stats->n_missed;
        goto out;
    }
    // 如果匹配到,则执行action
    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);
}

如果流表匹配成功,则执行流表相对应的action。函数是datapath/actions中的ovs_execute_actions函数对数据包执行action。代码如下:


int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb,
            const struct sw_flow_actions *acts,
            struct sw_flow_key *key)
{
    int err, level;
    level = __this_cpu_inc_return(exec_actions_level);
    if (unlikely(level > OVS_RECURSION_LIMIT)) {
        net_crit_ratelimited("ovs: recursion limit reached on datapath %s, probable configuration error\n",
                     ovs_dp_name(dp));
        kfree_skb(skb);
        err = -ENETDOWN;
        goto out;
    }
    err = do_execute_actions(dp, skb, key,
                 acts->actions, acts->actions_len);
    if (level == 1)
        process_deferred_actions(dp);
out:
    __this_cpu_dec(exec_actions_level);
    return err;
}

在上面的函数中有个do_execute_actions函数,里面是针对OVS_ACTION_ATTR_*来执行相对应的action函数。最终如果从某个端口转发出去,则会执行do_output函数,通过调用datapath/vport.c/ovs_vport_send函数进行端口转发。这就是一个数据包如果在datapath中匹配到流表的大致流程。

如果没有匹配成功,则执行upcall,函数是datapath/ovs_dp_upcall函数,代码如下:

int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
          const struct sw_flow_key *key,
          const struct dp_upcall_info *upcall_info,
          uint32_t cutlen)
{
    struct dp_stats_percpu *stats;
    int err;
    // 判断pid是否为0,这个是用来NetLink通讯使用的,为0表示传给内核空间
    if (upcall_info->portid == 0) {
        err = -ENOTCONN;
        goto err;
    }
    if (!skb_is_gso(skb))
    // 如果不是gso数据包,则直接发送到用户队列,这个在之前有说明
        err = queue_userspace_packet(dp, skb, key, upcall_info, cutlen);
    else
    // 如果是gso数据包,则先处理gso协议,然后继续发送到用户队列
    // 函数里最终会把数据包发送到上面的函数中 queue_userspace_packet
        err = queue_gso_packets(dp, skb, key, upcall_info, cutlen);
    if (err)
        goto err;
    return 0;
err:
    stats = this_cpu_ptr(dp->stats_percpu);
    u64_stats_update_begin(&stats->syncp);
    stats->n_lost++;
    u64_stats_update_end(&stats->syncp);
    return err;
}

点击关注阿里云科技快讯,关注最新大新闻!还有机会获得精美礼品!!


image


QQ_20180808145819
相关文章
|
数据库
OVS 总体架构、源码结构及数据流程全面解析
在前文「从 Bridge 到 OVS」中,我们已经对 OVS 进行了一番探索。本文决定从 OVS 的整体架构到各个组件都进行一个详细的介绍。 OVS 架构 OVS 是产品级的虚拟交换机,大量应用在生产环境中,支撑整个数据中心虚拟网络的运转。
4610 0
|
Linux C语言 Python
CentOS7下升级GLIBC2.31
CentOS7下升级GLIBC2.31
4001 0
CentOS7下升级GLIBC2.31
|
存储 缓存 网络安全
在局域网内访问项目时遇到了OSS路径错误的问题
在局域网内访问项目时遇到了OSS路径错误的问题
1030 2
Debian 官方源换为国内的源的操作方法
apt-get update 报错,采用更换源的方式解决问题。
56425 0
|
缓存 Linux 开发工具
CentOS 7- 配置阿里镜像源
阿里镜像官方地址http://mirrors.aliyun.com/ 1、点击官方提供的相应系统的帮助 :2、查看不同版本的系统操作: 下载源1、安装wget yum install -y wget2、下载CentOS 7的repo文件wget -O /etc/yum.
258402 0
|
人工智能 算法 安全
深度讲解-互联网算法备案指南和教程
随着人工智能和大数据技术的发展,互联网算法在内容推荐、用户画像等领域日益重要,但也带来了安全风险和合规挑战。国家互联网信息办公室为此发布了《互联网算法备案管理规定》,要求具有舆论属性或社会动员能力的互联网信息服务提供者进行算法备案,以确保算法透明性和合规性,维护网络健康秩序。唯安创远AI合规专家将解析备案的必要性、流程及其对企业的影响,帮助企业顺利完成备案。
1019 3
|
Linux
Red Hat下载ISO镜像的方法
Red Hat 是一家全球领先的开源技术解决方案提供商,总部位于美国北卡罗来纳州罗利。该公司成立于1993年,其主要产品是 Red Hat Enterprise Linux (RHEL) 操作系统。Red Hat 还提供其他产品和解决方案,如 OpenShift、Virtualization、Ansible 等,用于企业级应用的开发、部署和管理。Red Hat 的产品和服务广泛应用于各个行业的企业,其开源背景和社区合作模式使其成为许多企业的首选技术合作伙伴。
2544 1
|
算法 网络协议 Shell
掌握Linux网络:深入理解TC —— 你的流量控制利器
目前需要做一款关于Linux下对于某IP限制的一个工具(QOS),在网上寻找了许多关于TC的教程,大多数都是一些比较基础的教学,且多数都是对网口的一些限制,然后自己研究了一段时间,最后有一些小小的了解,故在此分享给大家。
2750 0
|
Ubuntu Linux 网络安全
|
存储 Kubernetes 负载均衡
kubernetes容器网络
K8S容器网络的原理及实践
1891 2
kubernetes容器网络