}
}
-/* Returns true if STP should process 'flow'. */
+/* Returns true if STP should process 'flow'. Sets fields in 'wc' that
+ * were used to make the determination.*/
static bool
-stp_should_process_flow(const struct flow *flow)
+stp_should_process_flow(const struct flow *flow, struct flow_wildcards *wc)
{
+ memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
return eth_addr_equals(flow->dl_dst, eth_addr_stp);
}
}
static enum slow_path_reason
-process_special(struct ofproto_dpif *ofproto, const struct flow *flow,
+process_special(struct xlate_ctx *ctx, const struct flow *flow,
const struct ofport_dpif *ofport, const struct ofpbuf *packet)
{
+ struct ofproto_dpif *ofproto = ctx->ofproto;
+ struct flow_wildcards *wc = &ctx->xout->wc;
+
if (!ofport) {
return 0;
- } else if (ofport->cfm && cfm_should_process_flow(ofport->cfm, flow)) {
+ } else if (ofport->cfm && cfm_should_process_flow(ofport->cfm, flow, wc)) {
if (packet) {
cfm_process_heartbeat(ofport->cfm, packet);
}
return SLOW_CFM;
} else if (ofport->bundle && ofport->bundle->lacp
&& flow->dl_type == htons(ETH_TYPE_LACP)) {
+ memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
if (packet) {
lacp_process_packet(ofport->bundle->lacp, ofport, packet);
}
return SLOW_LACP;
- } else if (ofproto->stp && stp_should_process_flow(flow)) {
+ } else if (ofproto->stp && stp_should_process_flow(flow, wc)) {
if (packet) {
stp_process_packet(ofport, packet);
}
return NULL;
}
+ if (wc) {
+ wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+ }
+
cls = &ofproto->up.tables[table_id].cls;
frag = (flow->nw_frag & FLOW_NW_FRAG_ANY) != 0;
if (frag && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
if (ofport->tnl_port) {
+ struct flow_wildcards wc;
struct dpif_flow_stats stats;
- odp_port = tnl_port_send(ofport->tnl_port, &flow);
+ odp_port = tnl_port_send(ofport->tnl_port, &flow, &wc);
if (odp_port == OVSP_NONE) {
return ENODEV;
}
bool check_stp)
{
const struct ofport_dpif *ofport = get_ofp_port(ctx->ofproto, ofp_port);
+ struct flow_wildcards *wc = &ctx->xout->wc;
ovs_be16 flow_vlan_tci;
uint32_t flow_skb_mark;
uint8_t flow_nw_tos;
memset(ctx->xin->flow.regs, 0, sizeof ctx->xin->flow.regs);
in_port = get_ofp_port(ctx->ofproto, ctx->xin->flow.in_port);
- special = process_special(ctx->ofproto, &ctx->xin->flow, in_port,
+ special = process_special(ctx, &ctx->xin->flow, in_port,
ctx->xin->packet);
if (special) {
ctx->xout->slow = special;
pdscp = get_priority(ofport, ctx->xin->flow.skb_priority);
if (pdscp) {
+ wc->masks.nw_tos |= IP_ECN_MASK;
ctx->xin->flow.nw_tos &= ~IP_DSCP_MASK;
ctx->xin->flow.nw_tos |= pdscp->dscp;
}
* matches, while explicit set actions on tunnel metadata are.
*/
struct flow_tnl flow_tnl = ctx->xin->flow.tunnel;
- odp_port = tnl_port_send(ofport->tnl_port, &ctx->xin->flow);
+ odp_port = tnl_port_send(ofport->tnl_port, &ctx->xin->flow,
+ &ctx->xout->wc);
if (odp_port == OVSP_NONE) {
xlate_report(ctx, "Tunneling decided against output");
goto out; /* restore flow_nw_tos */
ctx->xin->flow.tunnel = flow_tnl; /* Restore tunnel metadata */
} else {
uint16_t vlandev_port;
+
odp_port = ofport->odp_port;
+ if (!hmap_is_empty(&ctx->ofproto->realdev_vid_map)) {
+ wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
+ }
vlandev_port = vsp_realdev_to_vlandev(ctx->ofproto, ofp_port,
ctx->xin->flow.vlan_tci);
if (vlandev_port == ofp_port) {
ctx->xin->flow.skb_mark &= ~IPSEC_MARK;
}
commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
- &ctx->xout->odp_actions);
+ &ctx->xout->odp_actions, &ctx->xout->wc);
nl_msg_put_u32(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port);
ctx->sflow_odp_port = odp_port;
static void
execute_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type)
{
+ struct flow_wildcards *wc = &ctx->xout->wc;
ovs_assert(eth_type_mpls(eth_type));
- memset(&ctx->xout->wc.masks.dl_type, 0xff,
- sizeof ctx->xout->wc.masks.dl_type);
- memset(&ctx->xout->wc.masks.mpls_lse, 0xff,
- sizeof ctx->xout->wc.masks.mpls_lse);
- memset(&ctx->xout->wc.masks.mpls_depth, 0xff,
- sizeof ctx->xout->wc.masks.mpls_depth);
+ memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+ memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
+ memset(&wc->masks.mpls_depth, 0xff, sizeof wc->masks.mpls_depth);
if (ctx->base_flow.mpls_depth) {
ctx->xin->flow.mpls_lse &= ~htonl(MPLS_BOS_MASK);
} else {
label = htonl(0x0); /* IPV4 Explicit Null. */
}
+ wc->masks.nw_tos |= IP_DSCP_MASK;
+ wc->masks.nw_ttl = 0xff;
tc = (ctx->xin->flow.nw_tos & IP_DSCP_MASK) >> 2;
ttl = ctx->xin->flow.nw_ttl ? ctx->xin->flow.nw_ttl : 0x40;
ctx->xin->flow.mpls_lse = set_mpls_lse_values(ttl, tc, 1, label);
static void
execute_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type)
{
+ struct flow_wildcards *wc = &ctx->xout->wc;
+
ovs_assert(eth_type_mpls(ctx->xin->flow.dl_type));
ovs_assert(!eth_type_mpls(eth_type));
- memset(&ctx->xout->wc.masks.dl_type, 0xff,
- sizeof ctx->xout->wc.masks.dl_type);
- memset(&ctx->xout->wc.masks.mpls_lse, 0xff,
- sizeof ctx->xout->wc.masks.mpls_lse);
- memset(&ctx->xout->wc.masks.mpls_depth, 0xff,
- sizeof ctx->xout->wc.masks.mpls_depth);
+ memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+ memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
+ memset(&wc->masks.mpls_depth, 0xff, sizeof wc->masks.mpls_depth);
if (ctx->xin->flow.mpls_depth) {
ctx->xin->flow.mpls_depth--;
return false;
}
+ ctx->xout->wc.masks.nw_ttl = 0xff;
if (ctx->xin->flow.nw_ttl > 1) {
ctx->xin->flow.nw_ttl--;
return false;
execute_dec_mpls_ttl_action(struct xlate_ctx *ctx)
{
uint8_t ttl = mpls_lse_to_ttl(ctx->xin->flow.mpls_lse);
+ struct flow_wildcards *wc = &ctx->xout->wc;
+
+ memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+ memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
if (!eth_type_mpls(ctx->xin->flow.dl_type)) {
return false;
uint32_t probability = (os->probability << 16) | os->probability;
commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
- &ctx->xout->odp_actions);
+ &ctx->xout->odp_actions, &ctx->xout->wc);
compose_flow_sample_cookie(os->probability, os->collector_set_id,
os->obs_domain_id, os->obs_point_id, &cookie);
break;
case OFPACT_POP_QUEUE:
- memset(&ctx->xout->wc.masks.skb_priority, 0xff,
- sizeof ctx->xout->wc.masks.skb_priority);
-
ctx->xin->flow.skb_priority = ctx->orig_skb_priority;
break;
* that in the future we always keep a copy of the original flow for
* tracing purposes. */
static bool hit_resubmit_limit;
+ struct flow_wildcards *wc = &xout->wc;
enum slow_path_reason special;
const struct ofpact *ofpacts;
ctx.base_flow.tunnel.ip_tos = xin->initial_vals.tunnel_ip_tos;
flow_wildcards_init_catchall(&ctx.xout->wc);
- memset(&ctx.xout->wc.masks.in_port, 0xff,
- sizeof ctx.xout->wc.masks.in_port);
+ memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
+ memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority);
+ wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
if (tnl_port_should_receive(&ctx.xin->flow)) {
- memset(&ctx.xout->wc.masks.tunnel, 0xff,
- sizeof ctx.xout->wc.masks.tunnel);
+ memset(&wc->masks.tunnel, 0xff, sizeof wc->masks.tunnel);
}
/* Disable most wildcarding for NetFlow. */
if (xin->ofproto->netflow) {
- memset(&ctx.xout->wc.masks.dl_src, 0xff,
- sizeof ctx.xout->wc.masks.dl_src);
- memset(&ctx.xout->wc.masks.dl_dst, 0xff,
- sizeof ctx.xout->wc.masks.dl_dst);
- memset(&ctx.xout->wc.masks.dl_type, 0xff,
- sizeof ctx.xout->wc.masks.dl_type);
- memset(&ctx.xout->wc.masks.vlan_tci, 0xff,
- sizeof ctx.xout->wc.masks.vlan_tci);
- memset(&ctx.xout->wc.masks.nw_proto, 0xff,
- sizeof ctx.xout->wc.masks.nw_proto);
- memset(&ctx.xout->wc.masks.nw_src, 0xff,
- sizeof ctx.xout->wc.masks.nw_src);
- memset(&ctx.xout->wc.masks.nw_dst, 0xff,
- sizeof ctx.xout->wc.masks.nw_dst);
- memset(&ctx.xout->wc.masks.tp_src, 0xff,
- sizeof ctx.xout->wc.masks.tp_src);
- memset(&ctx.xout->wc.masks.tp_dst, 0xff,
- sizeof ctx.xout->wc.masks.tp_dst);
+ netflow_mask_wc(wc);
}
ctx.xout->tags = 0;
}
in_port = get_ofp_port(ctx.ofproto, ctx.xin->flow.in_port);
- special = process_special(ctx.ofproto, &ctx.xin->flow, in_port,
+ special = process_special(&ctx, &ctx.xin->flow, in_port,
ctx.xin->packet);
if (special) {
ctx.xout->slow = special;
static void
xlate_normal(struct xlate_ctx *ctx)
{
+ struct flow_wildcards *wc = &ctx->xout->wc;
struct ofport_dpif *in_port;
struct ofbundle *in_bundle;
struct mac_entry *mac;
ctx->xout->has_normal = true;
/* Check the dl_type, since we may check for gratuituous ARP. */
- memset(&ctx->xout->wc.masks.dl_type, 0xff,
- sizeof ctx->xout->wc.masks.dl_type);
-
- memset(&ctx->xout->wc.masks.dl_src, 0xff,
- sizeof ctx->xout->wc.masks.dl_src);
- memset(&ctx->xout->wc.masks.dl_dst, 0xff,
- sizeof ctx->xout->wc.masks.dl_dst);
- memset(&ctx->xout->wc.masks.vlan_tci, 0xff,
- sizeof ctx->xout->wc.masks.vlan_tci);
+ memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+ memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
+ memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+ wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
in_bundle = lookup_input_bundle(ctx->ofproto, ctx->xin->flow.in_port,
ctx->xin->packet != NULL, &in_port);
/* Learn source MAC. */
if (ctx->xin->may_learn) {
- update_learning_table(ctx->ofproto, &ctx->xin->flow, &ctx->xout->wc,
+ update_learning_table(ctx->ofproto, &ctx->xin->flow, wc,
vlan, in_bundle);
}
CLS_CURSOR_FOR_EACH (facet, cr, &cursor) {
cls_rule_format(&facet->cr, &ds);
ds_put_cstr(&ds, ", ");
- ds_put_format(&ds, "n_subfacets:%"PRIu64", ",
- list_size(&facet->subfacets));
+ ds_put_format(&ds, "n_subfacets:%zu, ", list_size(&facet->subfacets));
ds_put_format(&ds, "used:%.3fs, ", (now - facet->used) / 1000.0);
ds_put_cstr(&ds, "Datapath actions: ");
- format_odp_actions(&ds, facet->xout.odp_actions.data,
- facet->xout.odp_actions.size);
+ if (facet->xout.slow) {
+ uint64_t slow_path_stub[128 / 8];
+ const struct nlattr *actions;
+ size_t actions_len;
+
+ compose_slow_path(ofproto, &facet->flow, facet->xout.slow,
+ slow_path_stub, sizeof slow_path_stub,
+ &actions, &actions_len);
+ format_odp_actions(&ds, actions, actions_len);
+ } else {
+ format_odp_actions(&ds, facet->xout.odp_actions.data,
+ facet->xout.odp_actions.size);
+ }
ds_put_cstr(&ds, "\n");
}