struct rule {
struct cls_rule cr;
- uint64_t flow_cookie; /* Controller-issued identifier.
+ uint64_t flow_cookie; /* Controller-issued identifier.
(Kept in network-byte order.) */
uint16_t idle_timeout; /* In seconds from time of last use. */
uint16_t hard_timeout; /* In seconds from time of creation. */
{
struct rule *rule;
rule = rule_create(p, NULL, actions, n_actions,
- idle_timeout >= 0 ? idle_timeout : 5 /* XXX */,
+ idle_timeout >= 0 ? idle_timeout : 5 /* XXX */,
0, 0, false);
cls_rule_from_flow(flow, wildcards, priority, &rule->cr);
rule_insert(p, rule, NULL, 0);
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)
}
static void
-append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn,
+append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn,
struct ofpbuf **msgp)
{
struct netdev_stats stats;
struct ofp_port_stats *ops;
- /* Intentionally ignore return value, since errors will set
- * 'stats' to all-1s, which is correct for OpenFlow, and
+ /* Intentionally ignore return value, since errors will set
+ * 'stats' to all-1s, which is correct for OpenFlow, and
* netdev_get_stats() will log errors. */
netdev_get_stats(port->netdev, &stats);
msg = start_stats_reply(osr, sizeof *ops * 16);
if (psr->port_no != htons(OFPP_NONE)) {
- port = port_array_get(&p->ports,
+ port = port_array_get(&p->ports,
ofp_port_to_odp_port(ntohs(psr->port_no)));
if (port) {
append_port_stat(port, ntohs(psr->port_no), ofconn, &msg);
ds_put_cstr(results, "\n");
}
-/* Adds a pretty-printed description of all flows to 'results', including
+/* Adds a pretty-printed description of all flows to 'results', including
* those marked hidden by secchan (e.g., by in-band control). */
void
ofproto_get_all_flows(struct ofproto *p, struct ds *results)
}
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