Example #1
0
int
main(int argc, char *argv[])
{
    char *unixctl_path = NULL;
    char *run_command = NULL;
    struct unixctl_server *unixctl;
    struct ovsdb_jsonrpc_server *jsonrpc;
    struct shash remotes;
    struct ovsdb_error *error;
    struct ovsdb_file *file;
    struct ovsdb *db;
    struct process *run_process;
    char *file_name;
    bool exiting;
    int retval;

    proctitle_init(argc, argv);
    set_program_name(argv[0]);
    signal(SIGPIPE, SIG_IGN);
    process_init();

    parse_options(argc, argv, &file_name, &remotes, &unixctl_path,
                  &run_command);

    die_if_already_running();
    daemonize_start();

    error = ovsdb_file_open(file_name, false, &db, &file);
    if (error) {
        ovs_fatal(0, "%s", ovsdb_error_to_string(error));
    }

    jsonrpc = ovsdb_jsonrpc_server_create(db);
    reconfigure_from_db(jsonrpc, db, &remotes);

    retval = unixctl_server_create(unixctl_path, &unixctl);
    if (retval) {
        exit(EXIT_FAILURE);
    }

    if (run_command) {
        char *run_argv[4];

        run_argv[0] = "/bin/sh";
        run_argv[1] = "-c";
        run_argv[2] = run_command;
        run_argv[3] = NULL;

        retval = process_start(run_argv, NULL, 0, NULL, 0, &run_process);
        if (retval) {
            ovs_fatal(retval, "%s: process failed to start", run_command);
        }
    } else {
        run_process = NULL;
    }

    daemonize_complete();

    unixctl_command_register("exit", ovsdb_server_exit, &exiting);
    unixctl_command_register("ovsdb-server/compact", ovsdb_server_compact,
                             file);
    unixctl_command_register("ovsdb-server/reconnect", ovsdb_server_reconnect,
                             jsonrpc);

    exiting = false;
    while (!exiting) {
        reconfigure_from_db(jsonrpc, db, &remotes);
        ovsdb_jsonrpc_server_run(jsonrpc);
        unixctl_server_run(unixctl);
        ovsdb_trigger_run(db, time_msec());
        if (run_process && process_exited(run_process)) {
            exiting = true;
        }

        ovsdb_jsonrpc_server_wait(jsonrpc);
        unixctl_server_wait(unixctl);
        ovsdb_trigger_wait(db, time_msec());
        if (run_process) {
            process_wait(run_process);
        }
        poll_block();
    }
    ovsdb_jsonrpc_server_destroy(jsonrpc);
    ovsdb_destroy(db);
    shash_destroy(&remotes);
    unixctl_server_destroy(unixctl);

    if (run_process && process_exited(run_process)) {
        int status = process_status(run_process);
        if (status) {
            ovs_fatal(0, "%s: child exited, %s",
                      run_command, process_status_msg(status));
        }
    }

    return 0;
}
int
main(int argc, char *argv[])
{
    struct unixctl_server *server;
    enum { MAX_RECV = 1500 };
    const char *target;
    struct ofpbuf buf;
    bool exiting = false;
    int error;
    int sock;
    int n;

    proctitle_init(argc, argv);
    set_program_name(argv[0]);
    parse_options(argc, argv);

    if (argc - optind != 1) {
        ovs_fatal(0, "exactly one non-option argument required "
                  "(use --help for help)");
    }
    target = argv[optind];

    sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0);
    if (sock < 0) {
        ovs_fatal(0, "%s: failed to open (%s)", argv[1], strerror(-sock));
    }

    daemon_save_fd(STDOUT_FILENO);
    daemonize_start();

    error = unixctl_server_create(NULL, &server);
    if (error) {
        ovs_fatal(error, "failed to create unixctl server");
    }
    unixctl_command_register("exit", "", 0, 0, test_netflow_exit, &exiting);

    daemonize_complete();

    ofpbuf_init(&buf, MAX_RECV);
    n = 0;
    for (;;) {
        int retval;

        unixctl_server_run(server);

        ofpbuf_clear(&buf);
        do {
            retval = read(sock, buf.data, buf.allocated);
        } while (retval < 0 && errno == EINTR);
        if (retval > 0) {
            ofpbuf_put_uninit(&buf, retval);
            if (n++ > 0) {
                putchar('\n');
            }
            print_netflow(&buf);
            fflush(stdout);
        }

        if (exiting) {
            break;
        }

        poll_fd_wait(sock, POLLIN);
        unixctl_server_wait(server);
        poll_block();
    }

    return 0;
}
Example #3
0
/* Helper for bundle_parse and bundle_parse_load. */
static void
bundle_parse__(struct ofpbuf *b, const char *s, char **save_ptr,
               const char *fields, const char *basis, const char *algorithm,
               const char *slave_type, const char *dst,
               const char *slave_delim)
{
    enum ofputil_action_code code;
    struct nx_action_bundle *nab;
    uint16_t n_slaves;

    if (!slave_delim) {
        ovs_fatal(0, "%s: not enough arguments to bundle action", s);
    }

    if (strcasecmp(slave_delim, "slaves")) {
        ovs_fatal(0, "%s: missing slave delimiter, expected `slaves' got `%s'",
                   s, slave_delim);
    }

    code = dst ? OFPUTIL_NXAST_BUNDLE_LOAD : OFPUTIL_NXAST_BUNDLE;
    b->l2 = ofputil_put_action(code, b);

    n_slaves = 0;
    for (;;) {
        ovs_be16 slave_be;
        char *slave;

        slave = strtok_r(NULL, ", ", save_ptr);
        if (!slave || n_slaves >= BUNDLE_MAX_SLAVES) {
            break;
        }

        slave_be = htons(atoi(slave));
        ofpbuf_put(b, &slave_be, sizeof slave_be);

        n_slaves++;
    }

    /* Slaves array must be multiple of 8 bytes long. */
    if (b->size % 8) {
        ofpbuf_put_zeros(b, 8 - (b->size % 8));
    }

    nab = b->l2;
    nab->len = htons(b->size - ((char *) b->l2 - (char *) b->data));
    nab->n_slaves = htons(n_slaves);
    nab->basis = htons(atoi(basis));

    if (!strcasecmp(fields, "eth_src")) {
        nab->fields = htons(NX_HASH_FIELDS_ETH_SRC);
    } else if (!strcasecmp(fields, "symmetric_l4")) {
        nab->fields = htons(NX_HASH_FIELDS_SYMMETRIC_L4);
    } else {
        ovs_fatal(0, "%s: unknown fields `%s'", s, fields);
    }

    if (!strcasecmp(algorithm, "active_backup")) {
        nab->algorithm = htons(NX_BD_ALG_ACTIVE_BACKUP);
    } else if (!strcasecmp(algorithm, "hrw")) {
        nab->algorithm = htons(NX_BD_ALG_HRW);
    } else {
        ovs_fatal(0, "%s: unknown algorithm `%s'", s, algorithm);
    }

    if (!strcasecmp(slave_type, "ofport")) {
        nab->slave_type = htonl(NXM_OF_IN_PORT);
    } else {
        ovs_fatal(0, "%s: unknown slave_type `%s'", s, slave_type);
    }

    if (dst) {
        uint32_t reg;
        int ofs, n_bits;

        nxm_parse_field_bits(dst, &reg, &ofs, &n_bits);

        nab->dst = htonl(reg);
        nab->ofs_nbits = nxm_encode_ofs_nbits(ofs, n_bits);
    }

    b->l2 = NULL;
}
Example #4
0
int
main(int argc, char *argv[])
{
    const struct ovsdb_client_command *command;
    char *database;
    struct jsonrpc *rpc;

    ovs_cmdl_proctitle_init(argc, argv);
    set_program_name(argv[0]);
    parse_options(argc, argv);
    fatal_ignore_sigpipe();

    daemon_become_new_user(false);
    if (optind >= argc) {
        ovs_fatal(0, "missing command name; use --help for help");
    }

    for (command = get_all_commands(); ; command++) {
        if (!command->name) {
            VLOG_FATAL("unknown command '%s'; use --help for help",
                       argv[optind]);
        } else if (!strcmp(command->name, argv[optind])) {
            break;
        }
    }
    optind++;

    if (command->need != NEED_NONE) {
        if (argc - optind > command->min_args
            && (isalpha((unsigned char) argv[optind][0])
                && strchr(argv[optind], ':'))) {
            rpc = open_jsonrpc(argv[optind++]);
        } else {
            char *sock = xasprintf("unix:%s/db.sock", ovs_rundir());
            rpc = open_jsonrpc(sock);
            free(sock);
        }
    } else {
        rpc = NULL;
    }

    if (command->need == NEED_DATABASE) {
        struct svec dbs;

        svec_init(&dbs);
        fetch_dbs(rpc, &dbs);
        if (argc - optind > command->min_args
            && svec_contains(&dbs, argv[optind])) {
            database = xstrdup(argv[optind++]);
        } else if (dbs.n == 1) {
            database = xstrdup(dbs.names[0]);
        } else if (svec_contains(&dbs, "Open_vSwitch")) {
            database = xstrdup("Open_vSwitch");
        } else {
            jsonrpc_close(rpc);
            ovs_fatal(0, "no default database for `%s' command, please "
                      "specify a database name", command->name);
        }
        svec_destroy(&dbs);
    } else {
        database = NULL;
    }

    if (argc - optind < command->min_args ||
        argc - optind > command->max_args) {
        free(database);
        VLOG_FATAL("invalid syntax for '%s' (use --help for help)",
                    command->name);
    }

    command->handler(rpc, database, argc - optind, argv + optind);

    free(database);
    jsonrpc_close(rpc);

    if (ferror(stdout)) {
        VLOG_FATAL("write to stdout failed");
    }
    if (ferror(stderr)) {
        VLOG_FATAL("write to stderr failed");
    }

    return 0;
}
Example #5
0
/* Parses 'arg' as a set of arguments to the "learn" action and appends a
 * matching NXAST_LEARN action to 'b'.  The format parsed is described in
 * ovs-ofctl(8).
 *
 * Prints an error on stderr and aborts the program if 'arg' syntax is invalid.
 *
 * If 'flow' is nonnull, then it should be the flow from a cls_rule that is
 * the matching rule for the learning action.  This helps to better validate
 * the action's arguments.
 *
 * Modifies 'arg'. */
