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

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

2016-08-25 22:36 489 查看
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 void
bridge_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函数
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);
}

4、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_co
4000
ntrollers;
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 void
add_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(). */
void
rconn_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 void
reconnect(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. */
int
vconn_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 int
vconn_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中是如果建立流的待分析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  OVS openvswitch 网络