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

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

2016-08-28 16:56 441 查看
上两篇分析了ofservice的建立,请求处理的过程,本篇分析ovs-ofctl命令行是如何和 ofservice交互的。

1、mian函数

int
main(int argc, char *argv[])
{
struct ovs_cmdl_context ctx = { .argc = 0, };
set_program_name(argv[0]);
service_start(&argc, &argv);
parse_options(argc, argv);
fatal_ignore_sigpipe();
ctx.argc = argc - optind;
ctx.argv = argv + optind;

daemon_become_new_user(false);
ovs_cmdl_run_command(&ctx, get_all_commands()); //处理ovs-ofctl命令行
return 0;
}

2、ovs_cmdl_run_command函数
void
ovs_cmdl_run_command(struct ovs_cmdl_context *ctx, const struct ovs_cmdl_command commands[])
{
const struct ovs_cmdl_command *p;

if (ctx->argc < 1) {
ovs_fatal(0, "missing command name; use --help for help");
}

for (p = commands; p->name != NULL; p++) {
if (!strcmp(p->name, ctx->argv[0])) {
int n_arg = ctx->argc - 1;
if (n_arg < p->min_args) {
VLOG_FATAL( "'%s' command requires at least %d arguments",
p->name, p->min_args);
} else if (n_arg > p->max_args) {
VLOG_FATAL("'%s' command takes at most %d arguments",
p->name, p->max_args);
} else {
p->handler(ctx); //OVS注册多个command处理,以添加流表为例,实际会掉用ofctl_add_flow函数
if (ferror(stdout)) {
VLOG_FATAL("write to stdout failed");
}
if (ferror(stderr)) {
VLOG_FATAL("write to stderr failed");
}
return;
}
}
}

VLOG_FATAL("unknown command '%s'; use --help for help", ctx->argv[0]);
}

3、ofctl_add_flow函数
static void
ofctl_add_flow(struct ovs_cmdl_context *ctx)
{
ofctl_flow_mod(ctx->argc, ctx->argv, OFPFC_ADD);
}

4、ofctl_flow_mod函数
static void
ofctl_flow_mod(int argc, char *argv[], uint16_t command) //ovs-ofctl add-flow br1 "XXXX"
{
if (argc > 2 && !strcmp(argv[2], "-")) {
ofctl_flow_mod_file(argc, argv, command);
} else {
struct ofputil_flow_mod fm;
char *error;
enum ofputil_protocol usable_protocols;

error = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", command,
&usable_protocols);
if (error) {
ovs_fatal(0, "%s", error);
}
ofctl_flow_mod__(argv[1], &fm, 1, usable_protocols); //调用入口
}
}

5、ofctl_flow_mod__函数
static void
ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms,
size_t n_fms, enum ofputil_protocol usable_protocols)
{
enum ofputil_protocol protocol;
struct vconn *vconn;
size_t i;

if (bundle) {
bundle_flow_mod__(remote, fms, n_fms, usable_protocols);
return;
}

protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols); //打开vconn连接

for (i = 0; i < n_fms; i++) {
struct ofputil_flow_mod *fm = &fms[i];

transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol)); //发送请求
free(CONST_CAST(struct ofpact *, fm->ofpacts));
}
vconn_close(vconn);
}

6、open_vconn_for_flow_mod函数
static enum ofputil_protocol
open_vconn_for_flow_mod(const char *remote, struct vconn **vconnp,
enum ofputil_protocol usable_protocols)
{
enum ofputil_protocol cur_protocol;
char *usable_s;
int i;

if (!(usable_protocols & allowed_protocols)) {
char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
usable_s = ofputil_protocols_to_string(usable_protocols);
ovs_fatal(0, "none of the usable flow formats (%s) is among the "
"allowed flow formats (%s)", usable_s, allowed_s);
}

/* If the initial flow format is allowed and usable, keep it. */
cur_protocol = open_vconn(remote, vconnp); //打开vconn连接
if (usable_protocols & allowed_protocols & cur_protocol) {
return cur_protocol;
}

/* Otherwise try each flow format in turn. */
for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
enum ofputil_protocol f = 1 << i;

if (f != cur_protocol
&& f & usable_protocols & allowed_protocols
&& try_set_protocol(*vconnp, f, &cur_protocol)) {
return f;
}
}

usable_s = ofputil_protocols_to_string(usable_protocols);
ovs_fatal(0, "switch does not support any of the usable flow "
"formats (%s)", usable_s);
}

7、open_vconn函数
static enum ofputil_protocol
open_vconn(const char *name, struct vconn **vconnp)
{
return open_vconn__(name, MGMT, vconnp);
}

8、open_vconn__函数
static enum ofputil_protocol
open_vconn__(const char *name, enum open_target target,
struct vconn **vconnp)
{
const char *suffix = target == MGMT ? "mgmt" : "snoop";
char *datapath_name, *datapath_type, *socket_name;
enum ofputil_protocol protocol;
char *bridge_path;
int ofp_version;
int error;

bridge_path = xasprintf("%s/%s.%s", ovs_rundir(), name, suffix);

ofproto_parse_name(name, &datapath_name, &datapath_type);
socket_name = xasprintf("%s/%s.%s", ovs_rundir(), datapath_name, suffix);
free(datapath_name);
free(datapath_type);

if (strchr(name, ':')) { //如果name中包含“:”,一般不包含,会尝试多种连接路径
run(vconn_open(name, get_allowed_ofp_versions(), DSCP_DEFAULT, vconnp),
"connecting to %s", name);
} else if (!open_vconn_socket(name, vconnp)) {
/* Fall Through. */
} else if (!open_vconn_socket(bridge_path, vconnp)) { //ofservice socket bind的路径为 OVS_PATH/BR_NAME.mgmt
/* Fall Through. */
} else if (!open_vconn_socket(socket_name, vconnp)) {
/* Fall Through. */
} else {
ovs_fatal(0, "%s is not a bridge or a socket", name);
}

if (target == SNOOP) {
vconn_set_recv_any_version(*vconnp);
}

free(bridge_path);
free(socket_name);

VLOG_DBG("connecting to %s", vconn_get_name(*vconnp));
error = vconn_connect_block(*vconnp);
if (error) {
ovs_fatal(0, "%s: failed to connect to socket (%s)", name,
ovs_strerror(error));
}

ofp_version = vconn_get_version(*vconnp);
protocol = ofputil_protocol_from_ofp_version(ofp_version);
if (!protocol) {
ovs_fatal(0, "%s: unsupported OpenFlow version 0x%02x",
name, ofp_version);
}
return protocol;
}

9、open_vconn_socket函数
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); //建立unix socket连接
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;
}

到此,ofservice的连接过程应该是比较清晰了。 那么sockect是如何工作的,需要进一步分析Linux socket的使用,在后续需要分析。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  OVS openvswitch 网络