+}
+
+static void
+parse_controller(struct ofpbuf *b, char *arg)
+{
+ enum ofp_packet_in_reason reason = OFPR_ACTION;
+ uint16_t controller_id = 0;
+ uint16_t max_len = UINT16_MAX;
+
+ if (!arg[0]) {
+ /* Use defaults. */
+ } else if (strspn(arg, "0123456789") == strlen(arg)) {
+ max_len = str_to_u16(arg, "max_len");
+ } else {
+ char *name, *value;
+
+ while (ofputil_parse_key_value(&arg, &name, &value)) {
+ if (!strcmp(name, "reason")) {
+ if (!ofputil_packet_in_reason_from_string(value, &reason)) {
+ ovs_fatal(0, "unknown reason \"%s\"", value);
+ }
+ } else if (!strcmp(name, "max_len")) {
+ max_len = str_to_u16(value, "max_len");
+ } else if (!strcmp(name, "id")) {
+ controller_id = str_to_u16(value, "id");
+ } else {
+ ovs_fatal(0, "unknown key \"%s\" parsing controller action",
+ name);
+ }
+ }
+ }
+
+ if (reason == OFPR_ACTION && controller_id == 0) {
+ struct ofpact_output *output;
+
+ output = ofpact_put_OUTPUT(b);
+ output->port = OFPP_CONTROLLER;
+ output->max_len = max_len;
+ } else {
+ struct ofpact_controller *controller;
+
+ controller = ofpact_put_CONTROLLER(b);
+ controller->max_len = max_len;
+ controller->reason = reason;
+ controller->controller_id = controller_id;
+ }
+}
+
+static void
+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') {
+ 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)) {
+ uint16_t id = atoi(cntr);
+
+ ofpbuf_put(b, &id, sizeof id);
+ ids = b->l2;
+ ids->n_controllers++;
+ }
+ if (!ids->n_controllers) {
+ ovs_fatal(0, "dec_ttl_cnt_ids: expected at least one controller "
+ "id.");
+ }
+ ofpact_update_len(b, &ids->ofpact);
+ }
+}
+
+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_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));