ofp-actions: Make ofpacts_format() caller add "actions=" if it wants it.
[sliver-openvswitch.git] / lib / ofp-actions.c
index e1b44d8..1d0321a 100644 (file)
@@ -336,7 +336,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         break;
 
     case OFPUTIL_NXAST_WRITE_METADATA:
-        nawm = (const struct nx_action_write_metadata *) a;
+        nawm = ALIGNED_CAST(const struct nx_action_write_metadata *, a);
         error = metadata_from_nxast(nawm, out);
         break;
 
@@ -356,7 +356,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
 
     case OFPUTIL_NXAST_REG_LOAD:
         error = nxm_reg_load_from_openflow(
-            (const struct nx_action_reg_load *) a, out);
+            ALIGNED_CAST(const struct nx_action_reg_load *, a), out);
         break;
 
     case OFPUTIL_NXAST_STACK_PUSH:
@@ -375,7 +375,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         break;
 
     case OFPUTIL_NXAST_SET_TUNNEL64:
-        nast64 = (const struct nx_action_set_tunnel64 *) a;
+        nast64 = ALIGNED_CAST(const struct nx_action_set_tunnel64 *, a);
         tunnel = ofpact_put_SET_TUNNEL(out);
         tunnel->ofpact.compat = code;
         tunnel->tun_id = ntohll(nast64->tun_id);
@@ -402,7 +402,8 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         break;
 
     case OFPUTIL_NXAST_LEARN:
-        error = learn_from_openflow((const struct nx_action_learn *) a, out);
+        error = learn_from_openflow(
+            ALIGNED_CAST(const struct nx_action_learn *, a), out);
         break;
 
     case OFPUTIL_NXAST_EXIT:
@@ -859,6 +860,12 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         break;
     }
 
