X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-xlate.c;h=86d8222bc19a7522ad3f0da00028f238c94e0d16;hb=83b16b98ee4520196ab987b6937363112a2fdfc7;hp=8b672fd5cf682cf43b1da2ab3e7818e772c3d090;hpb=5e6af486775002b1b04a7cf585ed26e7f1bac930;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 8b672fd5c..86d8222bc 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" @@ -459,6 +461,93 @@ 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) { @@ -1404,7 +1493,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, } ctx->xin->flow = old_flow; - ctx->xbridge = xport->xbundle->xbridge; + ctx->xbridge = xport->xbridge; if (ctx->xin->resubmit_stats) { netdev_vport_inc_tx(xport->netdev, ctx->xin->resubmit_stats); @@ -1599,7 +1688,7 @@ 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 ofputil_packet_in *pin; struct ofpbuf *packet; struct flow key; @@ -1621,17 +1710,18 @@ execute_controller_action(struct xlate_ctx *ctx, int len, odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data, ctx->xout->odp_actions.size, NULL, NULL); - pin.packet = packet->data; - pin.packet_len = packet->size; - pin.reason = reason; - pin.controller_id = controller_id; - pin.table_id = ctx->table_id; - pin.cookie = ctx->rule ? ctx->rule->up.flow_cookie : 0; + 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 ? ctx->rule->up.flow_cookie : 0; - pin.send_len = len; - flow_get_metadata(&ctx->xin->flow, &pin.fmd); + pin->send_len = len; + flow_get_metadata(&ctx->xin->flow, &pin->fmd); - ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, &pin); + ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, pin); ofpbuf_delete(packet); } @@ -1946,12 +2036,16 @@ xlate_fin_timeout(struct xlate_ctx *ctx, if (ctx->xin->tcp_flags & (TCP_FIN | TCP_RST) && ctx->rule) { struct rule_dpif *rule = ctx->rule; - if (list_is_empty(&rule->up.expirable)) { - list_insert(&rule->up.ofproto->expirable, &rule->up.expirable); - } + ovs_mutex_lock(&rule->up.ofproto->expirable_mutex); + if (list_is_empty(&rule->up.expirable)) { + list_insert(&rule->up.ofproto->expirable, &rule->up.expirable); + } + ovs_mutex_unlock(&rule->up.ofproto->expirable_mutex); + ovs_mutex_lock(&rule->up.timeout_mutex); reduce_timeout(oft->fin_idle_timeout, &rule->up.idle_timeout); reduce_timeout(oft->fin_hard_timeout, &rule->up.hard_timeout); + ovs_mutex_unlock(&rule->up.timeout_mutex); } }