Example #1
0
static bool
str_to_ofpact__(char *pos, char *act, char *arg,
                struct ofpbuf *ofpacts, int n_actions)
{
    int code = ofputil_action_code_from_name(act);
    if (code >= 0) {
        parse_named_action(code, arg, ofpacts);
    } else if (!strcasecmp(act, "drop")) {
        if (n_actions) {
            ovs_fatal(0, "Drop actions must not be preceded by other "
                      "actions");
        } else if (ofputil_parse_key_value(&pos, &act, &arg)) {
            ovs_fatal(0, "Drop actions must not be followed by other "
                      "actions");
        }
        return false;
    } else {
        ofp_port_t port;
        if (ofputil_port_from_string(act, &port)) {
            ofpact_put_OUTPUT(ofpacts)->port = port;
        } else {
            ovs_fatal(0, "Unknown action: %s", act);
        }
    }

    return true;
}
Example #2
0
static void
parse_resubmit(char *arg, struct ofpbuf *ofpacts)
{
    struct ofpact_resubmit *resubmit;
    char *in_port_s, *table_s;

    resubmit = ofpact_put_RESUBMIT(ofpacts);

    in_port_s = strsep(&arg, ",");
    if (in_port_s && in_port_s[0]) {
        if (!ofputil_port_from_string(in_port_s, &resubmit->in_port)) {
            ovs_fatal(0, "%s: resubmit to unknown port", in_port_s);
        }
    } else {
        resubmit->in_port = OFPP_IN_PORT;
    }

    table_s = strsep(&arg, ",");
    resubmit->table_id = table_s && table_s[0] ? str_to_u32(table_s) : 255;

    if (resubmit->in_port == OFPP_IN_PORT && resubmit->table_id == 255) {
        ovs_fatal(0, "at least one \"in_port\" or \"table\" must be specified "
                  " on resubmit");
    }
}
Example #3
0
static void
parse_resubmit(struct ofpbuf *b, char *arg)
{
    struct nx_action_resubmit *nar;
    char *in_port_s, *table_s;
    uint16_t in_port;
    uint8_t table;

    in_port_s = strsep(&arg, ",");
    if (in_port_s && in_port_s[0]) {
        if (!ofputil_port_from_string(in_port_s, &in_port)) {
            in_port = str_to_u32(in_port_s);
        }
    } else {
        in_port = OFPP_IN_PORT;
    }

    table_s = strsep(&arg, ",");
    table = table_s && table_s[0] ? str_to_u32(table_s) : 255;

    if (in_port == OFPP_IN_PORT && table == 255) {
        ovs_fatal(0, "at least one \"in_port\" or \"table\" must be specified "
                  " on resubmit");
    }

    if (in_port != OFPP_IN_PORT && table == 255) {
        nar = ofputil_put_NXAST_RESUBMIT(b);
    } else {
        nar = ofputil_put_NXAST_RESUBMIT_TABLE(b);
        nar->table = table;
    }
    nar->in_port = htons(in_port);
}
Example #4
0
static void
str_to_action(const struct flow *flow, char *str, struct ofpbuf *b)
{
    char *pos, *act, *arg;
    int n_actions;

    pos = str;
    n_actions = 0;
    while (ofputil_parse_key_value(&pos, &act, &arg)) {
        uint16_t port;
        int code;

        code = ofputil_action_code_from_name(act);
        if (code >= 0) {
            parse_named_action(code, flow, b, arg);
        } else if (!strcasecmp(act, "drop")) {
            /* A drop action in OpenFlow occurs by just not setting
             * an action. */
            if (n_actions) {
                ovs_fatal(0, "Drop actions must not be preceded by other "
                          "actions");
            } else if (ofputil_parse_key_value(&pos, &act, &arg)) {
                ovs_fatal(0, "Drop actions must not be followed by other "
                          "actions");
            }
            break;
        } else if (!strcasecmp(act, "CONTROLLER")) {
            struct ofp_action_output *oao;
            oao = put_output_action(b, OFPP_CONTROLLER);

            /* Unless a numeric argument is specified, we send the whole
             * packet to the controller. */
            if (arg[0] && (strspn(arg, "0123456789") == strlen(arg))) {
               oao->max_len = htons(str_to_u32(arg));
            } else {
                oao->max_len = htons(UINT16_MAX);
            }
        } else if (ofputil_port_from_string(act, &port)) {
            put_output_action(b, port);
        } else {
            ovs_fatal(0, "Unknown action: %s", act);
        }
        n_actions++;
    }
}
Example #5
0
/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man
 * page) into 'fm' for sending the specified flow_mod 'command' to a switch.
 * If 'actions' is specified, an action must be in 'string' and may be expanded
 * or reallocated.
 *
 * To parse syntax for an OFPT_FLOW_MOD (or NXT_FLOW_MOD), use an OFPFC_*
 * constant for 'command'.  To parse syntax for an OFPST_FLOW or
 * OFPST_AGGREGATE (or NXST_FLOW or NXST_AGGREGATE), use -1 for 'command'. */
