ofproto: Inline actions in struct rule_actions.
[sliver-openvswitch.git] / lib / ofp-parse.c
index a4b6d2e..c759f03 100644 (file)
@@ -147,8 +147,7 @@ str_to_be64(const char *str, ovs_be64 *valuep)
 static char * WARN_UNUSED_RESULT
 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) {
+    if (!ovs_scan(str, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
         return xasprintf("invalid mac address %s", str);
     }
     return NULL;
@@ -179,12 +178,13 @@ static char * WARN_UNUSED_RESULT
 parse_enqueue(char *arg, struct ofpbuf *ofpacts)
 {
     char *sp = NULL;
-    char *port = strtok_r(arg, ":q", &sp);
+    char *port = strtok_r(arg, ":q,", &sp);
     char *queue = strtok_r(NULL, "", &sp);
     struct ofpact_enqueue *enqueue;
 
     if (port == NULL || queue == NULL) {
-        return xstrdup("\"enqueue\" syntax is \"enqueue:PORT:QUEUE\"");
+        return xstrdup("\"enqueue\" syntax is \"enqueue:PORT:QUEUE\" or "
+                       "\"enqueue(PORT,QUEUE)\"");
     }
 
     enqueue = ofpact_put_ENQUEUE(ofpacts);
@@ -212,10 +212,10 @@ parse_output(const char *arg, struct ofpbuf *ofpacts)
         struct ofpact_output *output;
 
         output = ofpact_put_OUTPUT(ofpacts);
-        output->max_len = output->port == OFPP_CONTROLLER ? UINT16_MAX : 0;
         if (!ofputil_port_from_string(arg, &output->port)) {
             return xasprintf("%s: output to unknown port", arg);
         }
+        output->max_len = output->port == OFPP_CONTROLLER ? UINT16_MAX : 0;
         return NULL;
     }
 }
@@ -291,7 +291,7 @@ parse_note(const char *arg, struct ofpbuf *ofpacts)
         }
         ofpbuf_put(ofpacts, &byte, 1);
 
-        note = ofpacts->l2;
+        note = ofpacts->frame;
         note->length++;
 
         arg += 2;
@@ -400,7 +400,7 @@ parse_noargs_dec_ttl(struct ofpbuf *b)
 
     ids = ofpact_put_DEC_TTL(b);
     ofpbuf_put(b, &id, sizeof id);
-    ids = b->l2;
+    ids = b->frame;
     ids->n_controllers++;
     ofpact_update_len(b, &ids->ofpact);
 }
@@ -426,7 +426,7 @@ parse_dec_ttl(struct ofpbuf *b, char *arg)
             uint16_t id = atoi(cntr);
 
             ofpbuf_put(b, &id, sizeof id);
-            ids = b->l2;
+            ids = b->frame;
             ids->n_controllers++;
         }
         if (!ids->n_controllers) {
@@ -438,6 +438,42 @@ parse_dec_ttl(struct ofpbuf *b, char *arg)
     return NULL;
 }
 
