【OVS2.5.0源码分析】openflow连接实现分析(5)

原创 2016年08月28日 15:21:41

上一篇分析了ofservice创建过程,本篇将分析ofservice处理请求的过程,ofservice处理请求的过程也是在connmgr_run函数。


1、connmgr_run函数

void
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);     //针对所有的ofconn(controller和ofservice),处理接收到请求
    }
    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) {   //常见的情况是有一个service
        struct vconn *vconn;
        int retval;

        retval = pvconn_accept(ofservice->pvconn, &vconn);   //感觉一个请求应该只能accept一次,该函数为非阻塞的
        if (!retval) {
            struct rconn *rconn;
            char *name;

            /* Passing default value for creation of the 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_connect_unreliably(rconn, vconn, name);
            free(name);

            ovs_mutex_lock(&ofproto_mutex);
            ofconn = ofconn_create(mgr, rconn, OFCONN_SERVICE,   //创建ofconn,会插入到all_conns链表中,下一次执行connmgr_run函数时,会调用ofconn_run
                                   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;

        retval = pvconn_accept(mgr->snoops[i], &vconn);
        if (!retval) {
            add_snooper(mgr, vconn);
        } else if (retval != EAGAIN) {
            VLOG_WARN_RL(&rl, "accept failed (%s)", ovs_strerror(retval));
        }
    }
}


2、pvconn_accept函数

/* Tries to accept a new connection on 'pvconn'.  If successful, stores the new
 * connection in '*new_vconn' and returns 0.  Otherwise, returns a positive
 * errno value.
 *
 * The new vconn will automatically negotiate an OpenFlow protocol version
 * acceptable to both peers on the connection.  The version negotiated will be
 * no lower than 'min_version' and no higher than 'max_version'.
 *
 * pvconn_accept() will not block waiting for a connection.  If no connection
 * is ready to be accepted, it returns EAGAIN immediately. */
int
pvconn_accept(struct pvconn *pvconn, struct vconn **new_vconn)
{
    int retval = (pvconn->pvclass->accept)(pvconn, new_vconn);	//实际调用pvconn_pstream_accept函数
    if (retval) {
        *new_vconn = NULL;
    } else {
        ovs_assert((*new_vconn)->state != VCS_CONNECTING
                   || (*new_vconn)->vclass->connect);
    }
    return retval;
}

3、pvconn_pstream_accept函数

static int
pvconn_pstream_accept(struct pvconn *pvconn, struct vconn **new_vconnp)
{
    struct pvconn_pstream *ps = pvconn_pstream_cast(pvconn);
    struct stream *stream;
    int error;

    error = pstream_accept(ps->pstream, &stream);   
    if (error) {
        if (error != EAGAIN) {
            VLOG_DBG_RL(&rl, "%s: accept: %s",
                        pstream_get_name(ps->pstream), ovs_strerror(error));
        }
        return error;
    }

    *new_vconnp = vconn_stream_new(stream, 0, pvconn->allowed_versions);   //建立连接,则构造vconn对象
    return 0;
}

4、pstream_accept函数

/* Tries to accept a new connection on 'pstream'.  If successful, stores the
 * new connection in '*new_stream' and returns 0.  Otherwise, returns a
 * positive errno value.
 *
 * pstream_accept() will not block waiting for a connection.  If no connection
 * is ready to be accepted, it returns EAGAIN immediately. */
int
pstream_accept(struct pstream *pstream, struct stream **new_stream)
{
    int retval = (pstream->class->accept)(pstream, new_stream);   //punix类型,调用fd_pstream_class
    if (retval) {
        *new_stream = NULL;
    } else {
        ovs_assert((*new_stream)->state != SCS_CONNECTING
                   || (*new_stream)->class->connect);
    }
    return retval;
}

5、pfd_accept函数

static int
pfd_accept(struct pstream *pstream, struct stream **new_streamp)
{
    struct fd_pstream *ps = fd_pstream_cast(pstream);
    struct sockaddr_storage ss;
    socklen_t ss_len = sizeof ss;
    int new_fd;
    int retval;

    new_fd = accept(ps->fd, (struct sockaddr *) &ss, &ss_len);   //调用linux的accept函数
    if (new_fd < 0) {
        retval = sock_errno();
#ifdef _WIN32
        if (retval == WSAEWOULDBLOCK) {
            retval = EAGAIN;
        }
#endif
        if (retval != EAGAIN) {
            VLOG_DBG_RL(&rl, "accept: %s", sock_strerror(retval));
        }
        return retval;
    }

    retval = set_nonblocking(new_fd);
    if (retval) {
        closesocket(new_fd);
        return retval;
    }

    return ps->accept_cb(new_fd, &ss, ss_len, new_streamp);    //执行accept回调函数,punix类型为punix_accept函数
}

6、punix_accept函数

static int
punix_accept(int fd, const struct sockaddr_storage *ss, size_t ss_len,
             struct stream **streamp)
{
    const struct sockaddr_un *sun = (const struct sockaddr_un *) ss;
    int name_len = get_unix_name_len(ss_len);
    char name[128];

    if (name_len > 0) {
        snprintf(name, sizeof name, "unix:%.*s", name_len, sun->sun_path);
    } else {
        strcpy(name, "unix");
    }
    return new_fd_stream(name, fd, 0, AF_UNIX, streamp);  //创建新的stream
}

从本次分析来看,要更进一步掌握of连接,需要对linux socket有一个清晰的理解,后续将分析linux socket的相关用法。



版权声明:本文为博主原创文章,未经博主允许不得转载。

【OVS2.5.0源码分析】openflow连接实现分析(3)

上两篇分析了controller连接建立的完整流程,本篇分析下接收openflow报文的过程,openflow报文的处理在后续文章中分析。 整个调用过程,可以根据上一篇的对象关系图得出,本篇只是把调用...
  • one_clouder
  • one_clouder
  • 2016年08月28日 08:07
  • 828

【OVS2.5.0源码分析】openflow连接实现分析(1)

openflow连接有两个用途: 1)与controller连接;2)提供给ovs-ofctl工具配置流表等。 我们先看连接的初始化过程,配置入口是bridge_reconfigure函数。 ...
  • one_clouder
  • one_clouder
  • 2016年08月25日 22:36
  • 996