+    case OFPUTIL_OFPAT11_GROUP: {
+        struct ofp11_action_group *oag = (struct ofp11_action_group *)a;
+        ofpact_put_GROUP(out)->group_id = ntohl(oag->group_id);
+        break;
+    }
+
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         return ofpact_from_nxast(a, code, out);
@@ -877,14 +884,14 @@ ofpacts_from_openflow11(const union ofp_action *in, size_t n_in,
 /* OpenFlow 1.1 instructions. */
 
 #define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME)             \
-    static inline const struct STRUCT *                         \
+    static inline const struct STRUCT * OVS_UNUSED              \
     instruction_get_##ENUM(const struct ofp11_instruction *inst)\
     {                                                           \
         ovs_assert(inst->type == htons(ENUM));                  \
-        return (struct STRUCT *)inst;                           \
+        return ALIGNED_CAST(struct STRUCT *, inst);             \
     }                                                           \
                                                                 \
-    static inline void                                          \
+    static inline void OVS_UNUSED                               \
     instruction_init_##ENUM(struct STRUCT *s)                   \
     {                                                           \
         memset(s, 0, sizeof *s);                                \
@@ -892,7 +899,7 @@ ofpacts_from_openflow11(const union ofp_action *in, size_t n_in,
         s->len = htons(sizeof *s);                              \
     }                                                           \
                                                                 \
-    static inline struct STRUCT *                               \
+    static inline struct STRUCT * OVS_UNUSED                    \
     instruction_put_##ENUM(struct ofpbuf *buf)                  \
     {                                                           \
         struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s);   \
@@ -944,6 +951,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
     case OFPACT_GOTO_TABLE:
         return OVSINST_OFPIT11_GOTO_TABLE;
     case OFPACT_OUTPUT:
+    case OFPACT_GROUP:
     case OFPACT_CONTROLLER:
     case OFPACT_ENQUEUE:
     case OFPACT_OUTPUT_REG:
@@ -1070,10 +1078,10 @@ decode_openflow11_instructions(const struct ofp11_instruction insts[],
 
 static void
 get_actions_from_instruction(const struct ofp11_instruction *inst,
-                         const union ofp_action **actions,
-                         size_t *n_actions)
+                             const union ofp_action **actions,
+                             size_t *n_actions)
 {
-    *actions = (const union ofp_action *) (inst + 1);
+    *actions = ALIGNED_CAST(const union ofp_action *, inst + 1);
     *n_actions = (ntohs(inst->len) - sizeof *inst) / OFP11_INSTRUCTION_ALIGN;
 }
 
@@ -1103,7 +1111,6 @@ ofpacts_pull_openflow11_actions(struct ofpbuf *openflow,
 enum ofperr
 ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
                                      unsigned int instructions_len,
-                                     uint8_t table_id,
                                      struct ofpbuf *ofpacts)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
@@ -1141,8 +1148,8 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
         const struct ofp13_instruction_meter *oim;
         struct ofpact_meter *om;
 
-        oim = (const struct ofp13_instruction_meter *)
-            insts[OVSINST_OFPIT13_METER];
+        oim = ALIGNED_CAST(const struct ofp13_instruction_meter *,
+                           insts[OVSINST_OFPIT13_METER]);
 
         om = ofpact_put_METER(ofpacts);
         om->meter_id = ntohl(oim->meter_id);
@@ -1168,8 +1175,8 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
         const struct ofp11_instruction_write_metadata *oiwm;
         struct ofpact_metadata *om;
 
-        oiwm = (const struct ofp11_instruction_write_metadata *)
-            insts[OVSINST_OFPIT11_WRITE_METADATA];
+        oiwm = ALIGNED_CAST(const struct ofp11_instruction_write_metadata *,
+                            insts[OVSINST_OFPIT11_WRITE_METADATA]);
 
         om = ofpact_put_WRITE_METADATA(ofpacts);
         om->metadata = oiwm->metadata;
@@ -1181,10 +1188,6 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
 
         oigt = instruction_get_OFPIT11_GOTO_TABLE(
             insts[OVSINST_OFPIT11_GOTO_TABLE]);
-        if (table_id >= oigt->table_id) {
-            error = OFPERR_OFPBRC_BAD_TABLE_ID;
-            goto exit;
-        }
         ogt = ofpact_put_GOTO_TABLE(ofpacts);
         ogt->table_id = oigt->table_id;
     }
@@ -1204,7 +1207,8 @@ exit:
 \f
 /* May modify flow->dl_type, caller must restore it. */
 static enum ofperr
-ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports)
+ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports,
+               uint8_t table_id)
 {
     const struct ofpact_enqueue *enqueue;
 
@@ -1289,7 +1293,6 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports)
 
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_WRITE_METADATA:
-    case OFPACT_GOTO_TABLE:
         return 0;
 
     case OFPACT_METER: {
@@ -1299,6 +1302,16 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports)
         }
         return 0;
     }
+
+    case OFPACT_GOTO_TABLE:
+        if (ofpact_get_GOTO_TABLE(a)->table_id <= table_id) {
+            return OFPERR_OFPBRC_BAD_TABLE_ID;
+        }
+        return 0;
+
+    case OFPACT_GROUP:
+        return 0;
+
     default:
         NOT_REACHED();
     }
@@ -1311,14 +1324,14 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports)
  * May temporarily modify 'flow', but restores the changes before returning. */
 enum ofperr
 ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
-              struct flow *flow, ofp_port_t max_ports)
+              struct flow *flow, ofp_port_t max_ports, uint8_t table_id)
 {
     const struct ofpact *a;
     ovs_be16 dl_type = flow->dl_type;
     enum ofperr error = 0;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
-        error = ofpact_check__(a, flow, max_ports);
+        error = ofpact_check__(a, flow, max_ports, table_id);
         if (error) {
             break;
         }
@@ -1434,7 +1447,7 @@ ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out)
     if (remainder) {
         ofpbuf_put_zeros(out, OFP_ACTION_ALIGN - remainder);
     }
