【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连接实现分析(2)

上回调用到vconn_stream_open函数,没有进一步分析,今天继续往下看,确定controller连接的整个过程。 9、stream_open_with_default_port函数 /*...

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

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

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

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

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

今天分析OVS_ACTION_ATTR_SET action的处理函数execute_set_action函数。 1、execute_set_action函数 static int execute_s...

【OVS2.5.0源码分析】mirror实现原理(1)

端口镜像是交换机的标准功能之一,针对某个端口的报文拷贝到除真实目的之外的另外一个目的地(output),这一篇我们先分析配置mirror之后,如何生成流表,在什么阶段生成流表。 1、xlate_ac...

【OVS2.5.0源码分析】mirror实现原理(2)

OVS实现mirror功能时,限制了out端口的通信能力。 1、限制mirror out端口通信总结 xlate_normal_flood函数 static void xlate_normal_...

【OVS2.5.0源码分析】sFlow实现分析(1)

sFlow实现可以分成4个部分:1)配置;2)流表生成(生成datapath的流表);3)datapath中的处理(已经分析);4)sFlow处理过程。本篇分析sFlow的配置过程。 1、bridg...

【OVS2.5.0源码分析】sFlow实现分析(2)

本篇分析,sFlow流表生成过程,sFlow流表是在xlate_actions函数中生成,然后通过netlink下发给datapath的。 1、xlate_actions函数 /*...

【OVS2.5.0源码分析】datapath之netlink

ovs datapath是通过netlink与用户态进行通信的,实现dp、端口、流表、packet的操作。 netlink的注册是在datapath模块的初始化函数中实现的。 1、dp_init函数...

【OVS2.5.0源码分析】datapath之流表查询

流表查询是datapath报文处理过程中,最为关键的一个步骤,一个skb报文进入如何能够快速地进行匹配流表? 本篇分析ovs是如何查询流表的。 1、ovs_flow_tbl_lookup_stats...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【OVS2.5.0源码分析】openflow连接实现分析(5)
举报原因:
原因补充:

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