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

【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函数
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的类结果关系如下图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  OVS openvswitch 网络