+/* Parses 'arg' as the argument to a "set_mpls_label" action, and appends such
+ * an action to 'b'.
+ *
+ * Returns NULL if successful, otherwise a malloc()'d string describing the
+ * error.  The caller is responsible for freeing the returned string. */
+static char * WARN_UNUSED_RESULT
+parse_set_mpls_label(struct ofpbuf *b, const char *arg)
+{
+    struct ofpact_mpls_label *mpls_label = ofpact_put_SET_MPLS_LABEL(b);
+
+    if (*arg == '\0') {
+        return xstrdup("parse_set_mpls_label: expected label.");
+    }
+
+    mpls_label->label = htonl(atoi(arg));
+    return NULL;
+}
+
+/* Parses 'arg' as the argument to a "set_mpls_tc" action, and appends such an
+ * action to 'b'.
+ *
+ * Returns NULL if successful, otherwise a malloc()'d string describing the
+ * error.  The caller is responsible for freeing the returned string. */
+static char * WARN_UNUSED_RESULT
+parse_set_mpls_tc(struct ofpbuf *b, const char *arg)
+{
+    struct ofpact_mpls_tc *mpls_tc = ofpact_put_SET_MPLS_TC(b);
+
+    if (*arg == '\0') {
+        return xstrdup("parse_set_mpls_tc: expected tc.");
+    }
+
+    mpls_tc->tc = atoi(arg);
+    return NULL;
+}
+
 /* Parses 'arg' as the argument to a "set_mpls_ttl" action, and appends such an
  * action to 'ofpacts'.
  *
@@ -465,13 +501,12 @@ static char * WARN_UNUSED_RESULT
 set_field_parse__(char *arg, struct ofpbuf *ofpacts,
                   enum ofputil_protocol *usable_protocols)
 {
-    struct ofpact_reg_load *load = ofpact_put_REG_LOAD(ofpacts);
+    struct ofpact_set_field *sf = ofpact_put_SET_FIELD(ofpacts);
     char *value;
     char *delim;
     char *key;
     const struct mf_field *mf;
     char *error;
-    union mf_value mf_value;
 
     value = arg;
     delim = strstr(arg, "->");
@@ -490,16 +525,16 @@ set_field_parse__(char *arg, struct ofpbuf *ofpacts,
     if (!mf->writable) {
         return xasprintf("%s is read-only", key);
     }
-
+    sf->field = mf;
     delim[0] = '\0';
-    error = mf_parse_value(mf, value, &mf_value);
+    error = mf_parse_value(mf, value, &sf->value);
     if (error) {
         return error;
     }
-    if (!mf_is_value_valid(mf, &mf_value)) {
+
+    if (!mf_is_value_valid(mf, &sf->value)) {
         return xasprintf("%s is not a valid value for field %s", value, key);
     }
-    ofpact_set_field_init(load, mf, &mf_value);
 
     *usable_protocols &= mf->usable_protocols;
     return NULL;
@@ -597,20 +632,25 @@ parse_named_action(enum ofputil_action_code code,
                    char *arg, struct ofpbuf *ofpacts,
                    enum ofputil_protocol *usable_protocols)
 {
-    size_t orig_size = ofpacts->size;
+    size_t orig_size = ofpbuf_size(ofpacts);
     struct ofpact_tunnel *tunnel;
+    struct ofpact_vlan_vid *vlan_vid;
+    struct ofpact_vlan_pcp *vlan_pcp;
     char *error = NULL;
     uint16_t ethertype = 0;
     uint16_t vid = 0;
-    uint8_t tos = 0, ecn, ttl;
+    uint8_t tos = 0;
+    uint8_t ecn = 0;
+    uint8_t ttl = 0;
     uint8_t pcp = 0;
 
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OFPUTIL_OFPAT10_OUTPUT:
     case OFPUTIL_OFPAT11_OUTPUT:
+    case OFPUTIL_OFPAT13_OUTPUT:
         error = parse_output(arg, ofpacts);
         break;
 
@@ -624,7 +664,10 @@ parse_named_action(enum ofputil_action_code code,
         if (vid & ~VLAN_VID_MASK) {
             return xasprintf("%s: not a valid VLAN VID", arg);
         }
-        ofpact_put_SET_VLAN_VID(ofpacts)->vlan_vid = vid;
+        vlan_vid = ofpact_put_SET_VLAN_VID(ofpacts);
+        vlan_vid->vlan_vid = vid;
+        vlan_vid->ofpact.compat = code;
+        vlan_vid->push_vlan_if_needed = code == OFPUTIL_OFPAT10_SET_VLAN_VID;
         break;
 
     case OFPUTIL_OFPAT10_SET_VLAN_PCP:
@@ -637,18 +680,24 @@ parse_named_action(enum ofputil_action_code code,
         if (pcp & ~7) {
             return xasprintf("%s: not a valid VLAN PCP", arg);
         }
-        ofpact_put_SET_VLAN_PCP(ofpacts)->vlan_pcp = pcp;
+        vlan_pcp = ofpact_put_SET_VLAN_PCP(ofpacts);
+        vlan_pcp->vlan_pcp = pcp;
+        vlan_pcp->ofpact.compat = code;
+        vlan_pcp->push_vlan_if_needed = code == OFPUTIL_OFPAT10_SET_VLAN_PCP;
         break;
 
     case OFPUTIL_OFPAT12_SET_FIELD:
+    case OFPUTIL_OFPAT13_SET_FIELD:
         return set_field_parse(arg, ofpacts, usable_protocols);
 
     case OFPUTIL_OFPAT10_STRIP_VLAN:
     case OFPUTIL_OFPAT11_POP_VLAN:
-        ofpact_put_STRIP_VLAN(ofpacts);
+    case OFPUTIL_OFPAT13_POP_VLAN:
+        ofpact_put_STRIP_VLAN(ofpacts)->ofpact.compat = code;
         break;
 
     case OFPUTIL_OFPAT11_PUSH_VLAN:
+    case OFPUTIL_OFPAT13_PUSH_VLAN:
         *usable_protocols &= OFPUTIL_P_OF11_UP;
         error = str_to_u16(arg, "ethertype", &ethertype);
         if (error) {
@@ -664,6 +713,7 @@ parse_named_action(enum ofputil_action_code code,
         break;
 
     case OFPUTIL_OFPAT11_SET_QUEUE:
+    case OFPUTIL_OFPAT13_SET_QUEUE:
         error = str_to_u32(arg, &ofpact_put_SET_QUEUE(ofpacts)->queue_id);
         break;
 
@@ -713,6 +763,7 @@ parse_named_action(enum ofputil_action_code code,
         break;
 
     case OFPUTIL_OFPAT11_SET_NW_TTL:
+    case OFPUTIL_OFPAT13_SET_NW_TTL:
         error = str_to_u8(arg, "TTL", &ttl);
         if (error) {
             return error;
@@ -722,7 +773,8 @@ parse_named_action(enum ofputil_action_code code,
         break;
 
     case OFPUTIL_OFPAT11_DEC_NW_TTL:
-        NOT_REACHED();
+    case OFPUTIL_OFPAT13_DEC_NW_TTL:
+        OVS_NOT_REACHED();
 
     case OFPUTIL_OFPAT10_SET_TP_SRC:
     case OFPUTIL_OFPAT11_SET_TP_SRC:
@@ -790,7 +842,7 @@ parse_named_action(enum ofputil_action_code code,
     case OFPUTIL_NXAST_RESUBMIT_TABLE:
     case OFPUTIL_NXAST_OUTPUT_REG:
     case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OFPUTIL_NXAST_LEARN:
         error = learn_parse(arg, ofpacts);
@@ -804,12 +856,24 @@ parse_named_action(enum ofputil_action_code code,
         error = parse_dec_ttl(ofpacts, arg);
         break;
 
+    case OFPUTIL_NXAST_SET_MPLS_LABEL:
+    case OFPUTIL_OFPAT11_SET_MPLS_LABEL:
+        error = parse_set_mpls_label(ofpacts, arg);
+        break;
+
+    case OFPUTIL_NXAST_SET_MPLS_TC:
+    case OFPUTIL_OFPAT11_SET_MPLS_TC:
+        error = parse_set_mpls_tc(ofpacts, arg);
+        break;
+
     case OFPUTIL_NXAST_SET_MPLS_TTL:
     case OFPUTIL_OFPAT11_SET_MPLS_TTL:
+    case OFPUTIL_OFPAT13_SET_MPLS_TTL:
         error = parse_set_mpls_ttl(ofpacts, arg);
         break;
 
     case OFPUTIL_OFPAT11_DEC_MPLS_TTL:
+    case OFPUTIL_OFPAT13_DEC_MPLS_TTL:
     case OFPUTIL_NXAST_DEC_MPLS_TTL:
         ofpact_put_DEC_MPLS_TTL(ofpacts);
         break;
@@ -823,6 +887,7 @@ parse_named_action(enum ofputil_action_code code,
         break;
 
     case OFPUTIL_OFPAT11_PUSH_MPLS:
+    case OFPUTIL_OFPAT13_PUSH_MPLS:
     case OFPUTIL_NXAST_PUSH_MPLS:
         error = str_to_u16(arg, "push_mpls", &ethertype);
         if (!error) {
@@ -831,6 +896,7 @@ parse_named_action(enum ofputil_action_code code,
         break;
 
     case OFPUTIL_OFPAT11_POP_MPLS:
+    case OFPUTIL_OFPAT13_POP_MPLS:
     case OFPUTIL_NXAST_POP_MPLS:
         error = str_to_u16(arg, "pop_mpls", &ethertype);
         if (!error) {
@@ -839,9 +905,17 @@ parse_named_action(enum ofputil_action_code code,
         break;
 
     case OFPUTIL_OFPAT11_GROUP:
+    case OFPUTIL_OFPAT13_GROUP:
         error = str_to_u32(arg, &ofpact_put_GROUP(ofpacts)->group_id);
         break;
 
+    /* FIXME when implement OFPAT13_* */
+    case OFPUTIL_OFPAT13_COPY_TTL_OUT:
+    case OFPUTIL_OFPAT13_COPY_TTL_IN:
+    case OFPUTIL_OFPAT13_PUSH_PBB:
+    case OFPUTIL_OFPAT13_POP_PBB:
+        OVS_NOT_REACHED();
+
     case OFPUTIL_NXAST_STACK_PUSH:
         error = nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg);
         break;
@@ -855,7 +929,7 @@ parse_named_action(enum ofputil_action_code code,
     }
 
     if (error) {
-        ofpacts->size = orig_size;
+        ofpbuf_set_size(ofpacts, orig_size);
     }
     return error;
 }
@@ -904,7 +978,7 @@ static char * WARN_UNUSED_RESULT
 str_to_ofpacts__(char *str, struct ofpbuf *ofpacts,
                  enum ofputil_protocol *usable_protocols)
 {
-    size_t orig_size = ofpacts->size;
+    size_t orig_size = ofpbuf_size(ofpacts);
     char *pos, *act, *arg;
     int n_actions;
 
@@ -914,7 +988,7 @@ str_to_ofpacts__(char *str, struct ofpbuf *ofpacts,
         char *error = str_to_ofpact__(pos, act, arg, ofpacts, n_actions,
                                       usable_protocols);
         if (error) {
-            ofpacts->size = orig_size;
+            ofpbuf_set_size(ofpacts, orig_size);
             return error;
         }
         n_actions++;
@@ -933,7 +1007,7 @@ static char * WARN_UNUSED_RESULT
 str_to_ofpacts(char *str, struct ofpbuf *ofpacts,
                enum ofputil_protocol *usable_protocols)
 {
-    size_t orig_size = ofpacts->size;
+    size_t orig_size = ofpbuf_size(ofpacts);
     char *error_s;
     enum ofperr error;
 
@@ -942,9 +1016,9 @@ str_to_ofpacts(char *str, struct ofpbuf *ofpacts,
         return error_s;
     }
 
-    error = ofpacts_verify(ofpacts->data, ofpacts->size);
+    error = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts));
     if (error) {
-        ofpacts->size = orig_size;
+        ofpbuf_set_size(ofpacts, orig_size);
         return xstrdup("Incorrect action ordering");
     }
 
@@ -968,7 +1042,7 @@ parse_named_instruction(enum ovs_instruction_type type,
 
     switch (type) {
     case OVSINST_OFPIT11_APPLY_ACTIONS:
-        NOT_REACHED();  /* This case is handled by str_to_inst_ofpacts() */
+        OVS_NOT_REACHED();  /* This case is handled by str_to_inst_ofpacts() */
         break;
 
     case OVSINST_OFPIT11_WRITE_ACTIONS: {
@@ -976,16 +1050,16 @@ parse_named_instruction(enum ovs_instruction_type type,
         size_t ofs;
 
         ofpact_pad(ofpacts);
-        ofs = ofpacts->size;
+        ofs = ofpbuf_size(ofpacts);
         on = ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS,
                         offsetof(struct ofpact_nest, actions));
         error_s = str_to_ofpacts__(arg, ofpacts, usable_protocols);
 
         on = ofpbuf_at_assert(ofpacts, ofs, sizeof *on);
-        on->ofpact.len = ofpacts->size - ofs;
+        on->ofpact.len = ofpbuf_size(ofpacts) - ofs;
 
         if (error_s) {
-            ofpacts->size = ofs;
+            ofpbuf_set_size(ofpacts, ofs);
         }
         break;
     }
@@ -1021,7 +1095,7 @@ parse_named_instruction(enum ovs_instruction_type type,
 
     /* If write_metadata is specified as an action AND an instruction, ofpacts
        could be invalid. */
-    error = ofpacts_verify(ofpacts->data, ofpacts->size);
+    error = ofpacts_verify(ofpbuf_data(ofpacts), ofpbuf_size(ofpacts));
     if (error) {
         return xstrdup("Incorrect instruction ordering");
     }
@@ -1036,7 +1110,7 @@ static char * WARN_UNUSED_RESULT
 str_to_inst_ofpacts(char *str, struct ofpbuf *ofpacts,
                     enum ofputil_protocol *usable_protocols)
 {
-    size_t orig_size = ofpacts->size;
+    size_t orig_size = ofpbuf_size(ofpacts);
     char *pos, *inst, *arg;
     int type;
     const char *prev_inst = NULL;
@@ -1050,7 +1124,7 @@ str_to_inst_ofpacts(char *str, struct ofpbuf *ofpacts,
             char *error = str_to_ofpact__(pos, inst, arg, ofpacts, n_actions,
                                           usable_protocols);
             if (error) {
-                ofpacts->size = orig_size;
+                ofpbuf_set_size(ofpacts, orig_size);
                 return error;
             }
 
@@ -1060,20 +1134,20 @@ str_to_inst_ofpacts(char *str, struct ofpbuf *ofpacts,
                 continue;
             }
         } else if (type == OVSINST_OFPIT11_APPLY_ACTIONS) {
-            ofpacts->size = orig_size;
+            ofpbuf_set_size(ofpacts, orig_size);
             return xasprintf("%s isn't supported. Just write actions then "
                              "it is interpreted as apply_actions", inst);
         } else {
             char *error = parse_named_instruction(type, arg, ofpacts,
                                                   usable_protocols);
             if (error) {
-                ofpacts->size = orig_size;
+                ofpbuf_set_size(ofpacts, orig_size);
                 return error;
             }
         }
 
         if (type <= prev_type) {
-            ofpacts->size = orig_size;
+            ofpbuf_set_size(ofpacts, orig_size);
             if (type == prev_type) {
                 return xasprintf("instruction %s may be specified only once",
                                  inst);
@@ -1193,7 +1267,7 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
         break;
 
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
     match_init_catchall(&fm->match);
@@ -1252,6 +1326,9 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
         } else if (fields & F_FLAGS && !strcmp(name, "no_byte_counts")) {
             fm->flags |= OFPUTIL_FF_NO_BYT_COUNTS;
             *usable_protocols &= OFPUTIL_P_OF13_UP;
+        } else if (!strcmp(name, "no_readonly_table")
+                   || !strcmp(name, "allow_hidden_fields")) {
+             /* ignore these fields. */
         } else {
             char *value;
 
@@ -1359,19 +1436,23 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
         if (!error) {
             enum ofperr err;
 
-            err = ofpacts_check(ofpacts.data, ofpacts.size, &fm->match.flow,
-                                OFPP_MAX, 0);
+            err = ofpacts_check(ofpbuf_data(&ofpacts), ofpbuf_size(&ofpacts), &fm->match.flow,
+                                OFPP_MAX, fm->table_id, 255, usable_protocols);
+            if (!err && !usable_protocols) {
+                err = OFPERR_OFPBAC_MATCH_INCONSISTENT;
+            }
             if (err) {
                 error = xasprintf("actions are invalid with specified match "
                                   "(%s)", ofperr_to_string(err));
             }
+
         }
         if (error) {
             ofpbuf_uninit(&ofpacts);
             return error;
         }
 
-        fm->ofpacts_len = ofpacts.size;
+        fm->ofpacts_len = ofpbuf_size(&ofpacts);
         fm->ofpacts = ofpbuf_steal_data(&ofpacts);
     } else {
         fm->ofpacts_len = 0;
@@ -1443,7 +1524,7 @@ parse_ofp_meter_mod_str__(struct ofputil_meter_mod *mm, char *string,
         break;
 
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
     mm->command = command;
@@ -1774,7 +1855,7 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id,
     *usable_protocols = OFPUTIL_P_OF11_UP;
 
     if (!strcasecmp(table_id, "all")) {
-        tm->table_id = 255;
+        tm->table_id = OFPTT_ALL;
     } else {
         char *error = str_to_u8(table_id, "table_id", &tm->table_id);
         if (error) {
@@ -1843,7 +1924,7 @@ parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
             size_t i;
 
             for (i = 0; i < *n_fms; i++) {
-                free((*fms)[i].ofpacts);
+                free(CONST_CAST(struct ofpact *, (*fms)[i].ofpacts));
             }
             free(*fms);
             *fms = NULL;
@@ -2052,8 +2133,8 @@ parse_bucket_str(struct ofputil_bucket *bucket, char *str_,
     }
 
     ofpact_pad(&ofpacts);
-    bucket->ofpacts = ofpacts.data;
-    bucket->ofpacts_len = ofpacts.size;
+    bucket->ofpacts = ofpbuf_data(&ofpacts);
+    bucket->ofpacts_len = ofpbuf_size(&ofpacts);
 
     return NULL;
 }
@@ -2089,7 +2170,7 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command,
         break;
 
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
     memset(gm, 0, sizeof *gm);
@@ -2259,7 +2340,12 @@ parse_ofp_group_mod_file(const char *file_name, uint16_t command,
         char *error;
 
         if (*n_gms >= allocated_gms) {
+            size_t i;
+
             *gms = x2nrealloc(*gms, &allocated_gms, sizeof **gms);
+            for (i = 0; i < *n_gms; i++) {
+                list_moved(&(*gms)[i].buckets);
+            }
         }
         error = parse_ofp_group_mod_str(&(*gms)[*n_gms], command, ds_cstr(&s),
                                         &usable);