X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-xlate.c;h=cced7cc23571b79a3e5f9932455994081509d888;hb=10e576406c7444ef198cc2d4b6c4adfe242c085c;hp=cb0912315a144762fd241e7ef6b587b70630cb79;hpb=a2143702724647df8a9aef570982738dd3721af0;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index cb0912315..cced7cc23 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -158,6 +158,13 @@ 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. */ + int recurse; /* Recursion level, via xlate_table_action. */ uint32_t orig_skb_priority; /* Priority when packet arrived. */ uint8_t table_id; /* OpenFlow table ID where flow was found. */ @@ -1534,7 +1541,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 == 20); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 21); if (!xport) { xlate_report(ctx, "Nonexistent output port"); @@ -1645,7 +1652,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, if (out_port != ODPP_NONE) { commit_odp_actions(flow, &ctx->base_flow, - &ctx->xout->odp_actions, &ctx->xout->wc); + &ctx->xout->odp_actions, &ctx->xout->wc, + &ctx->mpls_depth_delta); nl_msg_put_odp_port(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port); @@ -1800,7 +1808,8 @@ execute_controller_action(struct xlate_ctx *ctx, int len, memset(&key.tunnel, 0, sizeof key.tunnel); commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, - &ctx->xout->odp_actions, &ctx->xout->wc); + &ctx->xout->odp_actions, &ctx->xout->wc, + &ctx->mpls_depth_delta); odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data, ctx->xout->odp_actions.size, NULL, NULL); @@ -1820,7 +1829,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len, ofpbuf_delete(packet); } -static void +static bool compose_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type) { struct flow_wildcards *wc = &ctx->xout->wc; @@ -1828,12 +1837,35 @@ compose_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type) 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); - memset(&wc->masks.mpls_depth, 0xff, sizeof wc->masks.mpls_depth); - if (flow->mpls_depth) { + 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); - flow->mpls_depth++; } else { ovs_be32 label; uint8_t tc, ttl; @@ -1848,30 +1880,48 @@ compose_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type) 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; } flow->dl_type = eth_type; + ctx->mpls_depth_delta++; + + return false; } -static void +static bool 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)); + 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); - 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; - } + /* 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; } + + ctx->xin->flow.dl_type = eth_type; + ctx->mpls_depth_delta--; + + return false; } static bool @@ -1907,6 +1957,18 @@ compose_set_mpls_ttl_action(struct xlate_ctx *ctx, uint8_t ttl) 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; + } + ctx->xout->wc.masks.mpls_lse |= htonl(MPLS_TTL_MASK); set_mpls_lse_ttl(&ctx->xin->flow.mpls_lse, ttl); return false; @@ -2096,7 +2158,8 @@ static void xlate_learn_action(struct xlate_ctx *ctx, const struct ofpact_learn *learn) { - struct ofputil_flow_mod *fm; + uint64_t ofpacts_stub[1024 / 8]; + struct ofputil_flow_mod fm; struct ofpbuf ofpacts; ctx->xout->has_learn = true; @@ -2107,11 +2170,10 @@ xlate_learn_action(struct xlate_ctx *ctx, return; } - fm = xmalloc(sizeof *fm); - ofpbuf_init(&ofpacts, 0); - learn_execute(learn, &ctx->xin->flow, fm, &ofpacts); - - ofproto_dpif_flow_mod(ctx->xbridge->ofproto, fm); + ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); + learn_execute(learn, &ctx->xin->flow, &fm, &ofpacts); + ofproto_dpif_flow_mod(ctx->xbridge->ofproto, &fm); + ofpbuf_uninit(&ofpacts); } static void @@ -2134,7 +2196,8 @@ xlate_sample_action(struct xlate_ctx *ctx, uint32_t probability = (os->probability << 16) | os->probability; commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, - &ctx->xout->odp_actions, &ctx->xout->wc); + &ctx->xout->odp_actions, &ctx->xout->wc, + &ctx->mpls_depth_delta); compose_flow_sample_cookie(os->probability, os->collector_set_id, os->obs_domain_id, os->obs_point_id, &cookie); @@ -2309,11 +2372,17 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_PUSH_MPLS: - compose_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)->ethertype); + if (compose_mpls_push_action(ctx, + ofpact_get_PUSH_MPLS(a)->ethertype)) { + return; + } break; case OFPACT_POP_MPLS: - compose_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype); + if (compose_mpls_pop_action(ctx, + ofpact_get_POP_MPLS(a)->ethertype)) { + return; + } break; case OFPACT_SET_MPLS_TTL: @@ -2462,6 +2531,44 @@ xlate_out_copy(struct xlate_out *dst, const struct xlate_out *src) ofpbuf_put(&dst->odp_actions, src->odp_actions.data, src->odp_actions.size); } + +/* Returns a reference to the sflow handled associated with ofproto, or NULL if + * there is none. The caller is responsible for decrementing the results ref + * count with dpif_sflow_unref(). */ +struct dpif_sflow * +xlate_get_sflow(const struct ofproto_dpif *ofproto) +{ + struct dpif_sflow *sflow = NULL; + struct xbridge *xbridge; + + ovs_rwlock_rdlock(&xlate_rwlock); + xbridge = xbridge_lookup(ofproto); + if (xbridge) { + sflow = dpif_sflow_ref(xbridge->sflow); + } + ovs_rwlock_unlock(&xlate_rwlock); + + return sflow; +} + +/* Returns a reference to the ipfix handled associated with ofproto, or NULL if + * there is none. The caller is responsible for decrementing the results ref + * count with dpif_ipfix_unref(). */ +struct dpif_ipfix * +xlate_get_ipfix(const struct ofproto_dpif *ofproto) +{ + struct dpif_ipfix *ipfix = NULL; + struct xbridge *xbridge; + + ovs_rwlock_rdlock(&xlate_rwlock); + xbridge = xbridge_lookup(ofproto); + if (xbridge) { + ipfix = dpif_ipfix_ref(xbridge->ipfix); + } + ovs_rwlock_unlock(&xlate_rwlock); + + return ipfix; +} static struct skb_priority_to_dscp * get_skb_priority(const struct xport *xport, uint32_t skb_priority) @@ -2598,6 +2705,7 @@ 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) { ofpacts = xin->ofpacts;