Merge branch 'hotfix' into make-improv
[sliver-openvswitch.git] / lib / ofp-parse.c
index 122f4b3..dedfb7e 100644 (file)
@@ -279,13 +279,12 @@ parse_controller(struct ofpbuf *b, char *arg)
 }
 
 static void
-parse_noargs_dec_ttl(struct ofpbuf *b, enum ofputil_action_code compat)
+parse_noargs_dec_ttl(struct ofpbuf *b)
 {
     struct ofpact_cnt_ids *ids;
     uint16_t id = 0;
 
     ids = ofpact_put_DEC_TTL(b);
-    ids->ofpact.compat = compat;
     ofpbuf_put(b, &id, sizeof id);
     ids = b->l2;
     ids->n_controllers++;
@@ -293,10 +292,10 @@ parse_noargs_dec_ttl(struct ofpbuf *b, enum ofputil_action_code compat)
 }
 
 static void
-parse_dec_ttl(struct ofpbuf *b, char *arg, enum ofputil_action_code compat)
+parse_dec_ttl(struct ofpbuf *b, char *arg)
 {
     if (*arg == '\0') {
-        parse_noargs_dec_ttl(b, compat);
+        parse_noargs_dec_ttl(b);
     } else {
         struct ofpact_cnt_ids *ids;
         char *cntr;
@@ -361,12 +360,31 @@ set_field_parse(const char *arg, struct ofpbuf *ofpacts)
     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;
@@ -407,6 +425,15 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         ofpact_put_STRIP_VLAN(ofpacts);
         break;
 
+    case OFPUTIL_OFPAT11_PUSH_VLAN:
+        ethertype = str_to_u16(arg, "ethertype");
+        if (ethertype != ETH_TYPE_VLAN_8021Q) {
+            /* TODO:XXXX 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_OFPAT10_SET_DL_SRC:
     case OFPUTIL_OFPAT11_SET_DL_SRC:
         str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
@@ -439,8 +466,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_OFPAT11_DEC_NW_TTL:
-        parse_noargs_dec_ttl(ofpacts, code);
-        break;
+        NOT_REACHED();
 
     case OFPUTIL_OFPAT10_SET_TP_SRC:
     case OFPUTIL_OFPAT11_SET_TP_SRC:
@@ -467,6 +493,10 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         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;
@@ -517,7 +547,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_NXAST_DEC_TTL:
-        parse_dec_ttl(ofpacts, arg, code);
+        parse_dec_ttl(ofpacts, arg);
         break;
 
     case OFPUTIL_NXAST_FIN_TIMEOUT:
@@ -562,6 +592,7 @@ static void
 str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
 {
     char *pos, *act, *arg;
+    enum ofperr error;
     int n_actions;
 
     pos = str;
@@ -572,6 +603,12 @@ str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
         }
         n_actions++;
     }
+
+    error = ofpacts_verify(ofpacts->data, ofpacts->size);
+    if (error) {
+        ovs_fatal(0, "Incorrect action ordering");
+    }
+
     ofpact_pad(ofpacts);
 }
 
@@ -579,6 +616,8 @@ 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() */
@@ -594,8 +633,7 @@ parse_named_instruction(enum ovs_instruction_type type,
         break;
 
     case OVSINST_OFPIT11_WRITE_METADATA:
-        /* TODO:XXX */
-        ovs_fatal(0, "instruction write-metadata is not supported yet");
+        parse_metadata(ofpacts, arg);
         break;
 
     case OVSINST_OFPIT11_GOTO_TABLE: {
@@ -608,6 +646,13 @@ parse_named_instruction(enum ovs_instruction_type type,
         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