Before translating a datapath flow key into actions, ofproto-dpif must parse it, tweak it, and figure out what ofproto_dpif it belongs to. This patch brings all this logic into one place where it will be easier to extend in the future.
Signed-off-by: Ethan Jackson <et...@nicira.com> --- ofproto/ofproto-dpif.c | 160 +++++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 85 deletions(-) diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index d5155cf..186203d 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -3393,53 +3393,78 @@ handle_flow_miss(struct flow_miss *miss, struct flow_miss_op *ops, handle_flow_miss_with_facet(miss, facet, now, ops, n_ops); } -/* 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). The - * caller must have called odp_flow_key_to_flow() and supply 'fitness' and - * 'flow' from its output. The 'flow' argument must have had the "in_port" - * member converted to the OpenFlow number. +/* 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 'ofproto' with the ofproto_dpif, and + * 'odp_in_port' with the datapath in_port, that 'packet' ingressed. * - * Sets '*initial_tci' to the VLAN TCI with which the packet was really - * received, that is, the actual VLAN TCI extracted by odp_flow_key_to_flow(). - * (This differs from the value returned in flow->vlan_tci only for packets - * received on VLAN splinters.) */ + * 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). + * + * Optionally, if nonnull, sets '*initial_tci' to the VLAN TCI with which the + * packet was really received, that is, the actual VLAN TCI extracted by + * odp_flow_key_to_flow(). (This differs from the value returned in + * flow->vlan_tci only for packets received on VLAN splinters.) */ static enum odp_key_fitness -ofproto_dpif_vsp_adjust(const struct ofproto_dpif *ofproto, - enum odp_key_fitness fitness, - struct flow *flow, ovs_be16 *initial_tci, - struct ofpbuf *packet) +ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet, + const struct nlattr *key, size_t key_len, + struct flow *flow, struct ofproto_dpif **ofproto, + uint32_t *odp_in_port, ovs_be16 *initial_tci) + { + const struct ofport_dpif *port; + enum odp_key_fitness fitness; + + fitness = odp_flow_key_to_flow(key, key_len, flow); if (fitness == ODP_FIT_ERROR) { return fitness; } - *initial_tci = flow->vlan_tci; - if (vsp_adjust_flow(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); + if (initial_tci) { + *initial_tci = flow->vlan_tci; + } + + if (odp_in_port) { + *odp_in_port = flow->in_port; + } + + port = odp_port_to_ofport(backer, flow->in_port); + if (port) { + flow->in_port = (port)->up.ofp_port; + if (vsp_adjust_flow(ofproto_dpif_cast(port->up.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); + } + fitness = fitness == ODP_FIT_PERFECT ? ODP_FIT_TOO_MUCH : fitness; } + } else { + flow->in_port = OFPP_NONE; + } - /* Let the caller know that we can't reproduce 'key' from 'flow'. */ - if (fitness == ODP_FIT_PERFECT) { - fitness = ODP_FIT_TOO_MUCH; + if (ofproto) { + if (port) { + *ofproto = ofproto_dpif_cast(port->up.ofproto); + } else { + return ODP_FIT_ERROR; } } @@ -3474,32 +3499,15 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls, for (upcall = upcalls; upcall < &upcalls[n_upcalls]; upcall++) { struct flow_miss *miss = &misses[n_misses]; struct flow_miss *existing_miss; - enum odp_key_fitness fitness; struct ofproto_dpif *ofproto; - struct ofport_dpif *port; uint32_t odp_in_port; struct flow flow; uint32_t hash; - fitness = odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); - port = odp_port_to_ofport(backer, flow.in_port); - if (!port) { - /* Received packet on port for which we couldn't associate - * an ofproto. This can happen if a port is removed while - * traffic is being received. Print a rate-limited message - * in case it happens frequently. */ - VLOG_INFO_RL(&rl, "received packet on unassociated port %"PRIu32, - flow.in_port); - continue; - } - ofproto = ofproto_dpif_cast(port->up.ofproto); - odp_in_port = flow.in_port; - flow.in_port = port->up.ofp_port; - - /* Obtain metadata and check userspace/kernel agreement on flow match, - * then set 'flow''s header pointers. */ - miss->key_fitness = ofproto_dpif_vsp_adjust(ofproto, fitness, - &flow, &miss->initial_tci, upcall->packet); + miss->key_fitness = ofproto_receive(backer, upcall->packet, + upcall->key, upcall->key_len, + &flow, &ofproto, &odp_in_port, + &miss->initial_tci); if (miss->key_fitness == ODP_FIT_ERROR) { continue; } @@ -3604,28 +3612,13 @@ handle_sflow_upcall(struct dpif_backer *backer, struct ofproto_dpif *ofproto; union user_action_cookie cookie; enum odp_key_fitness fitness; - struct ofport_dpif *port; - ovs_be16 initial_tci; struct flow flow; uint32_t odp_in_port; - fitness = odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); - - port = odp_port_to_ofport(backer, flow.in_port); - if (!port) { - return; - } - - ofproto = ofproto_dpif_cast(port->up.ofproto); - if (!ofproto->sflow) { - return; - } - - odp_in_port = flow.in_port; - flow.in_port = port->up.ofp_port; - fitness = ofproto_dpif_vsp_adjust(ofproto, fitness, &flow, - &initial_tci, upcall->packet); - if (fitness == ODP_FIT_ERROR) { + fitness = ofproto_receive(backer, upcall->packet, upcall->key, + upcall->key_len, &flow, &ofproto, &odp_in_port, + NULL); + if (fitness == ODP_FIT_ERROR || !ofproto->sflow) { return; } @@ -7193,13 +7186,10 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], goto exit; } - fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow); - flow.in_port = odp_port_to_ofp_port(ofproto, flow.in_port); - - /* Convert odp_key to flow. */ - error = ofproto_dpif_vsp_adjust(ofproto, fitness, &flow, - &initial_tci, NULL); - if (error == ODP_FIT_ERROR) { + fitness = ofproto_receive(ofproto->backer, NULL, odp_key.data, + odp_key.size, &flow, NULL, NULL, + &initial_tci); + if (fitness == ODP_FIT_ERROR) { unixctl_command_reply_error(conn, "Invalid flow"); goto exit; } -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev