+ 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
+parse_flow_monitor_request(struct ofputil_flow_monitor_request *fmr,
+ const char *str_)
+{
+ static uint32_t id;
+
+ char *string = xstrdup(str_);
+ char *save_ptr = NULL;
+ char *name;
+
+ fmr->id = id++;
+ fmr->flags = (NXFMF_INITIAL | NXFMF_ADD | NXFMF_DELETE | NXFMF_MODIFY
+ | NXFMF_OWN | NXFMF_ACTIONS);
+ fmr->out_port = OFPP_NONE;
+ fmr->table_id = 0xff;
+ match_init_catchall(&fmr->match);
+
+ 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 (!strcmp(name, "!initial")) {
+ fmr->flags &= ~NXFMF_INITIAL;
+ } else if (!strcmp(name, "!add")) {
+ fmr->flags &= ~NXFMF_ADD;
+ } else if (!strcmp(name, "!delete")) {
+ fmr->flags &= ~NXFMF_DELETE;
+ } else if (!strcmp(name, "!modify")) {
+ fmr->flags &= ~NXFMF_MODIFY;
+ } else if (!strcmp(name, "!actions")) {
+ fmr->flags &= ~NXFMF_ACTIONS;
+ } else if (!strcmp(name, "!own")) {
+ fmr->flags &= ~NXFMF_OWN;
+ } else if (parse_protocol(name, &p)) {
+ match_set_dl_type(&fmr->match, htons(p->dl_type));
+ if (p->nw_proto) {
+ match_set_nw_proto(&fmr->match, p->nw_proto);
+ }
+ } else {
+ char *value;
+
+ value = strtok_r(NULL, ", \t\r\n", &save_ptr);
+ if (!value) {
+ ovs_fatal(0, "%s: field %s missing value", str_, name);
+ }
+
+ if (!strcmp(name, "table")) {
+ fmr->table_id = str_to_u8(value, name);
+ } else if (!strcmp(name, "out_port")) {
+ fmr->out_port = u16_to_ofp(atoi(value));
+ } else if (mf_from_name(name)) {
+ parse_field(mf_from_name(name), value, &fmr->match);
+ } else {
+ ovs_fatal(0, "%s: unknown keyword %s", str_, name);
+ }
+ }
+ }
+ free(string);
+}
+
+/* Parses 's' as a set of OpenFlow actions and appends the actions to
+ * 'actions'.
+ *
+ * Prints an error on stderr and aborts the program if 's' syntax is
+ * invalid. */
+void
+parse_ofpacts(const char *s_, struct ofpbuf *ofpacts)
+{
+ char *s = xstrdup(s_);
+ str_to_ofpacts(s, ofpacts);
+ free(s);
+}
+
+/* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command'
+ * (one of OFPFC_*) into 'fm'. */
+void
+parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string,
+ uint16_t command, bool verbose)
+{
+ struct match match_copy;
+
+ parse_ofp_str(fm, command, string, verbose);
+
+ /* Normalize a copy of the match. This ensures that non-normalized flows
+ * get logged but doesn't affect what gets sent to the switch, so that the
+ * switch can do whatever it likes with the flow. */
+ match_copy = fm->match;
+ ofputil_normalize_match(&match_copy);