/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
return !error;
}
-#define CHECK_FEATURE__(NAME, FIELD) \
+#define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE) \
static bool \
check_##NAME(struct dpif_backer *backer) \
{ \
struct odp_flow_key_parms odp_parms = { \
.flow = &flow, \
.support = { \
- .NAME = true, \
+ .SUPPORT = true, \
}, \
}; \
\
memset(&flow, 0, sizeof flow); \
- flow.FIELD = 1; \
+ flow.FIELD = VALUE; \
\
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); \
odp_flow_key_from_flow(&odp_parms, &key); \
\
return enable; \
}
-#define CHECK_FEATURE(FIELD) CHECK_FEATURE__(FIELD, FIELD)
+#define CHECK_FEATURE(FIELD) CHECK_FEATURE__(FIELD, FIELD, FIELD, 1)
CHECK_FEATURE(ct_state)
CHECK_FEATURE(ct_zone)
CHECK_FEATURE(ct_mark)
-CHECK_FEATURE__(ct_label, ct_label.u64.lo)
+CHECK_FEATURE__(ct_label, ct_label, ct_label.u64.lo, 1)
+CHECK_FEATURE__(ct_state_nat, ct_state, ct_state, CS_TRACKED|CS_SRC_NAT)
#undef CHECK_FEATURE
#undef CHECK_FEATURE__
backer->support.odp.ct_zone = check_ct_zone(backer);
backer->support.odp.ct_mark = check_ct_mark(backer);
backer->support.odp.ct_label = check_ct_label(backer);
+
+ backer->support.odp.ct_state_nat = check_ct_state_nat(backer);
}
static int
controller->max_len = UINT16_MAX;
controller->controller_id = 0;
controller->reason = OFPR_NO_MATCH;
- ofpact_pad(&ofpacts);
error = add_internal_miss_flow(ofproto, id++, &ofpacts,
&ofproto->miss_rule);
}
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 && support->ct_state_nat) {
+ 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_state & (CS_SRC_NAT | CS_DST_NAT)) && !support->ct_state_nat)
+ || (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 (ofpact->type != OFPACT_CT) {
+ continue;
+ }
- 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;
+ 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_state & CS_UNSUPPORTED_MASK) {
- return OFPERR_OFPBMC_BAD_MASK;
+ 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 (a->type == OFPACT_NAT && !support->ct_state_nat) {
+ /* The backer doesn't seem to support the NAT bits in
+ * 'ct_state': assume that it doesn't support the NAT
+ * action. */
+ return OFPERR_OFPBAC_BAD_TYPE;
+ }
+ 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
ofproto_use_tnl_push_pop = true;
unixctl_command_reply(conn, "Tunnel push-pop on");
ofproto_revalidate_all_backers();
+ } else {
+ unixctl_command_reply_error(conn, "Invalid argument");
}
}
struct rule_dpif *rule;
int error;
- ofm.fm.match = *match;
- ofm.fm.priority = priority;
- ofm.fm.new_cookie = htonll(0);
- ofm.fm.cookie = htonll(0);
- ofm.fm.cookie_mask = htonll(0);
- ofm.fm.modify_cookie = false;
- ofm.fm.table_id = TBL_INTERNAL;
- ofm.fm.command = OFPFC_ADD;
- ofm.fm.idle_timeout = idle_timeout;
- ofm.fm.hard_timeout = 0;
- ofm.fm.importance = 0;
- ofm.fm.buffer_id = 0;
- ofm.fm.out_port = 0;
- ofm.fm.flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY;
- ofm.fm.ofpacts = ofpacts->data;
- ofm.fm.ofpacts_len = ofpacts->size;
+ ofm.fm = (struct ofputil_flow_mod) {
+ .match = *match,
+ .priority = priority,
+ .table_id = TBL_INTERNAL,
+ .command = OFPFC_ADD,
+ .idle_timeout = idle_timeout,
+ .flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY,
+ .ofpacts = ofpacts->data,
+ .ofpacts_len = ofpacts->size,
+ .delete_reason = OVS_OFPRR_NONE,
+ };
error = ofproto_flow_mod(&ofproto->up, &ofm);
if (error) {
struct ofproto_flow_mod ofm;
int error;
- ofm.fm.match = *match;
- ofm.fm.priority = priority;
- ofm.fm.new_cookie = htonll(0);
- ofm.fm.cookie = htonll(0);
- ofm.fm.cookie_mask = htonll(0);
- ofm.fm.modify_cookie = false;
- ofm.fm.table_id = TBL_INTERNAL;
- ofm.fm.flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY;
- ofm.fm.command = OFPFC_DELETE_STRICT;
+ ofm.fm = (struct ofputil_flow_mod) {
+ .match = *match,
+ .priority = priority,
+ .table_id = TBL_INTERNAL,
+ .flags = OFPUTIL_FF_HIDDEN_FIELDS | OFPUTIL_FF_NO_READONLY,
+ .command = OFPFC_DELETE_STRICT,
+ };
error = ofproto_flow_mod(&ofproto->up, &ofm);
if (error) {