bool has_in_band; /* Bridge has in band control? */
bool forward_bpdu; /* Bridge forwards STP BPDUs? */
- /* True if the datapath supports recirculation. */
- bool enable_recirc;
-
- /* True if the datapath supports variable-length
- * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions.
- * False if the datapath supports only 8-byte (or shorter) userdata. */
- bool variable_length_userdata;
-
- /* Number of MPLS label stack entries that the datapath supports
- * in matches. */
- size_t max_mpls_depth;
-
- /* True if the datapath supports masked data in OVS_ACTION_ATTR_SET
- * actions. */
- bool masked_set_action;
+ /* Datapath feature support. */
+ struct dpif_backer_support support;
};
struct xbundle {
const struct xbridge *xbridge;
+ /* Flow tables version at the beginning of the translation. */
+ long long tables_version;
+
/* Flow at the last commit. */
struct flow base_flow;
const struct dpif_ipfix *,
const struct netflow *,
bool forward_bpdu, bool has_in_band,
- bool enable_recirc,
- bool variable_length_userdata,
- size_t max_mpls_depth,
- bool masked_set_action);
+ const struct dpif_backer_support *);
static void xlate_xbundle_set(struct xbundle *xbundle,
enum port_vlan_mode vlan_mode, int vlan,
unsigned long *trunks, bool use_priority_tags,
const struct dpif_ipfix *ipfix,
const struct netflow *netflow,
bool forward_bpdu, bool has_in_band,
- bool enable_recirc,
- bool variable_length_userdata,
- size_t max_mpls_depth,
- bool masked_set_action)
+ const struct dpif_backer_support *support)
{
if (xbridge->ml != ml) {
mac_learning_unref(xbridge->ml);
xbridge->dpif = dpif;
xbridge->forward_bpdu = forward_bpdu;
xbridge->has_in_band = has_in_band;
- xbridge->enable_recirc = enable_recirc;
- xbridge->variable_length_userdata = variable_length_userdata;
- xbridge->max_mpls_depth = max_mpls_depth;
- xbridge->masked_set_action = masked_set_action;
+ xbridge->support = *support;
}
static void
xbridge->dpif, xbridge->ml, xbridge->stp,
xbridge->rstp, xbridge->ms, xbridge->mbridge,
xbridge->sflow, xbridge->ipfix, xbridge->netflow,
- xbridge->forward_bpdu,
- xbridge->has_in_band, xbridge->enable_recirc,
- xbridge->variable_length_userdata,
- xbridge->max_mpls_depth, xbridge->masked_set_action);
+ xbridge->forward_bpdu, xbridge->has_in_band,
+ &xbridge->support);
LIST_FOR_EACH (xbundle, list_node, &xbridge->xbundles) {
xlate_xbundle_copy(new_xbridge, xbundle);
}
const struct dpif_sflow *sflow,
const struct dpif_ipfix *ipfix,
const struct netflow *netflow,
- bool forward_bpdu, bool has_in_band, bool enable_recirc,
- bool variable_length_userdata, size_t max_mpls_depth,
- bool masked_set_action)
+ bool forward_bpdu, bool has_in_band,
+ const struct dpif_backer_support *support)
{
struct xbridge *xbridge;
xbridge->name = xstrdup(name);
xlate_xbridge_set(xbridge, dpif, ml, stp, rstp, ms, mbridge, sflow, ipfix,
- netflow, forward_bpdu, has_in_band, enable_recirc,
- variable_length_userdata, max_mpls_depth,
- masked_set_action);
+ netflow, forward_bpdu, has_in_band, support);
}
static void
struct flow_wildcards *wc = &ctx->xout->wc;
struct ofport_dpif *ofport;
- if (ctx->xbridge->enable_recirc) {
+ if (ctx->xbridge->support.recirc) {
use_recirc = bond_may_recirc(
out_xbundle->bond, &xr.recirc_id, &xr.hash_basis);
: rstp_process_packet(xport, packet);
}
return SLOW_STP;
- } else if (xport->lldp && lldp_should_process_flow(flow)) {
+ } else if (xport->lldp && lldp_should_process_flow(xport->lldp, flow)) {
if (packet) {
lldp_process_packet(xport->lldp, packet);
}
const struct xport *peer = xport->peer;
struct flow old_flow = ctx->xin->flow;
bool old_was_mpls = ctx->was_mpls;
+ long long old_version = ctx->tables_version;
enum slow_path_reason special;
struct ofpbuf old_stack = ctx->stack;
union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)];
memset(flow->regs, 0, sizeof flow->regs);
flow->actset_output = OFPP_UNSET;
+ /* The bridge is now known so obtain its table version. */
+ ctx->tables_version
+ = ofproto_dpif_get_tables_version(ctx->xbridge->ofproto);
+
special = process_special(ctx, &ctx->xin->flow, peer,
ctx->xin->packet);
if (special) {
ofpbuf_uninit(&ctx->stack);
ctx->stack = old_stack;
+ /* Restore calling bridge's lookup version. */
+ ctx->tables_version = old_version;
+
/* The peer bridge popping MPLS should have no effect on the original
* bridge. */
ctx->was_mpls = old_was_mpls;
}
if (out_port != ODPP_NONE) {
+ bool use_masked = ctx->xbridge->support.masked_set_action;
+
ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow,
ctx->xout->odp_actions,
- wc,
- ctx->xbridge->masked_set_action);
+ wc, use_masked);
if (xr) {
struct ovs_action_hash *act_hash;
wc = (ctx->xin->skip_wildcards) ? NULL : &ctx->xout->wc;
rule = rule_dpif_lookup_from_table(ctx->xbridge->ofproto,
+ ctx->tables_version,
&ctx->xin->flow, wc,
ctx->xin->xcache != NULL,
ctx->xin->resubmit_stats,
{
struct ofproto_packet_in *pin;
struct dp_packet *packet;
+ bool use_masked;
ctx->xout->slow |= SLOW_CONTROLLER;
if (!ctx->xin->packet) {
packet = dp_packet_clone(ctx->xin->packet);
+ use_masked = ctx->xbridge->support.masked_set_action;
ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
ctx->xout->odp_actions,
- &ctx->xout->wc,
- ctx->xbridge->masked_set_action);
+ &ctx->xout->wc, use_masked);
odp_execute_actions(NULL, &packet, 1, false,
ctx->xout->odp_actions->data,
pin->up.table_id = ctx->table_id;
pin->up.cookie = ctx->rule_cookie;
- flow_get_metadata(&ctx->xin->flow, &pin->up.fmd);
+ flow_get_metadata(&ctx->xin->flow, &pin->up.flow_metadata);
pin->controller_id = controller_id;
pin->send_len = len;
compose_recirculate_action(struct xlate_ctx *ctx)
{
struct recirc_metadata md;
+ bool use_masked;
uint32_t id;
+ use_masked = ctx->xbridge->support.masked_set_action;
ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
ctx->xout->odp_actions,
- &ctx->xout->wc,
- ctx->xbridge->masked_set_action);
+ &ctx->xout->wc, use_masked);
recirc_metadata_from_flow(&md, &ctx->xin->flow);
n = flow_count_mpls_labels(flow, wc);
if (!n) {
+ bool use_masked = ctx->xbridge->support.masked_set_action;
+
ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow,
ctx->xout->odp_actions,
- &ctx->xout->wc,
- ctx->xbridge->masked_set_action);
+ &ctx->xout->wc, use_masked);
} else if (n >= FLOW_MAX_MPLS_LABELS) {
if (ctx->xin->packet != NULL) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
int n = flow_count_mpls_labels(flow, wc);
if (flow_pop_mpls(flow, n, eth_type, wc)) {
- if (ctx->xbridge->enable_recirc) {
+ if (ctx->xbridge->support.recirc) {
ctx->was_mpls = true;
}
} else if (n >= FLOW_MAX_MPLS_LABELS) {
/* Scale the probability from 16-bit to 32-bit while representing
* the same percentage. */
uint32_t probability = (os->probability << 16) | os->probability;
+ bool use_masked;
- if (!ctx->xbridge->variable_length_userdata) {
+ if (!ctx->xbridge->support.variable_length_userdata) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
VLOG_ERR_RL(&rl, "ignoring NXAST_SAMPLE action because datapath "
return;
}
+ use_masked = ctx->xbridge->support.masked_set_action;
ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
ctx->xout->odp_actions,
- &ctx->xout->wc,
- ctx->xbridge->masked_set_action);
+ &ctx->xout->wc, use_masked);
compose_flow_sample_cookie(os->probability, os->collector_set_id,
os->obs_domain_id, os->obs_point_id, &cookie);
if (is_ip_any(flow)) {
wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
}
- if (xbridge->enable_recirc) {
+ if (xbridge->support.recirc) {
/* Always exactly match recirc_id when datapath supports
* recirculation. */
wc->masks.recirc_id = UINT32_MAX;
flow->recirc_id);
return;
}
+ /* The bridge is now known so obtain its table version. */
+ ctx.tables_version = ofproto_dpif_get_tables_version(ctx.xbridge->ofproto);
if (!xin->ofpacts && !ctx.rule) {
- rule = rule_dpif_lookup_from_table(ctx.xbridge->ofproto, flow, wc,
+ rule = rule_dpif_lookup_from_table(ctx.xbridge->ofproto,
+ ctx.tables_version, flow, wc,
ctx.xin->xcache != NULL,
ctx.xin->resubmit_stats,
&ctx.table_id,
wc->masks.tp_src &= htons(UINT8_MAX);
wc->masks.tp_dst &= htons(UINT8_MAX);
}
+ /* VLAN_TCI CFI bit must be matched if any of the TCI is matched. */
+ if (wc->masks.vlan_tci) {
+ wc->masks.vlan_tci |= htons(VLAN_CFI);
+ }
}
}