+ char *pos, *act, *arg;
+ enum ofperr error;
+ int n_actions;
+
+ pos = str;
+ n_actions = 0;
+ while (ofputil_parse_key_value(&pos, &act, &arg)) {
+ if (!str_to_ofpact__(flow, pos, act, arg, ofpacts, n_actions)) {
+ break;
+ }
+ 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:
+ /* TODO: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_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_table_id(table_s);
+ 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(const struct flow *flow, 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 = ofpact_instruction_type_from_name(inst);
+ if (type < 0) {
+ if (!str_to_ofpact__(flow, 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);
+}
+
+struct protocol {
+ const char *name;
+ uint16_t dl_type;
+ uint8_t nw_proto;
+};
+
+static bool
+parse_protocol(const char *name, const struct protocol **p_out)
+{
+ static const struct protocol protocols[] = {
+ { "ip", ETH_TYPE_IP, 0 },
+ { "arp", ETH_TYPE_ARP, 0 },
+ { "icmp", ETH_TYPE_IP, IPPROTO_ICMP },
+ { "tcp", ETH_TYPE_IP, IPPROTO_TCP },
+ { "udp", ETH_TYPE_IP, IPPROTO_UDP },
+ { "ipv6", ETH_TYPE_IPV6, 0 },
+ { "ip6", ETH_TYPE_IPV6, 0 },
+ { "icmp6", ETH_TYPE_IPV6, IPPROTO_ICMPV6 },
+ { "tcp6", ETH_TYPE_IPV6, IPPROTO_TCP },
+ { "udp6", ETH_TYPE_IPV6, IPPROTO_UDP },
+ { "rarp", ETH_TYPE_RARP, 0},
+};
+ const struct protocol *p;
+
+ for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) {
+ if (!strcmp(p->name, name)) {
+ *p_out = p;
+ return true;
+ }
+ }
+ *p_out = NULL;
+ return false;
+}
+
+static void
+ofp_fatal(const char *flow, bool verbose, const char *format, ...)
+{
+ va_list args;
+
+ if (verbose) {
+ fprintf(stderr, "%s:\n", flow);
+ }
+
+ va_start(args, format);
+ ovs_fatal_valist(0, format, args);
+}
+
+static void
+parse_field(const struct mf_field *mf, const char *s, struct match *match)
+{
+ union mf_value value, mask;
+ char *error;
+
+ error = mf_parse(mf, s, &value, &mask);
+ if (error) {
+ ovs_fatal(0, "%s", error);
+ }
+
+ mf_set(mf, &value, &mask, match);
+}
+
+/* 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_);