OVS源码connmgr_run分析

connmgr即connect manager连接管理器,主要完成OVS网桥的连接管理。每一个网桥ofproto都有一个connmgr实体来管理连接。connmgr主要完成两种连接管理,一种是主动连接(即与控制器连接,作为客户端),一种是被动连接(主要提供ofctl等工具连接请求服务和snoop服务,作为服务端)。connmgr结构体中,all_conns是主动连接,services和snoops等提供被动连接服务。与connmgr_run流程相关的结构体如下图:


一个connmgr对应多个ofconn(如一个网桥连接多个控制器,则需要建立相应多个ofconn实例;和ofctl等工具连接时也要建立ofconn实例);一个ofconn对应一个rconn;一个rconn对应多个vconn(因为和控制器建立连接外,可能还会实现snoop功能,即监测并复制交互的of消息,则一个rconn会对应一个vconn和一个vconn结构体类型的数组monitor


connmgr_run主要包含in_band_run, ofconn_run,以及一些与被动连接相关的流程。

connmgr_run(struct connmgr *mgr,
            void (*handle_openflow)(struct ofconn *,
                                    const struct ofpbuf *ofp_msg))
    OVS_EXCLUDED(ofproto_mutex)
{
    struct ofconn *ofconn, *next_ofconn;
    struct ofservice *ofservice;
    size_t i;

    if (mgr->in_band) {
        if (!in_band_run(mgr->in_band)) {
            in_band_destroy(mgr->in_band);
            mgr->in_band = NULL;
        }
    }

    LIST_FOR_EACH_SAFE (ofconn, next_ofconn, node, &mgr->all_conns) {
        ofconn_run(ofconn, handle_openflow);
    }

    /*When too many flow monitor notifications back up in the transmit buffer,
     * we pause the transmission of further notifications.  These members track
     * the flow control state. */
    ofmonitor_run(mgr);                       

    /* Fail-open maintenance.  Do this after processing the ofconns since
     * fail-open checks the status of the controller rconn. */
    if (mgr->fail_open) {
        fail_open_run(mgr->fail_open);
    }

    HMAP_FOR_EACH (ofservice, node, &mgr->services) {
        struct vconn *vconn;
        int retval;

         /*最终将调用pstream_class->accept实现与punix,pssl,ptcp等被动连接*/
        retval = pvconn_accept(ofservice->pvconn, &vconn);    
        if (!retval) {
            struct rconn *rconn;
            char *name;

            /* 对被动连接创建默认rconn实例 */
            rconn = rconn_create(ofservice->probe_interval, 0, ofservice->dscp,
                                 vconn_get_allowed_versions(vconn));     
            name = ofconn_make_name(mgr, vconn_get_name(vconn));
            /*断开rconn现有连接,并将rconn与被动连接vconn相连*/
            rconn_connect_unreliably(rconn, vconn, name);                
            free(name);

            ovs_mutex_lock(&ofproto_mutex);

            /*根据rconn对被动连接创建ofconn实例*/
            ofconn = ofconn_create(mgr, rconn, OFCONN_SERVICE,
                                   ofservice->enable_async_msgs);      
            ovs_mutex_unlock(&ofproto_mutex);

            ofconn_set_rate_limit(ofconn, ofservice->rate_limit,
                                  ofservice->burst_limit);
        } else if (retval != EAGAIN) {
            VLOG_WARN_RL(&rl, "accept failed (%s)", ovs_strerror(retval));
        }
    }

    for (i = 0; i < mgr->n_snoops; i++) {
        struct vconn *vconn;
        int retval;

        /*为snoops创建vconn*/
        retval = pvconn_accept(mgr->snoops[i], &vconn);               
        if (!retval) {
            /*snooper与ofservice不同在于snooper不用创建ofconn与rconn实例
            *而是在所有的ofconn中根据ofconn->role等级挑选最佳的ofconn
            *然后将snoops的vconn加入到最佳ofconn的monitor中,对该rconn进行监听*/
            add_snooper(mgr, vconn);                 
        } else if (retval != EAGAIN) {
            VLOG_WARN_RL(&rl, "accept failed (%s)", ovs_strerror(retval));
        }
    }
}

in_band_run:因为OpenvSwitch不仅仅是一个OpenFlow Switch,它的流表组成除了of流表外,还有其他一些(隐藏)流表。这些隐藏流表是由于默认交换机和控制器在同一网络中(in-band),因此要保证两者互通。要关闭默认的inband可以通过“ovs-vsctl set controller br0 connection-mode=out-of-band”

in_band_run(struct in_band *ib)
{
    uint64_t ofpacts_stub[128 / 8];
    struct ofpbuf ofpacts;

    struct in_band_rule *rule, *next;

    ...

    refresh_local(ib);      //刷新本地MAC
    refresh_remotes(ib);    //刷新远端MAC

    update_rules(ib);       //处理本地local port以及所有远端port的ARP,DHCP,TCP等协议

    HMAP_FOR_EACH_SAFE (rule, next, hmap_node, &ib->rules) {
        switch (rule->op) {
        case ADD:
            ofproto_add_flow(ib->ofproto, &rule->match, rule->priority,
                             ofpacts.data, ofpacts.size);
            break;

        case DEL:
            ovs_mutex_lock(&ofproto_mutex);
            ofproto_delete_flow(ib->ofproto, &rule->match, rule->priority);
            ovs_mutex_unlock(&ofproto_mutex);
            hmap_remove(&ib->rules, &rule->hmap_node);
            free(rule);
            break;
        }
    }

    ofpbuf_uninit(&ofpacts);

    return ib->n_remotes || !hmap_is_empty(&ib->rules);
}
ofconn_run:对与connmgr所有的主动连接all_conns产生的ofconn进行处理,主要完成网桥与控制器连接的状态转移管理和of消息的接收处理等。
ofconn_run(struct ofconn *ofconn,
           void (*handle_openflow)(struct ofconn *,
                                   const struct ofpbuf *ofp_msg))
{
    struct connmgr *mgr = ofconn->connmgr;
    size_t i;

    for (i = 0; i < N_SCHEDULERS; i++) {
        struct ovs_list txq;


        pinsched_run(ofconn->schedulers[i], &txq);     //处理OFPT_PACKET_IN异步队列流程
        do_send_packet_ins(ofconn, &txq);
    }

    rconn_run(ofconn->rconn);                    //发送报文流程

    /* Limit the number of iterations to avoid starving other tasks. */
    for (i = 0; i < 50 && ofconn_may_recv(ofconn); i++) {
        struct ofpbuf *of_msg = rconn_recv(ofconn->rconn);          //接收报文流程

        ...

        handle_openflow(ofconn, of_msg);        //调用handle_openflow对openflow消息具体处理
        
        ...
    }

    ...
}

以下将具体分析openflow消息收发流程

pinsched_run根据令牌桶分配将pinqueue队列中的报文出队,然后将该该报文放入txq中

pinsched_run(struct pinsched *ps, struct ovs_list *txq)
{
    ovs_list_init(txq);
    if (ps) {
        int i;

        /* Drain some packets out of the bucket if possible, but limit the
         * number of iterations to allow other code to get work done too. */
        for (i = 0; ps->n_queued && get_token(ps) && i < 50; i++) {
            struct ofpbuf *packet = get_tx_packet(ps);     //在ps中删除该报文,并且返回该报文
            ovs_list_push_back(txq, &packet->list_node);
        }
    }
}
do_send_packet_ins最终将调用vconn_send发送报文。

rconn_run-->vconn_run-->vconn_stream_run-->stream_send-->fd_send最终发送报文。

rconn_run(struct rconn *rc)
{
    int old_state;
    size_t i;

    if (rc->vconn) {
        ...

        vconn_run(rc->vconn);

        ...
    }

    /*monitor连接后,复制得到的openflow消息发送回ofctl客户端
    并将监测复制得到的of消息接收到相应rc->n_monitors[i]实例中*/
    for (i = 0; i < rc->n_monitors; ) {
        struct ofpbuf *msg;
        int retval;

        vconn_run(rc->monitors[i]);

        /* Drain any stray message that came in on the monitor connection. */
        retval = vconn_recv(rc->monitors[i], &msg);
        if (!retval) {
            ofpbuf_delete(msg);
        } else if (retval != EAGAIN) {
            close_monitor(rc, i, retval);
            continue;
        }
        i++;
    }

    ...
}
rconn_recv->vconn_recv->do_recv->vconn_stream_recv->vconn_stream_recv__->stream_recv

rconn_recv(struct rconn *rc)
{
    struct ofpbuf *buffer = NULL;

    ovs_mutex_lock(&rc->mutex);
    if (rc->state & (S_ACTIVE | S_IDLE)) {
        int error = vconn_recv(rc->vconn, &buffer);    
        if (!error) {
            copy_to_monitor(rc, buffer);        //将vconn收的报文复制到每一个monitor
            ...
    }
    return buffer;
}
收发包过程最终都是操作ofpbuf结构体,该结构体图如下:



本文主要参考:https://www.sdnlab.com/16144.html,加上了一点点自己的理解,如有错误,请悉心指正,谢谢。

版权声明:本文为u010378472原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010378472/article/details/79087031

智能推荐

1638 统计只差一个字符的子串数目(动态规划)

1. 问题描述: 给你两个字符串 s 和 t ,请你找出 s 中的非空子串的数目,这些子串满足替换一个不同字符以后,是 t 串的子串。换言之,请你找到 s 和 t 串中恰好只有一个字符不同的子字符串对的数目。比方说, "computer" 和 "computation"...

websocket基本原理

HTTP中一个request只能有一个response。而且这个response也是被动的,不能主动发起 因此过去的服务端推送信息是通过客户端不停的轮询实现的 websocket是双向通信协议,提供了服务端主动推送信息的能力 需要客户端(浏览器)和服务端同时支持 如果经过代理的话,还需要代理支持,否则有些代理在长时间无通信时会自动切断连接 因此WS为了保证连接不被断掉,会发心跳 WebSocket...

mybatis+ehcache二级缓存

导入jar包 mapper.xml文件开启二级缓存 pojo类实现序列化接口 配置ehcache.xml 测试...

python+opencv实现图像拼接

任务 拍摄两张图片去除相同部分,拼接在一起 原图 结果 步骤 读取两张图片 使用sift检测关键点及描述因子 匹配关键点 处理并保存关键点 得到变换矩阵 图像变换并拼接 代码实现 扩展 这里对右边图像进行变换,右边变得模糊,可以修改代码对左边图像变换 这里只有两张图片拼接,可以封装实现多张图片拼接 可以修改代码实现上下图片的拼接...

python_sklearn机器学习算法系列之AdaBoost------人脸识别(PCA,决策树)

          注:在读本文之前建议读一下之前的一片文章python_sklearn机器学习算法系列之PCA(主成分分析)------人脸识别(k-NearestNeighbor,KNN)         本文主要目的是通过一个简单的小...

猜你喜欢

memmove函数与memcpy函数的模拟实现

memmove函数和memcpy函数都是在内存复制任意类型的,但是它俩也有区别。当源区域和目标区域有重复的,memmove函数会复制缓冲区重叠的部分,而memcpy相反,会报出未知错误。 下面给出两个函数的实现 首先,memmove函数。 实现的基本原理如下图。 具体代码如下: memcpy函数的实现很简单,就直接给出源代码了...

SpringFramework核心 - IOC容器的实现 - 总结

1. 概述 把Spring技术内幕第一章和第二章过了一遍,也做了一些笔记, 对IOC容器的实现有了一定皮毛理解,现在跟着源码再过一遍总结一下IOC容器的初始化,Bean的初始化的过程,做一下总结 ① IOC容器和简单工厂模式 在开始之前,先想想我们平时是怎么使用IOC容器为我们管理Bean的,假设我们要把下面的User类交给IOC容器管理 我们不想关心如何创建一个User对象实例的,仅仅在需要他的...

Python和Django的安装

个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈  一、下载并安装Python Python 官方下载地址:http://www.python.org/ftp/python/ 我们这里选择的是 Python 2.7.2 。虽然目前最新版是Python 3.2.2, 但是Django目前还不支持 Python 3.2.2。 安装步骤很简单,双击安装包开...

OpenStack代码贡献初体验

为什么80%的码农都做不了架构师?>>>     OpenStack如今已成为开源云平台中的明星项目,得到广泛关注。OpenStack的优秀出众依赖于众多开发者的努力,在享受其带来的便利与快捷的同时,为其做一份贡献也是一个开发者的义务。  在前段时间的OpenStack的测试过程中,我发现Nova项目中的一个Bug,于是向社区提交了Bug报...