X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fofp-parse.c;h=b1e369c94b02e1e5eb699b0e493cd034946daa43;hb=f80022d9df98d29ee41176a4bc6cb91025da84b8;hp=e3b7dc12269326bdfaa070e0c479fa57756d3cf3;hpb=c6100d92142bc3dd325180cb4e10553eb4341731;p=sliver-openvswitch.git diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index e3b7dc122..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. @@ -22,7 +22,6 @@ #include #include -#include "autopath.h" #include "bundle.h" #include "byte-order.h" #include "dynamic-string.h" @@ -46,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 @@ -136,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); } @@ -153,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; } } @@ -168,8 +167,7 @@ parse_resubmit(char *arg, struct ofpbuf *ofpacts) in_port_s = strsep(&arg, ","); if (in_port_s && in_port_s[0]) { - resubmit->in_port = ofputil_port_from_string(in_port_s); - if (!resubmit->in_port) { + if (!ofputil_port_from_string(in_port_s, &resubmit->in_port)) { ovs_fatal(0, "%s: resubmit to unknown port", in_port_s); } } else { @@ -280,22 +278,28 @@ parse_controller(struct ofpbuf *b, char *arg) } static void -parse_dec_ttl(struct ofpbuf *b, char *arg) +parse_noargs_dec_ttl(struct ofpbuf *b) { struct ofpact_cnt_ids *ids; + uint16_t id = 0; ids = ofpact_put_DEC_TTL(b); + ofpbuf_put(b, &id, sizeof id); + ids = b->l2; + ids->n_controllers++; + ofpact_update_len(b, &ids->ofpact); +} +static void +parse_dec_ttl(struct ofpbuf *b, char *arg) +{ if (*arg == '\0') { - uint16_t id = 0; - - ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL; - ofpbuf_put(b, &id, sizeof id); - ids = b->l2; - ids->n_controllers++; + parse_noargs_dec_ttl(b); } else { + struct ofpact_cnt_ids *ids; char *cntr; + ids = ofpact_put_DEC_TTL(b); ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL_CNT_IDS; for (cntr = strtok_r(arg, ", ", &arg); cntr != NULL; cntr = strtok_r(NULL, ", ", &arg)) { @@ -309,17 +313,117 @@ parse_dec_ttl(struct ofpbuf *b, char *arg) ovs_fatal(0, "dec_ttl_cnt_ids: expected at least one controller " "id."); } + ofpact_update_len(b, &ids->ofpact); + } +} + +static void +parse_set_mpls_ttl(struct ofpbuf *b, const char *arg) +{ + struct ofpact_mpls_ttl *mpls_ttl = ofpact_put_SET_MPLS_TTL(b); + if (*arg == '\0') { + ovs_fatal(0, "parse_set_mpls_ttl: expected ttl."); } - ofpact_update_len(b, &ids->ofpact); + + mpls_ttl->ttl = atoi(arg); +} + +static void +set_field_parse(const char *arg, struct ofpbuf *ofpacts) +{ + char *orig = xstrdup(arg); + struct ofpact_reg_load *load = ofpact_put_REG_LOAD(ofpacts); + char *value; + char *delim; + char *key; + const struct mf_field *mf; + const char *error; + union mf_value mf_value; + + value = orig; + delim = strstr(orig, "->"); + if (!delim) { + ovs_fatal(0, "%s: missing `->'", orig); + } + if (strlen(delim) <= strlen("->")) { + ovs_fatal(0, "%s: missing field name following `->'", orig); + } + + key = delim + strlen("->"); + mf = mf_from_name(key); + if (!mf) { + ovs_fatal(0, "%s is not valid oxm field name", key); + } + if (!mf->writable) { + ovs_fatal(0, "%s is not allowed to set", key); + } + + delim[0] = '\0'; + error = mf_parse_value(mf, value, &mf_value); + if (error) { + ovs_fatal(0, "%s", error); + } + if (!mf_is_value_valid(mf, &mf_value)) { + ovs_fatal(0, "%s is not valid valid for field %s", value, key); + } + ofpact_set_field_init(load, mf, &mf_value); + free(orig); } static void -parse_named_action(enum ofputil_action_code code, const struct flow *flow, +parse_metadata(struct ofpbuf *b, char *arg) +{ + struct ofpact_metadata *om; + char *mask = strchr(arg, '/'); + + om = ofpact_put_WRITE_METADATA(b); + + if (mask) { + *mask = '\0'; + om->mask = htonll(str_to_u64(mask + 1)); + } else { + om->mask = htonll(UINT64_MAX); + } + + om->metadata = htonll(str_to_u64(arg)); +} + +static void +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; uint16_t vid; + uint16_t ethertype; ovs_be32 ip; uint8_t pcp; uint8_t tos; @@ -352,15 +456,28 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, break; case OFPUTIL_OFPAT12_SET_FIELD: - NOT_REACHED(); /* This will be implemented by later patch and - * enabled using a non-NULL name in - * OFPAT12_ACTION(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); @@ -392,6 +509,9 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, 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); @@ -417,6 +537,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, 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; @@ -441,10 +565,6 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, 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; @@ -459,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: @@ -470,6 +590,16 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, parse_dec_ttl(ofpacts, arg); break; + case OFPUTIL_NXAST_SET_MPLS_TTL: + case OFPUTIL_OFPAT11_SET_MPLS_TTL: + parse_set_mpls_ttl(ofpacts, arg); + break; + + case OFPUTIL_OFPAT11_DEC_MPLS_TTL: + case OFPUTIL_NXAST_DEC_MPLS_TTL: + ofpact_put_DEC_MPLS_TTL(ofpacts); + break; + case OFPUTIL_NXAST_FIN_TIMEOUT: parse_fin_timeout(ofpacts, arg); break; @@ -477,38 +607,171 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow, case OFPUTIL_NXAST_CONTROLLER: parse_controller(ofpacts, arg); break; + + case OFPUTIL_OFPAT11_PUSH_MPLS: + case OFPUTIL_NXAST_PUSH_MPLS: + ofpact_put_PUSH_MPLS(ofpacts)->ethertype = + htons(str_to_u16(arg, "push_mpls")); + break; + + case OFPUTIL_OFPAT11_POP_MPLS: + case OFPUTIL_NXAST_POP_MPLS: + 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__(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; +} + 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; int n_actions; pos = str; n_actions = 0; while (ofputil_parse_key_value(&pos, &act, &arg)) { - int code = ofputil_action_code_from_name(act); - if (code >= 0) { - parse_named_action(code, flow, 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"); - } + if (!str_to_ofpact__(pos, act, arg, ofpacts, n_actions)) { break; - } else { - uint16_t port = ofputil_port_from_string(act); - if (port) { - ofpact_put_OUTPUT(ofpacts)->port = port; - } else { - ovs_fatal(0, "Unknown action: %s", act); + } + n_actions++; + } + + error = ofpacts_verify(ofpacts->data, ofpacts->size); + if (error) { + ovs_fatal(0, "Incorrect action ordering"); + } + + ofpact_pad(ofpacts); +} + +static void +parse_named_instruction(enum ovs_instruction_type type, + char *arg, struct ofpbuf *ofpacts) +{ + enum ofperr error; + + switch (type) { + case OVSINST_OFPIT11_APPLY_ACTIONS: + NOT_REACHED(); /* This case is handled by str_to_inst_ofpacts() */ + break; + + case OVSINST_OFPIT11_WRITE_ACTIONS: + /* XXX */ + ovs_fatal(0, "instruction write-actions is not supported yet"); + break; + + case OVSINST_OFPIT11_CLEAR_ACTIONS: + 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; + + case OVSINST_OFPIT11_GOTO_TABLE: { + struct ofpact_goto_table *ogt = ofpact_put_GOTO_TABLE(ofpacts); + char *table_s = strsep(&arg, ","); + if (!table_s || !table_s[0]) { + ovs_fatal(0, "instruction goto-table needs table id"); + } + ogt->table_id = str_to_u8(table_s, "table"); + break; + } + } + + /* If write_metadata is specified as an action AND an instruction, ofpacts + could be invalid. */ + error = ofpacts_verify(ofpacts->data, ofpacts->size); + if (error) { + ovs_fatal(0, "Incorrect instruction ordering"); + } +} + +static void +str_to_inst_ofpacts(char *str, struct ofpbuf *ofpacts) +{ + char *pos, *inst, *arg; + int type; + const char *prev_inst = NULL; + int prev_type = -1; + int n_actions = 0; + + pos = str; + while (ofputil_parse_key_value(&pos, &inst, &arg)) { + type = ovs_instruction_type_from_name(inst); + if (type < 0) { + if (!str_to_ofpact__(pos, inst, arg, ofpacts, n_actions)) { + break; + } + + type = OVSINST_OFPIT11_APPLY_ACTIONS; + if (prev_type == type) { + n_actions++; + continue; } + } else if (type == OVSINST_OFPIT11_APPLY_ACTIONS) { + ovs_fatal(0, "%s isn't supported. Just write actions then " + "it is interpreted as apply_actions", inst); + } else { + parse_named_instruction(type, arg, ofpacts); + } + + if (type == prev_type) { + ovs_fatal(0, "instruction can be specified at most once: %s", + inst); + } + if (type <= prev_type) { + ovs_fatal(0, "Instruction %s must be specified before %s", + inst, prev_inst); } + + prev_inst = inst; + prev_type = type; n_actions++; } ofpact_pad(ofpacts); @@ -534,6 +797,9 @@ parse_protocol(const char *name, const struct protocol **p_out) { "icmp6", ETH_TYPE_IPV6, IPPROTO_ICMPV6 }, { "tcp6", ETH_TYPE_IPV6, IPPROTO_TCP }, { "udp6", ETH_TYPE_IPV6, IPPROTO_UDP }, + { "rarp", ETH_TYPE_RARP, 0}, + { "mpls", ETH_TYPE_MPLS, 0 }, + { "mplsm", ETH_TYPE_MPLS_MCAST, 0 }, }; const struct protocol *p; @@ -642,7 +908,7 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, fm->idle_timeout = OFP_FLOW_PERMANENT; fm->hard_timeout = OFP_FLOW_PERMANENT; fm->buffer_id = UINT32_MAX; - fm->out_port = OFPP_NONE; + fm->out_port = OFPP_ANY; fm->flags = 0; if (fields & F_ACTIONS) { act_str = strstr(string, "action"); @@ -671,6 +937,12 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, 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; @@ -680,10 +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")) { - fm->out_port = ofputil_port_from_string(name); - if (!fm->out_port) { + if (!ofputil_port_from_string(value, &fm->out_port)) { ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port", name); } @@ -717,7 +988,9 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, parse_field(mf_from_name(name), value, &fm->match); } else if (!strcmp(name, "duration") || !strcmp(name, "n_packets") - || !strcmp(name, "n_bytes")) { + || !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. */ @@ -735,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_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; @@ -748,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 @@ -797,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 { @@ -819,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); } @@ -952,6 +1425,10 @@ parse_ofp_exact_flow(struct flow *flow, const char *s) } } + if (!flow->in_port.ofp_port) { + flow->in_port.ofp_port = OFPP_NONE; + } + exit: free(copy);