void
learn_parse(struct ofpbuf *b, char *arg, const struct flow *flow)
{
    char *orig = xstrdup(arg);
    char *name, *value;
    enum ofperr error;
    size_t learn_ofs;
    size_t len;

    struct nx_action_learn *learn;
    struct cls_rule rule;

    learn_ofs = b->size;
    learn = ofputil_put_NXAST_LEARN(b);
    learn->idle_timeout = htons(OFP_FLOW_PERMANENT);
    learn->hard_timeout = htons(OFP_FLOW_PERMANENT);
    learn->priority = htons(OFP_DEFAULT_PRIORITY);
    learn->cookie = htonll(0);
    learn->flags = htons(0);
    learn->table_id = 1;

    cls_rule_init_catchall(&rule, 0);
    while (ofputil_parse_key_value(&arg, &name, &value)) {
        learn = ofpbuf_at_assert(b, learn_ofs, sizeof *learn);
        if (!strcmp(name, "table")) {
            learn->table_id = atoi(value);
            if (learn->table_id == 255) {
                ovs_fatal(0, "%s: table id 255 not valid for `learn' action",
                          orig);
            }
        } else if (!strcmp(name, "priority")) {
            learn->priority = htons(atoi(value));
        } else if (!strcmp(name, "idle_timeout")) {
            learn->idle_timeout = htons(atoi(value));
        } else if (!strcmp(name, "hard_timeout")) {
            learn->hard_timeout = htons(atoi(value));
        } else if (!strcmp(name, "fin_idle_timeout")) {
            learn->fin_idle_timeout = htons(atoi(value));
        } else if (!strcmp(name, "fin_hard_timeout")) {
            learn->fin_hard_timeout = htons(atoi(value));
        } else if (!strcmp(name, "cookie")) {
            learn->cookie = htonll(strtoull(value, NULL, 0));
        } else {
            struct learn_spec spec;

            learn_parse_spec(orig, name, value, &spec);

            /* Check prerequisites. */
            if (spec.src_type == NX_LEARN_SRC_FIELD
                && flow && !mf_are_prereqs_ok(spec.src.field, flow)) {
                ovs_fatal(0, "%s: cannot specify source field %s because "
                          "prerequisites are not satisfied",
                          orig, spec.src.field->name);
            }
            if ((spec.dst_type == NX_LEARN_DST_MATCH
                 || spec.dst_type == NX_LEARN_DST_LOAD)
                && !mf_are_prereqs_ok(spec.dst.field, &rule.flow)) {
                ovs_fatal(0, "%s: cannot specify destination field %s because "
                          "prerequisites are not satisfied",
                          orig, spec.dst.field->name);
            }

            /* Update 'rule' to allow for satisfying destination
             * prerequisites. */
            if (spec.src_type == NX_LEARN_SRC_IMMEDIATE
                && spec.dst_type == NX_LEARN_DST_MATCH) {
                mf_write_subfield(&spec.dst, &spec.src_imm, &rule);
            }

            /* Output the flow_mod_spec. */
            put_u16(b, spec.n_bits | spec.src_type | spec.dst_type);
            if (spec.src_type == NX_LEARN_SRC_IMMEDIATE) {
                int n_bytes = DIV_ROUND_UP(spec.n_bits, 16) * 2;
                int ofs = sizeof spec.src_imm - n_bytes;
                ofpbuf_put(b, &spec.src_imm.u8[ofs], n_bytes);
            } else {
                put_u32(b, spec.src.field->nxm_header);
                put_u16(b, spec.src.ofs);
            }
            if (spec.dst_type == NX_LEARN_DST_MATCH ||
                spec.dst_type == NX_LEARN_DST_LOAD) {
                put_u32(b, spec.dst.field->nxm_header);
                put_u16(b, spec.dst.ofs);
            } else {
                assert(spec.dst_type == NX_LEARN_DST_OUTPUT);
            }
        }
    }

    put_u16(b, 0);

    len = b->size - learn_ofs;
    if (len % 8) {
        ofpbuf_put_zeros(b, 8 - len % 8);
    }

    learn = ofpbuf_at_assert(b, learn_ofs, sizeof *learn);
    learn->len = htons(b->size - learn_ofs);

    /* In theory the above should have caught any errors, but... */
    if (flow) {
        error = learn_check(learn, flow);
        if (error) {
            ovs_fatal(0, "%s: %s", orig, ofperr_to_string(error));
        }
    }
    free(orig);
}
Example #6
0
static char *
parse_options(int argc, char *argv[], char **unixctl_pathp)
{
    enum {
        OPT_PEER_CA_CERT = UCHAR_MAX + 1,
        OPT_MLOCKALL,
        OPT_UNIXCTL,
        VLOG_OPTION_ENUMS,
        OPT_BOOTSTRAP_CA_CERT,
        OPT_ENABLE_DUMMY,
        OPT_DISABLE_SYSTEM,
        DAEMON_OPTION_ENUMS,
        OPT_DPDK,
    };
    static const struct option long_options[] = {
        {"help",        no_argument, NULL, 'h'},
        {"version",     no_argument, NULL, 'V'},
        {"mlockall",    no_argument, NULL, OPT_MLOCKALL},
        {"unixctl",     required_argument, NULL, OPT_UNIXCTL},
        DAEMON_LONG_OPTIONS,
        VLOG_LONG_OPTIONS,
        STREAM_SSL_LONG_OPTIONS,
        {"peer-ca-cert", required_argument, NULL, OPT_PEER_CA_CERT},
        {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT},
        {"enable-dummy", optional_argument, NULL, OPT_ENABLE_DUMMY},
        {"disable-system", no_argument, NULL, OPT_DISABLE_SYSTEM},
        {"dpdk", optional_argument, NULL, OPT_DPDK},
        {NULL, 0, NULL, 0},
    };
    char *short_options = ovs_cmdl_long_options_to_short_options(long_options);

    for (;;) {
        int c;

        c = getopt_long(argc, argv, short_options, long_options, NULL);
        if (c == -1) {
            break;
        }

        switch (c) {
        case 'h':
            usage();

        case 'V':
            ovs_print_version(0, 0);
            exit(EXIT_SUCCESS);

        case OPT_MLOCKALL:
            want_mlockall = true;
            break;

        case OPT_UNIXCTL:
            *unixctl_pathp = optarg;
            break;

        VLOG_OPTION_HANDLERS
        DAEMON_OPTION_HANDLERS
        STREAM_SSL_OPTION_HANDLERS

        case OPT_PEER_CA_CERT:
            stream_ssl_set_peer_ca_cert_file(optarg);
            break;

        case OPT_BOOTSTRAP_CA_CERT:
            stream_ssl_set_ca_cert_file(optarg, true);
            break;

        case OPT_ENABLE_DUMMY:
            dummy_enable(optarg);
            break;

        case OPT_DISABLE_SYSTEM:
            dp_blacklist_provider("system");
            break;

        case '?':
            exit(EXIT_FAILURE);

        case OPT_DPDK:
            ovs_fatal(0, "Using --dpdk to configure DPDK is not supported.");
            break;

        default:
            abort();
        }
    }
    free(short_options);

    argc -= optind;
    argv += optind;

    switch (argc) {
    case 0:
        return xasprintf("unix:%s/db.sock", ovs_rundir());

    case 1:
        return xstrdup(argv[0]);

    default:
        VLOG_FATAL("at most one non-option argument accepted; "
                   "use --help for usage");
    }
}
Example #7
0
static int
parse_filter(char *filter_parse)
{
    struct ds in;
    struct flow flow_filter;
    struct flow_wildcards wc_filter;
    char *error, *filter = NULL;

    vlog_set_levels_from_string_assert("odp_util:console:dbg");
    if (filter_parse && !strncmp(filter_parse, "filter=", 7)) {
        filter = strdup(filter_parse+7);
        memset(&flow_filter, 0, sizeof(flow_filter));
        memset(&wc_filter, 0, sizeof(wc_filter));

        error = parse_ofp_exact_flow(&flow_filter, &wc_filter.masks, filter,
                                     NULL);
        if (error) {
            ovs_fatal(0, "Failed to parse filter (%s)", error);
        }
    } else {
        ovs_fatal(0, "No filter to parse.");
    }

    ds_init(&in);
    while (!ds_get_test_line(&in, stdin)) {
        struct ofpbuf odp_key;
        struct ofpbuf odp_mask;
        struct ds out;
        int error;

        /* Convert string to OVS DP key. */
        ofpbuf_init(&odp_key, 0);
        ofpbuf_init(&odp_mask, 0);
        error = odp_flow_from_string(ds_cstr(&in), NULL,
                                     &odp_key, &odp_mask);
        if (error) {
            printf("odp_flow_from_string: error\n");
            goto next;
        }

        if (filter) {
            struct flow flow;
            struct flow_wildcards wc;
            struct match match, match_filter;
            struct minimatch minimatch;

            odp_flow_key_to_flow(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key), &flow);
            odp_flow_key_to_mask(ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask), &wc.masks,
                                 &flow);
            match_init(&match, &flow, &wc);

            match_init(&match_filter, &flow_filter, &wc);
            match_init(&match_filter, &match_filter.flow, &wc_filter);
            minimatch_init(&minimatch, &match_filter);

            if (!minimatch_matches_flow(&minimatch, &match.flow)) {
                minimatch_destroy(&minimatch);
                goto next;
            }
            minimatch_destroy(&minimatch);
        }
        /* Convert odp_key to string. */
        ds_init(&out);
        odp_flow_format(ofpbuf_data(&odp_key), ofpbuf_size(&odp_key),
                        ofpbuf_data(&odp_mask), ofpbuf_size(&odp_mask), NULL, &out, false);
        puts(ds_cstr(&out));
        ds_destroy(&out);

    next:
        ofpbuf_uninit(&odp_key);
        ofpbuf_uninit(&odp_mask);
    }
    ds_destroy(&in);

    free(filter);
    return 0;
}
Example #8
0
/* Connects to a fake_pvconn with vconn_open(), accepts that connection and
 * sends the 'out' bytes in 'out_size' to it (presumably an OFPT_HELLO
 * message), then verifies that vconn_connect() reports
 * 'expect_connect_error'. */
