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

来源:互联网 发布:微信推广淘宝商品 编辑:程序博客网 时间:2024/06/05 03:48

前面几篇介绍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函数

voidofproto_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函数

voidconnmgr_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 intofservice_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_versions;    return 0;}

5、pvconn_open函数

intpvconn_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 intpvconn_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函数

intpstream_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函数

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


0 0