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;
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:
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);
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:
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);
/* 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); \
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); \
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:
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;
}
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);
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);
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;
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;
}
\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;
case OFPACT_CLEAR_ACTIONS:
case OFPACT_WRITE_METADATA:
- case OFPACT_GOTO_TABLE:
return 0;
case OFPACT_METER: {
}
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();
}
* 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;
}
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);
}
ofpact_sample_to_nxast(ofpact_get_SAMPLE(a), out);
break;
+ case OFPACT_GROUP:
case OFPACT_OUTPUT:
case OFPACT_ENQUEUE:
case OFPACT_SET_VLAN_VID:
/* XXX */
break;
+ case OFPACT_GROUP:
+ break;
+
case OFPACT_CONTROLLER:
case OFPACT_OUTPUT_REG:
case OFPACT_BUNDLE:
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:
case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE:
case OFPACT_METER:
+ case OFPACT_GROUP:
default:
return false;
}
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. */
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;
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;
}
}
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 {