-    nan = (struct nx_action_note *)((char *)out->data + start_ofs);
+    nan = ofpbuf_at(out, start_ofs, sizeof *nan);
     nan->len = htons(out->size - start_ofs);
 }
 
@@ -1595,6 +1608,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         ofpact_sample_to_nxast(ofpact_get_SAMPLE(a), out);
         break;
 
+    case OFPACT_GROUP:
     case OFPACT_OUTPUT:
     case OFPACT_ENQUEUE:
     case OFPACT_SET_VLAN_VID:
@@ -1707,6 +1721,9 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
         /* XXX */
         break;
 
+    case OFPACT_GROUP:
+        break;
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
@@ -1879,6 +1896,11 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_METER:
         NOT_REACHED();
 
+    case OFPACT_GROUP:
+        ofputil_put_OFPAT11_GROUP(out)->group_id =
+            htonl(ofpact_get_GROUP(a)->group_id);
+        break;
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
@@ -2048,6 +2070,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
     case OFPACT_METER:
+    case OFPACT_GROUP:
     default:
         return false;
     }
@@ -2070,12 +2093,54 @@ ofpacts_output_to_port(const struct ofpact *ofpacts, size_t ofpacts_len,
     return false;
 }
 
+/* Returns true if any action in the 'ofpacts_len' bytes of 'ofpacts' outputs
+ * to 'group', false otherwise. */
+bool
+ofpacts_output_to_group(const struct ofpact *ofpacts, size_t ofpacts_len,
+                        uint32_t group_id)
+{
+    const struct ofpact *a;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        if (a->type == OFPACT_GROUP
+            && ofpact_get_GROUP(a)->group_id == group_id) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 bool
 ofpacts_equal(const struct ofpact *a, size_t a_len,
               const struct ofpact *b, size_t b_len)
 {
     return a_len == b_len && !memcmp(a, b, a_len);
 }
+
+/* Finds the OFPACT_METER action, if any, in the 'ofpacts_len' bytes of
+ * 'ofpacts'.  If found, returns its meter ID; if not, returns 0.
+ *
+ * This function relies on the order of 'ofpacts' being correct (as checked by
+ * ofpacts_verify()). */
+uint32_t
+ofpacts_get_meter(const struct ofpact ofpacts[], size_t ofpacts_len)
+{
+    const struct ofpact *a;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        enum ovs_instruction_type inst;
+
+        inst = ovs_instruction_type_from_ofpact_type(a->type);
+        if (a->type == OFPACT_METER) {
+            return ofpact_get_METER(a)->meter_id;
+        } else if (inst > OVSINST_OFPIT13_METER) {
+            break;
+        }
+    }
+
+    return 0;
+}
 \f
 /* Formatting ofpacts. */
 
@@ -2363,7 +2428,7 @@ ofpact_format(const struct ofpact *a, struct ds *s)
                       ovs_instruction_name_from_type(
                           OVSINST_OFPIT11_WRITE_METADATA),
                       ntohll(metadata->metadata));
-        if (metadata->mask != htonll(UINT64_MAX)) {
+        if (metadata->mask != OVS_BE64_MAX) {
             ds_put_format(s, "/%#"PRIx64, ntohll(metadata->mask));
         }
         break;
@@ -2380,6 +2445,11 @@ ofpact_format(const struct ofpact *a, struct ds *s)
                       ovs_instruction_name_from_type(OVSINST_OFPIT13_METER),
                       ofpact_get_METER(a)->meter_id);
         break;
+
+    case OFPACT_GROUP:
+        ds_put_format(s, "group:%"PRIu32,
+                      ofpact_get_GROUP(a)->group_id);
+        break;
     }
 }
 
@@ -2389,7 +2459,6 @@ void
 ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len,
                struct ds *string)
 {
-    ds_put_cstr(string, "actions=");
     if (!ofpacts_len) {
         ds_put_cstr(string, "drop");
     } else {