return false;
}
+/* Executes, within 'ofproto', the 'n_actions' actions in 'actions' on
+ * 'packet', which arrived on 'in_port'.
+ *
+ * Takes ownership of 'packet'. */
static bool
execute_odp_actions(struct ofproto *ofproto, uint16_t in_port,
const union odp_action *actions, size_t n_actions,
- const struct ofpbuf *packet)
+ struct ofpbuf *packet)
{
- if (n_actions > 0 && actions[0].type == ODPAT_CONTROLLER) {
+ if (n_actions == 1 && actions[0].type == ODPAT_CONTROLLER) {
/* As an optimization, avoid a round-trip from userspace to kernel to
* userspace. This also avoids possibly filling up kernel packet
* buffers along the way. */
- struct ofpbuf *copy;
struct odp_msg *msg;
- copy = ofpbuf_new(DPIF_RECV_MSG_PADDING + sizeof(struct odp_msg)
- + packet->size);
- ofpbuf_reserve(copy, DPIF_RECV_MSG_PADDING);
- msg = ofpbuf_put_uninit(copy, sizeof *msg);
+ msg = ofpbuf_push_uninit(packet, sizeof *msg);
msg->type = _ODPL_ACTION_NR;
msg->length = sizeof(struct odp_msg) + packet->size;
msg->port = in_port;
msg->reserved = 0;
msg->arg = actions[0].controller.arg;
- ofpbuf_put(copy, packet->data, packet->size);
- send_packet_in(ofproto, copy);
+ send_packet_in(ofproto, packet);
- actions++;
- n_actions--;
- }
+ return true;
+ } else {
+ int error;
- return !n_actions || !dpif_execute(ofproto->dpif, in_port,
- actions, n_actions, packet);
+ error = dpif_execute(ofproto->dpif, in_port,
+ actions, n_actions, packet);
+ ofpbuf_delete(packet);
+ return !error;
+ }
}
/* Executes the actions indicated by 'rule' on 'packet', which is in flow
- * 'flow' and is considered to have arrived on ODP port 'in_port'.
+ * 'flow' and is considered to have arrived on ODP port 'in_port'. 'packet'
+ * must have at least sizeof(struct ofp_packet_in) bytes of headroom.
*
* The flow that 'packet' actually contains does not need to actually match
* 'rule'; the actions in 'rule' will be applied to it either way. Likewise,
* 'packet' using rule_make_actions(). If 'rule' is a wildcard rule, or if
* 'rule' is an exact-match rule but 'flow' is not the rule's flow, then this
* function will compose a set of ODP actions based on 'rule''s OpenFlow
- * actions and apply them to 'packet'. */
+ * actions and apply them to 'packet'.
+ *
+ * Takes ownership of 'packet'. */
static void
rule_execute(struct ofproto *ofproto, struct rule *rule,
struct ofpbuf *packet, const flow_t *flow)
{
const union odp_action *actions;
+ struct odp_flow_stats stats;
size_t n_actions;
struct odp_actions a;
+ assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
+
/* Grab or compose the ODP actions.
*
* The special case for an exact-match 'rule' where 'flow' is not the
struct rule *super = rule->super ? rule->super : rule;
if (xlate_actions(super->actions, super->n_actions, flow, ofproto,
packet, &a, NULL, 0, NULL)) {
+ ofpbuf_delete(packet);
return;
}
actions = a.actions;
}
/* Execute the ODP actions. */
+ flow_extract_stats(flow, packet, &stats);
if (execute_odp_actions(ofproto, flow->in_port,
actions, n_actions, packet)) {
- struct odp_flow_stats stats;
- flow_extract_stats(flow, packet, &stats);
update_stats(ofproto, rule, &stats);
rule->used = time_msec();
netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, rule->used);
}
}
+/* Inserts 'rule' into 'p''s flow table.
+ *
+ * If 'packet' is nonnull, takes ownership of 'packet', executes 'rule''s
+ * actions on it and credits the statistics for sending the packet to 'rule'.
+ * 'packet' must have at least sizeof(struct ofp_packet_in) bytes of
+ * headroom. */
static void
rule_insert(struct ofproto *p, struct rule *rule, struct ofpbuf *packet,
uint16_t in_port)
}
rule_insert(p, rule, packet, in_port);
- ofpbuf_delete(packet);
return error;
}
flow_extract(packet, 0, in_port, &flow);
rule_execute(ofproto, rule, packet, &flow);
- ofpbuf_delete(packet);
return 0;
}
}
}
- rule_execute(p, rule, &payload, &flow);
- rule_reinstall(p, rule);
-
if (rule->super && rule->super->cr.priority == FAIL_OPEN_PRIORITY) {
/*
* Extra-special case for fail-open mode.
*
* See the top-level comment in fail-open.c for more information.
*/
- send_packet_in(p, packet);
- } else {
- ofpbuf_delete(packet);
+ send_packet_in(p, ofpbuf_clone(packet));
}
+
+ ofpbuf_pull(packet, sizeof *msg);
+ rule_execute(p, rule, packet, &flow);
+ rule_reinstall(p, rule);
}
static void