#include "vlog.h"
COVERAGE_DEFINE(xlate_actions);
+COVERAGE_DEFINE(xlate_actions_oversize);
VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate);
/* If 'struct flow' gets additional metadata, we'll need to zero it out
* before traversing a patch port. */
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 21);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 22);
if (!xport) {
xlate_report(ctx, "Nonexistent output port");
ctx->recurse--;
}
-static void
-xlate_table_action(struct xlate_ctx *ctx,
- ofp_port_t in_port, uint8_t table_id, bool may_packet_in)
+static bool
+xlate_resubmit_resource_check(struct xlate_ctx *ctx)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
} else if (ctx->stack.size >= 65536) {
VLOG_ERR_RL(&rl, "resubmits yielded over 64 kB of stack");
} else {
+ return true;
+ }
+
+ return false;
+}
+
+static void
+xlate_table_action(struct xlate_ctx *ctx,
+ ofp_port_t in_port, uint8_t table_id, bool may_packet_in)
+{
+ if (xlate_resubmit_resource_check(ctx)) {
struct rule_dpif *rule;
ofp_port_t old_in_port = ctx->xin->flow.in_port.ofp_port;
uint8_t old_table_id = ctx->table_id;
}
}
+static bool
+compose_set_mpls_label_action(struct xlate_ctx *ctx, ovs_be32 label)
+{
+ if (!eth_type_mpls(ctx->xin->flow.dl_type)) {
+ return true;
+ }
+
+ /* If mpls_depth_delta is negative then an MPLS POP action has been
+ * executed and the resulting MPLS label stack is unknown. This means
+ * a SET MPLS LABEL action can't be executed as it needs to manipulate
+ * the top-most MPLS LSE. Thus, stop processing.
+ *
+ * It is planned that in the future this case will be handled
+ * by recirculation.
+ */
+ if (ctx->mpls_depth_delta < 0) {
+ return true;
+ }
+
+ ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_LABEL_MASK);
+ set_mpls_lse_label(&ctx->xin->flow.mpls_lse, label);
+ return false;
+}
+
+static bool
+compose_set_mpls_tc_action(struct xlate_ctx *ctx, uint8_t tc)
+{
+ if (!eth_type_mpls(ctx->xin->flow.dl_type)) {
+ return true;
+ }
+
+ /* If mpls_depth_delta is negative then an MPLS POP action has been
+ * executed and the resulting MPLS label stack is unknown. This means
+ * a SET MPLS TC action can't be executed as it needs to manipulate
+ * the top-most MPLS LSE. Thus, stop processing.
+ *
+ * It is planned that in the future this case will be handled
+ * by recirculation.
+ */
+ if (ctx->mpls_depth_delta < 0) {
+ return true;
+ }
+
+ ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_TC_MASK);
+ set_mpls_lse_tc(&ctx->xin->flow.mpls_lse, tc);
+ return false;
+}
+
static bool
compose_set_mpls_ttl_action(struct xlate_ctx *ctx, uint8_t ttl)
{
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
struct ofpact_controller *controller;
const struct ofpact_metadata *metadata;
+ const struct ofpact_set_field *set_field;
+ const struct mf_field *mf;
if (ctx->exit) {
break;
case OFPACT_SET_VLAN_VID:
wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
- flow->vlan_tci &= ~htons(VLAN_VID_MASK);
- flow->vlan_tci |= (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid)
- | htons(VLAN_CFI));
+ if (flow->vlan_tci & htons(VLAN_CFI) ||
+ ofpact_get_SET_VLAN_VID(a)->push_vlan_if_needed) {
+ flow->vlan_tci &= ~htons(VLAN_VID_MASK);
+ flow->vlan_tci |= (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid)
+ | htons(VLAN_CFI));
+ }
break;
case OFPACT_SET_VLAN_PCP:
wc->masks.vlan_tci |= htons(VLAN_PCP_MASK | VLAN_CFI);
- flow->vlan_tci &= ~htons(VLAN_PCP_MASK);
- flow->vlan_tci |=
- htons((ofpact_get_SET_VLAN_PCP(a)->vlan_pcp << VLAN_PCP_SHIFT)
- | VLAN_CFI);
+ if (flow->vlan_tci & htons(VLAN_CFI) ||
+ ofpact_get_SET_VLAN_PCP(a)->push_vlan_if_needed) {
+ flow->vlan_tci &= ~htons(VLAN_PCP_MASK);
+ flow->vlan_tci |= htons((ofpact_get_SET_VLAN_PCP(a)->vlan_pcp
+ << VLAN_PCP_SHIFT) | VLAN_CFI);
+ }
break;
case OFPACT_STRIP_VLAN:
}
break;
- case OFPACT_SET_IPV4_DSCP:
- /* 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;
nxm_execute_reg_load(ofpact_get_REG_LOAD(a), flow, wc);
break;
+ case OFPACT_SET_FIELD:
+ set_field = ofpact_get_SET_FIELD(a);
+ mf = set_field->field;
+ mf_mask_field_and_prereqs(mf, &wc->masks);
+
+ /* Set field action only ever overwrites packet's outermost
+ * applicable header fields. Do nothing if no header exists. */
+ if ((mf->id != MFF_VLAN_VID || flow->vlan_tci & htons(VLAN_CFI))
+ && ((mf->id != MFF_MPLS_LABEL && mf->id != MFF_MPLS_TC)
+ || flow->mpls_lse)) {
+ mf_set_flow_value(mf, &set_field->value, flow);
+ }
+ break;
+
case OFPACT_STACK_PUSH:
nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), flow, wc,
&ctx->stack);
}
break;
+ case OFPACT_SET_MPLS_LABEL:
+ if (compose_set_mpls_label_action(ctx,
+ ofpact_get_SET_MPLS_LABEL(a)->label)) {
+ return;
+ }
+ break;
+
+ case OFPACT_SET_MPLS_TC:
+ if (compose_set_mpls_tc_action(ctx,
+ ofpact_get_SET_MPLS_TC(a)->tc)) {
+ return;
+ }
+ break;
+
case OFPACT_SET_MPLS_TTL:
if (compose_set_mpls_ttl_action(ctx,
ofpact_get_SET_MPLS_TTL(a)->ttl)) {
break;
case OFPACT_GOTO_TABLE: {
- /* It is assumed that goto-table is the last action. */
struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a);
ovs_assert(ctx->table_id < ogt->table_id);
void
xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto,
const struct flow *flow, struct rule_dpif *rule,
- uint8_t tcp_flags, const struct ofpbuf *packet)
+ uint16_t tcp_flags, const struct ofpbuf *packet)
{
xin->ofproto = ofproto;
xin->flow = *flow;
if (nl_attr_oversized(ctx.xout->odp_actions.size)) {
/* These datapath actions are too big for a Netlink attribute, so we
- * can't execute them. */
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-
- VLOG_ERR_RL(&rl, "discarding oversize datapath actions");
- ofpbuf_clear(&ctx.xout->odp_actions);
+ * can't hand them to the kernel directly. dpif_execute() can execute
+ * them one by one with help, so just mark the result as SLOW_ACTION to
+ * prevent the flow from being installed. */
+ COVERAGE_INC(xlate_actions_oversize);
+ ctx.xout->slow |= SLOW_ACTION;
}
ofpbuf_uninit(&ctx.stack);