X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-xlate.c;h=fb4d0b45670f671076e92860d0963d41276b6167;hb=7aaeab4df24b7e9460705b1dad1010eef0354c50;hp=91ec01a5a2db86502f42ab927a2d64a175843136;hpb=f74e7df7450d6c31caaad66fe8b1dc923e86e9a7;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 91ec01a5a..fb4d0b456 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -16,6 +16,8 @@ #include "ofproto/ofproto-dpif-xlate.h" +#include + #include "bfd.h" #include "bitmap.h" #include "bond.h" @@ -61,6 +63,7 @@ struct xbridge { struct hmap xports; /* Indexed by ofp_port. */ char *name; /* Name used in log messages. */ + struct dpif *dpif; /* Datapath interface. */ struct mac_learning *ml; /* Mac learning handle. */ struct mbridge *mbridge; /* Mirroring. */ struct dpif_sflow *sflow; /* SFlow handle, or null. */ @@ -149,7 +152,6 @@ struct xlate_ctx { 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. */ @@ -197,7 +199,7 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); static struct xbridge *xbridge_lookup(const struct ofproto_dpif *); static struct xbundle *xbundle_lookup(const struct ofbundle *); -static struct xport *xport_lookup(struct ofport_dpif *); +static struct xport *xport_lookup(const struct ofport_dpif *); static struct xport *get_ofp_port(const struct xbridge *, ofp_port_t ofp_port); static struct skb_priority_to_dscp *get_skb_priority(const struct xport *, uint32_t skb_priority); @@ -207,8 +209,8 @@ static bool dscp_from_skb_priority(const struct xport *, uint32_t skb_priority, void xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name, - const struct mac_learning *ml, struct stp *stp, - const struct mbridge *mbridge, + struct dpif *dpif, const struct mac_learning *ml, + struct stp *stp, const struct mbridge *mbridge, const struct dpif_sflow *sflow, const struct dpif_ipfix *ipfix, enum ofp_config_flags frag, bool forward_bpdu, bool has_in_band, bool has_netflow) @@ -252,6 +254,7 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name, free(xbridge->name); xbridge->name = xstrdup(name); + xbridge->dpif = dpif; xbridge->forward_bpdu = forward_bpdu; xbridge->has_in_band = has_in_band; xbridge->has_netflow = has_netflow; @@ -397,7 +400,7 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle, if (xport->peer) { xport->peer->peer = NULL; } - xport->peer = peer ? xport_lookup(peer) : NULL; + xport->peer = xport_lookup(peer); if (xport->peer) { xport->peer->peer = xport; } @@ -405,7 +408,7 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle, if (xport->xbundle) { list_remove(&xport->bundle_node); } - xport->xbundle = ofbundle ? xbundle_lookup(ofbundle) : NULL; + xport->xbundle = xbundle_lookup(ofbundle); if (xport->xbundle) { list_insert(&xport->xbundle->xports, &xport->bundle_node); } @@ -415,9 +418,8 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle, struct skb_priority_to_dscp *pdscp; uint32_t skb_priority; - if (ofproto_dpif_queue_to_priority(xport->xbridge->ofproto, - qdscp_list[i].queue, - &skb_priority)) { + if (dpif_queue_to_priority(xport->xbridge->dpif, qdscp_list[i].queue, + &skb_priority)) { continue; } @@ -459,11 +461,102 @@ xlate_ofport_remove(struct ofport_dpif *ofport) free(xport); } +/* 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, and 'odp_in_port' with the datapath in_port, that + * 'packet' ingressed. + * + * If 'ofproto' is nonnull, requires 'flow''s in_port to exist. Otherwise sets + * 'flow''s in_port to OFPP_NONE. + * + * This function does post-processing on data returned from + * odp_flow_key_to_flow() to help make VLAN splinters transparent to the rest + * of the upcall processing logic. In particular, if the extracted in_port is + * a VLAN splinter port, it replaces flow->in_port by the "real" port, sets + * flow->vlan_tci correctly for the VLAN of the VLAN splinter port, and pushes + * a VLAN header onto 'packet' (if it is nonnull). + * + * Similarly, this function also includes some logic to help with tunnels. It + * may modify 'flow' as necessary to make the tunneling implementation + * transparent to the upcall processing logic. + * + * Returns 0 if successful, ENODEV if the parsed flow has no associated 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, + struct ofproto_dpif **ofproto, odp_port_t *odp_in_port) +{ + enum odp_key_fitness fitness; + const struct xport *xport; + int error = ENODEV; + + fitness = odp_flow_key_to_flow(key, key_len, flow); + if (fitness == ODP_FIT_ERROR) { + error = EINVAL; + goto exit; + } + + if (odp_in_port) { + *odp_in_port = flow->in_port.odp_port; + } + + xport = xport_lookup(tnl_port_should_receive(flow) + ? tnl_port_receive(flow) + : odp_port_to_ofport(backer, flow->in_port.odp_port)); + + flow->in_port.ofp_port = xport ? xport->ofp_port : OFPP_NONE; + if (!xport) { + goto exit; + } + + if (vsp_adjust_flow(xport->xbridge->ofproto, flow)) { + if (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); + } + /* We can't reproduce 'key' from 'flow'. */ + fitness = fitness == ODP_FIT_PERFECT ? ODP_FIT_TOO_MUCH : fitness; + } + error = 0; + + if (ofproto) { + *ofproto = xport->xbridge->ofproto; + } + +exit: + if (fitnessp) { + *fitnessp = fitness; + } + return error; +} + static struct xbridge * xbridge_lookup(const struct ofproto_dpif *ofproto) { struct xbridge *xbridge; + if (!ofproto) { + return NULL; + } + HMAP_FOR_EACH_IN_BUCKET (xbridge, hmap_node, hash_pointer(ofproto, 0), &xbridges) { if (xbridge->ofproto == ofproto) { @@ -478,6 +571,10 @@ xbundle_lookup(const struct ofbundle *ofbundle) { struct xbundle *xbundle; + if (!ofbundle) { + return NULL; + } + HMAP_FOR_EACH_IN_BUCKET (xbundle, hmap_node, hash_pointer(ofbundle, 0), &xbundles) { if (xbundle->ofbundle == ofbundle) { @@ -488,10 +585,14 @@ xbundle_lookup(const struct ofbundle *ofbundle) } static struct xport * -xport_lookup(struct ofport_dpif *ofport) +xport_lookup(const struct ofport_dpif *ofport) { struct xport *xport; + if (!ofport) { + return NULL; + } + HMAP_FOR_EACH_IN_BUCKET (xport, hmap_node, hash_pointer(ofport, 0), &xports) { if (xport->ofport == ofport) { @@ -501,25 +602,26 @@ xport_lookup(struct ofport_dpif *ofport) return NULL; } +static struct stp_port * +xport_get_stp_port(const struct xport *xport) +{ + return xport->xbridge->stp && xport->stp_port_no + ? stp_get_port(xport->xbridge->stp, xport->stp_port_no) + : NULL; +} static enum stp_state xport_stp_learn_state(const struct xport *xport) { - enum stp_state stp_state = xport->xbridge->stp && xport->stp_port_no - ? stp_port_get_state(stp_get_port(xport->xbridge->stp, - xport->stp_port_no)) - : STP_DISABLED; - return stp_learn_in_state(stp_state); + struct stp_port *sp = xport_get_stp_port(xport); + return stp_learn_in_state(sp ? stp_port_get_state(sp) : STP_DISABLED); } static bool xport_stp_forward_state(const struct xport *xport) { - enum stp_state stp_state = xport->xbridge->stp && xport->stp_port_no - ? stp_port_get_state(stp_get_port(xport->xbridge->stp, - xport->stp_port_no)) - : STP_DISABLED; - return stp_forward_in_state(stp_state); + struct stp_port *sp = xport_get_stp_port(xport); + return stp_forward_in_state(sp ? stp_port_get_state(sp) : STP_DISABLED); } /* Returns true if STP should process 'flow'. Sets fields in 'wc' that @@ -534,11 +636,9 @@ stp_should_process_flow(const struct flow *flow, struct flow_wildcards *wc) static void stp_process_packet(const struct xport *xport, const struct ofpbuf *packet) { + struct stp_port *sp = xport_get_stp_port(xport); struct ofpbuf payload = *packet; struct eth_header *eth = payload.data; - struct stp_port *sp = xport->xbridge->stp && xport->stp_port_no - ? stp_get_port(xport->xbridge->stp, xport->stp_port_no) - : NULL; /* Sink packets on ports that have STP disabled when the bridge has * STP enabled. */ @@ -875,7 +975,7 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, ofport = bond_choose_output_slave(out_xbundle->bond, &ctx->xin->flow, &ctx->xout->wc, vid); - xport = ofport ? xport_lookup(ofport) : NULL; + xport = xport_lookup(ofport); if (!xport) { /* No slaves enabled, so drop packet. */ @@ -1139,15 +1239,19 @@ compose_sample_action(const struct xbridge *xbridge, const size_t cookie_size) { size_t sample_offset, actions_offset; + odp_port_t odp_port; int cookie_offset; + uint32_t pid; sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE); nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability); actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS); - cookie_offset = put_userspace_action(xbridge->ofproto, odp_actions, flow, - cookie, cookie_size); + + odp_port = ofp_port_to_odp_port(xbridge, flow->in_port.ofp_port); + pid = dpif_port_get_pid(xbridge->dpif, odp_port); + cookie_offset = odp_put_userspace_action(pid, cookie, cookie_size, odp_actions); nl_msg_end_nested(odp_actions, actions_offset); nl_msg_end_nested(odp_actions, sample_offset); @@ -1536,7 +1640,6 @@ xlate_table_action(struct xlate_ctx *ctx, VLOG_ERR_RL(&recurse_rl, "resubmit actions recursed over %d times", MAX_RESUBMIT_RECURSION); - ctx->max_resubmit_trigger = true; } } @@ -1813,8 +1916,7 @@ xlate_enqueue_action(struct xlate_ctx *ctx, int error; /* Translate queue to priority. */ - error = ofproto_dpif_queue_to_priority(ctx->xbridge->ofproto, queue_id, - &priority); + error = dpif_queue_to_priority(ctx->xbridge->dpif, queue_id, &priority); if (error) { /* Fall back to ordinary output action. */ xlate_output_action(ctx, enqueue->port, 0, false); @@ -1847,8 +1949,7 @@ xlate_set_queue_action(struct xlate_ctx *ctx, uint32_t queue_id) { uint32_t skb_priority; - if (!ofproto_dpif_queue_to_priority(ctx->xbridge->ofproto, queue_id, - &skb_priority)) { + if (!dpif_queue_to_priority(ctx->xbridge->dpif, queue_id, &skb_priority)) { ctx->xin->flow.skb_priority = skb_priority; } else { /* Couldn't translate queue to a priority. Nothing to do. A warning @@ -2365,11 +2466,6 @@ actions_output_to_local_port(const struct xlate_ctx *ctx) void xlate_actions(struct xlate_in *xin, struct xlate_out *xout) { - /* Normally false. Set to true if we ever hit MAX_RESUBMIT_RECURSION, so - * 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; struct flow *flow = &xin->flow; @@ -2443,7 +2539,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } ctx.recurse = 0; - ctx.max_resubmit_trigger = false; ctx.orig_skb_priority = flow->skb_priority; ctx.table_id = 0; ctx.exit = false; @@ -2460,7 +2555,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack); - if (mbridge_has_mirrors(ctx.xbridge->mbridge) || hit_resubmit_limit) { + if (mbridge_has_mirrors(ctx.xbridge->mbridge)) { /* Do this conditionally because the copy is expensive enough that it * shows up in profiles. */ orig_flow = *flow; @@ -2494,7 +2589,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) if (special) { ctx.xout->slow = special; } else { - static struct vlog_rate_limit trace_rl = VLOG_RATE_LIMIT_INIT(1, 1); size_t sample_actions_len; if (flow->in_port.ofp_port @@ -2518,22 +2612,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } } - if (ctx.max_resubmit_trigger && !ctx.xin->resubmit_hook) { - if (!hit_resubmit_limit) { - /* We didn't record the original flow. Make sure we do from - * now on. */ - hit_resubmit_limit = true; - } else if (!VLOG_DROP_ERR(&trace_rl)) { - struct ds ds = DS_EMPTY_INITIALIZER; - - ofproto_trace(ctx.xbridge->ofproto, &orig_flow, - ctx.xin->packet, &ds); - VLOG_ERR("Trace triggered by excessive resubmit " - "recursion:\n%s", ds_cstr(&ds)); - ds_destroy(&ds); - } - } - if (ctx.xbridge->has_in_band && in_band_must_output_to_local_port(flow) && !actions_output_to_local_port(&ctx)) {