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

来源:互联网 发布:废旧金属行情软件 编辑:程序博客网 时间:2024/05/21 21:01

openflow连接有两个用途: 1)与controller连接;2)提供给ovs-ofctl工具配置流表等。

我们先看连接的初始化过程,配置入口是bridge_reconfigure函数。


1、bridge_reconfigure函数

    collect_in_band_managers(ovs_cfg, &managers, &n_managers);    //收集配置的manager信息    HMAP_FOR_EACH (br, node, &all_bridges) {        struct port *port;        /* We need the datapath ID early to allow LACP ports to use it as the         * default system ID. */        bridge_configure_datapath_id(br);        HMAP_FOR_EACH (port, hmap_node, &br->ports) {            struct iface *iface;            port_configure(port);            LIST_FOR_EACH (iface, port_elem, &port->ifaces) {                iface_set_ofport(iface->cfg, iface->ofp_port);                /* Clear eventual previous errors */                ovsrec_interface_set_error(iface->cfg, NULL);                iface_configure_cfm(iface);                iface_configure_qos(iface, port->cfg->qos);                iface_set_mac(br, port, iface);                ofproto_port_set_bfd(br->ofproto, iface->ofp_port,                                     &iface->cfg->bfd);                ofproto_port_set_lldp(br->ofproto, iface->ofp_port,                                      &iface->cfg->lldp);            }        }        bridge_configure_mirrors(br);        bridge_configure_forward_bpdu(br);        bridge_configure_mac_table(br);        bridge_configure_mcast_snooping(br);        bridge_configure_remotes(br, managers, n_managers);   //配置入口        bridge_configure_netflow(br);        bridge_configure_sflow(br, &sflow_bridge_number);        bridge_configure_ipfix(br);        bridge_configure_spanning_tree(br);        bridge_configure_tables(br);        bridge_configure_dp_desc(br);        bridge_configure_aa(br);    }

2、bridge_configure_remote函数

static voidbridge_configure_remotes(struct bridge *br,                         const struct sockaddr_in *managers, size_t n_managers){    bool disable_in_band;    struct ovsrec_controller **controllers;    size_t n_controllers;    enum ofproto_fail_mode fail_mode;    struct ofproto_controller *ocs;    size_t n_ocs;    size_t i;    /* Check if we should disable in-band control on this bridge. */    disable_in_band = smap_get_bool(&br->cfg->other_config, "disable-in-band",                                    false);    /* Set OpenFlow queue ID for in-band control. */    ofproto_set_in_band_queue(br->ofproto,                              smap_get_int(&br->cfg->other_config,                                           "in-band-queue", -1));    if (disable_in_band) {        ofproto_set_extra_in_band_remotes(br->ofproto, NULL, 0);    } else {        ofproto_set_extra_in_band_remotes(br->ofproto, managers, n_managers);    }    n_controllers = bridge_get_controllers(br, &controllers);     //获取controller配置信息    ocs = xmalloc((n_controllers + 1) * sizeof *ocs);    n_ocs = 0;    bridge_ofproto_controller_for_mgmt(br, &ocs[n_ocs++]);     //第1个,本质上不是controller,是作为管理供ovs-ofctl工具进行连接,使用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                            bridge_get_allowed_versions(br));    free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */    free(ocs);    /* Set the fail-mode. */    fail_mode = !br->cfg->fail_mode                || !strcmp(br->cfg->fail_mode, "standalone")                    ? OFPROTO_FAIL_STANDALONE                    : OFPROTO_FAIL_SECURE;    ofproto_set_fail_mode(br->ofproto, fail_mode);    /* Configure OpenFlow controller connection snooping. */    if (!ofproto_has_snoops(br->ofproto)) {        struct sset snoops;        sset_init(&snoops);        sset_add_and_free(&snoops, xasprintf("punix:%s/%s.snoop",                                             ovs_rundir(), br->name));        ofproto_set_snoops(br->ofproto, &snoops);        sset_destroy(&snoops);    }}

3、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);}

4、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);    //创建ofconn对象,并插入到controllers链表中;            }        } else if (!pvconn_verify_name(c->target)) {   //第一个controller使用punix,满足条件            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对象,并插入到mgr的services链表中            }        } else {            VLOG_WARN_RL(&rl, "%s: unsupported controller \"%s\"",                         mgr->name, c->target);            continue;        }        shash_add_once(&new_controllers, c->target, &controllers[i]);    }    /* Delete controllers that are no longer configured.     * Update configuration of all now-existing controllers. */    HMAP_FOR_EACH_SAFE (ofconn, next_ofconn, hmap_node, &mgr->controllers) {        const char *target = ofconn_get_target(ofconn);        struct ofproto_controller *c;        c = shash_find_data(&new_controllers, target);        if (!c) {            VLOG_INFO("%s: removed primary controller \"%s\"",                      mgr->name, target);            ofconn_destroy(ofconn);        } else {            ofconn_reconfigure(ofconn, c);        }    }    /* Delete services that are no longer configured.     * Update configuration of all now-existing services. */    HMAP_FOR_EACH_SAFE (ofservice, next_ofservice, node, &mgr->services) {        const char *target = pvconn_get_name(ofservice->pvconn);        struct ofproto_controller *c;        c = shash_find_data(&new_controllers, target);        if (!c) {            VLOG_INFO("%s: removed service controller \"%s\"",                      mgr->name, target);            ofservice_destroy(mgr, ofservice);        } else {            ofservice_reconfigure(ofservice, c);        }    }    shash_destroy(&new_controllers);    ovs_mutex_unlock(&ofproto_mutex);    update_in_band_remotes(mgr);    update_fail_open(mgr);    if (had_controllers != connmgr_has_controllers(mgr)) {        ofproto_flush_flows(mgr->ofproto);    }}

