您的位置:首页 > 运维架构

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

2016-08-28 07:34 507 查看
上回调用到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对象,简化管理。希望把整个内容分析完成后,能够体会到作者的设计意图。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  openvswitch OVS 网络