【OVS2.5.0源码分析】openflow连接实现分析(4)
2016-08-28 10:39
531 查看
前面几篇介绍controller的连接,这篇分析ofservice的创建过程,直接从bridge_configure_remotes函数开始分析。
1、bridge_configure_remotes函数
n_controllers = bridge_get_controllers(br, &controllers);
ocs = xmalloc((n_controllers + 1) * sizeof *ocs);
n_ocs = 0;
bridge_ofproto_controller_for_mgmt(br, &ocs[n_ocs++]); //如果没有配置controller,那么也存在一个controller,punix的连接方式
for (i = 0; i < n_controllers; i++) {
struct ovsrec_controller *c = controllers[i];
if (!strncmp(c->target, "punix:", 6)
|| !strncmp(c->target, "unix:", 5)) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
char *whitelist;
if (!strncmp(c->target, "unix:", 5)) {
/* Connect to a listening socket */
whitelist = xasprintf("unix:%s/", ovs_rundir());
if (strchr(c->target, '/') &&
!equal_pathnames(c->target, whitelist,
strlen(whitelist))) {
/* Absolute path specified, but not in ovs_rundir */
VLOG_ERR_RL(&rl, "bridge %s: Not connecting to socket "
"controller \"%s\" due to possibility for "
"remote exploit. Instead, specify socket "
"in whitelisted \"%s\" or connect to "
"\"unix:%s/%s.mgmt\" (which is always "
"available without special configuration).",
br->name, c->target, whitelist,
ovs_rundir(), br->name);
free(whitelist);
continue;
}
} else {
whitelist = xasprintf("punix:%s/%s.",
ovs_rundir(), br->name);
if (!equal_pathnames(c->target, whitelist, strlen(whitelist))
|| strchr(c->target + strlen(whitelist), '/')) {
/* Prevent remote ovsdb-server users from accessing
* arbitrary Unix domain sockets and overwriting arbitrary
* local files. */
VLOG_ERR_RL(&rl, "bridge %s: Not adding Unix domain socket "
"controller \"%s\" due to possibility of "
"overwriting local files. Instead, specify "
"path in whitelisted format \"%s*\" or "
"connect to \"unix:%s/%s.mgmt\" (which is "
"always available without special "
"configuration).",
br->name, c->target, whitelist,
ovs_rundir(), br->name);
free(whitelist);
continue;
}
}
free(whitelist);
}
bridge_configure_local_iface_netdev(br, c);
bridge_ofproto_controller_from_ovsrec(c, &ocs[n_ocs]);
if (disable_in_band) {
ocs[n_ocs].band = OFPROTO_OUT_OF_BAND;
}
n_ocs++;
}
ofproto_set_controllers(br->ofproto, ocs, n_ocs, //controller和service统一接口
bridge_get_allowed_versions(br));
free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */
free(ocs);
2、ofproto_set_controllers函数
void
ofproto_set_controllers(struct ofproto *p,
const struct ofproto_controller *controllers,
size_t n_controllers, uint32_t allowed_versions)
{
connmgr_set_controllers(p->connmgr, controllers, n_controllers,
allowed_versions);
}
3、connmgr_set_controllers函数
void
connmgr_set_controllers(struct connmgr *mgr,
const struct ofproto_controller *controllers,
size_t n_controllers, uint32_t allowed_versions)
OVS_EXCLUDED(ofproto_mutex)
{
bool had_controllers = connmgr_has_controllers(mgr);
struct shash new_controllers;
struct ofconn *ofconn, *next_ofconn;
struct ofservice *ofservice, *next_ofservice;
size_t i;
/* Required to add and remove ofconns. This could probably be narrowed to
* cover a smaller amount of code, if that yielded some benefit. */
ovs_mutex_lock(&ofproto_mutex);
/* Create newly configured controllers and services.
* Create a name to ofproto_controller mapping in 'new_controllers'. */
shash_init(&new_controllers);
for (i = 0; i < n_controllers; i++) {
const struct ofproto_controller *c = &controllers[i];
if (!vconn_verify_name(c->target)) {
bool add = false;
ofconn = find_controller_by_target(mgr, c->target);
if (!ofconn) {
VLOG_INFO("%s: added primary controller \"%s\"",
mgr->name, c->target);
add = true;
} else if (rconn_get_allowed_versions(ofconn->rconn) !=
allowed_versions) {
VLOG_INFO("%s: re-added primary controller \"%s\"",
mgr->name, c->target);
add = true;
ofconn_destroy(ofconn);
}
if (add) {
add_controller(mgr, c->target, c->dscp, allowed_versions);
}
} else if (!pvconn_verify_name(c->target)) {
bool add = false;
ofservice = ofservice_lookup(mgr, c->target);
if (!ofservice) {
VLOG_INFO("%s: added service controller \"%s\"",
mgr->name, c->target);
add = true;
} else if (ofservice->allowed_versions != allowed_versions) {
VLOG_INFO("%s: re-added service controller \"%s\"",
mgr->name, c->target);
ofservice_destroy(mgr, ofservice);
add = true;
}
if (add) {
ofservice_create(mgr, c->target, allowed_versions, c->dscp); //创建ofservice
}
} else {
VLOG_WARN_RL(&rl, "%s: unsupported controller \"%s\"",
mgr->name, c->target);
continue;
}
shash_add_once(&new_controllers, c->target, &controllers[i]);
}
4、ofservice_create函数
static int
ofservice_create(struct connmgr *mgr, const char *target,
uint32_t allowed_versions, uint8_t dscp)
{
struct ofservice *ofservice;
struct pvconn *pvconn;
int error;
error = pvconn_open(target, allowed_versions, dscp, &pvconn); //创建pvconn
if (error) {
return error;
}
ofservice = xzalloc(sizeof *ofservice);
hmap_insert(&mgr->services, &ofservice->node, hash_string(target, 0)); //添加到服务清单,在connmgr_run函数中会使用到
ofservice->pvconn = pvconn;
ofservice->allowed_versions = allowed_vers
4000
ions;
return 0;
}
5、pvconn_open函数
int
pvconn_open(const char *name, uint32_t allowed_versions, uint8_t dscp,
struct pvconn **pvconnp)
{
const struct pvconn_class *class;
struct pvconn *pvconn;
char *suffix_copy;
int error;
check_vconn_classes();
if (!allowed_versions) {
allowed_versions = OFPUTIL_DEFAULT_VERSIONS;
}
/* Look up the class. */
error = pvconn_lookup_class(name, &class);
if (!class) {
goto error;
}
/* Call class's "open" function. */
suffix_copy = xstrdup(strchr(name, ':') + 1);
error = class->listen(name, allowed_versions, suffix_copy, &pvconn, dscp); //实际调用pvconn_pstream_listen函数
free(suffix_copy);
if (error) {
goto error;
}
/* Success. */
*pvconnp = pvconn;
return 0;
error:
*pvconnp = NULL;
return error;
}
6、pvconn_pstream_listen函数
static int
pvconn_pstream_listen(const char *name, uint32_t allowed_versions,
char *suffix OVS_UNUSED, struct pvconn **pvconnp,
uint8_t dscp)
{
struct pvconn_pstream *ps;
struct pstream *pstream;
int error;
error = pstream_open_with_default_port(name, OFP_PORT, &pstream, dscp); //创建pstream
if (error) {
return error;
}
ps = xmalloc(sizeof *ps);
pvconn_init(&ps->pvconn, &pstream_pvconn_class, name, allowed_versions);
ps->pstream = pstream;
*pvconnp = &ps->pvconn;
return 0;
}
7、pstream_open_with_default_port函数
int
pstream_open_with_default_port(const char *name_,
uint16_t default_port,
struct pstream **pstreamp,
uint8_t dscp)
{
char *name;
int error;
if ((!strncmp(name_, "ptcp:", 5) || !strncmp(name_, "pssl:", 5))
&& count_fields(name_) < 2) {
name = xasprintf("%s%d", name_, default_port);
} else {
name = xstrdup(name_);
}
error = pstream_open(name, pstreamp, dscp);
free(name);
return error;
}
8、pstream_open函数
int
pstream_open(const char *name, struct pstream **pstreamp, uint8_t dscp)
{
const struct pstream_class *class;
struct pstream *pstream;
char *suffix_copy;
int error;
COVERAGE_INC(pstream_open);
/* Look up the class. */
error = pstream_lookup_class(name, &class); //punix类型的class为punix_pstream_class
if (!class) {
goto error;
}
/* Call class's "open" function. */
suffix_copy = xstrdup(strchr(name, ':') + 1);
error = class->listen(name, suffix_copy, &pstream, dscp); //<span style="font-family: Arial, Helvetica, sans-serif;">punix类型的listen函数为punix_open</span>
free(suffix_copy);
if (error) {
goto error;
}
/* Success. */
*pstreamp = pstream;
return 0;
error:
*pstreamp = NULL;
return error;
}
9、punix_open函数
static int
punix_open(const char *name OVS_UNUSED, char *suffix,
struct pstream **pstreamp, uint8_t dscp OVS_UNUSED)
{
char *bind_path;
int fd, error;
bind_path = abs_file_name(ovs_rundir(), suffix);
fd = make_unix_socket(SOCK_STREAM, true, bind_path, NULL); //创建unix socket
if (fd < 0) {
VLOG_ERR("%s: binding failed: %s", bind_path, ovs_strerror(errno));
free(bind_path);
return errno;
}
if (listen(fd, 64) < 0) {
error = errno;
VLOG_ERR("%s: listen: %s", name, ovs_strerror(error));
close(fd);
free(bind_path);
return error;
}
return new_fd_pstream(name, fd, punix_accept, bind_path, pstreamp); //创建pstream对象,pstream_class为fd_pstream_class
}
10、make_unix_socket函数
ofservice最终也是linux socket,调用关系和ofconn非常类似,只是一个最终是pstream(作为server角色),而另一个最终是stream(作为client角色)。 ofservice的类结果关系如下图:
1、bridge_configure_remotes函数
n_controllers = bridge_get_controllers(br, &controllers);
ocs = xmalloc((n_controllers + 1) * sizeof *ocs);
n_ocs = 0;
bridge_ofproto_controller_for_mgmt(br, &ocs[n_ocs++]); //如果没有配置controller,那么也存在一个controller,punix的连接方式
for (i = 0; i < n_controllers; i++) {
struct ovsrec_controller *c = controllers[i];
if (!strncmp(c->target, "punix:", 6)
|| !strncmp(c->target, "unix:", 5)) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
char *whitelist;
if (!strncmp(c->target, "unix:", 5)) {
/* Connect to a listening socket */
whitelist = xasprintf("unix:%s/", ovs_rundir());
if (strchr(c->target, '/') &&
!equal_pathnames(c->target, whitelist,
strlen(whitelist))) {
/* Absolute path specified, but not in ovs_rundir */
VLOG_ERR_RL(&rl, "bridge %s: Not connecting to socket "
"controller \"%s\" due to possibility for "
"remote exploit. Instead, specify socket "
"in whitelisted \"%s\" or connect to "
"\"unix:%s/%s.mgmt\" (which is always "
"available without special configuration).",
br->name, c->target, whitelist,
ovs_rundir(), br->name);
free(whitelist);
continue;
}
} else {
whitelist = xasprintf("punix:%s/%s.",
ovs_rundir(), br->name);
if (!equal_pathnames(c->target, whitelist, strlen(whitelist))
|| strchr(c->target + strlen(whitelist), '/')) {
/* Prevent remote ovsdb-server users from accessing
* arbitrary Unix domain sockets and overwriting arbitrary
* local files. */
VLOG_ERR_RL(&rl, "bridge %s: Not adding Unix domain socket "
"controller \"%s\" due to possibility of "
"overwriting local files. Instead, specify "
"path in whitelisted format \"%s*\" or "
"connect to \"unix:%s/%s.mgmt\" (which is "
"always available without special "
"configuration).",
br->name, c->target, whitelist,
ovs_rundir(), br->name);
free(whitelist);
continue;
}
}
free(whitelist);
}
bridge_configure_local_iface_netdev(br, c);
bridge_ofproto_controller_from_ovsrec(c, &ocs[n_ocs]);
if (disable_in_band) {
ocs[n_ocs].band = OFPROTO_OUT_OF_BAND;
}
n_ocs++;
}
ofproto_set_controllers(br->ofproto, ocs, n_ocs, //controller和service统一接口
bridge_get_allowed_versions(br));
free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */
free(ocs);
2、ofproto_set_controllers函数
void
ofproto_set_controllers(struct ofproto *p,
const struct ofproto_controller *controllers,
size_t n_controllers, uint32_t allowed_versions)
{
connmgr_set_controllers(p->connmgr, controllers, n_controllers,
allowed_versions);
}
3、connmgr_set_controllers函数
void
connmgr_set_controllers(struct connmgr *mgr,
const struct ofproto_controller *controllers,
size_t n_controllers, uint32_t allowed_versions)
OVS_EXCLUDED(ofproto_mutex)
{
bool had_controllers = connmgr_has_controllers(mgr);
struct shash new_controllers;
struct ofconn *ofconn, *next_ofconn;
struct ofservice *ofservice, *next_ofservice;
size_t i;
/* Required to add and remove ofconns. This could probably be narrowed to
* cover a smaller amount of code, if that yielded some benefit. */
ovs_mutex_lock(&ofproto_mutex);
/* Create newly configured controllers and services.
* Create a name to ofproto_controller mapping in 'new_controllers'. */
shash_init(&new_controllers);
for (i = 0; i < n_controllers; i++) {
const struct ofproto_controller *c = &controllers[i];
if (!vconn_verify_name(c->target)) {
bool add = false;
ofconn = find_controller_by_target(mgr, c->target);
if (!ofconn) {
VLOG_INFO("%s: added primary controller \"%s\"",
mgr->name, c->target);
add = true;
} else if (rconn_get_allowed_versions(ofconn->rconn) !=
allowed_versions) {
VLOG_INFO("%s: re-added primary controller \"%s\"",
mgr->name, c->target);
add = true;
ofconn_destroy(ofconn);
}
if (add) {
add_controller(mgr, c->target, c->dscp, allowed_versions);
}
} else if (!pvconn_verify_name(c->target)) {
bool add = false;
ofservice = ofservice_lookup(mgr, c->target);
if (!ofservice) {
VLOG_INFO("%s: added service controller \"%s\"",
mgr->name, c->target);
add = true;
} else if (ofservice->allowed_versions != allowed_versions) {
VLOG_INFO("%s: re-added service controller \"%s\"",
mgr->name, c->target);
ofservice_destroy(mgr, ofservice);
add = true;
}
if (add) {
ofservice_create(mgr, c->target, allowed_versions, c->dscp); //创建ofservice
}
} else {
VLOG_WARN_RL(&rl, "%s: unsupported controller \"%s\"",
mgr->name, c->target);
continue;
}
shash_add_once(&new_controllers, c->target, &controllers[i]);
}
4、ofservice_create函数
static int
ofservice_create(struct connmgr *mgr, const char *target,
uint32_t allowed_versions, uint8_t dscp)
{
struct ofservice *ofservice;
struct pvconn *pvconn;
int error;
error = pvconn_open(target, allowed_versions, dscp, &pvconn); //创建pvconn
if (error) {
return error;
}
ofservice = xzalloc(sizeof *ofservice);
hmap_insert(&mgr->services, &ofservice->node, hash_string(target, 0)); //添加到服务清单,在connmgr_run函数中会使用到
ofservice->pvconn = pvconn;
ofservice->allowed_versions = allowed_vers
4000
ions;
return 0;
}
5、pvconn_open函数
int
pvconn_open(const char *name, uint32_t allowed_versions, uint8_t dscp,
struct pvconn **pvconnp)
{
const struct pvconn_class *class;
struct pvconn *pvconn;
char *suffix_copy;
int error;
check_vconn_classes();
if (!allowed_versions) {
allowed_versions = OFPUTIL_DEFAULT_VERSIONS;
}
/* Look up the class. */
error = pvconn_lookup_class(name, &class);
if (!class) {
goto error;
}
/* Call class's "open" function. */
suffix_copy = xstrdup(strchr(name, ':') + 1);
error = class->listen(name, allowed_versions, suffix_copy, &pvconn, dscp); //实际调用pvconn_pstream_listen函数
free(suffix_copy);
if (error) {
goto error;
}
/* Success. */
*pvconnp = pvconn;
return 0;
error:
*pvconnp = NULL;
return error;
}
6、pvconn_pstream_listen函数
static int
pvconn_pstream_listen(const char *name, uint32_t allowed_versions,
char *suffix OVS_UNUSED, struct pvconn **pvconnp,
uint8_t dscp)
{
struct pvconn_pstream *ps;
struct pstream *pstream;
int error;
error = pstream_open_with_default_port(name, OFP_PORT, &pstream, dscp); //创建pstream
if (error) {
return error;
}
ps = xmalloc(sizeof *ps);
pvconn_init(&ps->pvconn, &pstream_pvconn_class, name, allowed_versions);
ps->pstream = pstream;
*pvconnp = &ps->pvconn;
return 0;
}
7、pstream_open_with_default_port函数
int
pstream_open_with_default_port(const char *name_,
uint16_t default_port,
struct pstream **pstreamp,
uint8_t dscp)
{
char *name;
int error;
if ((!strncmp(name_, "ptcp:", 5) || !strncmp(name_, "pssl:", 5))
&& count_fields(name_) < 2) {
name = xasprintf("%s%d", name_, default_port);
} else {
name = xstrdup(name_);
}
error = pstream_open(name, pstreamp, dscp);
free(name);
return error;
}
8、pstream_open函数
int
pstream_open(const char *name, struct pstream **pstreamp, uint8_t dscp)
{
const struct pstream_class *class;
struct pstream *pstream;
char *suffix_copy;
int error;
COVERAGE_INC(pstream_open);
/* Look up the class. */
error = pstream_lookup_class(name, &class); //punix类型的class为punix_pstream_class
if (!class) {
goto error;
}
/* Call class's "open" function. */
suffix_copy = xstrdup(strchr(name, ':') + 1);
error = class->listen(name, suffix_copy, &pstream, dscp); //<span style="font-family: Arial, Helvetica, sans-serif;">punix类型的listen函数为punix_open</span>
free(suffix_copy);
if (error) {
goto error;
}
/* Success. */
*pstreamp = pstream;
return 0;
error:
*pstreamp = NULL;
return error;
}
9、punix_open函数
static int
punix_open(const char *name OVS_UNUSED, char *suffix,
struct pstream **pstreamp, uint8_t dscp OVS_UNUSED)
{
char *bind_path;
int fd, error;
bind_path = abs_file_name(ovs_rundir(), suffix);
fd = make_unix_socket(SOCK_STREAM, true, bind_path, NULL); //创建unix socket
if (fd < 0) {
VLOG_ERR("%s: binding failed: %s", bind_path, ovs_strerror(errno));
free(bind_path);
return errno;
}
if (listen(fd, 64) < 0) {
error = errno;
VLOG_ERR("%s: listen: %s", name, ovs_strerror(error));
close(fd);
free(bind_path);
return error;
}
return new_fd_pstream(name, fd, punix_accept, bind_path, pstreamp); //创建pstream对象,pstream_class为fd_pstream_class
}
10、make_unix_socket函数
int make_unix_socket(int style, bool nonblock, const char *bind_path, const char *connect_path) { int error; int fd; fd = socket(PF_UNIX, style, 0); if (fd < 0) { return -errno; } /* Set nonblocking mode right away, if we want it. This prevents blocking * in connect(), if connect_path != NULL. (In turn, that's a corner case: * it will only happen if style is SOCK_STREAM or SOCK_SEQPACKET, and only * if a backlog of un-accepted connections has built up in the kernel.) */ if (nonblock) { error = set_nonblocking(fd); if (error) { goto error; } } if (bind_path) { //pstream进这个分支 char linkname[MAX_UN_LEN + 1]; struct sockaddr_un un; socklen_t un_len; int dirfd; if (unlink(bind_path) && errno != ENOENT) { VLOG_WARN("unlinking \"%s\": %s\n", bind_path, ovs_strerror(errno)); } fatal_signal_add_file_to_unlink(bind_path); error = make_sockaddr_un(bind_path, &un, &un_len, &dirfd, linkname); if (!error) { error = bind_unix_socket(fd, (struct sockaddr *) &un, un_len); } free_sockaddr_un(dirfd, linkname); if (error) { goto error; } } if (connect_path) { //stream进这个分支 char linkname[MAX_UN_LEN + 1]; struct sockaddr_un un; socklen_t un_len; int dirfd; error = make_sockaddr_un(connect_path, &un, &un_len, &dirfd, linkname); if (!error && connect(fd, (struct sockaddr*) &un, un_len) && errno != EINPROGRESS) { error = errno; } free_sockaddr_un(dirfd, linkname); if (error) { goto error; } } return fd; error: if (error == EAGAIN) { error = EPROTO; } if (bind_path) { fatal_signal_unlink_file_now(bind_path); } close(fd); return -error; }
ofservice最终也是linux socket,调用关系和ofconn非常类似,只是一个最终是pstream(作为server角色),而另一个最终是stream(作为client角色)。 ofservice的类结果关系如下图:
相关文章推荐
- 【OVS2.5.0源码分析】openflow连接实现分析(1)
- 【OVS2.5.0源码分析】openflow连接实现分析(2)
- 【OVS2.5.0源码分析】openflow连接实现分析(3)
- 【OVS2.5.0源码分析】openflow连接实现分析(6)
- 【OVS2.5.0源码分析】mirror实现原理(1)
- 【OVS2.5.0源码分析】sFlow实现分析(2)
- 【OVS2.5.0源码分析】sFlow实现分析(1)
- 【OVS2.5.0源码分析】sFlow实现分析(3)
- 【OVS2.5.0源码分析】vlan&trunk实现原理分析(2)
- 【OVS2.5.0源码分析】vlan&trunk实现原理分析(1)
- 【OVS2.5.0源码分析】mirror实现原理(2)
- smack 源码分析一(android上实现长连接)
- 【OVS2.5.0源码分析】datapath之action分析(1)
- 【OVS2.5.0源码分析】datapath之主流程分析
- smack 源码分析1(android上实现长连接)
- smack 源码分析一(android上实现长连接)【1】
- 【OVS2.5.0源码分析】ovsd进程运行机制分析(1)
- 【OVS2.5.0源码分析】ofpbuf数据结构分析
- smack 源码分析- PacketWriter (android上实现长连接)
- smack 源码分析一(android上实现长连接)【1】