static void
test_send_hello(const char *type, const void *out, size_t out_size,
                int expect_connect_error)
{
    struct fake_pvconn fpv;
    struct vconn *vconn;
    bool read_hello, connected;
    struct ofpbuf *msg;
    struct stream *stream;
    size_t n_sent;

    fpv_create(type, &fpv);
    CHECK_ERRNO(vconn_open(fpv.vconn_name, 0, DSCP_DEFAULT, &vconn), 0);
    vconn_run(vconn);
    stream = fpv_accept(&fpv);
    fpv_destroy(&fpv);

    n_sent = 0;
    while (n_sent < out_size) {
        int retval;

        retval = stream_send(stream, (char *) out + n_sent, out_size - n_sent);
        if (retval > 0) {
            n_sent += retval;
        } else if (retval == -EAGAIN) {
            stream_run(stream);
            vconn_run(vconn);
            stream_recv_wait(stream);
            vconn_connect_wait(vconn);
            vconn_run_wait(vconn);
            poll_block();
        } else {
            ovs_fatal(0, "stream_send returned unexpected value %d", retval);
        }
    }

    read_hello = connected = false;
    for (;;) {
       if (!read_hello) {
           struct ofp_header hello;
           int retval = stream_recv(stream, &hello, sizeof hello);
           if (retval == sizeof hello) {
               enum ofpraw raw;

               CHECK(hello.version, OFP13_VERSION);
               CHECK(ofpraw_decode_partial(&raw, &hello, sizeof hello), 0);
               CHECK(raw, OFPRAW_OFPT_HELLO);
               CHECK(ntohs(hello.length), sizeof hello);
               read_hello = true;
           } else {
               CHECK_ERRNO(retval, -EAGAIN);
           }
       }

       vconn_run(vconn);
       if (!connected) {
           int error = vconn_connect(vconn);
           if (error == expect_connect_error) {
               if (!error) {
                   connected = true;
               } else {
                   stream_close(stream);
                   vconn_close(vconn);
                   return;
               }
           } else {
               CHECK_ERRNO(error, EAGAIN);
           }
       }

       if (read_hello && connected) {
           break;
       }

       vconn_run_wait(vconn);
       if (!connected) {
           vconn_connect_wait(vconn);
       }
       if (!read_hello) {
           stream_recv_wait(stream);
       }
       poll_block();
    }
    stream_close(stream);
    CHECK_ERRNO(vconn_recv_block(vconn, &msg), EOF);
    vconn_close(vconn);
}
Example #9
0
static void
test_stp_main(int argc, char *argv[])
{
    struct test_case *tc;
    FILE *input_file;
    int i;

    vlog_set_pattern(VLF_CONSOLE, "%c|%p|%m");
    vlog_set_levels(NULL, VLF_SYSLOG, VLL_OFF);

    if (argc != 2) {
        ovs_fatal(0, "usage: test-stp INPUT.STP\n");
    }
    file_name = argv[1];

    input_file = fopen(file_name, "r");
    if (!input_file) {
        ovs_fatal(errno, "error opening \"%s\"", file_name);
    }

    tc = new_test_case();
    for (i = 0; i < 26; i++) {
        char name[2];
        name[0] = 'a' + i;
        name[1] = '\0';
        new_lan(tc, name);
    }

    for (line_number = 1; fgets(line, sizeof line, input_file);
         line_number++)
    {
        char *newline, *hash;

        newline = strchr(line, '\n');
        if (newline) {
            *newline = '\0';
        }
        hash = strchr(line, '#');
        if (hash) {
            *hash = '\0';
        }

        pos = line;
        if (!get_token()) {
            continue;
        }
        if (match("bridge")) {
            struct bridge *bridge;
            int bridge_no, port_no;

            bridge_no = must_get_int();
            if (bridge_no < tc->n_bridges) {
                bridge = tc->bridges[bridge_no];
            } else if (bridge_no == tc->n_bridges) {
                bridge = new_bridge(tc, must_get_int());
            } else {
                err("bridges must be numbered consecutively from 0");
            }
            if (match("^")) {
                stp_set_bridge_priority(bridge->stp, must_get_int());
            }

            if (match("=")) {
                for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) {
                    struct stp_port *p = stp_get_port(bridge->stp, port_no);
                    if (!token || match("X")) {
                        stp_port_disable(p);
                    } else if (match("_")) {
                        /* Nothing to do. */
                    } else {
                        struct lan *lan;
                        int path_cost;

                        if (!strcmp(token, "0")) {
                            lan = NULL;
                        } else if (strlen(token) == 1
                                && islower((unsigned char)*token)) {
                            lan = tc->lans[*token - 'a'];
                        } else {
                            err("%s is not a valid LAN name "
                                "(0 or a lowercase letter)", token);
                        }
                        get_token();

                        path_cost = match(":") ? must_get_int() : 10;
                        if (port_no < bridge->n_ports) {
                            stp_port_set_path_cost(p, path_cost);
                            stp_port_enable(p);
                            reconnect_port(bridge, port_no, lan);
                        } else if (port_no == bridge->n_ports) {
                            new_port(bridge, lan, path_cost);
                        } else {
                            err("ports must be numbered consecutively");
                        }
                        if (match("^")) {
                            stp_port_set_priority(p, must_get_int());
                        }
                    }
                }
            }
        } else if (match("run")) {
            simulate(tc, must_get_int());
        } else if (match("dump")) {
            dump(tc);
        } else if (match("tree")) {
            tree(tc);
        } else if (match("check")) {
            struct bridge *b;
            struct stp *stp;
            int bridge_no, port_no;

            bridge_no = must_get_int();
            if (bridge_no >= tc->n_bridges) {
                err("no bridge numbered %d", bridge_no);
            }
            b = tc->bridges[bridge_no];
            stp = b->stp;

            must_match("=");

            if (match("rootid")) {
                uint64_t rootid;
                must_match(":");
                rootid = must_get_int();
                if (match("^")) {
                    rootid |= (uint64_t) must_get_int() << 48;
                } else {
                    rootid |= UINT64_C(0x8000) << 48;
                }
                if (stp_get_designated_root(stp) != rootid) {
                    warn("%s: root %"PRIx64", not %"PRIx64,
                         stp_get_name(stp), stp_get_designated_root(stp),
                         rootid);
                }
            }

            if (match("root")) {
                if (stp_get_root_path_cost(stp)) {
                    warn("%s: root path cost of root is %u but should be 0",
                         stp_get_name(stp), stp_get_root_path_cost(stp));
                }
                if (!stp_is_root_bridge(stp)) {
                    warn("%s: root is %"PRIx64", not %"PRIx64,
                         stp_get_name(stp),
                         stp_get_designated_root(stp), stp_get_bridge_id(stp));
                }
                for (port_no = 0; port_no < b->n_ports; port_no++) {
                    struct stp_port *p = stp_get_port(stp, port_no);
                    enum stp_state state = stp_port_get_state(p);
                    if (!(state & (STP_DISABLED | STP_FORWARDING))) {
                        warn("%s: root port %d in state %s",
                             stp_get_name(b->stp), port_no,
                             stp_state_name(state));
                    }
                }
            } else {
                for (port_no = 0; port_no < STP_MAX_PORTS; port_no++) {
                    struct stp_port *p = stp_get_port(stp, port_no);
                    enum stp_state state;
                    if (token == NULL || match("D")) {
                        state = STP_DISABLED;
                    } else if (match("B")) {
                        state = STP_BLOCKING;
                    } else if (match("Li")) {
                        state = STP_LISTENING;
                    } else if (match("Le")) {
                        state = STP_LEARNING;
                    } else if (match("F")) {
                        state = STP_FORWARDING;
                    } else if (match("_")) {
                        continue;
                    } else {
                        err("unknown port state %s", token);
                    }
                    if (stp_port_get_state(p) != state) {
                        warn("%s port %d: state is %s but should be %s",
                             stp_get_name(stp), port_no,
                             stp_state_name(stp_port_get_state(p)),
                             stp_state_name(state));
                    }
                    if (state == STP_FORWARDING) {
                        struct stp_port *root_port = stp_get_root_port(stp);
                        if (match(":")) {
                            int root_path_cost = must_get_int();
                            if (p != root_port) {
                                warn("%s: port %d is not the root port",
                                     stp_get_name(stp), port_no);
                                if (!root_port) {
                                    warn("%s: (there is no root port)",
                                         stp_get_name(stp));
                                } else {
                                    warn("%s: (port %d is the root port)",
                                         stp_get_name(stp),
                                         stp_port_no(root_port));
                                }
                            } else if (root_path_cost
                                       != stp_get_root_path_cost(stp)) {
                                warn("%s: root path cost is %u, should be %d",
                                     stp_get_name(stp),
                                     stp_get_root_path_cost(stp),
                                     root_path_cost);
                            }
                        } else if (p == root_port) {
                            warn("%s: port %d is the root port but "
                                 "not expected to be",
                                 stp_get_name(stp), port_no);
                        }
                    }
                }
            }
            if (n_warnings) {
                exit(EXIT_FAILURE);
            }
        }
        if (get_token()) {
            err("trailing garbage on line");
        }
    }
    free(token);

    for (i = 0; i < tc->n_lans; i++) {
        struct lan *lan = tc->lans[i];
        free(CONST_CAST(char *, lan->name));
        free(lan);
    }
    for (i = 0; i < tc->n_bridges; i++) {
        struct bridge *bridge = tc->bridges[i];
        stp_unref(bridge->stp);
        free(bridge);
    }
    free(tc);
    fclose(input_file);
}
Example #10
0
static void
parse_options(int argc, char *argv[])
{
    static const struct option long_options[] = {
        {"local", required_argument, NULL, 'l'},
        {"remote", required_argument, NULL, 'r'},
        {"batches", required_argument, NULL, 'b'},
        {"sockets", required_argument, NULL, 's'},
        {"max-rate", required_argument, NULL, 'c'},
        {"timeout", required_argument, NULL, 'T'},
        {"help", no_argument, NULL, 'h'},
        {"version", no_argument, NULL, 'V'},
        {NULL, 0, NULL, 0},
    };
    char *short_options = ovs_cmdl_long_options_to_short_options(long_options);

    local_addr.s_addr = htonl(INADDR_ANY);
    local_min_port = local_max_port = 0;

    remote_addr.s_addr = htonl(0);
    remote_min_port = remote_max_port = 0;

    for (;;) {
        int c;

        c = getopt_long(argc, argv, short_options, long_options, NULL);
        if (c == -1) {
            break;
        }

        switch (c) {
        case 'l':
            parse_target(optarg,
                         &local_addr, &local_min_port, &local_max_port);
            break;

        case 'r':
            parse_target(optarg,
                         &remote_addr, &remote_min_port, &remote_max_port);
            if (remote_addr.s_addr == htonl(INADDR_ANY)) {
                ovs_fatal(0, "remote IP address is required");
            }
            break;

        case 'b':
            n_batches = atoi(optarg);
            if (n_batches < 0) {
                ovs_fatal(0, "--batches or -b argument must be at least 1");
            }
            break;

        case 's':
            n_sockets = atoi(optarg);
            if (n_sockets < 1 || n_sockets > MAX_SOCKETS) {
                ovs_fatal(0, "--sockets or -s argument must be between 1 "
                          "and %d (inclusive)", MAX_SOCKETS);
            }
            break;

        case 'c':
            max_rate = atof(optarg);
            if (max_rate <= 0.0) {
                ovs_fatal(0, "--max-rate or -c argument must be positive");
            }
            break;

        case 'T':
            timeout = atoi(optarg);
            if (!timeout) {
                ovs_fatal(0, "-T or --timeout argument must be positive");
            }
            break;

        case 'h':
            usage();

        case 'V':
            ovs_print_version(0, 0);
            exit(EXIT_SUCCESS);

        case '?':
            exit(EXIT_FAILURE);

        default:
            abort();
        }
    }
    free(short_options);
}
int
main(int argc, char *argv[])
{
    enum { MP_MAX_LINKS = 63 };
    struct ofpact_multipath mp;
    bool ok = true;
    char *error;
    int n;

    set_program_name(argv[0]);

    if (argc != 2) {
        ovs_fatal(0, "usage: %s multipath_action", program_name);
    }

    error = multipath_parse(&mp, argv[1]);
    if (error) {
        ovs_fatal(0, "%s", error);
    }

    for (n = 1; n <= MP_MAX_LINKS; n++) {
        enum { N_FLOWS = 65536 };
        double disruption, perfect, distribution;
        int histogram[MP_MAX_LINKS];
        double sum_dev2, stddev;
        int changed;
        int i;

        changed = 0;
        memset(histogram, 0, sizeof histogram);
        for (i = 0; i < N_FLOWS; i++) {
            int old_link, new_link;
            struct flow_wildcards wc;
            struct flow flow;

            flow_random_hash_fields(&flow);

            mp.max_link = n - 1;
            multipath_execute(&mp, &flow, &wc);
            old_link = flow.regs[0];

            mp.max_link = n;
            multipath_execute(&mp, &flow, &wc);
            new_link = flow.regs[0];

            assert(old_link >= 0 && old_link < n);
            assert(new_link >= 0 && new_link < n + 1);

            histogram[old_link]++;
            changed += old_link != new_link;
        }

        sum_dev2 = 0.0;
        for (i = 0; i < n; i++) {
            double mean = (double) N_FLOWS / n;
            double deviation = histogram[i] - mean;

            sum_dev2 += deviation * deviation;
        }
        stddev = sqrt(sum_dev2 / n);

        disruption = (double) changed / N_FLOWS;
        perfect = 1.0 / (n + 1);
        distribution = stddev / ((double) N_FLOWS / n);
        printf("%2d -> %2d: disruption=%.2f (perfect=%.2f); "
               "stddev/expected=%.4f\n",
               n, n + 1, disruption, perfect, distribution);

        switch (mp.algorithm) {
        case NX_MP_ALG_MODULO_N:
            if (disruption < (n < 2 ? .25 : .5)) {
                fprintf(stderr, "%d -> %d: disruption=%.2f < .5\n",
                        n, n + 1, disruption);
                ok = false;
            }
            break;

        case NX_MP_ALG_HASH_THRESHOLD:
            if (disruption < .48 || disruption > .52) {
                fprintf(stderr, "%d -> %d: disruption=%.2f not approximately "
                        ".5\n", n, n + 1, disruption);
                ok = false;
            }
            break;

        case NX_MP_ALG_ITER_HASH:
            if (!(n & (n - 1))) {
                break;
            }
            /* Fall through. */
        case NX_MP_ALG_HRW:
            if (fabs(disruption - perfect) >= .01) {
                fprintf(stderr, "%d -> %d: disruption=%.5f differs from "
                        "perfect=%.5f by more than .01\n",
                        n, n + 1, disruption, perfect);
                ok = false;
            }
            break;

        default:
            OVS_NOT_REACHED();
        }
    }

    return ok ? 0 : 1;
}
Example #12
0
int
main(int argc OVS_UNUSED, char *argv[])
{
    struct ofp10_match expected_match;
    FILE *flows, *pcap;
    int retval;
    int n = 0, errors = 0;

    set_program_name(argv[0]);

    flows = stdin;
    pcap = fdopen(3, "rb");
    if (!pcap) {
        ovs_fatal(errno, "failed to open fd 3 for reading");
    }

    retval = pcap_read_header(pcap);
    if (retval) {
        ovs_fatal(retval > 0 ? retval : 0, "reading pcap header failed");
    }

    while (fread(&expected_match, sizeof expected_match, 1, flows)) {
        struct ofpbuf *packet;
        struct ofp10_match extracted_match;
        struct match match;
        struct flow flow;

        n++;

        retval = pcap_read(pcap, &packet);
        if (retval == EOF) {
            ovs_fatal(0, "unexpected end of file reading pcap file");
        } else if (retval) {
            ovs_fatal(retval, "error reading pcap file");
        }

        flow_extract(packet, 0, NULL, 1, &flow);
        match_init_exact(&match, &flow);
        ofputil_match_to_ofp10_match(&match, &extracted_match);

        if (memcmp(&expected_match, &extracted_match, sizeof expected_match)) {
            char *exp_s = ofp10_match_to_string(&expected_match, 2);
            char *got_s = ofp10_match_to_string(&extracted_match, 2);
            errors++;
            printf("mismatch on packet #%d (1-based).\n", n);
            printf("Packet:\n");
            ofp_print_packet(stdout, packet->data, packet->size);
            ovs_hex_dump(stdout, packet->data, packet->size, 0, true);
            match_print(&match);
            printf("Expected flow:\n%s\n", exp_s);
            printf("Actually extracted flow:\n%s\n", got_s);
            ovs_hex_dump(stdout, &expected_match, sizeof expected_match, 0, false);
            ovs_hex_dump(stdout, &extracted_match, sizeof extracted_match, 0, false);
            printf("\n");
            free(exp_s);
            free(got_s);
        }

        ofpbuf_delete(packet);
    }
    printf("checked %d packets, %d errors\n", n, errors);
    return errors != 0;
}
Example #13
0
int
main(int argc OVS_UNUSED, char *argv[])
{
    uint64_t buf_stub[4096 / 64];
    struct nl_sock *sock;
    struct ofpbuf buf;
    int error;

    set_program_name(argv[0]);
    vlog_set_levels(NULL, VLF_ANY_FACILITY, VLL_DBG);

    error = nl_sock_create(NETLINK_ROUTE, &sock);
    if (error) {
        ovs_fatal(error, "could not create rtnetlink socket");
    }

    error = nl_sock_join_mcgroup(sock, RTNLGRP_LINK);
    if (error) {
        ovs_fatal(error, "could not join RTNLGRP_LINK multicast group");
    }

    ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub);
    for (;;) {
        error = nl_sock_recv(sock, &buf, false);
        if (error == EAGAIN) {
            /* Nothing to do. */
        } else if (error == ENOBUFS) {
            ovs_error(0, "network monitor socket overflowed");
        } else if (error) {
            ovs_fatal(error, "error on network monitor socket");
        } else {
            struct iff_flag {
                unsigned int flag;
                const char *name;
            };

            static const struct iff_flag flags[] = {
                { IFF_UP, "UP", },
                { IFF_BROADCAST, "BROADCAST", },
#ifndef _WIN32
                { IFF_DEBUG, "DEBUG", },
#endif
                { IFF_LOOPBACK, "LOOPBACK", },
#ifndef _WIN32
                { IFF_POINTOPOINT, "POINTOPOINT", },
                { IFF_NOTRAILERS, "NOTRAILERS", },
#endif
                { IFF_RUNNING, "RUNNING", },
#ifndef _WIN32
                { IFF_NOARP, "NOARP", },
#endif
                { IFF_PROMISC, "PROMISC", },
#ifndef _WIN32
                { IFF_ALLMULTI, "ALLMULTI", },
                { IFF_MASTER, "MASTER", },
                { IFF_SLAVE, "SLAVE", },
#endif
                { IFF_MULTICAST, "MULTICAST", },
#ifndef _WIN32
                { IFF_PORTSEL, "PORTSEL", },
                { IFF_AUTOMEDIA, "AUTOMEDIA", },
                { IFF_DYNAMIC, "DYNAMIC", },
#endif
            };

            struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)];
            struct nlmsghdr *nlh;
            struct ifinfomsg *iim;
            int i;

            nlh = ofpbuf_at(&buf, 0, NLMSG_HDRLEN);
            iim = ofpbuf_at(&buf, NLMSG_HDRLEN, sizeof *iim);
            if (!iim) {
                ovs_error(0, "received bad rtnl message (no ifinfomsg)");
                continue;
            }

            if (!nl_policy_parse(&buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
                                 rtnlgrp_link_policy,
                                 attrs, ARRAY_SIZE(rtnlgrp_link_policy))) {
                ovs_error(0, "received bad rtnl message (policy)");
                continue;
            }
            printf("netdev %s changed (%s):\n",
                   nl_attr_get_string(attrs[IFLA_IFNAME]),
                   (nlh->nlmsg_type == RTM_NEWLINK ? "RTM_NEWLINK"
#ifndef _WIN32
                    : nlh->nlmsg_type == RTM_DELLINK ? "RTM_DELLINK"
#endif
                    : nlh->nlmsg_type == RTM_GETLINK ? "RTM_GETLINK"
#ifndef _WIN32
                    : nlh->nlmsg_type == RTM_SETLINK ? "RTM_SETLINK"
#endif
                    : "other"));
            printf("\tflags:");
            for (i = 0; i < ARRAY_SIZE(flags); i++) {
                if (iim->ifi_flags & flags[i].flag) {
                    printf(" %s", flags[i].name);
                }
            }
            printf("\n");
            if (attrs[IFLA_MASTER]) {
                uint32_t idx = nl_attr_get_u32(attrs[IFLA_MASTER]);
                char ifname[IFNAMSIZ];
#ifndef _WIN32
                if (!if_indextoname(idx, ifname)) {
                    strcpy(ifname, "unknown");
                }
#endif
                printf("\tmaster=%"PRIu32" (%s)\n", idx, ifname);
            }
        }

        nl_sock_wait(sock, POLLIN);
        poll_block();
    }
}
Example #14
0
static void
parse_named_action(enum ofputil_action_code code, const struct flow *flow,
                   char *arg, struct ofpbuf *ofpacts)
{
    struct ofpact_tunnel *tunnel;
    uint16_t vid;
    uint16_t ethertype;
    ovs_be32 ip;
    uint8_t pcp;
    uint8_t tos;

    switch (code) {
    case OFPUTIL_ACTION_INVALID:
        NOT_REACHED();

    case OFPUTIL_OFPAT10_OUTPUT:
    case OFPUTIL_OFPAT11_OUTPUT:
        parse_output(arg, ofpacts);
        break;

    case OFPUTIL_OFPAT10_SET_VLAN_VID:
    case OFPUTIL_OFPAT11_SET_VLAN_VID:
        vid = str_to_u32(arg);
        if (vid & ~VLAN_VID_MASK) {
            ovs_fatal(0, "%s: not a valid VLAN VID", arg);
        }
        ofpact_put_SET_VLAN_VID(ofpacts)->vlan_vid = vid;
        break;

    case OFPUTIL_OFPAT10_SET_VLAN_PCP:
    case OFPUTIL_OFPAT11_SET_VLAN_PCP:
        pcp = str_to_u32(arg);
        if (pcp & ~7) {
            ovs_fatal(0, "%s: not a valid VLAN PCP", arg);
        }
        ofpact_put_SET_VLAN_PCP(ofpacts)->vlan_pcp = pcp;
        break;

    case OFPUTIL_OFPAT12_SET_FIELD:
        set_field_parse(arg, ofpacts);
        break;

    case OFPUTIL_OFPAT10_STRIP_VLAN:
    case OFPUTIL_OFPAT11_POP_VLAN:
        ofpact_put_STRIP_VLAN(ofpacts);
        break;

    case OFPUTIL_OFPAT11_PUSH_VLAN:
        ethertype = str_to_u16(arg, "ethertype");
        if (ethertype != ETH_TYPE_VLAN_8021Q) {
            /* XXX ETH_TYPE_VLAN_8021AD case isn't supported */
            ovs_fatal(0, "%s: not a valid VLAN ethertype", arg);
        }
        ofpact_put_PUSH_VLAN(ofpacts);
        break;

    case OFPUTIL_OFPAT11_SET_QUEUE:
        ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg);
        break;


    case OFPUTIL_OFPAT10_SET_DL_SRC:
    case OFPUTIL_OFPAT11_SET_DL_SRC:
        str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
        break;

    case OFPUTIL_OFPAT10_SET_DL_DST:
    case OFPUTIL_OFPAT11_SET_DL_DST:
        str_to_mac(arg, ofpact_put_SET_ETH_DST(ofpacts)->mac);
        break;

    case OFPUTIL_OFPAT10_SET_NW_SRC:
    case OFPUTIL_OFPAT11_SET_NW_SRC:
        str_to_ip(arg, &ip);
        ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4 = ip;
        break;

    case OFPUTIL_OFPAT10_SET_NW_DST:
    case OFPUTIL_OFPAT11_SET_NW_DST:
        str_to_ip(arg, &ip);
        ofpact_put_SET_IPV4_DST(ofpacts)->ipv4 = ip;
        break;

    case OFPUTIL_OFPAT10_SET_NW_TOS:
    case OFPUTIL_OFPAT11_SET_NW_TOS:
        tos = str_to_u32(arg);
        if (tos & ~IP_DSCP_MASK) {
            ovs_fatal(0, "%s: not a valid TOS", arg);
        }
        ofpact_put_SET_IPV4_DSCP(ofpacts)->dscp = tos;
        break;

    case OFPUTIL_OFPAT11_DEC_NW_TTL:
        NOT_REACHED();

    case OFPUTIL_OFPAT10_SET_TP_SRC:
    case OFPUTIL_OFPAT11_SET_TP_SRC:
        ofpact_put_SET_L4_SRC_PORT(ofpacts)->port = str_to_u32(arg);
        break;

    case OFPUTIL_OFPAT10_SET_TP_DST:
    case OFPUTIL_OFPAT11_SET_TP_DST:
        ofpact_put_SET_L4_DST_PORT(ofpacts)->port = str_to_u32(arg);
        break;

    case OFPUTIL_OFPAT10_ENQUEUE:
        parse_enqueue(arg, ofpacts);
        break;

    case OFPUTIL_NXAST_RESUBMIT:
        parse_resubmit(arg, ofpacts);
        break;

    case OFPUTIL_NXAST_SET_TUNNEL:
    case OFPUTIL_NXAST_SET_TUNNEL64:
        tunnel = ofpact_put_SET_TUNNEL(ofpacts);
        tunnel->ofpact.compat = code;
        tunnel->tun_id = str_to_u64(arg);
        break;

    case OFPUTIL_NXAST_WRITE_METADATA:
        parse_metadata(ofpacts, arg);
        break;

    case OFPUTIL_NXAST_SET_QUEUE:
        ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg);
        break;

    case OFPUTIL_NXAST_POP_QUEUE:
        ofpact_put_POP_QUEUE(ofpacts);
        break;

    case OFPUTIL_NXAST_REG_MOVE:
        nxm_parse_reg_move(ofpact_put_REG_MOVE(ofpacts), arg);
        break;

    case OFPUTIL_NXAST_REG_LOAD:
        nxm_parse_reg_load(ofpact_put_REG_LOAD(ofpacts), arg);
        break;

    case OFPUTIL_NXAST_NOTE:
        parse_note(arg, ofpacts);
        break;

    case OFPUTIL_NXAST_MULTIPATH:
        multipath_parse(ofpact_put_MULTIPATH(ofpacts), arg);
        break;

    case OFPUTIL_NXAST_AUTOPATH__DEPRECATED:
        autopath_parse(ofpact_put_AUTOPATH(ofpacts), arg);
        break;

    case OFPUTIL_NXAST_BUNDLE:
        bundle_parse(arg, ofpacts);
        break;

    case OFPUTIL_NXAST_BUNDLE_LOAD:
        bundle_parse_load(arg, ofpacts);
        break;

    case OFPUTIL_NXAST_RESUBMIT_TABLE:
    case OFPUTIL_NXAST_OUTPUT_REG:
    case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
        NOT_REACHED();

    case OFPUTIL_NXAST_LEARN:
        learn_parse(arg, flow, ofpacts);
        break;

    case OFPUTIL_NXAST_EXIT:
        ofpact_put_EXIT(ofpacts);
        break;

    case OFPUTIL_NXAST_DEC_TTL:
        parse_dec_ttl(ofpacts, arg);
        break;

    case OFPUTIL_NXAST_FIN_TIMEOUT:
        parse_fin_timeout(ofpacts, arg);
        break;

    case OFPUTIL_NXAST_CONTROLLER:
        parse_controller(ofpacts, arg);
        break;
    }
}
Example #15
0
/* Helper for bundle_parse and bundle_parse_load. */
static void
bundle_parse__(const char *s, char **save_ptr,
               const char *fields, const char *basis, const char *algorithm,
               const char *slave_type, const char *dst,
               const char *slave_delim, struct ofpbuf *ofpacts)
{
    struct ofpact_bundle *bundle;

    if (!slave_delim) {
        ovs_fatal(0, "%s: not enough arguments to bundle action", s);
    }

    if (strcasecmp(slave_delim, "slaves")) {
        ovs_fatal(0, "%s: missing slave delimiter, expected `slaves' got `%s'",
                   s, slave_delim);
    }

    bundle = ofpact_put_BUNDLE(ofpacts);

    for (;;) {
        uint16_t slave_port;
        char *slave;

        slave = strtok_r(NULL, ", []", save_ptr);
        if (!slave || bundle->n_slaves >= BUNDLE_MAX_SLAVES) {
            break;
        }

        if (!ofputil_port_from_string(slave, &slave_port)) {
            ovs_fatal(0, "%s: bad port number", slave);
        }
        ofpbuf_put(ofpacts, &slave_port, sizeof slave_port);

        bundle = ofpacts->l2;
        bundle->n_slaves++;
    }
    ofpact_update_len(ofpacts, &bundle->ofpact);

    bundle->basis = atoi(basis);

    if (!strcasecmp(fields, "eth_src")) {
        bundle->fields = NX_HASH_FIELDS_ETH_SRC;
    } else if (!strcasecmp(fields, "symmetric_l4")) {
        bundle->fields = NX_HASH_FIELDS_SYMMETRIC_L4;
    } else {
        ovs_fatal(0, "%s: unknown fields `%s'", s, fields);
    }

    if (!strcasecmp(algorithm, "active_backup")) {
        bundle->algorithm = NX_BD_ALG_ACTIVE_BACKUP;
    } else if (!strcasecmp(algorithm, "hrw")) {
        bundle->algorithm = NX_BD_ALG_HRW;
    } else {
        ovs_fatal(0, "%s: unknown algorithm `%s'", s, algorithm);
    }

    if (strcasecmp(slave_type, "ofport")) {
        ovs_fatal(0, "%s: unknown slave_type `%s'", s, slave_type);
    }

    if (dst) {
        mf_parse_subfield(&bundle->dst, dst);
    }
}
Example #16
0
static void
test_rstp_main(int argc, char *argv[])
{
    struct test_case *tc;
    FILE *input_file;
    int i;

    vlog_set_pattern(VLF_CONSOLE, "%c|%p|%m");
    vlog_set_levels(NULL, VLF_SYSLOG, VLL_OFF);

    if (argc != 2) {
        ovs_fatal(0, "usage: test-rstp INPUT.RSTP\n");
    }
    file_name = argv[1];

    input_file = fopen(file_name, "r");
    if (!input_file) {
        ovs_fatal(errno, "error opening \"%s\"", file_name);
    }

    tc = new_test_case();
    for (i = 0; i < 26; i++) {
        char name[2];

        name[0] = 'a' + i;
        name[1] = '\0';
        new_lan(tc, name);
    }

    for (line_number = 1; fgets(line, sizeof line, input_file);
         line_number++)
    {
        char *newline, *hash;

        newline = strchr(line, '\n');
        if (newline) {
            *newline = '\0';
        }
        hash = strchr(line, '#');
        if (hash) {
            *hash = '\0';
        }

        pos = line;
        if (!get_token()) {
            continue;
        }
        if (match("bridge")) {
            struct bridge *bridge;
            int bridge_no, port_no;

            bridge_no = must_get_int();
            if (bridge_no < tc->n_bridges) {
                bridge = tc->bridges[bridge_no];
            } else if (bridge_no == tc->n_bridges) {
                bridge = new_bridge(tc, must_get_int());
            } else {
                err("bridges must be numbered consecutively from 0");
            }
            if (match("^")) {
                rstp_set_bridge_priority(bridge->rstp, must_get_int());
            }
            if (match("=")) {
                for (port_no = 1; port_no < MAX_PORTS; port_no++) {
                    struct rstp_port *p = rstp_get_port(bridge->rstp, port_no);

                    if (!token || match("X")) {
                        /* Disable port. */
                        reinitialize_port(p);
                        rstp_port_set_state(p, RSTP_DISABLED);
                        rstp_port_set_mac_operational(p, false);
                    } else if (match("_")) {
                        /* Nothing to do. */
                    } else {
                        struct lan *lan;
                        uint32_t path_cost;

                        if (!strcmp(token, "0")) {
                            lan = NULL;
                        } else if (strlen(token) == 1
                                && islower((unsigned char)*token)) {
                            lan = tc->lans[*token - 'a'];
                        } else {
                            err("%s is not a valid LAN name "
                                "(0 or a lowercase letter)", token);
                        }
                        get_token();

                        path_cost = match(":") ? must_get_int() :
                                                 RSTP_DEFAULT_PORT_PATH_COST;
                        if (port_no < bridge->n_ports) {
                            /* Enable port. */
                            reinitialize_port(p);
                            rstp_port_set_path_cost(p, path_cost);
                            rstp_port_set_state(p, RSTP_DISCARDING);
                            rstp_port_set_mac_operational(p, true);
                            reconnect_port(bridge, port_no, lan);
                        } else if (port_no == bridge->n_ports) {
                            new_port(bridge, lan, path_cost);
                            bridge->n_active_ports++;
                        } else {
                            err("ports must be numbered consecutively");
                        }
                        if (match("^")) {
                            rstp_port_set_priority(p, must_get_int());
                        }
                    }
                }
            }
        } else if (match("run")) {
            simulate(tc, must_get_int());
        } else if (match("dump")) {
            dump(tc);
        } else if (match("tree")) {
            tree(tc);
        } else if (match("check")) {
            struct bridge *b;
            struct rstp *rstp;
            int bridge_no, port_no;
            uint32_t cost_value;

            bridge_no = must_get_int();
            if (bridge_no >= tc->n_bridges) {
                err("no bridge numbered %d", bridge_no);
            }
            b = tc->bridges[bridge_no];
            rstp = b->rstp;

            must_match("=");

            if (match("rootid")) {
                uint64_t rootid;

                must_match(":");
                rootid = must_get_int();
                if (match("^")) {
                    rootid |= (uint64_t) must_get_int() << 48;
                } else {
                    rootid |= UINT64_C(0x8000) << 48;
                }
                if (rstp_get_designated_root(rstp) != rootid) {
                    warn("%s: root "RSTP_ID_FMT", not %"PRIx64,
                         rstp_get_name(rstp),
                         RSTP_ID_ARGS(rstp_get_designated_root(rstp)),
                         rootid);
                }
            }
            cost_value = rstp_get_root_path_cost(rstp);
            if (match("root")) {
                if (cost_value != 0) {
                    warn("%s: root path cost of root is %d instead of 0 \n",
                         rstp_get_name(rstp), cost_value);
                }
                if (!rstp_is_root_bridge(rstp)) {
                    warn("%s: root is "RSTP_ID_FMT", not "RSTP_ID_FMT"",
                         rstp_get_name(rstp),
                         RSTP_ID_ARGS(rstp_get_designated_root(rstp)),
                         RSTP_ID_ARGS(rstp_get_bridge_id(rstp)));
                }
                for (port_no = 1; port_no < b->n_active_ports; port_no++) {
                    struct rstp_port *p = rstp_get_port(rstp, port_no);
                    enum rstp_state state = rstp_port_get_state(p);

                    if (state != RSTP_DISABLED && state != RSTP_FORWARDING) {
                        warn("%s: root port %d in state %s",
                             rstp_get_name(b->rstp), port_no,
                             rstp_state_name(state));
                    }
                }
            } else {
                for (port_no = 1; port_no < b->n_active_ports; port_no++) {
                    struct rstp_port *p = rstp_get_port(rstp, port_no);
                    enum rstp_state state;

                    if (token == NULL || match("D")) {
                        state = RSTP_DISABLED;
                    } else if (match("Di")) {
                        state = RSTP_DISCARDING;
                    } else if (match("Le")) {
                        state = RSTP_LEARNING;
                    } else if (match("F")) {
                        state = RSTP_FORWARDING;
                    } else if (match("_")) {
                        continue;
                    } else {
                        err("unknown port state %s", token);
                    }
                    if (rstp_port_get_state(p) != state) {
                        warn("%s port %d: state is %s but should be %s",
                             rstp_get_name(rstp), port_no,
                             rstp_state_name(rstp_port_get_state(p)),
                             rstp_state_name(state));
                    }
                    if (state == RSTP_FORWARDING) {
                        struct rstp_port *root_port = rstp_get_root_port(rstp);

                        if (match(":")) {
                            int root_path_cost = must_get_int();

                            if (p != root_port) {
                                warn("%s: port %d is not the root port",
                                     rstp_get_name(rstp), port_no);
                                if (!root_port) {
                                    warn("%s: (there is no root port)",
                                         rstp_get_name(rstp));
                                } else {
                                    warn("%s: (port %d is the root port)",
                                         rstp_get_name(rstp),
                                         rstp_port_get_number(root_port));
                                }
                            } else if (cost_value != root_path_cost) {
                                warn("%s: root path cost is %d, should be %d",
                                     rstp_get_name(rstp),
                                     cost_value,
                                     root_path_cost);
                            }
                        } else if (p == root_port) {
                            warn("%s: port %d is the root port but "
                                 "not expected to be",
                                 rstp_get_name(rstp), port_no);
                        }
                    }
                }
            }
            if (n_warnings) {
                printf("failing because of %d warnings\n", n_warnings);
                exit(EXIT_FAILURE);
            }
        }
        if (get_token()) {
            printf("failing because of errors\n");
            err("trailing garbage on line");
        }
    }
    free(token);

    for (i = 0; i < tc->n_lans; i++) {
        struct lan *lan = tc->lans[i];

        free(CONST_CAST(char *, lan->name));
        free(lan);
    }
    for (i = 0; i < tc->n_bridges; i++) {
        struct bridge *bridge = tc->bridges[i];
        int j;

        for (j = 1; j < MAX_PORTS; j++) {
            rstp_port_unref(rstp_get_port(bridge->rstp, j));
        }
        rstp_unref(bridge->rstp);
        free(bridge);
    }
    free(tc);
}
Example #17
0
/* Convert 'string' (as described in the Flow Syntax section of the ovs-ofctl
 * man page) into 'pf'.  If 'actions' is specified, an action must be in
 * 'string' and may be expanded or reallocated. */
