+static void
+parse_field_value(struct cls_rule *rule, enum field_index index,
+ const char *value)
+{
+ uint8_t mac[ETH_ADDR_LEN];
+ ovs_be64 tun_id, tun_mask;
+ ovs_be32 ip, mask;
+ struct in6_addr ipv6, ipv6_mask;
+ uint16_t port_no;
+
+ switch (index) {
+ case F_TUN_ID:
+ str_to_tun_id(value, &tun_id, &tun_mask);
+ cls_rule_set_tun_id_masked(rule, tun_id, tun_mask);
+ break;
+
+ case F_IN_PORT:
+ if (!parse_port_name(value, &port_no)) {
+ port_no = atoi(value);
+ }
+ if (port_no == OFPP_LOCAL) {
+ port_no = ODPP_LOCAL;
+ }
+ cls_rule_set_in_port(rule, port_no);
+ break;
+
+ case F_DL_VLAN:
+ cls_rule_set_dl_vlan(rule, htons(str_to_u32(value)));
+ break;
+
+ case F_DL_VLAN_PCP:
+ cls_rule_set_dl_vlan_pcp(rule, str_to_u32(value));
+ break;
+
+ case F_DL_SRC:
+ str_to_mac(value, mac);
+ cls_rule_set_dl_src(rule, mac);
+ break;
+
+ case F_DL_DST:
+ str_to_mac(value, mac);
+ cls_rule_set_dl_dst(rule, mac);
+ break;
+
+ case F_DL_TYPE:
+ cls_rule_set_dl_type(rule, htons(str_to_u32(value)));
+ break;
+
+ case F_NW_SRC:
+ str_to_ip(value, &ip, &mask);
+ cls_rule_set_nw_src_masked(rule, ip, mask);
+ break;
+
+ case F_NW_DST:
+ str_to_ip(value, &ip, &mask);
+ cls_rule_set_nw_dst_masked(rule, ip, mask);
+ break;
+
+ case F_NW_PROTO:
+ cls_rule_set_nw_proto(rule, str_to_u32(value));
+ break;
+
+ case F_NW_TOS:
+ cls_rule_set_nw_tos(rule, str_to_u32(value));
+ break;
+
+ case F_TP_SRC:
+ cls_rule_set_tp_src(rule, htons(str_to_u32(value)));
+ break;
+
+ case F_TP_DST:
+ cls_rule_set_tp_dst(rule, htons(str_to_u32(value)));
+ break;
+
+ case F_ICMP_TYPE:
+ cls_rule_set_icmp_type(rule, str_to_u32(value));
+ break;
+
+ case F_ICMP_CODE:
+ cls_rule_set_icmp_code(rule, str_to_u32(value));
+ break;
+
+ case F_ARP_SHA:
+ str_to_mac(value, mac);
+ cls_rule_set_arp_sha(rule, mac);
+ break;
+
+ case F_ARP_THA:
+ str_to_mac(value, mac);
+ cls_rule_set_arp_tha(rule, mac);
+ break;
+
+ case F_IPV6_SRC:
+ str_to_ipv6(value, &ipv6, &ipv6_mask);
+ cls_rule_set_ipv6_src_masked(rule, &ipv6, &ipv6_mask);
+ break;
+
+ case F_IPV6_DST:
+ str_to_ipv6(value, &ipv6, &ipv6_mask);
+ cls_rule_set_ipv6_dst_masked(rule, &ipv6, &ipv6_mask);
+ break;
+
+ case F_ND_TARGET:
+ str_to_ipv6(value, &ipv6, NULL);
+ cls_rule_set_nd_target(rule, ipv6);
+ break;
+
+ case F_ND_SLL:
+ str_to_mac(value, mac);
+ cls_rule_set_arp_sha(rule, mac);
+ break;
+
+ case F_ND_TLL:
+ str_to_mac(value, mac);
+ cls_rule_set_arp_tha(rule, mac);
+ break;
+
+ case N_FIELDS:
+ NOT_REACHED();
+ }
+}
+
+static void
+parse_reg_value(struct cls_rule *rule, int reg_idx, const char *value)
+{
+ uint32_t reg_value, reg_mask;
+
+ if (!strcmp(value, "ANY") || !strcmp(value, "*")) {
+ cls_rule_set_reg_masked(rule, reg_idx, 0, 0);
+ } else if (sscanf(value, "%"SCNi32"/%"SCNi32,
+ ®_value, ®_mask) == 2) {
+ cls_rule_set_reg_masked(rule, reg_idx, reg_value, reg_mask);
+ } else if (sscanf(value, "%"SCNi32, ®_value)) {
+ cls_rule_set_reg(rule, reg_idx, reg_value);
+ } else {
+ ovs_fatal(0, "register fields must take the form <value> "
+ "or <value>/<mask>");
+ }
+}
+
+/* Convert 'string' (as described in the Flow Syntax section of the ovs-ofctl
+ * man page) into 'pf'. If 'actions' is specified, an action must be in
+ * 'string' and may be expanded or reallocated. */
+static void
+parse_ofp_str(struct flow_mod *fm, uint8_t *table_idx,
+ struct ofpbuf *actions, char *string)