This additionally optimizes the common case of the first packet of a flow
that consists only of an OFPAT_CONTROLLER action, by avoiding an
ofpbuf_clone() call along that path.
+/* 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,
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)
- 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. */
/* 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. */
- 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;
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
}
/* 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,
*
* 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
* '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;
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;
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
/* 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)) {
struct rule *super = rule->super ? rule->super : rule;
if (xlate_actions(super->actions, super->n_actions, flow, ofproto,
packet, &a, NULL, 0, NULL)) {
return;
}
actions = a.actions;
return;
}
actions = a.actions;
}
/* Execute the ODP actions. */
}
/* Execute the ODP actions. */
+ flow_extract_stats(flow, packet, &stats);
if (execute_odp_actions(ofproto, flow->in_port,
actions, n_actions, packet)) {
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);
}
}
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)
static void
rule_insert(struct ofproto *p, struct rule *rule, struct ofpbuf *packet,
uint16_t in_port)
}
rule_insert(p, rule, packet, in_port);
}
rule_insert(p, rule, packet, in_port);
flow_extract(packet, 0, in_port, &flow);
rule_execute(ofproto, rule, packet, &flow);
flow_extract(packet, 0, in_port, &flow);
rule_execute(ofproto, rule, packet, &flow);
- 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.
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.
*/
*
* 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);
if (++p->cookie >= COOKIE_MAX) {
p->cookie = 0;
}
if (++p->cookie >= COOKIE_MAX) {
p->cookie = 0;
}
- p->buffer = ofpbuf_clone(buffer);
+ p->buffer = ofpbuf_new(sizeof(struct ofp_packet_in) + buffer->size);
+ ofpbuf_reserve(p->buffer, sizeof(struct ofp_packet_in));
+ ofpbuf_put(p->buffer, buffer->data, buffer->size);
p->timeout = time_msec() + OVERWRITE_MSECS;
p->in_port = in_port;
return make_id(p - pb->packets, p->cookie);
p->timeout = time_msec() + OVERWRITE_MSECS;
p->in_port = in_port;
return make_id(p - pb->packets, p->cookie);
* identifies a "null" packet buffer (created with pktbuf_get_null()), stores
* NULL in '*bufferp' and UINT16_max in '*in_port'.
*
* identifies a "null" packet buffer (created with pktbuf_get_null()), stores
* NULL in '*bufferp' and UINT16_max in '*in_port'.
*
+ * A returned packet will have at least sizeof(struct ofp_packet_in) bytes of
+ * headroom.
+ *
* On failure, stores NULL in in '*bufferp' and UINT16_MAX in '*in_port'. */
int
pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,
* On failure, stores NULL in in '*bufferp' and UINT16_MAX in '*in_port'. */
int
pktbuf_retrieve(struct pktbuf *pb, uint32_t id, struct ofpbuf **bufferp,