关闭

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

标签: OVSopenvswitch网络
492人阅读 评论(0) 收藏 举报
分类:

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

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:68095次
    • 积分:1512
    • 等级:
    • 排名:千里之外
    • 原创:88篇
    • 转载:0篇
    • 译文:0篇
    • 评论:12条
    最新评论