X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-xlate.c;h=a796f98600f623cc2cbef966262d9b520b1f4e5b;hb=ca077186ceac8cdf50dd76dc46e249cac78ce4c5;hp=ca650805a8ce79e3ecdcf1cd6bf5f8423a89af03;hpb=9583bc14430acc0578c1d00a78143c01d9cf7bee;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index ca650805a..a796f9860 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -43,6 +43,41 @@ COVERAGE_DEFINE(ofproto_dpif_xlate); VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate); +struct xlate_ctx { + struct xlate_in *xin; + struct xlate_out *xout; + + struct ofproto_dpif *ofproto; + + /* Flow at the last commit. */ + struct flow base_flow; + + /* Tunnel IP destination address as received. This is stored separately + * as the base_flow.tunnel is cleared on init to reflect the datapath + * behavior. Used to make sure not to send tunneled output to ourselves, + * which might lead to an infinite loop. This could happen easily + * if a tunnel is marked as 'ip_remote=flow', and the flow does not + * actually set the tun_dst field. */ + ovs_be32 orig_tunnel_ip_dst; + + /* Stack for the push and pop actions. Each stack element is of type + * "union mf_subvalue". */ + union mf_subvalue init_stack[1024 / sizeof(union mf_subvalue)]; + struct ofpbuf stack; + + /* The rule that we are currently translating, or NULL. */ + struct rule_dpif *rule; + + int recurse; /* Recursion level, via xlate_table_action. */ + bool max_resubmit_trigger; /* Recursed too deeply during translation. */ + uint32_t orig_skb_priority; /* Priority when packet arrived. */ + uint8_t table_id; /* OpenFlow table ID where flow was found. */ + uint32_t sflow_n_outputs; /* Number of output ports. */ + uint32_t sflow_odp_port; /* Output port for composing sFlow action. */ + uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */ + bool exit; /* No further actions should be processed. */ +}; + /* A controller may use OFPP_NONE as the ingress port to indicate that * it did not arrive on a "real" port. 'ofpp_none_bundle' exists for * when an input bundle is needed for validation (e.g., mirroring or @@ -335,6 +370,7 @@ static void output_normal(struct xlate_ctx *ctx, const struct ofbundle *out_bundle, uint16_t vlan) { + ovs_be16 *flow_tci = &ctx->xin->flow.vlan_tci; struct ofport_dpif *port; uint16_t vid; ovs_be16 tci, old_tci; @@ -351,18 +387,18 @@ output_normal(struct xlate_ctx *ctx, const struct ofbundle *out_bundle, } } - old_tci = ctx->xin->flow.vlan_tci; + old_tci = *flow_tci; tci = htons(vid); if (tci || out_bundle->use_priority_tags) { - tci |= ctx->xin->flow.vlan_tci & htons(VLAN_PCP_MASK); + tci |= *flow_tci & htons(VLAN_PCP_MASK); if (tci) { tci |= htons(VLAN_CFI); } } - ctx->xin->flow.vlan_tci = tci; + *flow_tci = tci; compose_output_action(ctx, port->up.ofp_port); - ctx->xin->flow.vlan_tci = old_tci; + *flow_tci = old_tci; } /* A VM broadcasts a gratuitous ARP to indicate that it has resumed after @@ -430,8 +466,7 @@ update_learning_table(struct ofproto_dpif *ofproto, in_bundle->name, vlan); mac->port.p = in_bundle; - tag_set_add(&ofproto->backer->revalidate_set, - mac_learning_changed(ofproto->ml, mac)); + mac_learning_changed(ofproto->ml, mac); } } @@ -495,6 +530,8 @@ is_admissible(struct xlate_ctx *ctx, struct ofport_dpif *in_port, static void xlate_normal(struct xlate_ctx *ctx) { + struct flow_wildcards *wc = &ctx->xout->wc; + struct flow *flow = &ctx->xin->flow; struct ofport_dpif *in_port; struct ofbundle *in_bundle; struct mac_entry *mac; @@ -504,17 +541,13 @@ xlate_normal(struct xlate_ctx *ctx) 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(&wc->masks.dl_type, 0xff, sizeof 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_src, 0xff, sizeof wc->masks.dl_src); + memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst); + memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci); - in_bundle = lookup_input_bundle(ctx->ofproto, ctx->xin->flow.in_port, + in_bundle = lookup_input_bundle(ctx->ofproto, flow->in_port, ctx->xin->packet != NULL, &in_port); if (!in_bundle) { xlate_report(ctx, "no input bundle, dropping"); @@ -522,8 +555,8 @@ xlate_normal(struct xlate_ctx *ctx) } /* Drop malformed frames. */ - if (ctx->xin->flow.dl_type == htons(ETH_TYPE_VLAN) && - !(ctx->xin->flow.vlan_tci & htons(VLAN_CFI))) { + if (flow->dl_type == htons(ETH_TYPE_VLAN) && + !(flow->vlan_tci & htons(VLAN_CFI))) { if (ctx->xin->packet != NULL) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "bridge %s: dropping packet with partial " @@ -547,7 +580,7 @@ xlate_normal(struct xlate_ctx *ctx) } /* Check VLAN. */ - vid = vlan_tci_to_vid(ctx->xin->flow.vlan_tci); + vid = vlan_tci_to_vid(flow->vlan_tci); if (!input_vid_is_valid(vid, in_bundle, ctx->xin->packet != NULL)) { xlate_report(ctx, "disallowed VLAN VID for this input port, dropping"); return; @@ -561,12 +594,11 @@ xlate_normal(struct xlate_ctx *ctx) /* Learn source MAC. */ if (ctx->xin->may_learn) { - update_learning_table(ctx->ofproto, &ctx->xin->flow, &ctx->xout->wc, - vlan, in_bundle); + update_learning_table(ctx->ofproto, flow, wc, vlan, in_bundle); } /* Determine output bundle. */ - mac = mac_learning_lookup(ctx->ofproto->ml, ctx->xin->flow.dl_dst, vlan, + mac = mac_learning_lookup(ctx->ofproto->ml, flow->dl_dst, vlan, &ctx->xout->tags); if (mac) { if (mac->port.p != in_bundle) { @@ -759,11 +791,12 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, bool check_stp) { const struct ofport_dpif *ofport = get_ofp_port(ctx->ofproto, ofp_port); + struct flow *flow = &ctx->xin->flow; ovs_be16 flow_vlan_tci; uint32_t flow_skb_mark; uint8_t flow_nw_tos; - struct priority_to_dscp *pdscp; uint32_t out_port, odp_port; + uint8_t dscp; /* If 'struct flow' gets additional metadata, we'll need to zero it out * before traversing a patch port. */ @@ -783,7 +816,6 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, if (netdev_vport_is_patch(ofport->up.netdev)) { struct ofport_dpif *peer = ofport_get_peer(ofport); struct flow old_flow = ctx->xin->flow; - const struct ofproto_dpif *peer_ofproto; enum slow_path_reason special; struct ofport_dpif *in_port; @@ -792,32 +824,26 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, return; } - peer_ofproto = ofproto_dpif_cast(peer->up.ofproto); - if (peer_ofproto->backer != ctx->ofproto->backer) { - xlate_report(ctx, "Patch port peer on a different datapath"); - return; - } - ctx->ofproto = ofproto_dpif_cast(peer->up.ofproto); - ctx->xin->flow.in_port = peer->up.ofp_port; - ctx->xin->flow.metadata = htonll(0); - memset(&ctx->xin->flow.tunnel, 0, sizeof ctx->xin->flow.tunnel); - memset(ctx->xin->flow.regs, 0, sizeof ctx->xin->flow.regs); + flow->in_port = peer->up.ofp_port; + flow->metadata = htonll(0); + memset(&flow->tunnel, 0, sizeof flow->tunnel); + memset(flow->regs, 0, sizeof flow->regs); - in_port = get_ofp_port(ctx->ofproto, ctx->xin->flow.in_port); + in_port = get_ofp_port(ctx->ofproto, flow->in_port); special = process_special(ctx->ofproto, &ctx->xin->flow, in_port, ctx->xin->packet); if (special) { ctx->xout->slow = special; } else if (!in_port || may_receive(in_port, ctx)) { if (!in_port || stp_forward_in_state(in_port->stp_state)) { - xlate_table_action(ctx, ctx->xin->flow.in_port, 0, true); + xlate_table_action(ctx, flow->in_port, 0, true); } else { /* Forwarding is disabled by STP. Let OFPP_NORMAL and the * learning action look at the packet, then drop it. */ struct flow old_base_flow = ctx->base_flow; size_t old_size = ctx->xout->odp_actions.size; - xlate_table_action(ctx, ctx->xin->flow.in_port, 0, true); + xlate_table_action(ctx, flow->in_port, 0, true); ctx->base_flow = old_base_flow; ctx->xout->odp_actions.size = old_size; } @@ -834,14 +860,13 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, return; } - flow_vlan_tci = ctx->xin->flow.vlan_tci; - flow_skb_mark = ctx->xin->flow.skb_mark; - flow_nw_tos = ctx->xin->flow.nw_tos; + flow_vlan_tci = flow->vlan_tci; + flow_skb_mark = flow->skb_mark; + flow_nw_tos = flow->nw_tos; - pdscp = get_priority(ofport, ctx->xin->flow.skb_priority); - if (pdscp) { - ctx->xin->flow.nw_tos &= ~IP_DSCP_MASK; - ctx->xin->flow.nw_tos |= pdscp->dscp; + if (ofproto_dpif_dscp_from_priority(ofport, flow->skb_priority, &dscp)) { + flow->nw_tos &= ~IP_DSCP_MASK; + flow->nw_tos |= dscp; } if (ofport->tnl_port) { @@ -849,13 +874,13 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, * the Logical (tunnel) Port are not visible for any further * 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); + struct flow_tnl flow_tnl = flow->tunnel; + odp_port = tnl_port_send(ofport->tnl_port, flow); if (odp_port == OVSP_NONE) { xlate_report(ctx, "Tunneling decided against output"); goto out; /* restore flow_nw_tos */ } - if (ctx->xin->flow.tunnel.ip_dst == ctx->orig_tunnel_ip_dst) { + if (flow->tunnel.ip_dst == ctx->orig_tunnel_ip_dst) { xlate_report(ctx, "Not tunneling to our own address"); goto out; /* restore flow_nw_tos */ } @@ -863,24 +888,23 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, netdev_vport_inc_tx(ofport->up.netdev, ctx->xin->resubmit_stats); } out_port = odp_port; - commit_odp_tunnel_action(&ctx->xin->flow, &ctx->base_flow, + commit_odp_tunnel_action(flow, &ctx->base_flow, &ctx->xout->odp_actions); - ctx->xin->flow.tunnel = flow_tnl; /* Restore tunnel metadata */ + flow->tunnel = flow_tnl; /* Restore tunnel metadata */ } else { uint16_t vlandev_port; odp_port = ofport->odp_port; vlandev_port = vsp_realdev_to_vlandev(ctx->ofproto, ofp_port, - ctx->xin->flow.vlan_tci); + flow->vlan_tci); if (vlandev_port == ofp_port) { out_port = odp_port; } else { out_port = ofp_port_to_odp_port(ctx->ofproto, vlandev_port); - ctx->xin->flow.vlan_tci = htons(0); + flow->vlan_tci = htons(0); } - ctx->xin->flow.skb_mark &= ~IPSEC_MARK; + flow->skb_mark &= ~IPSEC_MARK; } - commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, - &ctx->xout->odp_actions); + commit_odp_actions(flow, &ctx->base_flow, &ctx->xout->odp_actions); nl_msg_put_u32(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port); ctx->sflow_odp_port = odp_port; @@ -888,10 +912,10 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port, ctx->xout->nf_output_iface = ofp_port; /* Restore flow */ - ctx->xin->flow.vlan_tci = flow_vlan_tci; - ctx->xin->flow.skb_mark = flow_skb_mark; + flow->vlan_tci = flow_vlan_tci; + flow->skb_mark = flow_skb_mark; out: - ctx->xin->flow.nw_tos = flow_nw_tos; + flow->nw_tos = flow_nw_tos; } static void @@ -924,7 +948,7 @@ ctx_rule_hooks(struct xlate_ctx *ctx, struct rule_dpif *rule, bool may_packet_in) { if (ctx->xin->resubmit_hook) { - ctx->xin->resubmit_hook(ctx, rule); + ctx->xin->resubmit_hook(ctx->xin, rule, ctx->recurse); } if (rule == NULL && may_packet_in) { /* XXX @@ -1070,55 +1094,55 @@ execute_controller_action(struct xlate_ctx *ctx, int len, } static void -execute_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type) +compose_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type) { + struct flow_wildcards *wc = &ctx->xout->wc; + struct flow *flow = &ctx->xin->flow; + 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); - ctx->xin->flow.mpls_depth++; + if (flow->mpls_depth) { + flow->mpls_lse &= ~htonl(MPLS_BOS_MASK); + flow->mpls_depth++; } else { ovs_be32 label; uint8_t tc, ttl; - if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IPV6)) { + if (flow->dl_type == htons(ETH_TYPE_IPV6)) { label = htonl(0x2); /* IPV6 Explicit Null. */ } else { label = htonl(0x0); /* IPV4 Explicit Null. */ } - 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); - ctx->xin->flow.mpls_depth = 1; + tc = (flow->nw_tos & IP_DSCP_MASK) >> 2; + ttl = flow->nw_ttl ? flow->nw_ttl : 0x40; + flow->mpls_lse = set_mpls_lse_values(ttl, tc, 1, label); + flow->mpls_depth = 1; } - ctx->xin->flow.dl_type = eth_type; + flow->dl_type = eth_type; } static void -execute_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type) +compose_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type) { + struct flow_wildcards *wc = &ctx->xout->wc; + struct flow *flow = &ctx->xin->flow; + 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); - - if (ctx->xin->flow.mpls_depth) { - ctx->xin->flow.mpls_depth--; - ctx->xin->flow.mpls_lse = htonl(0); - if (!ctx->xin->flow.mpls_depth) { - ctx->xin->flow.dl_type = eth_type; + 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 (flow->mpls_depth) { + flow->mpls_depth--; + flow->mpls_lse = htonl(0); + if (!flow->mpls_depth) { + flow->dl_type = eth_type; } } } @@ -1126,13 +1150,14 @@ execute_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type) static bool compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) { - if (ctx->xin->flow.dl_type != htons(ETH_TYPE_IP) && - ctx->xin->flow.dl_type != htons(ETH_TYPE_IPV6)) { + struct flow *flow = &ctx->xin->flow; + + if (!is_ip_any(flow)) { return false; } - if (ctx->xin->flow.nw_ttl > 1) { - ctx->xin->flow.nw_ttl--; + if (flow->nw_ttl > 1) { + flow->nw_ttl--; return false; } else { size_t i; @@ -1148,7 +1173,7 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) } static bool -execute_set_mpls_ttl_action(struct xlate_ctx *ctx, uint8_t ttl) +compose_set_mpls_ttl_action(struct xlate_ctx *ctx, uint8_t ttl) { if (!eth_type_mpls(ctx->xin->flow.dl_type)) { return true; @@ -1159,17 +1184,18 @@ execute_set_mpls_ttl_action(struct xlate_ctx *ctx, uint8_t ttl) } static bool -execute_dec_mpls_ttl_action(struct xlate_ctx *ctx) +compose_dec_mpls_ttl_action(struct xlate_ctx *ctx) { - uint8_t ttl = mpls_lse_to_ttl(ctx->xin->flow.mpls_lse); + struct flow *flow = &ctx->xin->flow; + uint8_t ttl = mpls_lse_to_ttl(flow->mpls_lse); - if (!eth_type_mpls(ctx->xin->flow.dl_type)) { + if (!eth_type_mpls(flow->dl_type)) { return false; } if (ttl > 1) { ttl--; - set_mpls_lse_ttl(&ctx->xin->flow.mpls_lse, ttl); + set_mpls_lse_ttl(&flow->mpls_lse, ttl); return false; } else { execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0); @@ -1252,8 +1278,7 @@ xlate_enqueue_action(struct xlate_ctx *ctx, int error; /* Translate queue to priority. */ - error = dpif_queue_to_priority(ctx->ofproto->backer->dpif, - queue_id, &priority); + error = ofproto_dpif_queue_to_priority(ctx->ofproto, queue_id, &priority); if (error) { /* Fall back to ordinary output action. */ xlate_output_action(ctx, enqueue->port, 0, false); @@ -1286,8 +1311,8 @@ xlate_set_queue_action(struct xlate_ctx *ctx, uint32_t queue_id) { uint32_t skb_priority; - if (!dpif_queue_to_priority(ctx->ofproto->backer->dpif, - queue_id, &skb_priority)) { + if (!ofproto_dpif_queue_to_priority(ctx->ofproto, queue_id, + &skb_priority)) { ctx->xin->flow.skb_priority = skb_priority; } else { /* Couldn't translate queue to a priority. Nothing to do. A warning @@ -1446,6 +1471,8 @@ static void do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, struct xlate_ctx *ctx) { + struct flow_wildcards *wc = &ctx->xout->wc; + struct flow *flow = &ctx->xin->flow; bool was_evictable = true; const struct ofpact *a; @@ -1482,83 +1509,71 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_VLAN_VID: - ctx->xin->flow.vlan_tci &= ~htons(VLAN_VID_MASK); - ctx->xin->flow.vlan_tci |= - (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid) - | htons(VLAN_CFI)); + 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: - ctx->xin->flow.vlan_tci &= ~htons(VLAN_PCP_MASK); - ctx->xin->flow.vlan_tci |= + 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: - ctx->xin->flow.vlan_tci = htons(0); + flow->vlan_tci = htons(0); break; case OFPACT_PUSH_VLAN: /* XXX 802.1AD(QinQ) */ - ctx->xin->flow.vlan_tci = htons(VLAN_CFI); + flow->vlan_tci = htons(VLAN_CFI); break; case OFPACT_SET_ETH_SRC: - memcpy(ctx->xin->flow.dl_src, ofpact_get_SET_ETH_SRC(a)->mac, - ETH_ADDR_LEN); + memcpy(flow->dl_src, ofpact_get_SET_ETH_SRC(a)->mac, ETH_ADDR_LEN); break; case OFPACT_SET_ETH_DST: - memcpy(ctx->xin->flow.dl_dst, ofpact_get_SET_ETH_DST(a)->mac, - ETH_ADDR_LEN); + memcpy(flow->dl_dst, ofpact_get_SET_ETH_DST(a)->mac, ETH_ADDR_LEN); break; case OFPACT_SET_IPV4_SRC: - memset(&ctx->xout->wc.masks.dl_type, 0xff, - sizeof ctx->xout->wc.masks.dl_type); - if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IP)) { - ctx->xin->flow.nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4; + memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); + if (flow->dl_type == htons(ETH_TYPE_IP)) { + flow->nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4; } break; case OFPACT_SET_IPV4_DST: - memset(&ctx->xout->wc.masks.dl_type, 0xff, - sizeof ctx->xout->wc.masks.dl_type); - if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IP)) { - ctx->xin->flow.nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4; + memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); + if (flow->dl_type == htons(ETH_TYPE_IP)) { + flow->nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4; } break; case OFPACT_SET_IPV4_DSCP: /* OpenFlow 1.0 only supports IPv4. */ - memset(&ctx->xout->wc.masks.dl_type, 0xff, - sizeof ctx->xout->wc.masks.dl_type); - if (ctx->xin->flow.dl_type == htons(ETH_TYPE_IP)) { - ctx->xin->flow.nw_tos &= ~IP_DSCP_MASK; - ctx->xin->flow.nw_tos |= ofpact_get_SET_IPV4_DSCP(a)->dscp; + memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); + if (flow->dl_type == htons(ETH_TYPE_IP)) { + flow->nw_tos &= ~IP_DSCP_MASK; + flow->nw_tos |= ofpact_get_SET_IPV4_DSCP(a)->dscp; } break; case OFPACT_SET_L4_SRC_PORT: - memset(&ctx->xout->wc.masks.dl_type, 0xff, - sizeof ctx->xout->wc.masks.dl_type); - memset(&ctx->xout->wc.masks.nw_proto, 0xff, - sizeof ctx->xout->wc.masks.nw_proto); - if (is_ip_any(&ctx->xin->flow)) { - ctx->xin->flow.tp_src = - htons(ofpact_get_SET_L4_SRC_PORT(a)->port); + memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); + if (is_ip_any(flow)) { + flow->tp_src = htons(ofpact_get_SET_L4_SRC_PORT(a)->port); } break; case OFPACT_SET_L4_DST_PORT: - memset(&ctx->xout->wc.masks.dl_type, 0xff, - sizeof ctx->xout->wc.masks.dl_type); - memset(&ctx->xout->wc.masks.nw_proto, 0xff, - sizeof ctx->xout->wc.masks.nw_proto); - if (is_ip_any(&ctx->xin->flow)) { - ctx->xin->flow.tp_dst = - htons(ofpact_get_SET_L4_DST_PORT(a)->port); + memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); + if (is_ip_any(flow)) { + flow->tp_dst = htons(ofpact_get_SET_L4_DST_PORT(a)->port); } break; @@ -1567,8 +1582,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_TUNNEL: - ctx->xin->flow.tunnel.tun_id = - htonll(ofpact_get_SET_TUNNEL(a)->tun_id); + flow->tunnel.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id); break; case OFPACT_SET_QUEUE: @@ -1576,55 +1590,52 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_POP_QUEUE: - memset(&ctx->xout->wc.masks.skb_priority, 0xff, - sizeof ctx->xout->wc.masks.skb_priority); + memset(&wc->masks.skb_priority, 0xff, + sizeof wc->masks.skb_priority); - ctx->xin->flow.skb_priority = ctx->orig_skb_priority; + flow->skb_priority = ctx->orig_skb_priority; break; case OFPACT_REG_MOVE: - nxm_execute_reg_move(ofpact_get_REG_MOVE(a), &ctx->xin->flow, - &ctx->xout->wc); + nxm_execute_reg_move(ofpact_get_REG_MOVE(a), flow, wc); break; case OFPACT_REG_LOAD: - nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->xin->flow); + nxm_execute_reg_load(ofpact_get_REG_LOAD(a), flow); break; case OFPACT_STACK_PUSH: - nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), &ctx->xin->flow, - &ctx->xout->wc, &ctx->stack); + nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), flow, wc, + &ctx->stack); break; case OFPACT_STACK_POP: - nxm_execute_stack_pop(ofpact_get_STACK_POP(a), &ctx->xin->flow, - &ctx->stack); + nxm_execute_stack_pop(ofpact_get_STACK_POP(a), flow, &ctx->stack); break; case OFPACT_PUSH_MPLS: - execute_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)->ethertype); + compose_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)->ethertype); break; case OFPACT_POP_MPLS: - execute_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype); + compose_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype); break; case OFPACT_SET_MPLS_TTL: - if (execute_set_mpls_ttl_action(ctx, + if (compose_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl)) { goto out; } break; case OFPACT_DEC_MPLS_TTL: - if (execute_dec_mpls_ttl_action(ctx)) { + if (compose_dec_mpls_ttl_action(ctx)) { goto out; } break; case OFPACT_DEC_TTL: - memset(&ctx->xout->wc.masks.dl_type, 0xff, - sizeof ctx->xout->wc.masks.dl_type); + memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) { goto out; } @@ -1635,8 +1646,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_MULTIPATH: - multipath_execute(ofpact_get_MULTIPATH(a), &ctx->xin->flow, - &ctx->xout->wc); + multipath_execute(ofpact_get_MULTIPATH(a), flow, wc); break; case OFPACT_BUNDLE: @@ -1657,10 +1667,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_FIN_TIMEOUT: - memset(&ctx->xout->wc.masks.dl_type, 0xff, - sizeof ctx->xout->wc.masks.dl_type); - memset(&ctx->xout->wc.masks.nw_proto, 0xff, - sizeof ctx->xout->wc.masks.nw_proto); + memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); ctx->xout->has_fin_timeout = true; xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a)); break; @@ -1675,8 +1683,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_WRITE_METADATA: metadata = ofpact_get_WRITE_METADATA(a); - ctx->xin->flow.metadata &= ~metadata->mask; - ctx->xin->flow.metadata |= metadata->metadata & metadata->mask; + flow->metadata &= ~metadata->mask; + flow->metadata |= metadata->metadata & metadata->mask; break; case OFPACT_GOTO_TABLE: { @@ -1689,8 +1697,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, ctx->table_id = ogt->table_id; /* Look up a flow from the new table. */ - rule = rule_dpif_lookup_in_table(ctx->ofproto, &ctx->xin->flow, - &ctx->xout->wc, ctx->table_id); + rule = rule_dpif_lookup_in_table(ctx->ofproto, flow, wc, + ctx->table_id); tag_the_flow(ctx, rule); @@ -1765,7 +1773,7 @@ static void xlate_report(struct xlate_ctx *ctx, const char *s) { if (ctx->xin->report_hook) { - ctx->xin->report_hook(ctx, s); + ctx->xin->report_hook(ctx->xin, s, ctx->recurse); } } @@ -1798,6 +1806,9 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) * tracing purposes. */ static bool hit_resubmit_limit; + struct flow_wildcards *wc = &xout->wc; + struct flow *flow = &xin->flow; + enum slow_path_reason special; const struct ofpact *ofpacts; struct ofport_dpif *in_port; @@ -1834,39 +1845,28 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.ofproto = xin->ofproto; ctx.rule = xin->rule; - ctx.base_flow = ctx.xin->flow; + ctx.base_flow = *flow; memset(&ctx.base_flow.tunnel, 0, sizeof ctx.base_flow.tunnel); - ctx.orig_tunnel_ip_dst = ctx.xin->flow.tunnel.ip_dst; + ctx.orig_tunnel_ip_dst = flow->tunnel.ip_dst; - flow_wildcards_init_catchall(&ctx.xout->wc); - memset(&ctx.xout->wc.masks.in_port, 0xff, - sizeof ctx.xout->wc.masks.in_port); + flow_wildcards_init_catchall(wc); + memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port); 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); + memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src); + memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst); + memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); + memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci); + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); + memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); + memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); + memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); + memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); } ctx.xout->tags = 0; @@ -1883,7 +1883,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.recurse = 0; ctx.max_resubmit_trigger = false; - ctx.orig_skb_priority = ctx.xin->flow.skb_priority; + ctx.orig_skb_priority = flow->skb_priority; ctx.table_id = 0; ctx.exit = false; @@ -1902,15 +1902,15 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) if (ctx.ofproto->has_mirrors || hit_resubmit_limit) { /* Do this conditionally because the copy is expensive enough that it * shows up in profiles. */ - orig_flow = ctx.xin->flow; + orig_flow = *flow; } - if (ctx.xin->flow.nw_frag & FLOW_NW_FRAG_ANY) { + if (flow->nw_frag & FLOW_NW_FRAG_ANY) { switch (ctx.ofproto->up.frag_handling) { case OFPC_FRAG_NORMAL: /* We must pretend that transport ports are unavailable. */ - ctx.xin->flow.tp_src = ctx.base_flow.tp_src = htons(0); - ctx.xin->flow.tp_dst = ctx.base_flow.tp_dst = htons(0); + flow->tp_src = ctx.base_flow.tp_src = htons(0); + flow->tp_dst = ctx.base_flow.tp_dst = htons(0); break; case OFPC_FRAG_DROP: @@ -1928,9 +1928,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } } - in_port = get_ofp_port(ctx.ofproto, ctx.xin->flow.in_port); - special = process_special(ctx.ofproto, &ctx.xin->flow, in_port, - ctx.xin->packet); + in_port = get_ofp_port(ctx.ofproto, flow->in_port); + special = process_special(ctx.ofproto, flow, in_port, ctx.xin->packet); if (special) { ctx.xout->slow = special; } else { @@ -1938,9 +1937,9 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) size_t sample_actions_len; uint32_t local_odp_port; - if (ctx.xin->flow.in_port - != vsp_realdev_to_vlandev(ctx.ofproto, ctx.xin->flow.in_port, - ctx.xin->flow.vlan_tci)) { + if (flow->in_port + != vsp_realdev_to_vlandev(ctx.ofproto, flow->in_port, + flow->vlan_tci)) { ctx.base_flow.vlan_tci = 0; } @@ -1974,7 +1973,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } local_odp_port = ofp_port_to_odp_port(ctx.ofproto, OFPP_LOCAL); - if (!connmgr_must_output_local(ctx.ofproto->up.connmgr, &ctx.xin->flow, + if (!connmgr_must_output_local(ctx.ofproto->up.connmgr, flow, local_odp_port, ctx.xout->odp_actions.data, ctx.xout->odp_actions.size)) { @@ -1990,7 +1989,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) /* Clear the metadata and register wildcard masks, because we won't * use non-header fields as part of the cache. */ - memset(&ctx.xout->wc.masks.metadata, 0, - sizeof ctx.xout->wc.masks.metadata); - memset(&ctx.xout->wc.masks.regs, 0, sizeof ctx.xout->wc.masks.regs); + memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata); + memset(&wc->masks.regs, 0, sizeof wc->masks.regs); }