【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
- 【OVS2.5.0源码分析】openflow连接实现分析(1)
- 【OVS2.5.0源码分析】openflow连接实现分析(2)
- 【OVS2.5.0源码分析】openflow连接实现分析(3)
- 【OVS2.5.0源码分析】openflow连接实现分析(4)
- 【OVS2.5.0源码分析】openflow连接实现分析(5)
- 【OVS2.5.0源码分析】openflow连接实现分析(6)
- 【OVS2.5.0源码分析】sFlow实现分析(1)
- 【OVS2.5.0源码分析】mirror实现原理(1)
- 【OVS2.5.0源码分析】sFlow实现分析(2)
- 【OVS2.5.0源码分析】sFlow实现分析(3)
- 【OVS2.5.0源码分析】bridge&bundle&port分析(1)
- 【OVS2.5.0源码分析】ovsd进程运行机制分析(1)
- 【OVS2.5.0源码分析】datapath之action分析(1)
- 【OVS2.5.0源码分析】upcall处理线程分析(1)
- 【OVS2.5.0源码分析】mirror实现原理(2)
- 【OVS2.5.0源码分析】vlan&trunk实现原理分析(1)
- 【OVS2.5.0源码分析】datapath之action分析(2)
- 【OVS2.5.0源码分析】datapath之action分析(3)
- uva 536Tree Recovery
- 在活动中使用menu
- POJ 3273 Conscription(最小生成树)
- java学习之路 之 IO流-练习题
- Spark运行架构
- 【OVS2.5.0源码分析】openflow连接实现分析(1)
- C# 怎么子窗体调用父窗体的控件
- 湖南省第十一届程序设计大赛 (水题)聊天止于呵呵
- 面试试题干货2
- Android+ThinkPHP(后台)实现用户登录功能
- 如何让您的网站符合W3C标准
- Session机制、持久化、session="false"属性不创建session、显示创建session及其销毁
- http://chr10003566.github.io/2016/04/20/BluetoothTest/
- 两个有序数组的中位数