void
parse_ofp_str(struct flow_mod *fm, uint8_t *table_idx,
              struct ofpbuf *actions, char *string)
{
    char *save_ptr = NULL;
    char *name;

    if (table_idx) {
        *table_idx = 0xff;
    }
    cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY);
    fm->cookie = htonll(0);
    fm->command = UINT16_MAX;
    fm->idle_timeout = OFP_FLOW_PERMANENT;
    fm->hard_timeout = OFP_FLOW_PERMANENT;
    fm->buffer_id = UINT32_MAX;
    fm->out_port = OFPP_NONE;
    fm->flags = 0;
    if (actions) {
        char *act_str = strstr(string, "action");
        if (!act_str) {
            ovs_fatal(0, "must specify an action");
        }
        *act_str = '\0';

        act_str = strchr(act_str + 1, '=');
        if (!act_str) {
            ovs_fatal(0, "must specify an action");
        }

        act_str++;

        str_to_action(act_str, actions);
        fm->actions = actions->data;
        fm->n_actions = actions->size / sizeof(union ofp_action);
    } else {
        fm->actions = NULL;
        fm->n_actions = 0;
    }
    for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name;
         name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
        const struct protocol *p;

        if (parse_protocol(name, &p)) {
            cls_rule_set_dl_type(&fm->cr, htons(p->dl_type));
            if (p->nw_proto) {
                cls_rule_set_nw_proto(&fm->cr, p->nw_proto);
            }
        } else {
            const struct field *f;
            char *value;

            value = strtok_r(NULL, ", \t\r\n", &save_ptr);
            if (!value) {
                ovs_fatal(0, "field %s missing value", name);
            }

            if (table_idx && !strcmp(name, "table")) {
                *table_idx = atoi(value);
            } else if (!strcmp(name, "out_port")) {
                fm->out_port = atoi(value);
            } else if (!strcmp(name, "priority")) {
                fm->cr.priority = atoi(value);
            } else if (!strcmp(name, "idle_timeout")) {
                fm->idle_timeout = atoi(value);
            } else if (!strcmp(name, "hard_timeout")) {
                fm->hard_timeout = atoi(value);
            } else if (!strcmp(name, "cookie")) {
                fm->cookie = htonll(str_to_u64(value));
            } else if (parse_field_name(name, &f)) {
                if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
                    if (f->wildcard) {
                        fm->cr.wc.wildcards |= f->wildcard;
                        cls_rule_zero_wildcarded_fields(&fm->cr);
                    } else if (f->index == F_NW_SRC) {
                        cls_rule_set_nw_src_masked(&fm->cr, 0, 0);
                    } else if (f->index == F_NW_DST) {
                        cls_rule_set_nw_dst_masked(&fm->cr, 0, 0);
                    } else if (f->index == F_IPV6_SRC) {
                        cls_rule_set_ipv6_src_masked(&fm->cr,
                                &in6addr_any, &in6addr_any);
                    } else if (f->index == F_IPV6_DST) {
                        cls_rule_set_ipv6_dst_masked(&fm->cr,
                                &in6addr_any, &in6addr_any);
                    } else if (f->index == F_DL_VLAN) {
                        cls_rule_set_any_vid(&fm->cr);
                    } else if (f->index == F_DL_VLAN_PCP) {
                        cls_rule_set_any_pcp(&fm->cr);
                    } else {
                        NOT_REACHED();
                    }
                } else {
                    parse_field_value(&fm->cr, f->index, value);
                }
            } else if (!strncmp(name, "reg", 3)
                       && isdigit((unsigned char) name[3])) {
                unsigned int reg_idx = atoi(name + 3);
                if (reg_idx >= FLOW_N_REGS) {
                    ovs_fatal(0, "only %d registers supported", FLOW_N_REGS);
                }
                parse_reg_value(&fm->cr, reg_idx, value);
            } else {
                ovs_fatal(0, "unknown keyword %s", name);
            }
        }
    }
}
Example #18
0
static void
do_listen(int argc OVS_UNUSED, char *argv[])
{
    struct pstream *pstream;
    struct jsonrpc **rpcs;
    size_t n_rpcs, allocated_rpcs;
    bool done;
    int error;

    error = jsonrpc_pstream_open(argv[1], &pstream, DSCP_DEFAULT);
    if (error) {
        ovs_fatal(error, "could not listen on \"%s\"", argv[1]);
    }

    daemonize();

    rpcs = NULL;
    n_rpcs = allocated_rpcs = 0;
    done = false;
    for (;;) {
        struct stream *stream;
        size_t i;

        /* Accept new connections. */
        error = pstream_accept(pstream, &stream);
        if (!error) {
            if (n_rpcs >= allocated_rpcs) {
                rpcs = x2nrealloc(rpcs, &allocated_rpcs, sizeof *rpcs);
            }
            rpcs[n_rpcs++] = jsonrpc_open(stream);
        } else if (error != EAGAIN) {
            ovs_fatal(error, "pstream_accept failed");
        }

        /* Service existing connections. */
        for (i = 0; i < n_rpcs; ) {
            struct jsonrpc *rpc = rpcs[i];
            struct jsonrpc_msg *msg;

            jsonrpc_run(rpc);
            if (!jsonrpc_get_backlog(rpc)) {
                error = jsonrpc_recv(rpc, &msg);
                if (!error) {
                    error = handle_rpc(rpc, msg, &done);
                    jsonrpc_msg_destroy(msg);
                } else if (error == EAGAIN) {
                    error = 0;
                }
            }

            if (!error) {
                error = jsonrpc_get_status(rpc);
            }
            if (error) {
                jsonrpc_close(rpc);
                ovs_error(error, "connection closed");
                memmove(&rpcs[i], &rpcs[i + 1],
                        (n_rpcs - i - 1) * sizeof *rpcs);
                n_rpcs--;
            } else {
                i++;
            }
        }

        /* Wait for something to do. */
        if (done && !n_rpcs) {
            break;
        }
        pstream_wait(pstream);
        for (i = 0; i < n_rpcs; i++) {
            struct jsonrpc *rpc = rpcs[i];

            jsonrpc_wait(rpc);
            if (!jsonrpc_get_backlog(rpc)) {
                jsonrpc_recv_wait(rpc);
            }
        }
        poll_block();
    }
    free(rpcs);
    pstream_close(pstream);
}
Example #19
0
static void
learn_parse_spec(const char *orig, char *name, char *value,
                 struct learn_spec *spec)
{
    memset(spec, 0, sizeof *spec);
    if (mf_from_name(name)) {
        const struct mf_field *dst = mf_from_name(name);
        union mf_value imm;
        char *error;

        error = mf_parse_value(dst, value, &imm);
        if (error) {
            ovs_fatal(0, "%s", error);
        }

        spec->n_bits = dst->n_bits;
        spec->src_type = NX_LEARN_SRC_IMMEDIATE;
        memset(&spec->src_imm, 0, sizeof spec->src_imm);
        memcpy(&spec->src_imm.u8[sizeof spec->src_imm - dst->n_bytes],
               &imm, dst->n_bytes);
        spec->dst_type = NX_LEARN_DST_MATCH;
        spec->dst.field = dst;
        spec->dst.ofs = 0;
        spec->dst.n_bits = dst->n_bits;
    } else if (strchr(name, '[')) {
        /* Parse destination and check prerequisites. */
        if (mf_parse_subfield(&spec->dst, name)[0] != '\0') {
            ovs_fatal(0, "%s: syntax error after NXM field name `%s'",
                      orig, name);
        }

        /* Parse source and check prerequisites. */
        if (value[0] != '\0') {
            if (mf_parse_subfield(&spec->src, value)[0] != '\0') {
                ovs_fatal(0, "%s: syntax error after NXM field name `%s'",
                          orig, value);
            }
            if (spec->src.n_bits != spec->dst.n_bits) {
                ovs_fatal(0, "%s: bit widths of %s (%u) and %s (%u) differ",
                          orig, name, spec->src.n_bits, value,
                          spec->dst.n_bits);
            }
        } else {
            spec->src = spec->dst;
        }

        spec->n_bits = spec->src.n_bits;
        spec->src_type = NX_LEARN_SRC_FIELD;
        spec->dst_type = NX_LEARN_DST_MATCH;
    } else if (!strcmp(name, "load")) {
        if (value[strcspn(value, "[-")] == '-') {
            learn_parse_load_immediate(value, spec);
        } else {
            struct nx_action_reg_move move;

            nxm_parse_reg_move(&move, value);

            spec->n_bits = ntohs(move.n_bits);
            spec->src_type = NX_LEARN_SRC_FIELD;
            nxm_decode_discrete(&spec->src,
                                move.src, move.src_ofs, move.n_bits);
            spec->dst_type = NX_LEARN_DST_LOAD;
            nxm_decode_discrete(&spec->dst,
                                move.dst, move.dst_ofs, move.n_bits);
        }
    } else if (!strcmp(name, "output")) {
        if (mf_parse_subfield(&spec->src, value)[0] != '\0') {
            ovs_fatal(0, "%s: syntax error after NXM field name `%s'",
                      orig, name);
        }

        spec->n_bits = spec->src.n_bits;
        spec->src_type = NX_LEARN_SRC_FIELD;
        spec->dst_type = NX_LEARN_DST_OUTPUT;
    } else {
        ovs_fatal(0, "%s: unknown keyword %s", orig, name);
    }
}