X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-xlate.c;h=ffcfdf9be6ff1973ae3d3276aa8e9fa8b668e654;hb=f1c8a79c626f383926b70eb1885c40f8a427ba23;hp=065560f9b2f0d65f18c1d0443a5c156f31a4335b;hpb=3f2079100ba9f7d24586dec4237c942e214cc571;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 065560f9b..ffcfdf9be 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. +/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +42,7 @@ #include "ofp-actions.h" #include "ofproto/ofproto-dpif-ipfix.h" #include "ofproto/ofproto-dpif-mirror.h" +#include "ofproto/ofproto-dpif-monitor.h" #include "ofproto/ofproto-dpif-sflow.h" #include "ofproto/ofproto-dpif.h" #include "ofproto/ofproto-provider.h" @@ -50,6 +51,7 @@ COVERAGE_DEFINE(xlate_actions); COVERAGE_DEFINE(xlate_actions_oversize); +COVERAGE_DEFINE(xlate_actions_mpls_overflow); VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate); @@ -86,6 +88,15 @@ struct xbridge { enum ofp_config_flags frag; /* Fragmentation handling. */ bool has_in_band; /* Bridge has in band control? */ bool forward_bpdu; /* Bridge forwards STP BPDUs? */ + + /* 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; }; struct xbundle { @@ -164,13 +175,6 @@ struct xlate_ctx { /* The rule that we are currently translating, or NULL. */ struct rule_dpif *rule; - int mpls_depth_delta; /* Delta of the mpls stack depth since - * actions were last committed. - * Must be between -1 and 1 inclusive. */ - ovs_be32 pre_push_mpls_lse; /* Used to record the top-most MPLS LSE - * prior to an mpls_push so that it may be - * used for a subsequent mpls_pop. */ - /* Resubmit statistics, via xlate_table_action(). */ int recurse; /* Current resubmit nesting depth. */ int resubmits; /* Total number of resubmits. */ @@ -248,7 +252,9 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name, const struct dpif_sflow *sflow, const struct dpif_ipfix *ipfix, const struct netflow *netflow, enum ofp_config_flags frag, - bool forward_bpdu, bool has_in_band) + bool forward_bpdu, bool has_in_band, + bool variable_length_userdata, + size_t max_mpls_depth) { struct xbridge *xbridge = xbridge_lookup(ofproto); @@ -300,6 +306,8 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name, xbridge->frag = frag; xbridge->miss_rule = miss_rule; xbridge->no_packet_in_rule = no_packet_in_rule; + xbridge->variable_length_userdata = variable_length_userdata; + xbridge->max_mpls_depth = max_mpls_depth; } void @@ -512,12 +520,10 @@ xlate_ofport_remove(struct ofport_dpif *ofport) /* Given a datpath, packet, and flow metadata ('backer', 'packet', and 'key' * respectively), populates 'flow' with the result of odp_flow_key_to_flow(). - * Optionally, if nonnull, populates 'fitnessp' with the fitness of 'flow' as - * returned by odp_flow_key_to_flow(). Also, optionally populates 'ofproto' - * with the ofproto_dpif, 'odp_in_port' with the datapath in_port, that - * 'packet' ingressed, and 'ipfix', 'sflow', and 'netflow' with the appropriate - * handles for those protocols if they're enabled. Caller is responsible for - * unrefing them. + * Optionally populates 'ofproto' with the ofproto_dpif, 'odp_in_port' with + * the datapath in_port, that 'packet' ingressed, and 'ipfix', 'sflow', and + * 'netflow' with the appropriate handles for those protocols if they're + * enabled. Caller is responsible for unrefing them. * * If 'ofproto' is nonnull, requires 'flow''s in_port to exist. Otherwise sets * 'flow''s in_port to OFPP_NONE. @@ -537,19 +543,16 @@ xlate_ofport_remove(struct ofport_dpif *ofport) * or some other positive errno if there are other problems. */ int xlate_receive(const struct dpif_backer *backer, struct ofpbuf *packet, - const struct nlattr *key, size_t key_len, - struct flow *flow, enum odp_key_fitness *fitnessp, + const struct nlattr *key, size_t key_len, struct flow *flow, struct ofproto_dpif **ofproto, struct dpif_ipfix **ipfix, struct dpif_sflow **sflow, struct netflow **netflow, odp_port_t *odp_in_port) { - enum odp_key_fitness fitness; const struct xport *xport; int error = ENODEV; ovs_rwlock_rdlock(&xlate_rwlock); - fitness = odp_flow_key_to_flow(key, key_len, flow); - if (fitness == ODP_FIT_ERROR) { + if (odp_flow_key_to_flow(key, key_len, flow) == ODP_FIT_ERROR) { error = EINVAL; goto exit; } @@ -572,22 +575,9 @@ xlate_receive(const struct dpif_backer *backer, struct ofpbuf *packet, /* Make the packet resemble the flow, so that it gets sent to * an OpenFlow controller properly, so that it looks correct * for sFlow, and so that flow_extract() will get the correct - * vlan_tci if it is called on 'packet'. - * - * The allocated space inside 'packet' probably also contains - * 'key', that is, both 'packet' and 'key' are probably part of - * a struct dpif_upcall (see the large comment on that - * structure definition), so pushing data on 'packet' is in - * general not a good idea since it could overwrite 'key' or - * free it as a side effect. However, it's OK in this special - * case because we know that 'packet' is inside a Netlink - * attribute: pushing 4 bytes will just overwrite the 4-byte - * "struct nlattr", which is fine since we don't need that - * header anymore. */ - eth_push_vlan(packet, flow->vlan_tci); + * vlan_tci if it is called on 'packet'. */ + eth_push_vlan(packet, htons(ETH_TYPE_VLAN), flow->vlan_tci); } - /* We can't reproduce 'key' from 'flow'. */ - fitness = fitness == ODP_FIT_PERFECT ? ODP_FIT_TOO_MUCH : fitness; } error = 0; @@ -608,9 +598,6 @@ xlate_receive(const struct dpif_backer *backer, struct ofpbuf *packet, } exit: - if (fitnessp) { - *fitnessp = fitness; - } ovs_rwlock_unlock(&xlate_rwlock); return error; } @@ -979,7 +966,7 @@ add_mirror_actions(struct xlate_ctx *ctx, const struct flow *orig_flow) bool has_mirror; int out_vlan; - has_mirror = mirror_get(xbridge->mbridge, mirror_mask_ffs(mirrors) - 1, + has_mirror = mirror_get(xbridge->mbridge, raw_ctz(mirrors), &vlans, &dup_mirrors, &out, &out_vlan); ovs_assert(has_mirror); @@ -1037,7 +1024,7 @@ input_vid_to_vlan(const struct xbundle *in_xbundle, uint16_t vid) return vid ? vid : in_xbundle->vlan; default: - NOT_REACHED(); + OVS_NOT_REACHED(); } } @@ -1090,7 +1077,7 @@ input_vid_is_valid(uint16_t vid, struct xbundle *in_xbundle, bool warn) return true; default: - NOT_REACHED(); + OVS_NOT_REACHED(); } } @@ -1117,7 +1104,7 @@ output_vlan_to_vid(const struct xbundle *out_xbundle, uint16_t vlan) return vlan == out_xbundle->vlan ? 0 : vlan; default: - NOT_REACHED(); + OVS_NOT_REACHED(); } } @@ -1656,6 +1643,14 @@ process_special(struct xlate_ctx *ctx, const struct flow *flow, } else if (xport->bfd && bfd_should_process_flow(xport->bfd, flow, wc)) { if (packet) { bfd_process_packet(xport->bfd, flow, packet); + /* If POLL received, immediately sends FINAL back. */ + if (bfd_should_send_packet(xport->bfd)) { + if (xport->peer) { + ofproto_dpif_monitor_port_send_soon(xport->ofport); + } else { + ofproto_dpif_monitor_port_send_soon_safe(xport->ofport); + } + } } return SLOW_BFD; } else if (xport->xbundle && xport->xbundle->lacp @@ -1689,7 +1684,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, /* If 'struct flow' gets additional metadata, we'll need to zero it out * before traversing a patch port. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 23); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 24); if (!xport) { xlate_report(ctx, "Nonexistent output port"); @@ -1804,8 +1799,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, if (out_port != ODPP_NONE) { ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc, - &ctx->mpls_depth_delta); + &ctx->xout->wc); nl_msg_put_odp_port(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port); @@ -1999,7 +1993,7 @@ xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group) xlate_ff_group(ctx, group); break; default: - NOT_REACHED(); + OVS_NOT_REACHED(); } group_dpif_release(group); } @@ -2069,7 +2063,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len, { struct ofproto_packet_in *pin; struct ofpbuf *packet; - struct flow key; + struct pkt_metadata md = PKT_METADATA_INITIALIZER(0); ctx->xout->slow |= SLOW_CONTROLLER; if (!ctx->xin->packet) { @@ -2078,17 +2072,12 @@ execute_controller_action(struct xlate_ctx *ctx, int len, packet = ofpbuf_clone(ctx->xin->packet); - key.skb_priority = 0; - key.pkt_mark = 0; - memset(&key.tunnel, 0, sizeof key.tunnel); - ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc, - &ctx->mpls_depth_delta); + &ctx->xout->wc); - odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data, - ctx->xout->odp_actions.size, NULL, NULL); + odp_execute_actions(NULL, packet, &md, ctx->xout->odp_actions.data, + ctx->xout->odp_actions.size, NULL); pin = xmalloc(sizeof *pin); pin->up.packet_len = packet->size; @@ -2109,99 +2098,56 @@ execute_controller_action(struct xlate_ctx *ctx, int len, ofpbuf_delete(packet); } -static bool -compose_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type) +static void +compose_mpls_push_action(struct xlate_ctx *ctx, struct ofpact_push_mpls *mpls) { struct flow_wildcards *wc = &ctx->xout->wc; struct flow *flow = &ctx->xin->flow; + int n; - ovs_assert(eth_type_mpls(eth_type)); - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * composed and the resulting MPLS label stack is unknown. This means - * an MPLS PUSH action can't be composed as it needs to know either the - * top-most MPLS LSE to use as a template for the new MPLS LSE, or that - * there is no MPLS label stack present. Thus, stop processing. - * - * If mpls_depth_delta is positive then an MPLS PUSH action has been - * composed and no further MPLS PUSH action may be performed without - * losing MPLS LSE and ether type information held in xtx->xin->flow. - * Thus, stop processing. - * - * If the MPLS LSE of the flow and base_flow differ then the MPLS LSE - * has been updated. Performing a MPLS PUSH action may be would result in - * losing MPLS LSE and ether type information held in xtx->xin->flow. - * Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation */ - if (ctx->mpls_depth_delta || - ctx->xin->flow.mpls_lse != ctx->base_flow.mpls_lse) { - return true; - } - - memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse); - - ctx->pre_push_mpls_lse = ctx->xin->flow.mpls_lse; - - if (eth_type_mpls(ctx->xin->flow.dl_type)) { - flow->mpls_lse &= ~htonl(MPLS_BOS_MASK); - } else { - ovs_be32 label; - uint8_t tc, ttl; + ovs_assert(eth_type_mpls(mpls->ethertype)); - if (flow->dl_type == htons(ETH_TYPE_IPV6)) { - label = htonl(0x2); /* IPV6 Explicit Null. */ - } else { - label = htonl(0x0); /* IPV4 Explicit Null. */ + n = flow_count_mpls_labels(flow, wc); + if (!n) { + ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow, + &ctx->xout->odp_actions, + &ctx->xout->wc); + } else if (n >= FLOW_MAX_MPLS_LABELS) { + 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 on which an " + "MPLS push action can't be performed as it would " + "have more MPLS LSEs than the %d supported.", + ctx->xbridge->name, FLOW_MAX_MPLS_LABELS); } - wc->masks.nw_tos |= IP_DSCP_MASK; - wc->masks.nw_ttl = 0xff; - 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); + ctx->exit = true; + return; + } else if (n >= ctx->xbridge->max_mpls_depth) { + COVERAGE_INC(xlate_actions_mpls_overflow); + ctx->xout->slow |= SLOW_ACTION; } - flow->dl_type = eth_type; - ctx->mpls_depth_delta++; - return false; + flow_push_mpls(flow, n, mpls->ethertype, wc); } -static bool +static void 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; + int n = flow_count_mpls_labels(flow, wc); - if (!eth_type_mpls(ctx->xin->flow.dl_type)) { - return true; - } - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * composed. Performing another MPLS POP action - * would result in losing ether type that results from - * the already composed MPLS POP. Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation */ - if (ctx->mpls_depth_delta < 0) { - return true; - } - - memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse); - - /* If mpls_depth_delta is positive then an MPLS PUSH action has been - * executed and the previous MPLS LSE saved in ctx->pre_push_mpls_lse. The - * flow's MPLS LSE should be restored to that value to allow any - * subsequent actions that update of the LSE to be executed correctly. - */ - if (ctx->mpls_depth_delta > 0) { - ctx->xin->flow.mpls_lse = ctx->pre_push_mpls_lse; + if (!flow_pop_mpls(flow, n, eth_type, wc) && n >= FLOW_MAX_MPLS_LABELS) { + 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 on which an " + "MPLS pop action can't be performed as it has " + "more MPLS LSEs than the %d supported.", + ctx->xbridge->name, FLOW_MAX_MPLS_LABELS); + } + ctx->exit = true; + ofpbuf_clear(&ctx->xout->odp_actions); } - - ctx->xin->flow.dl_type = eth_type; - ctx->mpls_depth_delta--; - - return false; } static bool @@ -2230,99 +2176,53 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids) } } -static bool +static void compose_set_mpls_label_action(struct xlate_ctx *ctx, ovs_be32 label) { - if (!eth_type_mpls(ctx->xin->flow.dl_type)) { - return true; - } - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * executed and the resulting MPLS label stack is unknown. This means - * a SET MPLS LABEL action can't be executed as it needs to manipulate - * the top-most MPLS LSE. Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation. - */ - if (ctx->mpls_depth_delta < 0) { - return true; + if (eth_type_mpls(ctx->xin->flow.dl_type)) { + ctx->xout->wc.masks.mpls_lse[0] |= htonl(MPLS_LABEL_MASK); + set_mpls_lse_label(&ctx->xin->flow.mpls_lse[0], label); } - - ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_LABEL_MASK); - set_mpls_lse_label(&ctx->xin->flow.mpls_lse, label); - return false; } -static bool +static void compose_set_mpls_tc_action(struct xlate_ctx *ctx, uint8_t tc) { - if (!eth_type_mpls(ctx->xin->flow.dl_type)) { - return true; - } - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * executed and the resulting MPLS label stack is unknown. This means - * a SET MPLS TC action can't be executed as it needs to manipulate - * the top-most MPLS LSE. Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation. - */ - if (ctx->mpls_depth_delta < 0) { - return true; + if (eth_type_mpls(ctx->xin->flow.dl_type)) { + ctx->xout->wc.masks.mpls_lse[0] |= htonl(MPLS_TC_MASK); + set_mpls_lse_tc(&ctx->xin->flow.mpls_lse[0], tc); } - - ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_TC_MASK); - set_mpls_lse_tc(&ctx->xin->flow.mpls_lse, tc); - return false; } -static bool +static void compose_set_mpls_ttl_action(struct xlate_ctx *ctx, uint8_t ttl) { - if (!eth_type_mpls(ctx->xin->flow.dl_type)) { - return true; - } - - /* If mpls_depth_delta is negative then an MPLS POP action has been - * executed and the resulting MPLS label stack is unknown. This means - * a SET MPLS TTL push action can't be executed as it needs to manipulate - * the top-most MPLS LSE. Thus, stop processing. - * - * It is planned that in the future this case will be handled - * by recirculation. - */ - if (ctx->mpls_depth_delta < 0) { - return true; + if (eth_type_mpls(ctx->xin->flow.dl_type)) { + ctx->xout->wc.masks.mpls_lse[0] |= htonl(MPLS_TTL_MASK); + set_mpls_lse_ttl(&ctx->xin->flow.mpls_lse[0], ttl); } - - ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_TTL_MASK); - set_mpls_lse_ttl(&ctx->xin->flow.mpls_lse, ttl); - return false; } static bool compose_dec_mpls_ttl_action(struct xlate_ctx *ctx) { struct flow *flow = &ctx->xin->flow; - uint8_t ttl = mpls_lse_to_ttl(flow->mpls_lse); + uint8_t ttl = mpls_lse_to_ttl(flow->mpls_lse[0]); struct flow_wildcards *wc = &ctx->xout->wc; memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse); + if (eth_type_mpls(flow->dl_type)) { + if (ttl > 1) { + ttl--; + set_mpls_lse_ttl(&flow->mpls_lse[0], ttl); + return false; + } else { + execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0); - if (!eth_type_mpls(flow->dl_type)) { - return false; - } - - if (ttl > 1) { - ttl--; - set_mpls_lse_ttl(&flow->mpls_lse, ttl); - return false; + /* Stop processing for current table. */ + return true; + } } else { - execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0); - - /* Stop processing for current table. */ return true; } } @@ -2523,10 +2423,18 @@ xlate_sample_action(struct xlate_ctx *ctx, * the same percentage. */ uint32_t probability = (os->probability << 16) | os->probability; + if (!ctx->xbridge->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 " + "lacks support (needs Linux 3.10+ or kernel module from " + "OVS 1.11+)"); + return; + } + ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, &ctx->xout->odp_actions, - &ctx->xout->wc, - &ctx->mpls_depth_delta); + &ctx->xout->wc); compose_flow_sample_cookie(os->probability, os->collector_set_id, os->obs_domain_id, os->obs_point_id, &cookie); @@ -2744,7 +2652,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, * applicable header fields. Do nothing if no header exists. */ if ((mf->id != MFF_VLAN_VID || flow->vlan_tci & htons(VLAN_CFI)) && ((mf->id != MFF_MPLS_LABEL && mf->id != MFF_MPLS_TC) - || flow->mpls_lse)) { + || eth_type_mpls(flow->dl_type))) { mf_set_flow_value(mf, &set_field->value, flow); } break; @@ -2760,38 +2668,24 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_PUSH_MPLS: - if (compose_mpls_push_action(ctx, - ofpact_get_PUSH_MPLS(a)->ethertype)) { - return; - } + compose_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)); break; case OFPACT_POP_MPLS: - if (compose_mpls_pop_action(ctx, - ofpact_get_POP_MPLS(a)->ethertype)) { - return; - } + compose_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype); break; case OFPACT_SET_MPLS_LABEL: - if (compose_set_mpls_label_action(ctx, - ofpact_get_SET_MPLS_LABEL(a)->label)) { - return; - } - break; + compose_set_mpls_label_action( + ctx, ofpact_get_SET_MPLS_LABEL(a)->label); + break; case OFPACT_SET_MPLS_TC: - if (compose_set_mpls_tc_action(ctx, - ofpact_get_SET_MPLS_TC(a)->tc)) { - return; - } + compose_set_mpls_tc_action(ctx, ofpact_get_SET_MPLS_TC(a)->tc); break; case OFPACT_SET_MPLS_TTL: - if (compose_set_mpls_ttl_action(ctx, - ofpact_get_SET_MPLS_TTL(a)->ttl)) { - return; - } + compose_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl); break; case OFPACT_DEC_MPLS_TTL: @@ -2989,6 +2883,7 @@ actions_output_to_local_port(const struct xlate_ctx *ctx) /* Thread safe call to xlate_actions__(). */ void xlate_actions(struct xlate_in *xin, struct xlate_out *xout) + OVS_EXCLUDED(xlate_rwlock) { ovs_rwlock_rdlock(&xlate_rwlock); xlate_actions__(xin, xout); @@ -3016,6 +2911,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) struct xlate_ctx ctx; size_t ofpacts_len; bool tnl_may_send; + bool is_icmp; COVERAGE_INC(xlate_actions); @@ -3067,7 +2963,10 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port); memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority); memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); - wc->masks.nw_frag |= FLOW_NW_FRAG_MASK; + if (is_ip_any(flow)) { + wc->masks.nw_frag |= FLOW_NW_FRAG_MASK; + } + is_icmp = is_icmpv4(flow) || is_icmpv6(flow); tnl_may_send = tnl_xlate_init(&ctx.base_flow, flow, wc); if (ctx.xbridge->netflow) { @@ -3079,7 +2978,6 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) ctx.orig_skb_priority = flow->skb_priority; ctx.table_id = 0; ctx.exit = false; - ctx.mpls_depth_delta = 0; if (!xin->ofpacts && !ctx.rule) { rule_dpif_lookup(ctx.xbridge->ofproto, flow, @@ -3099,7 +2997,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) ofpacts = actions->ofpacts; ofpacts_len = actions->ofpacts_len; } else { - NOT_REACHED(); + OVS_NOT_REACHED(); } ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack); @@ -3124,14 +3022,14 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) goto out; case OFPC_FRAG_REASM: - NOT_REACHED(); + OVS_NOT_REACHED(); case OFPC_FRAG_NX_MATCH: /* Nothing to do. */ break; case OFPC_INVALID_TTL_TO_CONTROLLER: - NOT_REACHED(); + OVS_NOT_REACHED(); } } @@ -3228,6 +3126,21 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) * use non-header fields as part of the cache. */ flow_wildcards_clear_non_packet_fields(wc); + /* ICMPv4 and ICMPv6 have 8-bit "type" and "code" fields. struct flow uses + * the low 8 bits of the 16-bit tp_src and tp_dst members to represent + * these fields. The datapath interface, on the other hand, represents + * them with just 8 bits each. This means that if the high 8 bits of the + * masks for these fields somehow become set, then they will get chopped + * off by a round trip through the datapath, and revalidation will spot + * that as an inconsistency and delete the flow. Avoid the problem here by + * making sure that only the low 8 bits of either field can be unwildcarded + * for ICMP. + */ + if (is_icmp) { + wc->masks.tp_src &= htons(UINT8_MAX); + wc->masks.tp_dst &= htons(UINT8_MAX); + } + out: rule_actions_unref(actions); rule_dpif_unref(rule); @@ -3243,7 +3156,6 @@ xlate_send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) struct ofpact_output output; struct flow flow; union flow_in_port in_port_; - int error; ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output); /* Use OFPP_NONE as the in_port to avoid special packet processing. */ @@ -3258,9 +3170,9 @@ xlate_send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) } output.port = xport->ofp_port; output.max_len = 0; - error = ofproto_dpif_execute_actions(xport->xbridge->ofproto, &flow, NULL, - &output.ofpact, sizeof output, - packet); ovs_rwlock_unlock(&xlate_rwlock); - return error; + + return ofproto_dpif_execute_actions(xport->xbridge->ofproto, &flow, NULL, + &output.ofpact, sizeof output, + packet); }