add_controller函数

static voidadd_controller(struct connmgr *mgr, const char *target, uint8_t dscp,               uint32_t allowed_versions)    OVS_REQUIRES(ofproto_mutex){    char *name = ofconn_make_name(mgr, target);    struct ofconn *ofconn;    ofconn = ofconn_create(mgr, rconn_create(5, 8, dscp, allowed_versions),   //构建ofconn对象                           OFCONN_PRIMARY, true);    ofconn->pktbuf = pktbuf_create();    rconn_connect(ofconn->rconn, target, name);     //建立连接    hmap_insert(&mgr->controllers, &ofconn->hmap_node, hash_string(target, 0));    free(name);}

ofconn_create函数

static struct ofconn *ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type,              bool enable_async_msgs){    struct ofconn *ofconn;    ofconn = xzalloc(sizeof *ofconn);    ofconn->connmgr = mgr;    list_push_back(&mgr->all_conns, &ofconn->node);   //connmgr_run函数会使用到all_conns,遍历所有连接并处理    ofconn->rconn = rconn;    ofconn->type = type;    ofconn->enable_async_msgs = enable_async_msgs;    hmap_init(&ofconn->monitors);    list_init(&ofconn->updates);    hmap_init(&ofconn->bundles);    ofconn_flush(ofconn);    return ofconn;}

5、rconn_connect函数

/* Drops any existing connection on 'rc', then sets up 'rc' to connect to * 'target' and reconnect as needed.  'target' should be a remote OpenFlow * target in a form acceptable to vconn_open(). * * If 'name' is nonnull, then it is used in log messages in place of 'target'. * It should presumably give more information to a human reader than 'target', * but it need not be acceptable to vconn_open(). */voidrconn_connect(struct rconn *rc, const char *target, const char *name)    OVS_EXCLUDED(rc->mutex){    ovs_mutex_lock(&rc->mutex);    rconn_disconnect__(rc);    rconn_set_target__(rc, target, name);    rc->reliable = true;    reconnect(rc);    ovs_mutex_unlock(&rc->mutex);}

6、reconnect函数

static voidreconnect(struct rconn *rc)    OVS_REQUIRES(rc->mutex){    int retval;    if (rconn_logging_connection_attempts__(rc)) {        VLOG_INFO("%s: connecting...", rc->name);    }    rc->n_attempted_connections++;    retval = vconn_open(rc->target, rc->allowed_versions, rc->dscp,    //打开vconn对象,通信都是基于vconn的                        &rc->vconn);    if (!retval) {        rc->backoff_deadline = time_now() + rc->backoff;        state_transition(rc, S_CONNECTING);    } else {        VLOG_WARN("%s: connection failed (%s)",                  rc->name, ovs_strerror(retval));        rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */        disconnect(rc, retval);    }}

7、vconn_open函数

/* Attempts to connect to an OpenFlow device.  'name' is a connection name in * the form "TYPE:ARGS", where TYPE is an active vconn class's name and ARGS * are vconn class-specific. * * The vconn will automatically negotiate an OpenFlow protocol version * acceptable to both peers on the connection.  The version negotiated will be * one of those in the 'allowed_versions' bitmap: version 'x' is allowed if * allowed_versions & (1 << x) is nonzero.  If 'allowed_versions' is zero, then * OFPUTIL_DEFAULT_VERSIONS are allowed. * * Returns 0 if successful, otherwise a positive errno value.  If successful, * stores a pointer to the new connection in '*vconnp', otherwise a null * pointer.  */intvconn_open(const char *name, uint32_t allowed_versions, uint8_t dscp,           struct vconn **vconnp){    const struct vconn_class *class;    struct vconn *vconn;    char *suffix_copy;    int error;    COVERAGE_INC(vconn_open);    check_vconn_classes();    if (!allowed_versions) {        allowed_versions = OFPUTIL_DEFAULT_VERSIONS;    }    /* Look up the class. */    error = vconn_lookup_class(name, &class);    //    if (!class) {        goto error;    }    /* Call class's "open" function. */    suffix_copy = xstrdup(strchr(name, ':') + 1);    error = class->open(name, allowed_versions, suffix_copy, &vconn, dscp);    //调用vconn_class对象打开,实际为vconn_stream_open函数    free(suffix_copy);    if (error) {        goto error;    }    /* Success. */    ovs_assert(vconn->state != VCS_CONNECTING || vconn->vclass->connect);    *vconnp = vconn;    return 0;error:    *vconnp = NULL;    return error;}

8、vconn_stream_open函数

/* Creates a new vconn that will send and receive data on a stream named 'name' * and stores a pointer to the vconn in '*vconnp'. * * Returns 0 if successful, otherwise a positive errno value. */static intvconn_stream_open(const char *name, uint32_t allowed_versions,                  char *suffix OVS_UNUSED, struct vconn **vconnp, uint8_t dscp){    struct stream *stream;    int error;    error = stream_open_with_default_port(name, OFP_PORT, &stream, dscp);   //open stream流    if (!error) {        error = stream_connect(stream);           //建立stream连接        if (!error || error == EAGAIN) {            *vconnp = vconn_stream_new(stream, error, allowed_versions);    //vconn对象            return 0;        }    }    stream_close(stream);    return error;}

本文介绍了openflow流的建立过程, 仅到vconn对象,stream中是如果建立流的待分析。



0 0
原创粉丝点击