instruction/clear-actions: string parser/formater, of packet decoder/encoder
[sliver-openvswitch.git] / lib / ofp-actions.c
index 0e8b9da..4a72e29 100644 (file)
@@ -282,7 +282,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -333,7 +333,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
                                         ofpact_put_MULTIPATH(out));
         break;
 
-    case OFPUTIL_NXAST_AUTOPATH:
+    case OFPUTIL_NXAST_AUTOPATH__DEPRECATED:
         error = autopath_from_openflow((const struct nx_action_autopath *) a,
                                        ofpact_put_AUTOPATH(out));
         break;
@@ -396,7 +396,7 @@ ofpact_from_openflow10(const union ofp_action *a, struct ofpbuf *out)
 
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -607,19 +607,24 @@ static enum ofperr
 decode_openflow11_action(const union ofp_action *a,
                          enum ofputil_action_code *code)
 {
+    uint16_t len;
+
     switch (a->type) {
     case CONSTANT_HTONS(OFPAT11_EXPERIMENTER):
         return decode_nxast_action(a, code);
 
-#define OFPAT11_ACTION(ENUM, STRUCT, NAME)                          \
-        case CONSTANT_HTONS(ENUM):                                  \
-            if (a->header.len == htons(sizeof(struct STRUCT))) {    \
-                *code = OFPUTIL_##ENUM;                             \
-                return 0;                                           \
-            } else {                                                \
-                return OFPERR_OFPBAC_BAD_LEN;                       \
-            }                                                       \
-            break;
+#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)  \
+        case CONSTANT_HTONS(ENUM):                      \
+            len = ntohs(a->header.len);                 \
+            if (EXTENSIBLE                              \
+                ? len >= sizeof(struct STRUCT)          \
+                : len == sizeof(struct STRUCT)) {       \
+                *code = OFPUTIL_##ENUM;                 \
+                return 0;                               \
+            } else {                                    \
+                return OFPERR_OFPBAC_BAD_LEN;           \
+            }                                           \
+            NOT_REACHED();
 #include "ofp-util.def"
 
     default:
@@ -713,6 +718,10 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(a->tp_port.tp_port);
         break;
 
+    case OFPUTIL_OFPAT12_SET_FIELD:
+        return nxm_reg_load_from_openflow12_set_field(
+            (const struct ofp12_action_set_field *)a, out);
+
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         return ofpact_from_nxast(a, code, out);
@@ -770,13 +779,7 @@ OVS_INSTRUCTIONS
 const char *
 ofpact_instruction_name_from_type(enum ovs_instruction_type type)
 {
-    const struct instruction_type_info *p;
-    for (p = inst_info; p < &inst_info[ARRAY_SIZE(inst_info)]; p++) {
-        if (p->type == type) {
-            return p->name;
-        }
-    }
-    return NULL;
+    return inst_info[type].name;
 }
 
 int
@@ -863,7 +866,7 @@ decode_openflow11_instructions(const struct ofp11_instruction insts[],
         }
 
         if (out[type]) {
-            return OFPERR_NXBIC_DUP_TYPE;
+            return OFPERR_OFPIT_BAD_INSTRUCTION;
         }
         out[type] = inst;
     }
@@ -955,11 +958,25 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
             goto exit;
         }
     }
+    if (insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+        instruction_get_OFPIT11_CLEAR_ACTIONS(
+            insts[OVSINST_OFPIT11_CLEAR_ACTIONS]);
+        ofpact_put_CLEAR_ACTIONS(ofpacts);
+    }
+    /* TODO:XXX Write-Actions */
+    /* TODO:XXX Write-Metadata */
+    if (insts[OVSINST_OFPIT11_GOTO_TABLE]) {
+        const struct ofp11_instruction_goto_table *oigt;
+        struct ofpact_goto_table *ogt;
+
+        oigt = instruction_get_OFPIT11_GOTO_TABLE(
+            insts[OVSINST_OFPIT11_GOTO_TABLE]);
+        ogt = ofpact_put_GOTO_TABLE(ofpacts);
+        ogt->table_id = oigt->table_id;
+    }
 
-    if (insts[OVSINST_OFPIT11_GOTO_TABLE] ||
-        insts[OVSINST_OFPIT11_WRITE_METADATA] ||
-        insts[OVSINST_OFPIT11_WRITE_ACTIONS] ||
-        insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+    if (insts[OVSINST_OFPIT11_WRITE_METADATA] ||
+        insts[OVSINST_OFPIT11_WRITE_ACTIONS]) {
         error = OFPERR_OFPBIC_UNSUP_INST;
         goto exit;
     }
@@ -1037,6 +1054,10 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
     case OFPACT_EXIT:
         return 0;
 
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
+        return 0;
+
     default:
         NOT_REACHED();
     }
@@ -1252,6 +1273,8 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_SET_IPV4_DSCP:
     case OFPACT_SET_L4_SRC_PORT:
     case OFPACT_SET_L4_DST_PORT:
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
         NOT_REACHED();
     }
 }
@@ -1341,6 +1364,11 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
             = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
         break;
 
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
+        /* TODO:XXX */
+        break;
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
@@ -1449,6 +1477,10 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
             = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
         break;
 
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
+        NOT_REACHED();
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
@@ -1487,18 +1519,10 @@ ofpacts_put_openflow11_actions(const struct ofpact ofpacts[],
     return openflow->size - start_size;
 }
 
