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,
+ struct ofpbuf *packet)
+{
+ 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 odp_msg *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;
+
+ send_packet_in(ofproto, packet);
+
+ return true;
+ } else {
+ int error;
+
+ 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. */
- if (!dpif_execute(ofproto->dpif, flow->in_port,
- actions, n_actions, packet)) {
- struct odp_flow_stats stats;
- flow_extract_stats(flow, packet, &stats);
+ flow_extract_stats(flow, packet, &stats);
+ if (execute_odp_actions(ofproto, flow->in_port,
+ actions, n_actions, packet)) {
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)
uint16_t nf_output_iface; /* Output interface index for NetFlow. */
};
+/* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a
+ * flow translation. */
+#define MAX_RESUBMIT_RECURSION 8
+
static void do_xlate_actions(const union ofp_action *in, size_t n_in,
struct action_xlate_ctx *ctx);
static void
xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
{
- if (!ctx->recurse) {
+ if (ctx->recurse < MAX_RESUBMIT_RECURSION) {
uint16_t old_in_port;
struct rule *rule;
do_xlate_actions(rule->actions, rule->n_actions, ctx);
ctx->recurse--;
}
+ } else {
+ struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+ VLOG_ERR_RL(&recurse_rl, "NXAST_RESUBMIT recursed over %d times",
+ MAX_RESUBMIT_RECURSION);
}
}
ctx->flow.tun_id = oa->tunnel.tun_id = nast->tun_id;
break;
+ case NXAST_DROP_SPOOFED_ARP:
+ if (ctx->flow.dl_type == htons(ETH_TYPE_ARP)) {
+ odp_actions_add(ctx->out, ODPAT_DROP_SPOOFED_ARP);
+ }
+ break;
+
/* If you add a new action here that modifies flow data, don't forget to
* update the flow key in ctx->flow at the same time. */
*nf_output_iface = ctx.nf_output_iface;
}
if (odp_actions_overflow(out)) {
+ COVERAGE_INC(odp_overflow);
odp_actions_init(out);
return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_TOO_MANY);
}
}
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