openflow引擎源码分析(数据结构)

本文主要介绍ovs on dpdk的openflow处理引擎相关的数据结构,分析其设计的原因和精彩之处。...
  • zycamym
  • zycamym
  • 2016年09月30日 02:13
  • 975

【OVS2.5.0源码分析】openflow连接实现分析(6)

上两篇分析了ofservice的建立,请求处理的过程,本篇分析ovs-ofctl命令行是如何和 ofservice交互的。 1、mian函数 int main(int argc, char...
  • one_clouder
  • one_clouder
  • 2016年08月28日 16:56
  • 611

【OVS2.5.0源码分析】openflow连接实现分析(2)

上回调用到vconn_stream_open函数,没有进一步分析,今天继续往下看,确定controller连接的整个过程。 9、stream_open_with_default_port函数 /*...
  • one_clouder
  • one_clouder
  • 2016年08月28日 07:34
  • 604

【OVS2.5.0源码分析】openflow连接实现分析(4)

前面几篇介绍controller的连接,这篇分析ofservice的创建过程,直接从bridge_configure_remotes函数开始分析。 1、bridge_configure_remote...
  • one_clouder
  • one_clouder
  • 2016年08月28日 10:39
  • 403

一步一步分析odl【第二弹】openflow协议栈的运行流程之建立tcp连接

接上一弹继续讲。 在上一弹最后讲到在SwitchConnectionProvider的startup()方法中创建了一个Tcp server,这个Server的实例为TcpHandler, pub...
  • anzheangel
  • anzheangel
  • 2015年09月24日 00:01
  • 1359

【OVS2.5.0源码分析】datapath之action分析(5)

今天分析OVS_ACTION_ATTR_SET action的处理函数execute_set_action函数。 1、execute_set_action函数 static int execute_s...
  • one_clouder
  • one_clouder
  • 2016年09月05日 21:52
  • 469

【OVS2.5.0源码分析】ovsd进程运行机制分析(1)

ovsd作为ovs的用户态管理主进程,负责处理ovs-vsctl命令接口、ovs-ofctl命令接口、与controller交互等等。 本篇分析它的整个处理机制。 1、main函数 bri...
  • one_clouder
  • one_clouder
  • 2016年08月30日 22:03
  • 1488

实战录 | 基于openflow协议的抓包分析

《实战录》导语 云端卫士《实战录》栏目定期会向粉丝朋友们分享一些在开发运维中的经验和技巧,希望对于关注我们的朋友有所裨益。本期分享人为云端卫士安全SDN工程师宋飞虎,将带来基于openflow协...
  • cloudguarder
  • cloudguarder
  • 2016年11月01日 11:13
  • 1943
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【OVS2.5.0源码分析】openflow连接实现分析(5)
举报原因:
原因补充:

(最多只允许输入30个字)