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

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

9、stream_open_with_default_port函数

/* Like stream_open(), but the port defaults to 'default_port' if no port
 * number is given. */
int
stream_open_with_default_port(const char *name_,
                              uint16_t default_port,
                              struct stream **streamp,
                              uint8_t dscp)
{
    char *name;
    int error;
    if ((!strncmp(name_, "tcp:", 4) || !strncmp(name_, "ssl:", 4))   //如果是tcp和ssl需要确定端口号
        && count_fields(name_) < 3) {
        if (default_port == OFP_PORT) {
            VLOG_WARN_ONCE("The default OpenFlow port number has changed "
                           "from %d to %d",
                           OFP_OLD_PORT, OFP_PORT);
        } else if (default_port == OVSDB_PORT) {
            VLOG_WARN_ONCE("The default OVSDB port number has changed "
                           "from %d to %d",
                           OVSDB_OLD_PORT, OVSDB_PORT);
        }
        name = xasprintf("%s:%d", name_, default_port);
    } else {
        name = xstrdup(name_);
    }
    error = stream_open(name, streamp, dscp);    //调用stream的open函数
    free(name);
    return error;
}

10、stream_open函数

int
stream_open(const char *name, struct stream **streamp, uint8_t dscp)
{
    const struct stream_class *class;
    struct stream *stream;
    char *suffix_copy;
    int error;

    COVERAGE_INC(stream_open);

    /* Look up the class. */
    error = stream_lookup_class(name, &class);   //stream_class有要有4个,ssl_stream_class和stream_fd_class,还有tcp和unnix
    if (!class) {
        goto error;
    }

    /* Call class's "open" function. */
    suffix_copy = xstrdup(strchr(name, ':') + 1);
    error = class->open(name, suffix_copy, &stream, dscp);  //以tcp为例,调用tcp_open函数
    free(suffix_copy);
    if (error) {
        goto error;
    }

    /* Success. */
    *streamp = stream;
    return 0;

error:
    *streamp = NULL;
    return error;
}
11、tcp_open函数

static int
tcp_open(const char *name, char *suffix, struct stream **streamp, uint8_t dscp)
{
    int fd, error;

    error = inet_open_active(SOCK_STREAM, suffix, 0, NULL, &fd, dscp);    //创建socket
    if (fd >= 0) {
        return new_tcp_stream(name, fd, error, streamp);    //创建stream对象
    } else {
        VLOG_ERR("%s: connect: %s", name, ovs_strerror(error));
        return error;
    }
}
12、inet_open_active函数

int
inet_open_active(int style, const char *target, uint16_t default_port,
                 struct sockaddr_storage *ssp, int *fdp, uint8_t dscp)
{
    struct sockaddr_storage ss;
    int fd = -1;
    int error;

    /* Parse. */
    if (!inet_parse_active(target, default_port, &ss)) {
        error = EAFNOSUPPORT;
        goto exit;
    }

    /* Create non-blocking socket. */
    fd = socket(ss.ss_family, style, 0);
    if (fd < 0) {
        error = sock_errno();
        VLOG_ERR("%s: socket: %s", target, sock_strerror(error));
        goto exit;
    }
    error = set_nonblocking(fd);
    if (error) {
        goto exit;
    }

    /* The dscp bits must be configured before connect() to ensure that the
     * TOS field is set during the connection establishment.  If set after
     * connect(), the handshake SYN frames will be sent with a TOS of 0. */
    error = set_dscp(fd, ss.ss_family, dscp);
    if (error) {
        VLOG_ERR("%s: set_dscp: %s", target, sock_strerror(error));
        goto exit;
    }

    /* Connect. */
    error = connect(fd, (struct sockaddr *) &ss, ss_length(&ss)) == 0
                    ? 0
                    : sock_errno();
    if (error == EINPROGRESS
#ifdef _WIN32
        || error == WSAEALREADY || error == WSAEWOULDBLOCK
#endif
        ) {
        error = EAGAIN;
    }

exit:
    if (error && error != EAGAIN) {
        if (ssp) {
            memset(ssp, 0, sizeof *ssp);
        }
        if (fd >= 0) {
            closesocket(fd);
            fd = -1;
        }
    } else {
        if (ssp) {
            *ssp = ss;
        }
    }
    *fdp = fd;
    return error;
}
到此可以看到,连接最底层使用的是linux socket,stream是对socket最基本的封装,整个数据结构关系如下图:


目前还没体会到这个层次设计的意图,暂时能够体会到stream对象是为了封装Linux socket对象,简化管理。希望把整个内容分析完成后,能够体会到作者的设计意图。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值