mcast_snooping_wait(ofproto->ms);
stp_wait(ofproto);
if (ofproto->backer->need_revalidate) {
- /* Shouldn't happen, but if it does just go around again. */
- VLOG_DBG_RL(&rl, "need revalidate in ofproto_wait_cb()");
poll_immediate_wake();
}
xin.resubmit_stats = &stats;
xin.recurse = recurse;
xin.resubmits = resubmits;
- xlate_actions(&xin, &xout);
+ if (xlate_actions(&xin, &xout) != XLATE_OK) {
+ error = EINVAL;
+ goto out;
+ }
execute.actions = odp_actions.data;
execute.actions_len = odp_actions.size;
execute.packet->md.in_port.odp_port = ofp_port_to_odp_port(ofproto, in_port);
error = dpif_execute(ofproto->backer->dpif, &execute);
-
+out:
xlate_out_uninit(&xout);
ofpbuf_uninit(&odp_actions);
}
static enum ofperr
-rule_check(struct rule *rule)
+check_mask(struct ofproto_dpif *ofproto, const struct miniflow *flow)
{
+ const struct odp_support *support;
uint16_t ct_state, ct_zone;
- const ovs_u128 *labelp;
- ovs_u128 ct_label = { { 0, 0 } };
+ ovs_u128 ct_label;
uint32_t ct_mark;
- ct_state = MINIFLOW_GET_U16(rule->cr.match.flow, ct_state);
- ct_zone = MINIFLOW_GET_U16(rule->cr.match.flow, ct_zone);
- ct_mark = MINIFLOW_GET_U32(rule->cr.match.flow, ct_mark);
- labelp = MINIFLOW_GET_U128_PTR(rule->cr.match.flow, ct_label);
- if (labelp) {
- ct_label = *labelp;
+ support = &ofproto_dpif_get_support(ofproto)->odp;
+ ct_state = MINIFLOW_GET_U16(flow, ct_state);
+ if (support->ct_state && support->ct_zone && support->ct_mark
+ && support->ct_label) {
+ return ct_state & CS_UNSUPPORTED_MASK ? OFPERR_OFPBMC_BAD_MASK : 0;
+ }
+
+ ct_zone = MINIFLOW_GET_U16(flow, ct_zone);
+ ct_mark = MINIFLOW_GET_U32(flow, ct_mark);
+ ct_label = MINIFLOW_GET_U128(flow, ct_label);
+
+ if ((ct_state && !support->ct_state)
+ || (ct_state & CS_UNSUPPORTED_MASK)
+ || (ct_zone && !support->ct_zone)
+ || (ct_mark && !support->ct_mark)
+ || (!ovs_u128_is_zero(&ct_label) && !support->ct_label)) {
+ return OFPERR_OFPBMC_BAD_MASK;
}
- if (ct_state || ct_zone || ct_mark
- || !ovs_u128_is_zero(&ct_label)) {
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->ofproto);
- const struct odp_support *support = &ofproto_dpif_get_support(ofproto)->odp;
+ return 0;
+}
+
+static enum ofperr
+check_actions(const struct ofproto_dpif *ofproto,
+ const struct rule_actions *const actions)
+{
+ const struct ofpact *ofpact;
+
+ OFPACT_FOR_EACH (ofpact, actions->ofpacts, actions->ofpacts_len) {
+ const struct odp_support *support;
+ const struct ofpact_conntrack *ct;
+ const struct ofpact *a;
- if ((ct_state && !support->ct_state)
- || (ct_zone && !support->ct_zone)
- || (ct_mark && !support->ct_mark)
- || (!ovs_u128_is_zero(&ct_label) && !support->ct_label)) {
- return OFPERR_OFPBMC_BAD_FIELD;
+ if (ofpact->type != OFPACT_CT) {
+ continue;
}
- if (ct_state & CS_UNSUPPORTED_MASK) {
- return OFPERR_OFPBMC_BAD_MASK;
+
+ ct = CONTAINER_OF(ofpact, struct ofpact_conntrack, ofpact);
+ support = &ofproto_dpif_get_support(ofproto)->odp;
+
+ if (!support->ct_state) {
+ return OFPERR_OFPBAC_BAD_TYPE;
+ }
+ if ((ct->zone_imm || ct->zone_src.field) && !support->ct_zone) {
+ return OFPERR_OFPBAC_BAD_ARGUMENT;
+ }
+
+ OFPACT_FOR_EACH(a, ct->actions, ofpact_ct_get_action_len(ct)) {
+ const struct mf_field *dst = ofpact_get_mf_dst(a);
+
+ if (dst && ((dst->id == MFF_CT_MARK && !support->ct_mark)
+ || (dst->id == MFF_CT_LABEL && !support->ct_label))) {
+ return OFPERR_OFPBAC_BAD_SET_ARGUMENT;
+ }
}
}
+
return 0;
}
+static enum ofperr
+rule_check(struct rule *rule)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->ofproto);
+ enum ofperr err;
+
+ err = check_mask(ofproto, &rule->cr.match.mask->masks);
+ if (err) {
+ return err;
+ }
+ return check_actions(ofproto, rule->actions);
+}
+
static enum ofperr
rule_construct(struct rule *rule_)
OVS_NO_THREAD_SAFETY_ANALYSIS
struct ds *ds)
{
struct trace_ctx trace;
+ enum xlate_error error;
ds_put_format(ds, "Bridge: %s\n", ofproto->up.name);
ds_put_cstr(ds, "Flow: ");
trace.xin.resubmit_hook = trace_resubmit;
trace.xin.report_hook = trace_report_valist;
- xlate_actions(&trace.xin, &trace.xout);
-
+ error = xlate_actions(&trace.xin, &trace.xout);
ds_put_char(ds, '\n');
trace_format_flow(ds, 0, "Final flow", &trace);
trace_format_megaflow(ds, 0, "Megaflow", &trace);
ds_put_cstr(ds, "Datapath actions: ");
format_odp_actions(ds, trace.odp_actions.data, trace.odp_actions.size);
- if (trace.xout.slow) {
+ if (error != XLATE_OK) {
+ ds_put_format(ds, "\nTranslation failed (%s), packet is dropped.\n",
+ xlate_strerror(error));
+ } else if (trace.xout.slow) {
enum slow_path_reason slow;
ds_put_cstr(ds, "\nThis flow is handled by the userspace "