void
parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
              bool verbose)
{
    enum {
        F_OUT_PORT = 1 << 0,
        F_ACTIONS = 1 << 1,
        F_TIMEOUT = 1 << 3,
        F_PRIORITY = 1 << 4,
        F_FLAGS = 1 << 5,
    } fields;
    char *string = xstrdup(str_);
    char *save_ptr = NULL;
    char *act_str = NULL;
    char *name;

    switch (command) {
    case -1:
        fields = F_OUT_PORT;
        break;

    case OFPFC_ADD:
        fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
        break;

    case OFPFC_DELETE:
        fields = F_OUT_PORT;
        break;

    case OFPFC_DELETE_STRICT:
        fields = F_OUT_PORT | F_PRIORITY;
        break;

    case OFPFC_MODIFY:
        fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
        break;

    case OFPFC_MODIFY_STRICT:
        fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS;
        break;

    default:
        NOT_REACHED();
    }

    match_init_catchall(&fm->match);
    fm->priority = OFP_DEFAULT_PRIORITY;
    fm->cookie = htonll(0);
    fm->cookie_mask = htonll(0);
    if (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT) {
        /* For modify, by default, don't update the cookie. */
        fm->new_cookie = htonll(UINT64_MAX);
    } else{
        fm->new_cookie = htonll(0);
    }
    fm->table_id = 0xff;
    fm->command = command;
    fm->idle_timeout = OFP_FLOW_PERMANENT;
    fm->hard_timeout = OFP_FLOW_PERMANENT;
    fm->buffer_id = UINT32_MAX;
    fm->out_port = OFPP_ANY;
    fm->flags = 0;
    if (fields & F_ACTIONS) {
        act_str = strstr(string, "action");
        if (!act_str) {
            ofp_fatal(str_, verbose, "must specify an action");
        }
        *act_str = '\0';

        act_str = strchr(act_str + 1, '=');
        if (!act_str) {
            ofp_fatal(str_, verbose, "must specify an action");
        }

        act_str++;
    }
    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)) {
            match_set_dl_type(&fm->match, htons(p->dl_type));
            if (p->nw_proto) {
                match_set_nw_proto(&fm->match, p->nw_proto);
            }
        } else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) {
            fm->flags |= OFPFF_SEND_FLOW_REM;
        } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) {
            fm->flags |= OFPFF_CHECK_OVERLAP;
        } else if (fields & F_FLAGS && !strcmp(name, "reset_counts")) {
            fm->flags |= OFPFF12_RESET_COUNTS;
        } else if (fields & F_FLAGS && !strcmp(name, "no_packet_counts")) {
            fm->flags |= OFPFF13_NO_PKT_COUNTS;
        } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) {
            fm->flags |= OFPFF13_NO_BYT_COUNTS;
        } else {
            char *value;

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

            if (!strcmp(name, "table")) {
                fm->table_id = str_to_u8(value, name);
            } else if (!strcmp(name, "out_port")) {
                if (!ofputil_port_from_string(value, &fm->out_port)) {
                    ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port",
                              name);
                }
            } else if (fields & F_PRIORITY && !strcmp(name, "priority")) {
                fm->priority = str_to_u16(value, name);
            } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) {
                fm->idle_timeout = str_to_u16(value, name);
            } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) {
                fm->hard_timeout = str_to_u16(value, name);
            } else if (!strcmp(name, "cookie")) {
                char *mask = strchr(value, '/');

                if (mask) {
                    /* A mask means we're searching for a cookie. */
                    if (command == OFPFC_ADD) {
                        ofp_fatal(str_, verbose, "flow additions cannot use "
                                  "a cookie mask");
                    }
                    *mask = '\0';
                    fm->cookie = htonll(str_to_u64(value));
                    fm->cookie_mask = htonll(str_to_u64(mask+1));
                } else {
                    /* No mask means that the cookie is being set. */
                    if (command != OFPFC_ADD && command != OFPFC_MODIFY
                            && command != OFPFC_MODIFY_STRICT) {
                        ofp_fatal(str_, verbose, "cannot set cookie");
                    }
                    fm->new_cookie = htonll(str_to_u64(value));
                }
            } else if (mf_from_name(name)) {
                parse_field(mf_from_name(name), value, &fm->match);
            } else if (!strcmp(name, "duration")
                       || !strcmp(name, "n_packets")
                       || !strcmp(name, "n_bytes")
                       || !strcmp(name, "idle_age")
                       || !strcmp(name, "hard_age")) {
                /* Ignore these, so that users can feed the output of
                 * "ovs-ofctl dump-flows" back into commands that parse
                 * flows. */
            } else {
                ofp_fatal(str_, verbose, "unknown keyword %s", name);
            }
        }
    }
    if (!fm->cookie_mask && fm->new_cookie == htonll(UINT64_MAX)
            && (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT)) {
        /* On modifies without a mask, we are supposed to add a flow if
         * one does not exist.  If a cookie wasn't been specified, use a
         * default of zero. */
        fm->new_cookie = htonll(0);
    }
    if (fields & F_ACTIONS) {
        struct ofpbuf ofpacts;
        enum ofperr err;

        ofpbuf_init(&ofpacts, 32);
        str_to_inst_ofpacts(act_str, &ofpacts);
        fm->ofpacts_len = ofpacts.size;
        fm->ofpacts = ofpbuf_steal_data(&ofpacts);

        err = ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow,
                            OFPP_MAX, 0);
        if (err) {
            exit(EXIT_FAILURE);
        }

    } else {
        fm->ofpacts_len = 0;
        fm->ofpacts = NULL;
    }

    free(string);
}
Example #6
0
/* Helper for bundle_parse and bundle_parse_load.
 *
 * Returns NULL if successful, otherwise a malloc()'d string describing the
 * error.  The caller is responsible for freeing the returned string.*/
static char * WARN_UNUSED_RESULT
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) {
        return xasprintf("%s: not enough arguments to bundle action", s);
    }

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

    bundle = ofpact_put_BUNDLE(ofpacts);

    for (;;) {
        ofp_port_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)) {
            return xasprintf("%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 {
        return xasprintf("%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 {
        return xasprintf("%s: unknown algorithm `%s'", s, algorithm);
    }

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

    if (dst) {
        char *error = mf_parse_subfield(&bundle->dst, dst);
        if (error) {
            return error;
        }
    }

    return NULL;
}