- ovs_fatal(0, "invalid numeric format %s", str);
- }
- return value;
-}
-
-static void
-str_to_mac(const char *str, uint8_t mac[6])
-{
- if (sscanf(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
- != ETH_ADDR_SCAN_COUNT) {
- ovs_fatal(0, "invalid mac address %s", str);
- }
-}
-
-static void
-str_to_ip(const char *str, ovs_be32 *ip)
-{
- struct in_addr in_addr;
-
- if (lookup_ip(str, &in_addr)) {
- ovs_fatal(0, "%s: could not convert to IP address", str);
- }
- *ip = in_addr.s_addr;
-}
-
-static void
-parse_enqueue(char *arg, struct ofpbuf *ofpacts)
-{
- char *sp = NULL;
- char *port = strtok_r(arg, ":q", &sp);
- char *queue = strtok_r(NULL, "", &sp);
- struct ofpact_enqueue *enqueue;
-
- if (port == NULL || queue == NULL) {
- ovs_fatal(0, "\"enqueue\" syntax is \"enqueue:PORT:QUEUE\"");
- }
-
- enqueue = ofpact_put_ENQUEUE(ofpacts);
- enqueue->port = str_to_u32(port);
- enqueue->queue = str_to_u32(queue);
-}
-
-static void
-parse_output(char *arg, struct ofpbuf *ofpacts)
-{
- if (strchr(arg, '[')) {
- struct ofpact_output_reg *output_reg;
-
- output_reg = ofpact_put_OUTPUT_REG(ofpacts);
- mf_parse_subfield(&output_reg->src, arg);
- output_reg->max_len = UINT16_MAX;
- } else {
- struct ofpact_output *output;
-
- output = ofpact_put_OUTPUT(ofpacts);
- output->port = str_to_u32(arg);
- output->max_len = output->port == OFPP_CONTROLLER ? UINT16_MAX : 0;
- }
-}
-
-static void
-parse_resubmit(char *arg, struct ofpbuf *ofpacts)
-{
- struct ofpact_resubmit *resubmit;
- char *in_port_s, *table_s;
-
- resubmit = ofpact_put_RESUBMIT(ofpacts);
-
- in_port_s = strsep(&arg, ",");
- if (in_port_s && in_port_s[0]) {
- if (!ofputil_port_from_string(in_port_s, &resubmit->in_port)) {
- ovs_fatal(0, "%s: resubmit to unknown port", in_port_s);
- }
- } else {
- resubmit->in_port = OFPP_IN_PORT;
- }
-
- table_s = strsep(&arg, ",");
- resubmit->table_id = table_s && table_s[0] ? str_to_u32(table_s) : 255;
-
- if (resubmit->in_port == OFPP_IN_PORT && resubmit->table_id == 255) {
- ovs_fatal(0, "at least one \"in_port\" or \"table\" must be specified "
- " on resubmit");
- }
-}
-
-static void
-parse_note(const char *arg, struct ofpbuf *ofpacts)
-{
- struct ofpact_note *note;
-
- note = ofpact_put_NOTE(ofpacts);
- while (*arg != '\0') {
- uint8_t byte;
- bool ok;
-
- if (*arg == '.') {
- arg++;
- }
- if (*arg == '\0') {
- break;
- }
-
- byte = hexits_value(arg, 2, &ok);
- if (!ok) {
- ovs_fatal(0, "bad hex digit in `note' argument");
- }
- ofpbuf_put(ofpacts, &byte, 1);
-
- note = ofpacts->l2;
- note->length++;
-
- arg += 2;
- }
- ofpact_update_len(ofpacts, ¬e->ofpact);
-}
-
-static void
-parse_fin_timeout(struct ofpbuf *b, char *arg)
-{
- struct ofpact_fin_timeout *oft = ofpact_put_FIN_TIMEOUT(b);
- char *key, *value;
-
- while (ofputil_parse_key_value(&arg, &key, &value)) {
- if (!strcmp(key, "idle_timeout")) {
- oft->fin_idle_timeout = str_to_u16(value, key);
- } else if (!strcmp(key, "hard_timeout")) {
- oft->fin_hard_timeout = str_to_u16(value, key);
- } else {
- ovs_fatal(0, "invalid key '%s' in 'fin_timeout' argument", key);
- }
- }
-}
-
-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));
-}
-
-static void
-parse_named_action(enum ofputil_action_code code, const struct flow *flow,
- char *arg, struct ofpbuf *ofpacts)
-{
- struct ofpact_tunnel *tunnel;
- uint16_t vid;
- uint16_t ethertype;
- ovs_be32 ip;
- uint8_t pcp;
- uint8_t tos;
-
- switch (code) {
- case OFPUTIL_ACTION_INVALID:
- NOT_REACHED();
-
- case OFPUTIL_OFPAT10_OUTPUT:
- case OFPUTIL_OFPAT11_OUTPUT:
- parse_output(arg, ofpacts);
- break;
-
- case OFPUTIL_OFPAT10_SET_VLAN_VID:
- case OFPUTIL_OFPAT11_SET_VLAN_VID:
- vid = str_to_u32(arg);
- if (vid & ~VLAN_VID_MASK) {
- ovs_fatal(0, "%s: not a valid VLAN VID", arg);
- }
- ofpact_put_SET_VLAN_VID(ofpacts)->vlan_vid = vid;
- break;
-
- case OFPUTIL_OFPAT10_SET_VLAN_PCP:
- case OFPUTIL_OFPAT11_SET_VLAN_PCP:
- pcp = str_to_u32(arg);
- if (pcp & ~7) {
- ovs_fatal(0, "%s: not a valid VLAN PCP", arg);
- }
- ofpact_put_SET_VLAN_PCP(ofpacts)->vlan_pcp = pcp;
- break;
-
- case OFPUTIL_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);
- break;
-
- case OFPUTIL_OFPAT10_SET_DL_DST:
- case OFPUTIL_OFPAT11_SET_DL_DST:
- str_to_mac(arg, ofpact_put_SET_ETH_DST(ofpacts)->mac);
- break;
-
- case OFPUTIL_OFPAT10_SET_NW_SRC:
- case OFPUTIL_OFPAT11_SET_NW_SRC:
- str_to_ip(arg, &ip);
- ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4 = ip;
- break;
-
- case OFPUTIL_OFPAT10_SET_NW_DST:
- case OFPUTIL_OFPAT11_SET_NW_DST:
- str_to_ip(arg, &ip);
- ofpact_put_SET_IPV4_DST(ofpacts)->ipv4 = ip;
- break;
-
- case OFPUTIL_OFPAT10_SET_NW_TOS:
- case OFPUTIL_OFPAT11_SET_NW_TOS:
- tos = str_to_u32(arg);
- if (tos & ~IP_DSCP_MASK) {
- ovs_fatal(0, "%s: not a valid TOS", arg);
- }
- 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);
- break;
-
- case OFPUTIL_OFPAT10_SET_TP_DST:
- case OFPUTIL_OFPAT11_SET_TP_DST:
- ofpact_put_SET_L4_DST_PORT(ofpacts)->port = str_to_u32(arg);
- break;
-
- case OFPUTIL_OFPAT10_ENQUEUE:
- parse_enqueue(arg, ofpacts);
- break;
-
- case OFPUTIL_NXAST_RESUBMIT:
- parse_resubmit(arg, ofpacts);
- break;
-
- case OFPUTIL_NXAST_SET_TUNNEL:
- case OFPUTIL_NXAST_SET_TUNNEL64:
- tunnel = ofpact_put_SET_TUNNEL(ofpacts);
- tunnel->ofpact.compat = code;
- 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;
-
- case OFPUTIL_NXAST_POP_QUEUE:
- ofpact_put_POP_QUEUE(ofpacts);
- break;
-
- case OFPUTIL_NXAST_REG_MOVE:
- nxm_parse_reg_move(ofpact_put_REG_MOVE(ofpacts), arg);
- break;
-
- case OFPUTIL_NXAST_REG_LOAD:
- nxm_parse_reg_load(ofpact_put_REG_LOAD(ofpacts), arg);
- break;
-
- case OFPUTIL_NXAST_NOTE:
- parse_note(arg, ofpacts);
- break;
-
- case OFPUTIL_NXAST_MULTIPATH:
- 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;
-
- case OFPUTIL_NXAST_BUNDLE_LOAD:
- bundle_parse_load(arg, ofpacts);
- break;
-
- case OFPUTIL_NXAST_RESUBMIT_TABLE:
- case OFPUTIL_NXAST_OUTPUT_REG:
- case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
- NOT_REACHED();
-
- case OFPUTIL_NXAST_LEARN:
- learn_parse(arg, flow, ofpacts);
- break;
-
- case OFPUTIL_NXAST_EXIT:
- ofpact_put_EXIT(ofpacts);
- break;
-
- case OFPUTIL_NXAST_DEC_TTL:
- parse_dec_ttl(ofpacts, arg);
- break;
-
- case OFPUTIL_NXAST_FIN_TIMEOUT:
- parse_fin_timeout(ofpacts, arg);
- break;
-
- 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;
- }
-}
-
-static bool
-str_to_ofpact__(const struct flow *flow, 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, 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");
- }
- return false;
- } else {
- uint16_t port;
- if (ofputil_port_from_string(act, &port)) {
- ofpact_put_OUTPUT(ofpacts)->port = port;
- } else {
- ovs_fatal(0, "Unknown action: %s", act);
- }