odp_port_t sflow_odp_port; /* Output port for composing sFlow action. */
uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */
bool exit; /* No further actions should be processed. */
+
+ /* OpenFlow 1.1+ action set.
+ *
+ * 'action_set' accumulates "struct ofpact"s added by OFPACT_WRITE_ACTIONS.
+ * When translation is otherwise complete, ofpacts_execute_action_set()
+ * converts it to a set of "struct ofpact"s that can be translated into
+ * datapath actions. */
+ struct ofpbuf action_set; /* Action set. */
+ uint64_t action_set_stub[1024 / 8];
};
/* A controller may use OFPP_NONE as the ingress port to indicate that
enum ofp_packet_in_reason reason,
uint16_t controller_id)
{
- struct ofputil_packet_in *pin;
+ struct ofproto_packet_in *pin;
struct ofpbuf *packet;
struct flow key;
ctx->xout->odp_actions.size, NULL, NULL);
pin = xmalloc(sizeof *pin);
- pin->packet_len = packet->size;
- pin->packet = ofpbuf_steal_data(packet);
- pin->reason = reason;
- pin->controller_id = controller_id;
- pin->table_id = ctx->table_id;
- pin->cookie = ctx->rule ? rule_dpif_get_flow_cookie(ctx->rule) : 0;
+ pin->up.packet_len = packet->size;
+ pin->up.packet = ofpbuf_steal_data(packet);
+ pin->up.reason = reason;
+ pin->up.table_id = ctx->table_id;
+ pin->up.cookie = (ctx->rule
+ ? rule_dpif_get_flow_cookie(ctx->rule)
+ : OVS_BE64_MAX);
- pin->send_len = len;
- flow_get_metadata(&ctx->xin->flow, &pin->fmd);
+ flow_get_metadata(&ctx->xin->flow, &pin->up.fmd);
+ pin->controller_id = controller_id;
+ pin->send_len = len;
+ pin->generated_by_table_miss = (ctx->rule
+ && rule_dpif_is_table_miss(ctx->rule));
ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, pin);
ofpbuf_delete(packet);
}
return true;
}
+static void
+xlate_write_actions(struct xlate_ctx *ctx, const struct ofpact *a)
+{
+ struct ofpact_nest *on = ofpact_get_WRITE_ACTIONS(a);
+ ofpbuf_put(&ctx->action_set, on->actions, ofpact_nest_get_action_len(on));
+ ofpact_pad(&ctx->action_set);
+}
+
+static void
+xlate_action_set(struct xlate_ctx *ctx)
+{
+ uint64_t action_list_stub[1024 / 64];
+ struct ofpbuf action_list;
+
+ ofpbuf_use_stub(&action_list, action_list_stub, sizeof action_list_stub);
+ ofpacts_execute_action_set(&action_list, &ctx->action_set);
+ do_xlate_actions(action_list.data, action_list.size, ctx);
+ ofpbuf_uninit(&action_list);
+}
+
static void
do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
struct xlate_ctx *ctx)
struct flow *flow = &ctx->xin->flow;
const struct ofpact *a;
+ /* dl_type already in the mask, not set below. */
+
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
struct ofpact_controller *controller;
const struct ofpact_metadata *metadata;
break;
case OFPACT_SET_IPV4_SRC:
- memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
if (flow->dl_type == htons(ETH_TYPE_IP)) {
+ memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
flow->nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4;
}
break;
case OFPACT_SET_IPV4_DST:
- memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
if (flow->dl_type == htons(ETH_TYPE_IP)) {
+ memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
flow->nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4;
}
break;
- case OFPACT_SET_IPV4_DSCP:
- wc->masks.nw_tos |= IP_DSCP_MASK;
- /* OpenFlow 1.0 only supports IPv4. */
- if (flow->dl_type == htons(ETH_TYPE_IP)) {
+ case OFPACT_SET_IP_DSCP:
+ if (is_ip_any(flow)) {
+ wc->masks.nw_tos |= IP_DSCP_MASK;
flow->nw_tos &= ~IP_DSCP_MASK;
- flow->nw_tos |= ofpact_get_SET_IPV4_DSCP(a)->dscp;
+ flow->nw_tos |= ofpact_get_SET_IP_DSCP(a)->dscp;
+ }
+ break;
+
+ case OFPACT_SET_IP_ECN:
+ if (is_ip_any(flow)) {
+ wc->masks.nw_tos |= IP_ECN_MASK;
+ flow->nw_tos &= ~IP_ECN_MASK;
+ flow->nw_tos |= ofpact_get_SET_IP_ECN(a)->ecn;
+ }
+ break;
+
+ case OFPACT_SET_IP_TTL:
+ if (is_ip_any(flow)) {
+ wc->masks.nw_ttl = 0xff;
+ flow->nw_ttl = ofpact_get_SET_IP_TTL(a)->ttl;
}
break;
case OFPACT_SET_L4_SRC_PORT:
- memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
- memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
if (is_ip_any(flow)) {
+ memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+ memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
flow->tp_src = htons(ofpact_get_SET_L4_SRC_PORT(a)->port);
}
break;
case OFPACT_SET_L4_DST_PORT:
- memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
- memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
if (is_ip_any(flow)) {
+ memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+ memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
flow->tp_dst = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
}
break;
break;
case OFPACT_REG_LOAD:
- nxm_execute_reg_load(ofpact_get_REG_LOAD(a), flow);
+ nxm_execute_reg_load(ofpact_get_REG_LOAD(a), flow, wc);
break;
case OFPACT_STACK_PUSH:
break;
case OFPACT_CLEAR_ACTIONS:
- /* XXX
- * Nothing to do because writa-actions is not supported for now.
- * When writa-actions is supported, clear-actions also must
- * be supported at the same time.
- */
+ ofpbuf_clear(&ctx->action_set);
+ break;
+
+ case OFPACT_WRITE_ACTIONS:
+ xlate_write_actions(ctx, a);
break;
case OFPACT_WRITE_METADATA:
}
ctx.rule = rule;
}
- xout->fail_open = ctx.rule && rule_dpif_fail_open(ctx.rule);
+ xout->fail_open = ctx.rule && rule_dpif_is_fail_open(ctx.rule);
if (xin->ofpacts) {
ofpacts = xin->ofpacts;
}
ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack);
+ ofpbuf_use_stub(&ctx.action_set,
+ ctx.action_set_stub, sizeof ctx.action_set_stub);
if (mbridge_has_mirrors(ctx.xbridge->mbridge)) {
/* Do this conditionally because the copy is expensive enough that it
}
}
+ if (ctx.action_set.size) {
+ xlate_action_set(&ctx);
+ }
+
if (ctx.xbridge->has_in_band
&& in_band_must_output_to_local_port(flow)
&& !actions_output_to_local_port(&ctx)) {
}
ofpbuf_uninit(&ctx.stack);
+ ofpbuf_uninit(&ctx.action_set);
/* Clear the metadata and register wildcard masks, because we won't
* use non-header fields as part of the cache. */
int
xlate_send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
{
- uint64_t odp_actions_stub[1024 / 8];
struct xport *xport;
- struct ofpbuf key, odp_actions;
- struct dpif_flow_stats stats;
- struct odputil_keybuf keybuf;
struct ofpact_output output;
- struct xlate_out xout;
- struct xlate_in xin;
struct flow flow;
union flow_in_port in_port_;
int error;
- ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
- ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output);
/* Use OFPP_NONE as the in_port to avoid special packet processing. */
in_port_.ofp_port = OFPP_NONE;
ovs_rwlock_unlock(&xlate_rwlock);
return EINVAL;
}
-
- odp_flow_key_from_flow(&key, &flow, ofp_port_to_odp_port(xport->xbridge, OFPP_LOCAL));
- dpif_flow_stats_extract(&flow, packet, time_msec(), &stats);
output.port = xport->ofp_port;
output.max_len = 0;
- xlate_in_init(&xin, xport->xbridge->ofproto, &flow, NULL, 0, packet);
- xin.ofpacts_len = sizeof output;
- xin.ofpacts = &output.ofpact;
- xin.resubmit_stats = &stats;
- /* Calls xlate_actions__ directly, since the rdlock is acquired. */
- xlate_actions__(&xin, &xout);
- error = dpif_execute(xport->xbridge->dpif,
- key.data, key.size,
- xout.odp_actions.data, xout.odp_actions.size,
- packet, (xout.slow & SLOW_ACTION) != 0);
+ error = ofproto_dpif_execute_actions(xport->xbridge->ofproto, &flow, NULL,
+ &output.ofpact, sizeof output,
+ packet);
ovs_rwlock_unlock(&xlate_rwlock);
- xlate_out_uninit(&xout);
return error;
}