ovs-ofctl: Accept port keywords, OF1.1 port numbers, reject port number 0.
[sliver-openvswitch.git] / lib / ofp-actions.c
index 0874cc4..19ed7a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -148,6 +148,58 @@ note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
     memcpy(note->data, nan->note, length);
 }
 
+static enum ofperr
+dec_ttl_from_openflow(struct ofpbuf *out)
+{
+    uint16_t id = 0;
+    struct ofpact_cnt_ids *ids;
+    enum ofperr error = 0;
+
+    ids = ofpact_put_DEC_TTL(out);
+    ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL;
+    ids->n_controllers = 1;
+    ofpbuf_put(out, &id, sizeof id);
+    ids = out->l2;
+    ofpact_update_len(out, &ids->ofpact);
+    return error;
+}
+
+static enum ofperr
+dec_ttl_cnt_ids_from_openflow(const struct nx_action_cnt_ids *nac_ids,
+                      struct ofpbuf *out)
+{
+    struct ofpact_cnt_ids *ids;
+    size_t ids_size;
+    int i;
+
+    ids = ofpact_put_DEC_TTL(out);
+    ids->ofpact.compat = OFPUTIL_NXAST_DEC_TTL_CNT_IDS;
+    ids->n_controllers = ntohs(nac_ids->n_controllers);
+    ids_size = ntohs(nac_ids->len) - sizeof *nac_ids;
+
+    if (!is_all_zeros(nac_ids->zeros, sizeof nac_ids->zeros)) {
+        return OFPERR_NXBRC_MUST_BE_ZERO;
+    }
+
+    if (ids_size < ids->n_controllers * sizeof(ovs_be16)) {
+        VLOG_WARN_RL(&rl, "Nicira action dec_ttl_cnt_ids only has %zu bytes "
+                     "allocated for controller ids.  %zu bytes are required for "
+                     "%"PRIu16" controllers.", ids_size,
+                     ids->n_controllers * sizeof(ovs_be16), ids->n_controllers);
+        return OFPERR_OFPBAC_BAD_LEN;
+    }
+
+    for (i = 0; i < ids->n_controllers; i++) {
+        uint16_t id = ntohs(((ovs_be16 *)(nac_ids + 1))[i]);
+        ofpbuf_put(out, &id, sizeof id);
+    }
+
+    ids = out->l2;
+    ofpact_update_len(out, &ids->ofpact);
+
+    return 0;
+}
+
 static enum ofperr
 decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code)
 {
@@ -231,6 +283,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     case OFPUTIL_ACTION_INVALID:
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
 #define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT12_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -281,7 +334,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;
@@ -310,7 +363,12 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         break;
 
     case OFPUTIL_NXAST_DEC_TTL:
-        ofpact_put_DEC_TTL(out);
+        error = dec_ttl_from_openflow(out);
+        break;
+
+    case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
+        error = dec_ttl_cnt_ids_from_openflow(
+                    (const struct nx_action_cnt_ids *) a, out);
         break;
 
     case OFPUTIL_NXAST_FIN_TIMEOUT:
@@ -340,6 +398,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 OFPAT12_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -602,6 +661,7 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT12_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         NOT_REACHED();
 
@@ -673,40 +733,14 @@ ofpacts_from_openflow11(const union ofp_action *in, size_t n_in,
 \f
 /* OpenFlow 1.1 instructions. */
 
-#define OVS_INSTRUCTIONS                                    \
-    DEFINE_INST(OFPIT11_GOTO_TABLE,                         \
-                ofp11_instruction_goto_table,     false,    \
-                "goto_table")                               \
-                                                            \
-    DEFINE_INST(OFPIT11_WRITE_METADATA,                     \
-                ofp11_instruction_write_metadata, false,    \
-                "write_metadata")                           \
-                                                            \
-    DEFINE_INST(OFPIT11_WRITE_ACTIONS,                      \
-                ofp11_instruction_actions,        true,     \
-                "write_actions")                            \
-                                                            \
-    DEFINE_INST(OFPIT11_APPLY_ACTIONS,                      \
-                ofp11_instruction_actions,        true,     \
-                "apply_actions")                            \
-                                                            \
-    DEFINE_INST(OFPIT11_CLEAR_ACTIONS,                      \
-                ofp11_instruction,                false,    \
-                "clear_actions")
-
-enum ovs_instruction_type {
-#define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) OVSINST_##ENUM,
-    OVS_INSTRUCTIONS
-#undef DEFINE_INST
-};
-
-enum {
-#define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
-    N_OVS_INSTRUCTIONS = OVS_INSTRUCTIONS
-#undef DEFINE_INST
-};
-
 #define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME)             \
+    static inline const struct STRUCT *                         \
+    instruction_get_##ENUM(const struct ofp11_instruction *inst)\
+    {                                                           \
+        assert(inst->type == htons(ENUM));                      \
+        return (struct STRUCT *)inst;                           \
+    }                                                           \
+                                                                \
     static inline void                                          \
     instruction_init_##ENUM(struct STRUCT *s)                   \
     {                                                           \
@@ -725,6 +759,35 @@ enum {
 OVS_INSTRUCTIONS
 #undef DEFINE_INST
 
+struct instruction_type_info {
+    enum ovs_instruction_type type;
+    const char *name;
+};
+
+static const struct instruction_type_info inst_info[] = {
+#define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME)    {OVSINST_##ENUM, NAME},
+OVS_INSTRUCTIONS
+#undef DEFINE_INST
+};
+
+const char *
+ofpact_instruction_name_from_type(enum ovs_instruction_type type)
+{
+    return inst_info[type].name;
+}
+
+int
+ofpact_instruction_type_from_name(const char *name)
+{
+    const struct instruction_type_info *p;
+    for (p = inst_info; p < &inst_info[ARRAY_SIZE(inst_info)]; p++) {
+        if (!strcasecmp(name, p->name)) {
+            return p->type;
+        }
+    }
+    return -1;
+}
+
 static inline struct ofp11_instruction *
 instruction_next(const struct ofp11_instruction *inst)
 {
@@ -797,7 +860,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;
     }
@@ -1073,6 +1136,29 @@ ofpact_controller_to_nxast(const struct ofpact_controller *oc,
     nac->reason = oc->reason;
 }
 
+static void
+ofpact_dec_ttl_to_nxast(const struct ofpact_cnt_ids *oc_ids,
+                        struct ofpbuf *out)
+{
+    if (oc_ids->ofpact.compat == OFPUTIL_NXAST_DEC_TTL) {
+        ofputil_put_NXAST_DEC_TTL(out);
+    } else {
+        struct nx_action_cnt_ids *nac_ids =
+            ofputil_put_NXAST_DEC_TTL_CNT_IDS(out);
+        int ids_len = ROUND_UP(2 * oc_ids->n_controllers, OFP_ACTION_ALIGN);
+        ovs_be16 *ids;
+        size_t i;
+
+        nac_ids->len = htons(ntohs(nac_ids->len) + ids_len);
+        nac_ids->n_controllers = htons(oc_ids->n_controllers);
+
+        ids = ofpbuf_put_zeros(out, ids_len);
+        for (i = 0; i < oc_ids->n_controllers; i++) {
+            ids[i] = htons(oc_ids->cnt_ids[i]);
+        }
+    }
+}
+
 static void
 ofpact_fin_timeout_to_nxast(const struct ofpact_fin_timeout *fin_timeout,
                             struct ofpbuf *out)
@@ -1107,7 +1193,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         break;
 
     case OFPACT_DEC_TTL:
-        ofputil_put_NXAST_DEC_TTL(out);
+        ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out);
         break;
 
     case OFPACT_SET_TUNNEL:
@@ -1384,15 +1470,18 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
 /* Converts the ofpacts in 'ofpacts' (terminated by OFPACT_END) into OpenFlow
  * 1.1 actions in 'openflow', appending the actions to any existing data in
  * 'openflow'. */
-void
+size_t
 ofpacts_put_openflow11_actions(const struct ofpact ofpacts[],
                                size_t ofpacts_len, struct ofpbuf *openflow)
 {
     const struct ofpact *a;
+    size_t start_size = openflow->size;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
         ofpact_to_openflow11(a, openflow);
     }
+
+    return openflow->size - start_size;
 }
 
 void
@@ -1499,6 +1588,25 @@ print_note(const struct ofpact_note *note, struct ds *string)
     }
 }
 
+static void
+print_dec_ttl(const struct ofpact_cnt_ids *ids,
+              struct ds *s)
+{
+    size_t i;
+
+    ds_put_cstr(s, "dec_ttl");
+    if (ids->ofpact.compat == OFPUTIL_NXAST_DEC_TTL_CNT_IDS) {
+        ds_put_cstr(s, "(");
+        for (i = 0; i < ids->n_controllers; i++) {
+            if (i) {
+                ds_put_cstr(s, ",");
+            }
+            ds_put_format(s, "%"PRIu16, ids->cnt_ids[i]);
+        }
+        ds_put_cstr(s, ")");
+    }
+}
+
 static void
 print_fin_timeout(const struct ofpact_fin_timeout *fin_timeout,
                   struct ds *s)
@@ -1635,7 +1743,7 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         break;
 
     case OFPACT_DEC_TTL:
-        ds_put_cstr(s, "dec_ttl");
+        print_dec_ttl(ofpact_get_DEC_TTL(a), s);
         break;
 
     case OFPACT_SET_TUNNEL:
@@ -1662,7 +1770,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) {
@@ -1686,7 +1795,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;