/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <config.h>
#include "ofp-actions.h"
-#include "autopath.h"
#include "bundle.h"
#include "byte-order.h"
#include "compiler.h"
#include "nx-match.h"
#include "ofp-util.h"
#include "ofpbuf.h"
+#include "util.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(ofp_actions);
struct ofpact_output *output;
output = ofpact_put_OUTPUT(out);
- output->port = ntohs(oao->port);
+ output->port = u16_to_ofp(ntohs(oao->port));
output->max_len = ntohs(oao->max_len);
return ofputil_check_output_port(output->port, OFPP_MAX);
}
static enum ofperr
-enqueue_from_openflow10(const struct ofp_action_enqueue *oae,
+enqueue_from_openflow10(const struct ofp10_action_enqueue *oae,
struct ofpbuf *out)
{
struct ofpact_enqueue *enqueue;
enqueue = ofpact_put_ENQUEUE(out);
- enqueue->port = ntohs(oae->port);
+ enqueue->port = u16_to_ofp(ntohs(oae->port));
enqueue->queue = ntohl(oae->queue_id);
- if (enqueue->port >= OFPP_MAX && enqueue->port != OFPP_IN_PORT
+ if (ofp_to_u16(enqueue->port) >= ofp_to_u16(OFPP_MAX)
+ && enqueue->port != OFPP_IN_PORT
&& enqueue->port != OFPP_LOCAL) {
return OFPERR_OFPBAC_BAD_OUT_PORT;
}
resubmit = ofpact_put_RESUBMIT(out);
resubmit->ofpact.compat = OFPUTIL_NXAST_RESUBMIT;
- resubmit->in_port = ntohs(nar->in_port);
+ resubmit->in_port = u16_to_ofp(ntohs(nar->in_port));
resubmit->table_id = 0xff;
}
resubmit = ofpact_put_RESUBMIT(out);
resubmit->ofpact.compat = OFPUTIL_NXAST_RESUBMIT_TABLE;
- resubmit->in_port = ntohs(nar->in_port);
+ resubmit->in_port = u16_to_ofp(ntohs(nar->in_port));
resubmit->table_id = nar->table;
return 0;
}
oc->reason = nac->reason;
}
+static enum ofperr
+metadata_from_nxast(const struct nx_action_write_metadata *nawm,
+ struct ofpbuf *out)
+{
+ struct ofpact_metadata *om;
+
+ if (!is_all_zeros(nawm->zeros, sizeof nawm->zeros)) {
+ return OFPERR_NXBRC_MUST_BE_ZERO;
+ }
+
+ om = ofpact_put_WRITE_METADATA(out);
+ om->metadata = nawm->metadata;
+ om->mask = nawm->mask;
+
+ return 0;
+}
+
static void
note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
{
}
static enum ofperr
-dec_ttl_from_openflow(struct ofpbuf *out)
+dec_ttl_from_openflow(struct ofpbuf *out, enum ofputil_action_code compat)
{
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->ofpact.compat = compat;
ids->n_controllers = 1;
ofpbuf_put(out, &id, sizeof id);
ids = out->l2;
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;
}
- ids = out->l2;
ofpact_update_len(out, &ids->ofpact);
return 0;
}
+static enum ofperr
+sample_from_openflow(const struct nx_action_sample *nas,
+ struct ofpbuf *out)
+{
+ struct ofpact_sample *sample;
+
+ sample = ofpact_put_SAMPLE(out);
+ sample->probability = ntohs(nas->probability);
+ sample->collector_set_id = ntohl(nas->collector_set_id);
+ sample->obs_domain_id = ntohl(nas->obs_domain_id);
+ sample->obs_point_id = ntohl(nas->obs_point_id);
+
+ if (sample->probability == 0) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+
+ return 0;
+}
+
static enum ofperr
decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code)
{
const struct nx_action_set_queue *nasq;
const struct nx_action_note *nan;
const struct nx_action_set_tunnel64 *nast64;
+ const struct nx_action_write_metadata *nawm;
struct ofpact_tunnel *tunnel;
enum ofperr error = 0;
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();
tunnel->tun_id = ntohl(nast->tun_id);
break;
+ case OFPUTIL_NXAST_WRITE_METADATA:
+ nawm = ALIGNED_CAST(const struct nx_action_write_metadata *, a);
+ error = metadata_from_nxast(nawm, out);
+ break;
+
case OFPUTIL_NXAST_SET_QUEUE:
nasq = (const struct nx_action_set_queue *) a;
ofpact_put_SET_QUEUE(out)->queue_id = ntohl(nasq->queue_id);
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:
+ error = nxm_stack_push_from_openflow(
+ (const struct nx_action_stack *) a, out);
+ break;
+
+ case OFPUTIL_NXAST_STACK_POP:
+ error = nxm_stack_pop_from_openflow(
+ (const struct nx_action_stack *) a, out);
break;
case OFPUTIL_NXAST_NOTE:
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);
ofpact_put_MULTIPATH(out));
break;
- case OFPUTIL_NXAST_AUTOPATH__DEPRECATED:
- error = autopath_from_openflow((const struct nx_action_autopath *) a,
- ofpact_put_AUTOPATH(out));
- break;
-
case OFPUTIL_NXAST_BUNDLE:
case OFPUTIL_NXAST_BUNDLE_LOAD:
error = bundle_from_openflow((const struct nx_action_bundle *) a, out);
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_NXAST_DEC_TTL:
- error = dec_ttl_from_openflow(out);
+ error = dec_ttl_from_openflow(out, code);
break;
case OFPUTIL_NXAST_DEC_TTL_CNT_IDS:
case OFPUTIL_NXAST_CONTROLLER:
controller_from_openflow((const struct nx_action_controller *) a, out);
break;
+
+ case OFPUTIL_NXAST_PUSH_MPLS: {
+ struct nx_action_push_mpls *nxapm = (struct nx_action_push_mpls *)a;
+ if (!eth_type_mpls(nxapm->ethertype)) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ ofpact_put_PUSH_MPLS(out)->ethertype = nxapm->ethertype;
+ break;
+ }
+
+ case OFPUTIL_NXAST_SET_MPLS_TTL: {
+ struct nx_action_mpls_ttl *nxamt = (struct nx_action_mpls_ttl *)a;
+ ofpact_put_SET_MPLS_TTL(out)->ttl = nxamt->ttl;
+ break;
+ }
+
+ case OFPUTIL_NXAST_DEC_MPLS_TTL:
+ ofpact_put_DEC_MPLS_TTL(out);
+ break;
+
+ case OFPUTIL_NXAST_POP_MPLS: {
+ struct nx_action_pop_mpls *nxapm = (struct nx_action_pop_mpls *)a;
+ if (eth_type_mpls(nxapm->ethertype)) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ ofpact_put_POP_MPLS(out)->ethertype = nxapm->ethertype;
+ break;
+ }
+
+ case OFPUTIL_NXAST_SAMPLE:
+ error = sample_from_openflow(
+ (const struct nx_action_sample *) a, out);
+ break;
}
return error;
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();
break;
case OFPUTIL_OFPAT10_ENQUEUE:
- error = enqueue_from_openflow10((const struct ofp_action_enqueue *) a,
+ error = enqueue_from_openflow10((const struct ofp10_action_enqueue *) a,
out);
break;
}
error = translate(actions, actions_len / OFP_ACTION_ALIGN, ofpacts);
+ if (error) {
+ ofpbuf_clear(ofpacts);
+ return error;
+ }
+
+ error = ofpacts_verify(ofpacts->data, ofpacts->size);
if (error) {
ofpbuf_clear(ofpacts);
}
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:
ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
break;
+ case OFPUTIL_OFPAT11_PUSH_VLAN:
+ if (((const struct ofp11_action_push *)a)->ethertype !=
+ htons(ETH_TYPE_VLAN_8021Q)) {
+ /* XXX 802.1AD(QinQ) isn't supported at the moment */
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ ofpact_put_PUSH_VLAN(out);
+ break;
+
+ case OFPUTIL_OFPAT11_POP_VLAN:
+ ofpact_put_STRIP_VLAN(out);
+ break;
+
+ case OFPUTIL_OFPAT11_SET_QUEUE:
+ ofpact_put_SET_QUEUE(out)->queue_id =
+ ntohl(((const struct ofp11_action_set_queue *)a)->queue_id);
+ break;
+
case OFPUTIL_OFPAT11_SET_DL_SRC:
memcpy(ofpact_put_SET_ETH_SRC(out)->mac,
((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
break;
+ case OFPUTIL_OFPAT11_DEC_NW_TTL:
+ dec_ttl_from_openflow(out, code);
+ break;
+
case OFPUTIL_OFPAT11_SET_NW_SRC:
ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
break;
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);
+
+ case OFPUTIL_OFPAT11_SET_MPLS_TTL: {
+ struct ofp11_action_mpls_ttl *oamt = (struct ofp11_action_mpls_ttl *)a;
+ ofpact_put_SET_MPLS_TTL(out)->ttl = oamt->mpls_ttl;
+ break;
+ }
+
+ case OFPUTIL_OFPAT11_DEC_MPLS_TTL:
+ ofpact_put_DEC_MPLS_TTL(out);
+ break;
+
+ case OFPUTIL_OFPAT11_PUSH_MPLS: {
+ struct ofp11_action_push *oap = (struct ofp11_action_push *)a;
+ if (!eth_type_mpls(oap->ethertype)) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ ofpact_put_PUSH_MPLS(out)->ethertype = oap->ethertype;
+ break;
+ }
+
+ case OFPUTIL_OFPAT11_POP_MPLS: {
+ struct ofp11_action_pop_mpls *oapm = (struct ofp11_action_pop_mpls *)a;
+ if (eth_type_mpls(oapm->ethertype)) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+ ofpact_put_POP_MPLS(out)->ethertype = oapm->ethertype;
+ 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);
static inline const struct STRUCT * \
instruction_get_##ENUM(const struct ofp11_instruction *inst)\
{ \
- assert(inst->type == htons(ENUM)); \
- return (struct STRUCT *)inst; \
+ ovs_assert(inst->type == htons(ENUM)); \
+ return ALIGNED_CAST(struct STRUCT *, inst); \
} \
\
static inline void \
};
const char *
-ofpact_instruction_name_from_type(enum ovs_instruction_type type)
+ovs_instruction_name_from_type(enum ovs_instruction_type type)
{
return inst_info[type].name;
}
int
-ofpact_instruction_type_from_name(const char *name)
+ovs_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++) {
return -1;
}
+enum ovs_instruction_type
+ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
+{
+ switch (type) {
+ case OFPACT_METER:
+ return OVSINST_OFPIT13_METER;
+ case OFPACT_CLEAR_ACTIONS:
+ return OVSINST_OFPIT11_CLEAR_ACTIONS;
+ case OFPACT_WRITE_METADATA:
+ return OVSINST_OFPIT11_WRITE_METADATA;
+ 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:
+ case OFPACT_BUNDLE:
+ case OFPACT_SET_VLAN_VID:
+ case OFPACT_SET_VLAN_PCP:
+ case OFPACT_STRIP_VLAN:
+ case OFPACT_PUSH_VLAN:
+ case OFPACT_SET_ETH_SRC:
+ case OFPACT_SET_ETH_DST:
+ case OFPACT_SET_IPV4_SRC:
+ case OFPACT_SET_IPV4_DST:
+ case OFPACT_SET_IPV4_DSCP:
+ case OFPACT_SET_L4_SRC_PORT:
+ case OFPACT_SET_L4_DST_PORT:
+ case OFPACT_REG_MOVE:
+ case OFPACT_REG_LOAD:
+ case OFPACT_STACK_PUSH:
+ case OFPACT_STACK_POP:
+ case OFPACT_DEC_TTL:
+ case OFPACT_SET_MPLS_TTL:
+ case OFPACT_DEC_MPLS_TTL:
+ case OFPACT_PUSH_MPLS:
+ case OFPACT_POP_MPLS:
+ case OFPACT_SET_TUNNEL:
+ case OFPACT_SET_QUEUE:
+ case OFPACT_POP_QUEUE:
+ case OFPACT_FIN_TIMEOUT:
+ case OFPACT_RESUBMIT:
+ case OFPACT_LEARN:
+ case OFPACT_MULTIPATH:
+ case OFPACT_NOTE:
+ case OFPACT_EXIT:
+ case OFPACT_SAMPLE:
+ default:
+ return OVSINST_OFPIT11_APPLY_ACTIONS;
+ }
+}
+
static inline struct ofp11_instruction *
instruction_next(const struct ofp11_instruction *inst)
{
}
if (out[type]) {
- return OFPERR_NXBIC_DUP_TYPE;
+ return OFPERR_ONFBIC_DUP_INSTRUCTION;
}
out[type] = inst;
}
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;
}
goto exit;
}
+ if (insts[OVSINST_OFPIT13_METER]) {
+ const struct ofp13_instruction_meter *oim;
+ struct ofpact_meter *om;
+
+ oim = ALIGNED_CAST(const struct ofp13_instruction_meter *,
+ insts[OVSINST_OFPIT13_METER]);
+
+ om = ofpact_put_METER(ofpacts);
+ om->meter_id = ntohl(oim->meter_id);
+ }
if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) {
const union ofp_action *actions;
size_t n_actions;
goto exit;
}
}
+ if (insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+ instruction_get_OFPIT11_CLEAR_ACTIONS(
+ insts[OVSINST_OFPIT11_CLEAR_ACTIONS]);
+ ofpact_put_CLEAR_ACTIONS(ofpacts);
+ }
+ /* XXX Write-Actions */
+ if (insts[OVSINST_OFPIT11_WRITE_METADATA]) {
+ const struct ofp11_instruction_write_metadata *oiwm;
+ struct ofpact_metadata *om;
+
+ oiwm = ALIGNED_CAST(const struct ofp11_instruction_write_metadata *,
+ insts[OVSINST_OFPIT11_WRITE_METADATA]);
- if (insts[OVSINST_OFPIT11_GOTO_TABLE] ||
- insts[OVSINST_OFPIT11_WRITE_METADATA] ||
- insts[OVSINST_OFPIT11_WRITE_ACTIONS] ||
- insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+ om = ofpact_put_WRITE_METADATA(ofpacts);
+ om->metadata = oiwm->metadata;
+ om->mask = oiwm->metadata_mask;
+ }
+ 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_WRITE_ACTIONS]) {
error = OFPERR_OFPBIC_UNSUP_INST;
goto exit;
}
+ error = ofpacts_verify(ofpacts->data, ofpacts->size);
exit:
if (error) {
ofpbuf_clear(ofpacts);
return error;
}
\f
+/* May modify flow->dl_type, caller must restore it. */
static enum ofperr
-ofpact_check__(const struct ofpact *a, const struct flow *flow, int 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_ENQUEUE:
enqueue = ofpact_get_ENQUEUE(a);
- if (enqueue->port >= max_ports && enqueue->port != OFPP_IN_PORT
+ if (ofp_to_u16(enqueue->port) >= ofp_to_u16(max_ports)
+ && enqueue->port != OFPP_IN_PORT
&& enqueue->port != OFPP_LOCAL) {
return OFPERR_OFPBAC_BAD_OUT_PORT;
}
case OFPACT_SET_VLAN_VID:
case OFPACT_SET_VLAN_PCP:
case OFPACT_STRIP_VLAN:
+ case OFPACT_PUSH_VLAN:
case OFPACT_SET_ETH_SRC:
case OFPACT_SET_ETH_DST:
case OFPACT_SET_IPV4_SRC:
case OFPACT_REG_LOAD:
return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
+ case OFPACT_STACK_PUSH:
+ return nxm_stack_push_check(ofpact_get_STACK_PUSH(a), flow);
+
+ case OFPACT_STACK_POP:
+ return nxm_stack_pop_check(ofpact_get_STACK_POP(a), flow);
+
case OFPACT_DEC_TTL:
+ case OFPACT_SET_MPLS_TTL:
+ case OFPACT_DEC_MPLS_TTL:
case OFPACT_SET_TUNNEL:
case OFPACT_SET_QUEUE:
case OFPACT_POP_QUEUE:
case OFPACT_MULTIPATH:
return multipath_check(ofpact_get_MULTIPATH(a), flow);
- case OFPACT_AUTOPATH:
- return autopath_check(ofpact_get_AUTOPATH(a), flow);
-
case OFPACT_NOTE:
case OFPACT_EXIT:
return 0;
+ case OFPACT_PUSH_MPLS:
+ flow->dl_type = ofpact_get_PUSH_MPLS(a)->ethertype;
+ return 0;
+
+ case OFPACT_POP_MPLS:
+ flow->dl_type = ofpact_get_POP_MPLS(a)->ethertype;
+ return 0;
+
+ case OFPACT_SAMPLE:
+ return 0;
+
+ case OFPACT_CLEAR_ACTIONS:
+ case OFPACT_WRITE_METADATA:
+ return 0;
+
+ case OFPACT_METER: {
+ uint32_t mid = ofpact_get_METER(a)->meter_id;
+ if (mid == 0 || mid > OFPM13_MAX) {
+ return OFPERR_OFPMMFC_INVALID_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();
}
/* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are
* appropriate for a packet with the prerequisites satisfied by 'flow' in a
- * switch with no more than 'max_ports' ports. */
+ * switch with no more than 'max_ports' ports.
+ *
+ * May temporarily modify 'flow', but restores the changes before returning. */
enum ofperr
ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
- const struct flow *flow, int 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) {
- enum ofperr error = ofpact_check__(a, flow, max_ports);
+ error = ofpact_check__(a, flow, max_ports, table_id);
if (error) {
- return error;
+ break;
+ }
+ }
+ flow->dl_type = dl_type; /* Restore. */
+ return error;
+}
+
+/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
+ * in the appropriate order as defined by the OpenFlow spec. */
+enum ofperr
+ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len)
+{
+ const struct ofpact *a;
+ enum ovs_instruction_type inst;
+
+ inst = OVSINST_OFPIT11_APPLY_ACTIONS;
+ OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+ enum ovs_instruction_type next;
+
+ next = ovs_instruction_type_from_ofpact_type(a->type);
+ if (inst != OVSINST_OFPIT11_APPLY_ACTIONS && next <= inst) {
+ const char *name = ovs_instruction_name_from_type(inst);
+ const char *next_name = ovs_instruction_name_from_type(next);
+
+ if (next == inst) {
+ VLOG_WARN("duplicate %s instruction not allowed, for OpenFlow "
+ "1.1+ compatibility", name);
+ } else {
+ VLOG_WARN("invalid instruction ordering: %s must appear "
+ "before %s, for OpenFlow 1.1+ compatibility",
+ next_name, name);
+ }
+ return OFPERR_OFPBAC_UNSUPPORTED_ORDER;
}
+
+ inst = next;
}
return 0;
nar = ofputil_put_NXAST_RESUBMIT_TABLE(out);
nar->table = resubmit->table_id;
}
- nar->in_port = htons(resubmit->in_port);
+ nar->in_port = htons(ofp_to_u16(resubmit->in_port));
}
static void
}
}
+static void
+ofpact_write_metadata_to_nxast(const struct ofpact_metadata *om,
+ struct ofpbuf *out)
+{
+ struct nx_action_write_metadata *nawm;
+
+ nawm = ofputil_put_NXAST_WRITE_METADATA(out);
+ nawm->metadata = om->metadata;
+ nawm->mask = om->mask;
+}
+
static void
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);
}
naft->fin_hard_timeout = htons(fin_timeout->fin_hard_timeout);
}
+static void
+ofpact_sample_to_nxast(const struct ofpact_sample *os,
+ struct ofpbuf *out)
+{
+ struct nx_action_sample *nas;
+
+ nas = ofputil_put_NXAST_SAMPLE(out);
+ nas->probability = htons(os->probability);
+ nas->collector_set_id = htonl(os->collector_set_id);
+ nas->obs_domain_id = htonl(os->obs_domain_id);
+ nas->obs_point_id = htonl(os->obs_point_id);
+}
+
static void
ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
{
nxm_reg_load_to_nxast(ofpact_get_REG_LOAD(a), out);
break;
+ case OFPACT_STACK_PUSH:
+ nxm_stack_push_to_nxast(ofpact_get_STACK_PUSH(a), out);
+ break;
+
+ case OFPACT_STACK_POP:
+ nxm_stack_pop_to_nxast(ofpact_get_STACK_POP(a), out);
+ break;
+
case OFPACT_DEC_TTL:
ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out);
break;
+ case OFPACT_SET_MPLS_TTL:
+ ofputil_put_NXAST_SET_MPLS_TTL(out)->ttl
+ = ofpact_get_SET_MPLS_TTL(a)->ttl;
+ break;
+
+ case OFPACT_DEC_MPLS_TTL:
+ ofputil_put_NXAST_DEC_MPLS_TTL(out);
+ break;
+
case OFPACT_SET_TUNNEL:
ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out);
break;
+ case OFPACT_WRITE_METADATA:
+ ofpact_write_metadata_to_nxast(ofpact_get_WRITE_METADATA(a), out);
+ break;
+
case OFPACT_SET_QUEUE:
ofputil_put_NXAST_SET_QUEUE(out)->queue_id
= htonl(ofpact_get_SET_QUEUE(a)->queue_id);
multipath_to_nxast(ofpact_get_MULTIPATH(a), out);
break;
- case OFPACT_AUTOPATH:
- autopath_to_nxast(ofpact_get_AUTOPATH(a), out);
- break;
-
case OFPACT_NOTE:
ofpact_note_to_nxast(ofpact_get_NOTE(a), out);
break;
ofputil_put_NXAST_EXIT(out);
break;
+ case OFPACT_PUSH_MPLS:
+ ofputil_put_NXAST_PUSH_MPLS(out)->ethertype =
+ ofpact_get_PUSH_MPLS(a)->ethertype;
+ break;
+
+ case OFPACT_POP_MPLS:
+ ofputil_put_NXAST_POP_MPLS(out)->ethertype =
+ ofpact_get_POP_MPLS(a)->ethertype;
+ break;
+
+ case OFPACT_SAMPLE:
+ ofpact_sample_to_nxast(ofpact_get_SAMPLE(a), out);
+ break;
+
+ case OFPACT_GROUP:
case OFPACT_OUTPUT:
case OFPACT_ENQUEUE:
case OFPACT_SET_VLAN_VID:
case OFPACT_SET_VLAN_PCP:
case OFPACT_STRIP_VLAN:
+ case OFPACT_PUSH_VLAN:
case OFPACT_SET_ETH_SRC:
case OFPACT_SET_ETH_DST:
case OFPACT_SET_IPV4_SRC:
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:
+ case OFPACT_METER:
NOT_REACHED();
}
}
struct ofp10_action_output *oao;
oao = ofputil_put_OFPAT10_OUTPUT(out);
- oao->port = htons(output->port);
+ oao->port = htons(ofp_to_u16(output->port));
oao->max_len = htons(output->max_len);
}
ofpact_enqueue_to_openflow10(const struct ofpact_enqueue *enqueue,
struct ofpbuf *out)
{
- struct ofp_action_enqueue *oae;
+ struct ofp10_action_enqueue *oae;
oae = ofputil_put_OFPAT10_ENQUEUE(out);
- oae->port = htons(enqueue->port);
+ oae->port = htons(ofp_to_u16(enqueue->port));
oae->queue_id = htonl(enqueue->queue);
}
= htons(ofpact_get_SET_L4_DST_PORT(a)->port);
break;
+ case OFPACT_PUSH_VLAN:
+ case OFPACT_CLEAR_ACTIONS:
+ case OFPACT_GOTO_TABLE:
+ case OFPACT_METER:
+ /* XXX */
+ break;
+
+ case OFPACT_GROUP:
+ break;
+
case OFPACT_CONTROLLER:
case OFPACT_OUTPUT_REG:
case OFPACT_BUNDLE:
case OFPACT_REG_MOVE:
case OFPACT_REG_LOAD:
+ case OFPACT_STACK_PUSH:
+ case OFPACT_STACK_POP:
case OFPACT_DEC_TTL:
+ case OFPACT_SET_MPLS_TTL:
+ case OFPACT_DEC_MPLS_TTL:
case OFPACT_SET_TUNNEL:
+ case OFPACT_WRITE_METADATA:
case OFPACT_SET_QUEUE:
case OFPACT_POP_QUEUE:
case OFPACT_FIN_TIMEOUT:
case OFPACT_RESUBMIT:
case OFPACT_LEARN:
case OFPACT_MULTIPATH:
- case OFPACT_AUTOPATH:
case OFPACT_NOTE:
case OFPACT_EXIT:
+ case OFPACT_PUSH_MPLS:
+ case OFPACT_POP_MPLS:
+ case OFPACT_SAMPLE:
ofpact_to_nxast(a, out);
break;
}
oao->max_len = htons(output->max_len);
}
+static void
+ofpact_dec_ttl_to_openflow11(const struct ofpact_cnt_ids *dec_ttl,
+ struct ofpbuf *out)
+{
+ if (dec_ttl->n_controllers == 1 && dec_ttl->cnt_ids[0] == 0
+ && (!dec_ttl->ofpact.compat ||
+ dec_ttl->ofpact.compat == OFPUTIL_OFPAT11_DEC_NW_TTL)) {
+ ofputil_put_OFPAT11_DEC_NW_TTL(out);
+ } else {
+ ofpact_dec_ttl_to_nxast(dec_ttl, out);
+ }
+}
+
static void
ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
{
break;
case OFPACT_STRIP_VLAN:
- /* XXX */
+ ofputil_put_OFPAT11_POP_VLAN(out);
+ break;
+
+ case OFPACT_PUSH_VLAN:
+ /* XXX ETH_TYPE_VLAN_8021AD case */
+ ofputil_put_OFPAT11_PUSH_VLAN(out)->ethertype =
+ htons(ETH_TYPE_VLAN_8021Q);
+ break;
+
+ case OFPACT_SET_QUEUE:
+ ofputil_put_OFPAT11_SET_QUEUE(out)->queue_id
+ = htonl(ofpact_get_SET_QUEUE(a)->queue_id);
break;
case OFPACT_SET_ETH_SRC:
= htons(ofpact_get_SET_L4_DST_PORT(a)->port);
break;
+ case OFPACT_DEC_TTL:
+ ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out);
+ break;
+
+ case OFPACT_SET_MPLS_TTL:
+ ofputil_put_OFPAT11_SET_MPLS_TTL(out)->mpls_ttl
+ = ofpact_get_SET_MPLS_TTL(a)->ttl;
+ break;
+
+ case OFPACT_DEC_MPLS_TTL:
+ ofputil_put_OFPAT11_DEC_MPLS_TTL(out);
+ break;
+
+ case OFPACT_WRITE_METADATA:
+ /* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */
+ break;
+
+ case OFPACT_PUSH_MPLS:
+ ofputil_put_OFPAT11_PUSH_MPLS(out)->ethertype =
+ ofpact_get_PUSH_MPLS(a)->ethertype;
+ break;
+
+ case OFPACT_POP_MPLS:
+ ofputil_put_OFPAT11_POP_MPLS(out)->ethertype =
+ ofpact_get_POP_MPLS(a)->ethertype;
+
+ break;
+
+ case OFPACT_CLEAR_ACTIONS:
+ case OFPACT_GOTO_TABLE:
+ 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_REG_MOVE:
case OFPACT_REG_LOAD:
- case OFPACT_DEC_TTL:
+ case OFPACT_STACK_PUSH:
+ case OFPACT_STACK_POP:
case OFPACT_SET_TUNNEL:
- case OFPACT_SET_QUEUE:
case OFPACT_POP_QUEUE:
case OFPACT_FIN_TIMEOUT:
case OFPACT_RESUBMIT:
case OFPACT_LEARN:
case OFPACT_MULTIPATH:
- case OFPACT_AUTOPATH:
case OFPACT_NOTE:
case OFPACT_EXIT:
+ case OFPACT_SAMPLE:
ofpact_to_nxast(a, out);
break;
}
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);
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) {
+ switch (ovs_instruction_type_from_ofpact_type(a->type)) {
+ case OVSINST_OFPIT11_CLEAR_ACTIONS:
+ instruction_put_OFPIT11_CLEAR_ACTIONS(openflow);
+ break;
+
+ case OVSINST_OFPIT11_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);
+ break;
+ }
+
+ case OVSINST_OFPIT11_WRITE_METADATA: {
+ const struct ofpact_metadata *om;
+ struct ofp11_instruction_write_metadata *oiwm;
+
+ om = ofpact_get_WRITE_METADATA(a);
+ oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow);
+ oiwm->metadata = om->metadata;
+ oiwm->metadata_mask = om->mask;
+ break;
+ }
+
+ case OVSINST_OFPIT13_METER: {
+ const struct ofpact_meter *om;
+ struct ofp13_instruction_meter *oim;
+
+ om = ofpact_get_METER(a);
+ oim = instruction_put_OFPIT13_METER(openflow);
+ oim->meter_id = htonl(om->meter_id);
+ break;
+ }
+
+ case OVSINST_OFPIT11_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 (ovs_instruction_type_from_ofpact_type(action->type)
+ != OVSINST_OFPIT11_APPLY_ACTIONS) {
+ break;
+ }
+ ofpact_to_openflow11(action, openflow);
+ processed = action;
+ }
+ ofpacts_update_instruction_actions(openflow, ofs);
+ a = processed;
+ break;
+ }
+
+ case OVSINST_OFPIT11_WRITE_ACTIONS:
+ NOT_REACHED();
+ }
+ }
+}
\f
/* Returns true if 'action' outputs to 'port', false otherwise. */
static bool
-ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
+ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
{
switch (ofpact->type) {
case OFPACT_OUTPUT:
case OFPACT_SET_VLAN_VID:
case OFPACT_SET_VLAN_PCP:
case OFPACT_STRIP_VLAN:
+ case OFPACT_PUSH_VLAN:
case OFPACT_SET_ETH_SRC:
case OFPACT_SET_ETH_DST:
case OFPACT_SET_IPV4_SRC:
case OFPACT_SET_L4_DST_PORT:
case OFPACT_REG_MOVE:
case OFPACT_REG_LOAD:
+ case OFPACT_STACK_PUSH:
+ case OFPACT_STACK_POP:
case OFPACT_DEC_TTL:
+ case OFPACT_SET_MPLS_TTL:
+ case OFPACT_DEC_MPLS_TTL:
case OFPACT_SET_TUNNEL:
+ case OFPACT_WRITE_METADATA:
case OFPACT_SET_QUEUE:
case OFPACT_POP_QUEUE:
case OFPACT_FIN_TIMEOUT:
case OFPACT_RESUBMIT:
case OFPACT_LEARN:
case OFPACT_MULTIPATH:
- case OFPACT_AUTOPATH:
case OFPACT_NOTE:
case OFPACT_EXIT:
+ case OFPACT_PUSH_MPLS:
+ case OFPACT_POP_MPLS:
+ case OFPACT_SAMPLE:
+ case OFPACT_CLEAR_ACTIONS:
+ case OFPACT_GOTO_TABLE:
+ case OFPACT_METER:
+ case OFPACT_GROUP:
default:
return false;
}
* to 'port', false otherwise. */
bool
ofpacts_output_to_port(const struct ofpact *ofpacts, size_t ofpacts_len,
- uint16_t port)
+ ofp_port_t port)
{
const struct ofpact *a;
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. */
{
const struct ofpact_enqueue *enqueue;
const struct ofpact_resubmit *resubmit;
- const struct ofpact_autopath *autopath;
const struct ofpact_controller *controller;
+ const struct ofpact_metadata *metadata;
const struct ofpact_tunnel *tunnel;
- uint16_t port;
+ const struct ofpact_sample *sample;
+ ofp_port_t port;
switch (a->type) {
case OFPACT_OUTPUT:
port = ofpact_get_OUTPUT(a)->port;
- if (port < OFPP_MAX) {
+ if (ofp_to_u16(port) < ofp_to_u16(OFPP_MAX)) {
ds_put_format(s, "output:%"PRIu16, port);
} else {
ofputil_format_port(port, s);
ds_put_cstr(s, "controller(");
if (reason != OFPR_ACTION) {
+ char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
+
ds_put_format(s, "reason=%s,",
- ofputil_packet_in_reason_to_string(reason));
+ ofputil_packet_in_reason_to_string(
+ reason, reasonbuf, sizeof reasonbuf));
}
if (controller->max_len != UINT16_MAX) {
ds_put_format(s, "max_len=%"PRIu16",", controller->max_len);
ds_put_cstr(s, "strip_vlan");
break;
+ case OFPACT_PUSH_VLAN:
+ /* XXX 802.1AD case*/
+ ds_put_format(s, "push_vlan:%#"PRIx16, ETH_TYPE_VLAN_8021Q);
+ break;
+
case OFPACT_SET_ETH_SRC:
ds_put_format(s, "mod_dl_src:"ETH_ADDR_FMT,
ETH_ADDR_ARGS(ofpact_get_SET_ETH_SRC(a)->mac));
case OFPACT_SET_IPV4_SRC:
ds_put_format(s, "mod_nw_src:"IP_FMT,
- IP_ARGS(&ofpact_get_SET_IPV4_SRC(a)->ipv4));
+ IP_ARGS(ofpact_get_SET_IPV4_SRC(a)->ipv4));
break;
case OFPACT_SET_IPV4_DST:
ds_put_format(s, "mod_nw_dst:"IP_FMT,
- IP_ARGS(&ofpact_get_SET_IPV4_DST(a)->ipv4));
+ IP_ARGS(ofpact_get_SET_IPV4_DST(a)->ipv4));
break;
case OFPACT_SET_IPV4_DSCP:
nxm_format_reg_load(ofpact_get_REG_LOAD(a), s);
break;
+ case OFPACT_STACK_PUSH:
+ nxm_format_stack_push(ofpact_get_STACK_PUSH(a), s);
+ break;
+
+ case OFPACT_STACK_POP:
+ nxm_format_stack_pop(ofpact_get_STACK_POP(a), s);
+ break;
+
case OFPACT_DEC_TTL:
print_dec_ttl(ofpact_get_DEC_TTL(a), s);
break;
+ case OFPACT_SET_MPLS_TTL:
+ ds_put_format(s, "set_mpls_ttl(%"PRIu8")",
+ ofpact_get_SET_MPLS_TTL(a)->ttl);
+ break;
+
+ case OFPACT_DEC_MPLS_TTL:
+ ds_put_cstr(s, "dec_mpls_ttl");
+ break;
+
case OFPACT_SET_TUNNEL:
tunnel = ofpact_get_SET_TUNNEL(a);
ds_put_format(s, "set_tunnel%s:%#"PRIx64,
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) {
multipath_format(ofpact_get_MULTIPATH(a), s);
break;
- case OFPACT_AUTOPATH:
- autopath = ofpact_get_AUTOPATH(a);
- ds_put_format(s, "autopath(%u,", autopath->port);
- mf_format_subfield(&autopath->dst, s);
- ds_put_char(s, ')');
- break;
-
case OFPACT_NOTE:
print_note(ofpact_get_NOTE(a), s);
break;
+ case OFPACT_PUSH_MPLS:
+ ds_put_format(s, "push_mpls:0x%04"PRIx16,
+ ntohs(ofpact_get_PUSH_MPLS(a)->ethertype));
+ break;
+
+ case OFPACT_POP_MPLS:
+ ds_put_format(s, "pop_mpls:0x%04"PRIx16,
+ ntohs(ofpact_get_POP_MPLS(a)->ethertype));
+ break;
+
case OFPACT_EXIT:
ds_put_cstr(s, "exit");
break;
+
+ case OFPACT_SAMPLE:
+ sample = ofpact_get_SAMPLE(a);
+ ds_put_format(
+ s, "sample(probability=%"PRIu16",collector_set_id=%"PRIu32
+ ",obs_domain_id=%"PRIu32",obs_point_id=%"PRIu32")",
+ sample->probability, sample->collector_set_id,
+ sample->obs_domain_id, sample->obs_point_id);
+ break;
+
+ case OFPACT_CLEAR_ACTIONS:
+ ds_put_format(s, "%s",
+ ovs_instruction_name_from_type(
+ OVSINST_OFPIT11_CLEAR_ACTIONS));
+ break;
+
+ case OFPACT_WRITE_METADATA:
+ metadata = ofpact_get_WRITE_METADATA(a);
+ ds_put_format(s, "%s:%#"PRIx64,
+ ovs_instruction_name_from_type(
+ OVSINST_OFPIT11_WRITE_METADATA),
+ ntohll(metadata->metadata));
+ if (metadata->mask != htonll(UINT64_MAX)) {
+ ds_put_format(s, "/%#"PRIx64, ntohll(metadata->mask));
+ }
+ break;
+
+ case OFPACT_GOTO_TABLE:
+ ds_put_format(s, "%s:%"PRIu8,
+ ovs_instruction_name_from_type(
+ OVSINST_OFPIT11_GOTO_TABLE),
+ ofpact_get_GOTO_TABLE(a)->table_id);
+ break;
+
+ case OFPACT_METER:
+ ds_put_format(s, "%s:%"PRIu32,
+ 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;
}
}
if (a != ofpacts) {
ds_put_cstr(string, ",");
}
+
+ /* XXX write-actions */
ofpact_format(a, string);
}
}
void
ofpact_update_len(struct ofpbuf *ofpacts, struct ofpact *ofpact)
{
- assert(ofpact == ofpacts->l2);
+ ovs_assert(ofpact == ofpacts->l2);
ofpact->len = (char *) ofpbuf_tail(ofpacts) - (char *) ofpact;
}
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);
+}