-void
-ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
-                                    size_t ofpacts_len,
-                                    struct ofpbuf *openflow)
+static void
+ofpacts_update_instruction_actions(struct ofpbuf *openflow, size_t ofs)
 {
     struct ofp11_instruction_actions *oia;
-    size_t ofs;
-
-    /* Put an OFPIT11_APPLY_ACTIONS instruction and fill it in. */
-    ofs = openflow->size;
-    instruction_put_OFPIT11_APPLY_ACTIONS(openflow);
-    ofpacts_put_openflow11_actions(ofpacts, ofpacts_len, openflow);
 
     /* Update the instruction's length (or, if it's empty, delete it). */
     oia = ofpbuf_at_assert(openflow, ofs, sizeof *oia);
@@ -1508,6 +1532,47 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
         openflow->size = ofs;
     }
 }
+
+void
+ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
+                                    size_t ofpacts_len,
+                                    struct ofpbuf *openflow)
+{
+    const struct ofpact *a;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        /* TODO:XXX Write-Actions */
+        /* TODO:XXX Write-Metadata */
+        if (a->type == OFPACT_CLEAR_ACTIONS) {
+            struct ofp11_instruction *oi;
+            oi = instruction_put_OFPIT11_CLEAR_ACTIONS(openflow);
+        } else if (a->type == OFPACT_GOTO_TABLE) {
+            struct ofp11_instruction_goto_table *oigt;
+
+            oigt = instruction_put_OFPIT11_GOTO_TABLE(openflow);
+            oigt->table_id = ofpact_get_GOTO_TABLE(a)->table_id;
+            memset(oigt->pad, 0, sizeof oigt->pad);
+        } else if (!ofpact_is_instruction(a)) {
+            /* Apply-actions */
+            const size_t ofs = openflow->size;
+            const size_t ofpacts_len_left =
+                (uint8_t*)ofpact_end(ofpacts, ofpacts_len) - (uint8_t*)a;
+            const struct ofpact *action;
+            const struct ofpact *processed = a;
+
+            instruction_put_OFPIT11_APPLY_ACTIONS(openflow);
+            OFPACT_FOR_EACH(action, a, ofpacts_len_left) {
+                if (ofpact_is_instruction(action)) {
+                    break;
+                }
+                ofpact_to_openflow11(action, openflow);
+                processed = action;
+            }
+            ofpacts_update_instruction_actions(openflow, ofs);
+            a = processed;
+        }
+    }
+}
 \f
 /* Returns true if 'action' outputs to 'port', false otherwise. */
 static bool
@@ -1546,6 +1611,8 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_CLEAR_ACTIONS:
+    case OFPACT_GOTO_TABLE:
     default:
         return false;
     }
@@ -1773,7 +1840,8 @@ ofpact_format(const struct ofpact *a, struct ds *s)
     case OFPACT_RESUBMIT:
         resubmit = ofpact_get_RESUBMIT(a);
         if (resubmit->in_port != OFPP_IN_PORT && resubmit->table_id == 255) {
-            ds_put_format(s, "resubmit:%"PRIu16, resubmit->in_port);
+            ds_put_cstr(s, "resubmit:");
+            ofputil_format_port(resubmit->in_port, s);
         } else {
             ds_put_format(s, "resubmit(");
             if (resubmit->in_port != OFPP_IN_PORT) {
@@ -1797,7 +1865,9 @@ ofpact_format(const struct ofpact *a, struct ds *s)
 
     case OFPACT_AUTOPATH:
         autopath = ofpact_get_AUTOPATH(a);
-        ds_put_format(s, "autopath(%u,", autopath->port);
+        ds_put_cstr(s, "autopath(");
+        ofputil_format_port(autopath->port, s);
+        ds_put_char(s, ',');
         mf_format_subfield(&autopath->dst, s);
         ds_put_char(s, ')');
         break;
@@ -1809,6 +1879,19 @@ ofpact_format(const struct ofpact *a, struct ds *s)
     case OFPACT_EXIT:
         ds_put_cstr(s, "exit");
         break;
+
+    case OFPACT_CLEAR_ACTIONS:
+        ds_put_format(s, "%s",
+                      ofpact_instruction_name_from_type(
+                          OVSINST_OFPIT11_CLEAR_ACTIONS));
+        break;
+
+    case OFPACT_GOTO_TABLE:
+        ds_put_format(s, "%s:%"PRIu8,
+                      ofpact_instruction_name_from_type(
+                          OVSINST_OFPIT11_GOTO_TABLE),
+                      ofpact_get_GOTO_TABLE(a)->table_id);
+        break;
     }
 }
 
@@ -1828,6 +1911,9 @@ ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len,
             if (a != ofpacts) {
                 ds_put_cstr(string, ",");
             }
+
+            /* TODO:XXX write-actions */
+            /* TODO:XXX write-metadata */
             ofpact_format(a, string);
         }
     }
@@ -1886,3 +1972,15 @@ ofpact_pad(struct ofpbuf *ofpacts)
         ofpbuf_put_zeros(ofpacts, OFPACT_ALIGNTO - rem);
     }
 }
+
+void
+ofpact_set_field_init(struct ofpact_reg_load *load, const struct mf_field *mf,
+                      const void *src)
+{
+    load->ofpact.compat = OFPUTIL_OFPAT12_SET_FIELD;
+    load->dst.field = mf;
+    load->dst.ofs = 0;
+    load->dst.n_bits = mf->n_bits;
+    bitwise_copy(src, mf->n_bytes, load->dst.ofs,
+                 &load->subvalue, sizeof load->subvalue, 0, mf->n_bits);
+}