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);
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;
}
}
if (out[type]) {
- return OFPERR_OFPBAC_UNSUPPORTED_ORDER; /* No specific code for
- * a duplicate instruction
- * exist */
+ return OFPERR_ONFBIC_DUP_INSTRUCTION;
}
out[type] = inst;
}
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);
goto exit;
}
+ if (insts[OVSINST_OFPIT13_METER]) {
+ const struct ofp13_instruction_meter *oim;
+ struct ofpact_meter *om;
+
+ oim = (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;
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;
}
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,
- ovs_be16 *dl_type)
+ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports)
{
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;
}
return 0;
case OFPACT_PUSH_MPLS:
- *dl_type = ofpact_get_PUSH_MPLS(a)->ethertype;
+ flow->dl_type = ofpact_get_PUSH_MPLS(a)->ethertype;
return 0;
case OFPACT_POP_MPLS:
- *dl_type = ofpact_get_POP_MPLS(a)->ethertype;
+ flow->dl_type = ofpact_get_POP_MPLS(a)->ethertype;
return 0;
case OFPACT_SAMPLE:
case OFPACT_CLEAR_ACTIONS:
case OFPACT_WRITE_METADATA:
+ case OFPACT_METER:
case OFPACT_GOTO_TABLE:
return 0;
/* 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)
{
const struct ofpact *a;
ovs_be16 dl_type = flow->dl_type;
- struct flow updated_flow;
+ enum ofperr error = 0;
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
- enum ofperr error;
-
- /* If the dl_type was changed by an action then its new value
- * should be present in the flow passed to ofpact_check__(). */
- if (flow->dl_type != dl_type) {
- /* Only copy flow at most once */
- if (flow != &updated_flow) {
- updated_flow = *flow;
- flow = &updated_flow;
- }
- updated_flow.dl_type = dl_type;
- }
-
- error = ofpact_check__(a, flow, max_ports, &dl_type);
+ error = ofpact_check__(a, flow, max_ports);
if (error) {
- return error;
+ break;
}
}
-
- return 0;
+ flow->dl_type = dl_type; /* Restore. */
+ return error;
}
/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
enum ovs_instruction_type next;
- if (a->type == OFPACT_CLEAR_ACTIONS) {
+ if (a->type == OFPACT_METER) {
+ next = OVSINST_OFPIT13_METER;
+ } else if (a->type == OFPACT_CLEAR_ACTIONS) {
next = OVSINST_OFPIT11_CLEAR_ACTIONS;
} else if (a->type == OFPACT_WRITE_METADATA) {
next = OVSINST_OFPIT11_WRITE_METADATA;
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
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);
}
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);
}
case OFPACT_PUSH_VLAN:
case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE:
+ case OFPACT_METER:
/* XXX */
break;
case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE:
+ case OFPACT_METER:
NOT_REACHED();
case OFPACT_CONTROLLER:
oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow);
oiwm->metadata = om->metadata;
oiwm->metadata_mask = om->mask;
+ } else if (a->type == OFPACT_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);
} else if (!ofpact_is_instruction(a)) {
/* Apply-actions */
const size_t ofs = openflow->size;
\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_SAMPLE:
case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE:
+ case OFPACT_METER:
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;
const struct ofpact_metadata *metadata;
const struct ofpact_tunnel *tunnel;
const struct ofpact_sample *sample;
- uint16_t port;
+ 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);
OVSINST_OFPIT11_GOTO_TABLE),
ofpact_get_GOTO_TABLE(a)->table_id);
break;
+
+ case OFPACT_METER:
+ ds_put_format(s, "%s:%"PRIu32,
+ ofpact_instruction_name_from_type(OVSINST_OFPIT13_METER),
+ ofpact_get_METER(a)->meter_id);
+ break;
}
}