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

原创 2016年08月28日 16:56:34

上两篇分析了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的使用,在后续需要分析。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Doxygen

最近研究了下linux 下的doxygen的使用,很有意思,把经验分享下: 1.    安装doxygen 安装包 doxygen-1.7.4.linux.bin.tar.gz(可在官网下载)...

C/C++ Linux 程序员必须了解的 10 个工具

想成为 Linux 下专业的 C/C++ 程序员,下面工具都是必须要了解的。 1. 基本命令 http://mally.stanford.edu/~sr/computing/basic-unix....

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

上一篇分析了ofservice创建过程,本篇将分析ofservice处理请求的过程,ofservice处理请求的过程也是在connmgr_run函数。 1、connmgr_run函数 vo...

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

上回调用到vconn_stream_open函数,没有进一步分析,今天继续往下看,确定controller连接的整个过程。 9、stream_open_with_default_port函数 /*...

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

上两篇分析了controller连接建立的完整流程,本篇分析下接收openflow报文的过程,openflow报文的处理在后续文章中分析。 整个调用过程,可以根据上一篇的对象关系图得出,本篇只是把调用...

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

openflow连接有两个用途: 1)与controller连接;2)提供给ovs-ofctl工具配置流表等。 我们先看连接的初始化过程,配置入口是bridge_reconfigure函数。 ...

【OVS2.5.0源码分析】datapath之action分析(6)

今天分析OVS_ACTION_ATTR_RECIRC action的处理函数execute_recirc。 1、execute_recirc函数 static int execute_recirc...

【OVS2.5.0源码分析】mirror实现原理(1)

端口镜像是交换机的标准功能之一,针对某个端口的报文拷贝到除真实目的之外的另外一个目的地(output),这一篇我们先分析配置mirror之后,如何生成流表,在什么阶段生成流表。 1、xlate_ac...

【OVS2.5.0源码分析】mirror实现原理(2)

OVS实现mirror功能时,限制了out端口的通信能力。 1、限制mirror out端口通信总结 xlate_normal_flood函数 static void xlate_normal_...

【OVS2.5.0源码分析】sFlow实现分析(2)

本篇分析,sFlow流表生成过程,sFlow流表是在xlate_actions函数中生成,然后通过netlink下发给datapath的。 1、xlate_actions函数 /*...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【OVS2.5.0源码分析】openflow连接实现分析(6)
举报原因:
原因补充:

(最多只允许输入30个字)