X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-xlate.c;h=7be691c7fc31c3a90d3f92cf8091e86518584618;hb=0c20dbe410f011354dda72e1534b4070e77603d4;hp=9090b054658967c80c2cbbe2a50902e99396d5d8;hpb=98b07853dfd6046938c41937d60ce693437c1f25;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 9090b0546..7be691c7f 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -179,6 +179,15 @@ struct xlate_ctx { odp_port_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. */ + + /* OpenFlow 1.1+ action set. + * + * 'action_set' accumulates "struct ofpact"s added by OFPACT_WRITE_ACTIONS. + * When translation is otherwise complete, ofpacts_execute_action_set() + * converts it to a set of "struct ofpact"s that can be translated into + * datapath actions. */ + struct ofpbuf action_set; /* Action set. */ + uint64_t action_set_stub[1024 / 8]; }; /* A controller may use OFPP_NONE as the ingress port to indicate that @@ -206,6 +215,8 @@ static struct hmap xports = HMAP_INITIALIZER(&xports); static bool may_receive(const struct xport *, struct xlate_ctx *); static void do_xlate_actions(const struct ofpact *, size_t ofpacts_len, struct xlate_ctx *); +static void xlate_actions__(struct xlate_in *, struct xlate_out *) + OVS_REQ_RDLOCK(xlate_rwlock); static void xlate_normal(struct xlate_ctx *); static void xlate_report(struct xlate_ctx *, const char *); static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port, @@ -1580,7 +1591,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, special = process_special(ctx, &ctx->xin->flow, peer, ctx->xin->packet); if (special) { - ctx->xout->slow = special; + ctx->xout->slow |= special; } else if (may_receive(peer, ctx)) { if (xport_stp_forward_state(peer)) { xlate_table_action(ctx, flow->in_port.ofp_port, 0, true); @@ -1658,9 +1669,10 @@ 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->mpls_depth_delta); + ctx->xout->slow |= commit_odp_actions(flow, &ctx->base_flow, + &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); @@ -1808,12 +1820,11 @@ execute_controller_action(struct xlate_ctx *ctx, int len, enum ofp_packet_in_reason reason, uint16_t controller_id) { - struct ofputil_packet_in *pin; + struct ofproto_packet_in *pin; struct ofpbuf *packet; struct flow key; - ovs_assert(!ctx->xout->slow || ctx->xout->slow == SLOW_CONTROLLER); - ctx->xout->slow = SLOW_CONTROLLER; + ctx->xout->slow |= SLOW_CONTROLLER; if (!ctx->xin->packet) { return; } @@ -1824,24 +1835,29 @@ execute_controller_action(struct xlate_ctx *ctx, int len, key.pkt_mark = 0; memset(&key.tunnel, 0, sizeof key.tunnel); - commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, - &ctx->xout->odp_actions, &ctx->xout->wc, - &ctx->mpls_depth_delta); + ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, + &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); pin = xmalloc(sizeof *pin); - pin->packet_len = packet->size; - pin->packet = ofpbuf_steal_data(packet); - pin->reason = reason; - pin->controller_id = controller_id; - pin->table_id = ctx->table_id; - pin->cookie = ctx->rule ? rule_dpif_get_flow_cookie(ctx->rule) : 0; + pin->up.packet_len = packet->size; + pin->up.packet = ofpbuf_steal_data(packet); + pin->up.reason = reason; + pin->up.table_id = ctx->table_id; + pin->up.cookie = (ctx->rule + ? rule_dpif_get_flow_cookie(ctx->rule) + : OVS_BE64_MAX); - pin->send_len = len; - flow_get_metadata(&ctx->xin->flow, &pin->fmd); + flow_get_metadata(&ctx->xin->flow, &pin->up.fmd); + pin->controller_id = controller_id; + pin->send_len = len; + pin->generated_by_table_miss = (ctx->rule + && rule_dpif_is_table_miss(ctx->rule)); ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, pin); ofpbuf_delete(packet); } @@ -2212,9 +2228,10 @@ xlate_sample_action(struct xlate_ctx *ctx, * the same percentage. */ 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->mpls_depth_delta); + ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow, + &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); @@ -2242,6 +2259,26 @@ may_receive(const struct xport *xport, struct xlate_ctx *ctx) return true; } +static void +xlate_write_actions(struct xlate_ctx *ctx, const struct ofpact *a) +{ + struct ofpact_nest *on = ofpact_get_WRITE_ACTIONS(a); + ofpbuf_put(&ctx->action_set, on->actions, ofpact_nest_get_action_len(on)); + ofpact_pad(&ctx->action_set); +} + +static void +xlate_action_set(struct xlate_ctx *ctx) +{ + uint64_t action_list_stub[1024 / 64]; + struct ofpbuf action_list; + + ofpbuf_use_stub(&action_list, action_list_stub, sizeof action_list_stub); + ofpacts_execute_action_set(&action_list, &ctx->action_set); + do_xlate_actions(action_list.data, action_list.size, ctx); + ofpbuf_uninit(&action_list); +} + static void do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, struct xlate_ctx *ctx) @@ -2250,6 +2287,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, struct flow *flow = &ctx->xin->flow; const struct ofpact *a; + /* dl_type already in the mask, not set below. */ + OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { struct ofpact_controller *controller; const struct ofpact_metadata *metadata; @@ -2316,40 +2355,54 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_SET_IPV4_SRC: - memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); if (flow->dl_type == htons(ETH_TYPE_IP)) { + memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src); flow->nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4; } break; case OFPACT_SET_IPV4_DST: - memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); if (flow->dl_type == htons(ETH_TYPE_IP)) { + memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst); flow->nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4; } break; - case OFPACT_SET_IPV4_DSCP: - wc->masks.nw_tos |= IP_DSCP_MASK; - /* OpenFlow 1.0 only supports IPv4. */ - if (flow->dl_type == htons(ETH_TYPE_IP)) { + case OFPACT_SET_IP_DSCP: + if (is_ip_any(flow)) { + wc->masks.nw_tos |= IP_DSCP_MASK; flow->nw_tos &= ~IP_DSCP_MASK; - flow->nw_tos |= ofpact_get_SET_IPV4_DSCP(a)->dscp; + flow->nw_tos |= ofpact_get_SET_IP_DSCP(a)->dscp; + } + break; + + case OFPACT_SET_IP_ECN: + if (is_ip_any(flow)) { + wc->masks.nw_tos |= IP_ECN_MASK; + flow->nw_tos &= ~IP_ECN_MASK; + flow->nw_tos |= ofpact_get_SET_IP_ECN(a)->ecn; + } + break; + + case OFPACT_SET_IP_TTL: + if (is_ip_any(flow)) { + wc->masks.nw_ttl = 0xff; + flow->nw_ttl = ofpact_get_SET_IP_TTL(a)->ttl; } break; case OFPACT_SET_L4_SRC_PORT: - memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); - memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); if (is_ip_any(flow)) { + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); + memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src); flow->tp_src = htons(ofpact_get_SET_L4_SRC_PORT(a)->port); } break; case OFPACT_SET_L4_DST_PORT: - memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); - memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); if (is_ip_any(flow)) { + memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto); + memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst); flow->tp_dst = htons(ofpact_get_SET_L4_DST_PORT(a)->port); } break; @@ -2375,7 +2428,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_REG_LOAD: - nxm_execute_reg_load(ofpact_get_REG_LOAD(a), flow); + nxm_execute_reg_load(ofpact_get_REG_LOAD(a), flow, wc); break; case OFPACT_STACK_PUSH: @@ -2453,11 +2506,11 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_CLEAR_ACTIONS: - /* XXX - * Nothing to do because writa-actions is not supported for now. - * When writa-actions is supported, clear-actions also must - * be supported at the same time. - */ + ofpbuf_clear(&ctx->action_set); + break; + + case OFPACT_WRITE_ACTIONS: + xlate_write_actions(ctx, a); break; case OFPACT_WRITE_METADATA: @@ -2639,16 +2692,27 @@ actions_output_to_local_port(const struct xlate_ctx *ctx) return false; } +/* Thread safe call to xlate_actions__(). */ +void +xlate_actions(struct xlate_in *xin, struct xlate_out *xout) +{ + ovs_rwlock_rdlock(&xlate_rwlock); + xlate_actions__(xin, xout); + ovs_rwlock_unlock(&xlate_rwlock); +} + /* Translates the 'ofpacts_len' bytes of "struct ofpacts" starting at 'ofpacts' * into datapath actions in 'odp_actions', using 'ctx'. * * The caller must take responsibility for eventually freeing 'xout', with * xlate_out_uninit(). */ -void -xlate_actions(struct xlate_in *xin, struct xlate_out *xout) +static void +xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) + OVS_REQ_RDLOCK(xlate_rwlock) { struct flow_wildcards *wc = &xout->wc; struct flow *flow = &xin->flow; + struct rule_dpif *rule = NULL; struct rule_actions *actions = NULL; enum slow_path_reason special; @@ -2661,8 +2725,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) COVERAGE_INC(xlate_actions); - ovs_rwlock_rdlock(&xlate_rwlock); - /* Flow initialization rules: * - 'base_flow' must match the kernel's view of the packet at the * time that action processing starts. 'flow' represents any @@ -2725,11 +2787,20 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.exit = false; ctx.mpls_depth_delta = 0; + if (!xin->ofpacts && !ctx.rule) { + rule_dpif_lookup(ctx.xbridge->ofproto, flow, wc, &rule); + if (ctx.xin->resubmit_stats) { + rule_dpif_credit_stats(rule, ctx.xin->resubmit_stats); + } + ctx.rule = rule; + } + xout->fail_open = ctx.rule && rule_dpif_is_fail_open(ctx.rule); + if (xin->ofpacts) { ofpacts = xin->ofpacts; ofpacts_len = xin->ofpacts_len; - } else if (xin->rule) { - actions = rule_dpif_get_actions(xin->rule); + } else if (ctx.rule) { + actions = rule_dpif_get_actions(ctx.rule); ofpacts = actions->ofpacts; ofpacts_len = actions->ofpacts_len; } else { @@ -2737,6 +2808,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack); + ofpbuf_use_stub(&ctx.action_set, + ctx.action_set_stub, sizeof ctx.action_set_stub); if (mbridge_has_mirrors(ctx.xbridge->mbridge)) { /* Do this conditionally because the copy is expensive enough that it @@ -2770,7 +2843,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) in_port = get_ofp_port(ctx.xbridge, flow->in_port.ofp_port); special = process_special(&ctx, flow, in_port, ctx.xin->packet); if (special) { - ctx.xout->slow = special; + ctx.xout->slow |= special; } else { size_t sample_actions_len; @@ -2795,6 +2868,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } } + if (ctx.action_set.size) { + xlate_action_set(&ctx); + } + if (ctx.xbridge->has_in_band && in_band_must_output_to_local_port(flow) && !actions_output_to_local_port(&ctx)) { @@ -2808,7 +2885,17 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } } + if (nl_attr_oversized(ctx.xout->odp_actions.size)) { + /* These datapath actions are too big for a Netlink attribute, so we + * can't execute them. */ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + + VLOG_ERR_RL(&rl, "discarding oversize datapath actions"); + ofpbuf_clear(&ctx.xout->odp_actions); + } + ofpbuf_uninit(&ctx.stack); + ofpbuf_uninit(&ctx.action_set); /* Clear the metadata and register wildcard masks, because we won't * use non-header fields as part of the cache. */ @@ -2816,7 +2903,38 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) memset(&wc->masks.regs, 0, sizeof wc->masks.regs); out: - ovs_rwlock_unlock(&xlate_rwlock); - rule_actions_unref(actions); + rule_dpif_unref(rule); +} + +/* Sends 'packet' out 'ofport'. + * May modify 'packet'. + * Returns 0 if successful, otherwise a positive errno value. */ +int +xlate_send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) +{ + struct xport *xport; + 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. */ + in_port_.ofp_port = OFPP_NONE; + flow_extract(packet, 0, 0, NULL, &in_port_, &flow); + + ovs_rwlock_rdlock(&xlate_rwlock); + xport = xport_lookup(ofport); + if (!xport) { + ovs_rwlock_unlock(&xlate_rwlock); + return EINVAL; + } + 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; }