X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-parse.c;h=b1e369c94b02e1e5eb699b0e493cd034946daa43;hb=f80022d9df98d29ee41176a4bc6cb91025da84b8;hp=e8abc9f6d246f7d98d3e090ed32889622e64f072;hpb=7fa0f73fb284b4406bcd085ee62552891b3fa6cd;p=sliver-openvswitch.git diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index e8abc9f6d..b1e369c94 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,14 +45,14 @@ static void ofp_fatal(const char *flow, bool verbose, const char *format, ...) NO_RETURN; static uint8_t -str_to_table_id(const char *str) +str_to_u8(const char *str, const char *name) { - int table_id; + int value; - if (!str_to_int(str, 10, &table_id) || table_id < 0 || table_id > 255) { - ovs_fatal(0, "invalid table \"%s\"", str); + if (!str_to_int(str, 10, &value) || value < 0 || value > 255) { + ovs_fatal(0, "invalid %s \"%s\"", name, str); } - return table_id; + return value; } static uint16_t @@ -135,7 +135,7 @@ parse_enqueue(char *arg, struct ofpbuf *ofpacts) } enqueue = ofpact_put_ENQUEUE(ofpacts); - enqueue->port = str_to_u32(port); + enqueue->port = u16_to_ofp(str_to_u32(port)); enqueue->queue = str_to_u32(queue); } @@ -152,7 +152,7 @@ parse_output(char *arg, struct ofpbuf *ofpacts) struct ofpact_output *output; output = ofpact_put_OUTPUT(ofpacts); - output->port = str_to_u32(arg); + output->port = u16_to_ofp(str_to_u32(arg)); output->max_len = output->port == OFPP_CONTROLLER ? UINT16_MAX : 0; } } @@ -390,7 +390,35 @@ parse_metadata(struct ofpbuf *b, char *arg) } static void -parse_named_action(enum ofputil_action_code code, const struct flow *flow, +parse_sample(struct ofpbuf *b, char *arg) +{ + struct ofpact_sample *os = ofpact_put_SAMPLE(b); + char *key, *value; + + while (ofputil_parse_key_value(&arg, &key, &value)) { + if (!strcmp(key, "probability")) { + os->probability = str_to_u16(value, "probability"); + if (os->probability == 0) { + ovs_fatal(0, "invalid probability value \"%s\"", value); + } + } else if (!strcmp(key, "collector_set_id")) { + os->collector_set_id = str_to_u32(value); + } else if (!strcmp(key, "obs_domain_id")) { + os->obs_domain_id = str_to_u32(value); + } else if (!strcmp(key, "obs_point_id")) { + os->obs_point_id = str_to_u32(value); + } else { + ovs_fatal(0, "invalid key \"%s\" in \"sample\" argument", + key); + } + } + if (os->probability == 0) { + ovs_fatal(0, "non-zero \"probability\" must be specified on sample"); + } +} + +static void +parse_named_action(enum ofputil_action_code code, char *arg, struct ofpbuf *ofpacts) { struct ofpact_tunnel *tunnel; @@ -551,7 +579,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, NOT_REACHED(); case OFPUTIL_NXAST_LEARN: - learn_parse(arg, flow, ofpacts); + learn_parse(arg, ofpacts); break; case OFPUTIL_NXAST_EXIT: @@ -591,22 +619,27 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, ofpact_put_POP_MPLS(ofpacts)->ethertype = htons(str_to_u16(arg, "pop_mpls")); break; + case OFPUTIL_NXAST_STACK_PUSH: nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg); break; case OFPUTIL_NXAST_STACK_POP: nxm_parse_stack_action(ofpact_put_STACK_POP(ofpacts), arg); break; + + case OFPUTIL_NXAST_SAMPLE: + parse_sample(ofpacts, arg); + break; } } static bool -str_to_ofpact__(const struct flow *flow, char *pos, char *act, char *arg, +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, flow, arg, ofpacts); + 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 " @@ -617,7 +650,7 @@ str_to_ofpact__(const struct flow *flow, char *pos, char *act, char *arg, } return false; } else { - uint16_t port; + ofp_port_t port; if (ofputil_port_from_string(act, &port)) { ofpact_put_OUTPUT(ofpacts)->port = port; } else { @@ -629,7 +662,7 @@ str_to_ofpact__(const struct flow *flow, char *pos, char *act, char *arg, } static void -str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts) +str_to_ofpacts(char *str, struct ofpbuf *ofpacts) { char *pos, *act, *arg; enum ofperr error; @@ -638,7 +671,7 @@ str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts) pos = str; n_actions = 0; while (ofputil_parse_key_value(&pos, &act, &arg)) { - if (!str_to_ofpact__(flow, pos, act, arg, ofpacts, n_actions)) { + if (!str_to_ofpact__(pos, act, arg, ofpacts, n_actions)) { break; } n_actions++; @@ -672,6 +705,10 @@ parse_named_instruction(enum ovs_instruction_type type, ofpact_put_CLEAR_ACTIONS(ofpacts); break; + case OVSINST_OFPIT13_METER: + ofpact_put_METER(ofpacts)->meter_id = str_to_u32(arg); + break; + case OVSINST_OFPIT11_WRITE_METADATA: parse_metadata(ofpacts, arg); break; @@ -682,7 +719,7 @@ parse_named_instruction(enum ovs_instruction_type type, if (!table_s || !table_s[0]) { ovs_fatal(0, "instruction goto-table needs table id"); } - ogt->table_id = str_to_table_id(table_s); + ogt->table_id = str_to_u8(table_s, "table"); break; } } @@ -696,7 +733,7 @@ parse_named_instruction(enum ovs_instruction_type type, } static void -str_to_inst_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts) +str_to_inst_ofpacts(char *str, struct ofpbuf *ofpacts) { char *pos, *inst, *arg; int type; @@ -706,9 +743,9 @@ str_to_inst_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts) pos = str; while (ofputil_parse_key_value(&pos, &inst, &arg)) { - type = ofpact_instruction_type_from_name(inst); + type = ovs_instruction_type_from_name(inst); if (type < 0) { - if (!str_to_ofpact__(flow, pos, inst, arg, ofpacts, n_actions)) { + if (!str_to_ofpact__(pos, inst, arg, ofpacts, n_actions)) { break; } @@ -915,9 +952,9 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, } if (!strcmp(name, "table")) { - fm->table_id = str_to_table_id(value); + fm->table_id = str_to_u8(value, name); } else if (!strcmp(name, "out_port")) { - if (!ofputil_port_from_string(name, &fm->out_port)) { + if (!ofputil_port_from_string(value, &fm->out_port)) { ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port", name); } @@ -971,11 +1008,19 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, } if (fields & F_ACTIONS) { struct ofpbuf ofpacts; + enum ofperr err; ofpbuf_init(&ofpacts, 32); - str_to_inst_ofpacts(&fm->match.flow, act_str, &ofpacts); + 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; @@ -984,6 +1029,198 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, free(string); } +/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man + * page) into 'mm' for sending the specified meter_mod 'command' to a switch. + */ +void +parse_ofp_meter_mod_str(struct ofputil_meter_mod *mm, const char *str_, + int command, bool verbose) +{ + enum { + F_METER = 1 << 0, + F_FLAGS = 1 << 1, + F_BANDS = 1 << 2, + } fields; + char *string = xstrdup(str_); + char *save_ptr = NULL; + char *band_str = NULL; + char *name; + + switch (command) { + case -1: + fields = F_METER; + break; + + case OFPMC13_ADD: + fields = F_METER | F_FLAGS | F_BANDS; + break; + + case OFPMC13_DELETE: + fields = F_METER; + break; + + case OFPMC13_MODIFY: + fields = F_METER | F_FLAGS | F_BANDS; + break; + + default: + NOT_REACHED(); + } + + mm->command = command; + mm->meter.meter_id = 0; + mm->meter.flags = 0; + if (fields & F_BANDS) { + band_str = strstr(string, "band"); + if (!band_str) { + ofp_fatal(str_, verbose, "must specify bands"); + } + *band_str = '\0'; + + band_str = strchr(band_str + 1, '='); + if (!band_str) { + ofp_fatal(str_, verbose, "must specify bands"); + } + + band_str++; + } + for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; + name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { + + if (fields & F_FLAGS && !strcmp(name, "kbps")) { + mm->meter.flags |= OFPMF13_KBPS; + } else if (fields & F_FLAGS && !strcmp(name, "pktps")) { + mm->meter.flags |= OFPMF13_PKTPS; + } else if (fields & F_FLAGS && !strcmp(name, "burst")) { + mm->meter.flags |= OFPMF13_BURST; + } else if (fields & F_FLAGS && !strcmp(name, "stats")) { + mm->meter.flags |= OFPMF13_STATS; + } 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, "meter")) { + if (!strcmp(value, "all")) { + mm->meter.meter_id = OFPM13_ALL; + } else if (!strcmp(value, "controller")) { + mm->meter.meter_id = OFPM13_CONTROLLER; + } else if (!strcmp(value, "slowpath")) { + mm->meter.meter_id = OFPM13_SLOWPATH; + } else { + mm->meter.meter_id = str_to_u32(value); + if (mm->meter.meter_id > OFPM13_MAX) { + ofp_fatal(str_, verbose, "invalid value for %s", name); + } + } + } else { + ofp_fatal(str_, verbose, "unknown keyword %s", name); + } + } + } + if (fields & F_METER && !mm->meter.meter_id) { + ofp_fatal(str_, verbose, "must specify 'meter'"); + } + if (fields & F_FLAGS && !mm->meter.flags) { + ofp_fatal(str_, verbose, + "meter must specify either 'kbps' or 'pktps'"); + } + + if (fields & F_BANDS) { + struct ofpbuf bands; + uint16_t n_bands = 0; + struct ofputil_meter_band *band = NULL; + int i; + + ofpbuf_init(&bands, 64); + + for (name = strtok_r(band_str, "=, \t\r\n", &save_ptr); name; + name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { + + 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, "type")) { + /* Start a new band */ + band = ofpbuf_put_zeros(&bands, sizeof *band); + n_bands++; + + if (!strcmp(value, "drop")) { + band->type = OFPMBT13_DROP; + } else if (!strcmp(value, "dscp_remark")) { + band->type = OFPMBT13_DSCP_REMARK; + } else { + ofp_fatal(str_, verbose, "field %s unknown value %s", name, + value); + } + } else if (!band || !band->type) { + ofp_fatal(str_, verbose, + "band must start with the 'type' keyword"); + } else if (!strcmp(name, "rate")) { + band->rate = str_to_u32(value); + } else if (!strcmp(name, "burst_size")) { + band->burst_size = str_to_u32(value); + } else if (!strcmp(name, "prec_level")) { + band->prec_level = str_to_u8(value, name); + } else { + ofp_fatal(str_, verbose, "unknown keyword %s", name); + } + } + /* validate bands */ + if (!n_bands) { + ofp_fatal(str_, verbose, "meter must have bands"); + } + + mm->meter.n_bands = n_bands; + mm->meter.bands = ofpbuf_steal_data(&bands); + + for (i = 0; i < n_bands; ++i) { + band = &mm->meter.bands[i]; + + if (!band->type) { + ofp_fatal(str_, verbose, "band must have 'type'"); + } + if (band->type == OFPMBT13_DSCP_REMARK) { + if (!band->prec_level) { + ofp_fatal(str_, verbose, "'dscp_remark' band must have" + " 'prec_level'"); + } + } else { + if (band->prec_level) { + ofp_fatal(str_, verbose, "Only 'dscp_remark' band may have" + " 'prec_level'"); + } + } + if (!band->rate) { + ofp_fatal(str_, verbose, "band must have 'rate'"); + } + if (mm->meter.flags & OFPMF13_BURST) { + if (!band->burst_size) { + ofp_fatal(str_, verbose, "band must have 'burst_size' " + "when 'burst' flag is set"); + } + } else { + if (band->burst_size) { + ofp_fatal(str_, verbose, "band may have 'burst_size' only " + "when 'burst' flag is set"); + } + } + } + } else { + mm->meter.n_bands = 0; + mm->meter.bands = NULL; + } + + free(string); +} + /* Convert 'str_' (as described in the documentation for the "monitor" command * in the ovs-ofctl man page) into 'fmr'. */ void @@ -1033,9 +1270,9 @@ parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr, } if (!strcmp(name, "table")) { - fmr->table_id = str_to_table_id(value); + fmr->table_id = str_to_u8(value, name); } else if (!strcmp(name, "out_port")) { - fmr->out_port = atoi(value); + fmr->out_port = u16_to_ofp(atoi(value)); } else if (mf_from_name(name)) { parse_field(mf_from_name(name), value, &fmr->match); } else { @@ -1055,7 +1292,7 @@ void parse_ofpacts(const char *s_, struct ofpbuf *ofpacts) { char *s = xstrdup(s_); - str_to_ofpacts(NULL, s, ofpacts); + str_to_ofpacts(s, ofpacts); free(s); } @@ -1188,8 +1425,8 @@ parse_ofp_exact_flow(struct flow *flow, const char *s) } } - if (!flow->in_port) { - flow->in_port = OFPP_NONE; + if (!flow->in_port.ofp_port) { + flow->in_port.ofp_port = OFPP_NONE; } exit: