summaryrefslogtreecommitdiff
path: root/ofproto/ofproto-dpif-xlate.c
diff options
context:
space:
mode:
authorZoltan Balogh <zoltan.balogh@ericsson.com>2018-01-12 14:34:11 +0100
committerBen Pfaff <blp@ovn.org>2018-01-23 11:13:15 -0800
commit00135b869d7c848527aa22caa4698694202eb762 (patch)
tree69bb77fdeb38b671bdced9760850d7d68a777caf /ofproto/ofproto-dpif-xlate.c
parentc3594cc320ef060dea45391dce9ae3b451bf012b (diff)
downloadopenvswitch-00135b869d7c848527aa22caa4698694202eb762.tar.gz
xlate: fix xport lookup for recirc
Xlate_lookup and xlate_lookup_ofproto_() provides in_port and ofproto based on xport determined using flow, which is extracted from packet. The lookup can happen due to recirculation as well. It can happen, that packet_type has been modified during xlate before recirculation is triggered, so the lookup fails or delivers wrong xport. This can be worked around by propagating xport to ctx->xin after the very first lookup and store it in frozen state of the recirculation. So, when lookup is performed due to recirculation, the xport can be retrieved from the frozen state. The packet-type-aware unit tests are updated with a new one to verify this behavior. Signed-off-by: Zoltan Balogh <zoltan.balogh@ericsson.com> CC: Jan Scheurich <jan.scheurich@ericsson.com> Fixes: beb75a40fdc2 ("userspace: Switching of L3 packets in L2 pipeline") Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'ofproto/ofproto-dpif-xlate.c')
-rw-r--r--ofproto/ofproto-dpif-xlate.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index b70a0ac44..40c04cc4f 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -561,6 +561,8 @@ static struct xbundle *xbundle_lookup(struct xlate_cfg *,
const struct ofbundle *);
static struct xport *xport_lookup(struct xlate_cfg *,
const struct ofport_dpif *);
+static struct xport *xport_lookup_by_uuid(struct xlate_cfg *,
+ const struct uuid *);
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);
@@ -1374,12 +1376,36 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer, const struct flow *flow,
struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
const struct xport *xport;
+ /* If packet is recirculated, xport can be retrieved from frozen state. */
+ if (flow->recirc_id) {
+ const struct recirc_id_node *recirc_id_node;
+
+ recirc_id_node = recirc_id_node_find(flow->recirc_id);
+
+ if (OVS_UNLIKELY(!recirc_id_node)) {
+ return NULL;
+ }
+
+ /* If recirculation was initiated due to bond (in_port = OFPP_NONE)
+ * then frozen state is static and xport_uuid is not defined, so xport
+ * cannot be restored from frozen state. */
+ if (recirc_id_node->state.metadata.in_port != OFPP_NONE) {
+ struct uuid xport_uuid = recirc_id_node->state.xport_uuid;
+ xport = xport_lookup_by_uuid(xcfg, &xport_uuid);
+ if (xport && xport->xbridge && xport->xbridge->ofproto) {
+ goto out;
+ }
+ }
+ }
+
xport = xport_lookup(xcfg, tnl_port_should_receive(flow)
? tnl_port_receive(flow)
: odp_port_to_ofport(backer, flow->in_port.odp_port));
if (OVS_UNLIKELY(!xport)) {
return NULL;
}
+
+out:
*xportp = xport;
if (ofp_in_port) {
*ofp_in_port = xport->ofp_port;
@@ -1517,6 +1543,26 @@ xport_lookup(struct xlate_cfg *xcfg, const struct ofport_dpif *ofport)
return NULL;
}
+static struct xport *
+xport_lookup_by_uuid(struct xlate_cfg *xcfg, const struct uuid *uuid)
+{
+ struct hmap *xports;
+ struct xport *xport;
+
+ if (uuid_is_zero(uuid) || !xcfg) {
+ return NULL;
+ }
+
+ xports = &xcfg->xports_uuid;
+
+ HMAP_FOR_EACH_IN_BUCKET (xport, uuid_node, uuid_hash(uuid), xports) {
+ if (uuid_equals(&xport->uuid, uuid)) {
+ return xport;
+ }
+ }
+ return NULL;
+}
+
static struct stp_port *
xport_get_stp_port(const struct xport *xport)
{
@@ -4492,6 +4538,7 @@ finish_freezing__(struct xlate_ctx *ctx, uint8_t table)
.stack_size = ctx->stack.size,
.mirrors = ctx->mirrors,
.conntracked = ctx->conntracked,
+ .xport_uuid = ctx->xin->xport_uuid,
.ofpacts = ctx->frozen_actions.data,
.ofpacts_len = ctx->frozen_actions.size,
.action_set = ctx->action_set.data,
@@ -6532,6 +6579,7 @@ xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto,
xin->odp_actions = odp_actions;
xin->in_packet_out = false;
xin->recirc_queue = NULL;
+ xin->xport_uuid = UUID_ZERO;
/* Do recirc lookup. */
xin->frozen_state = NULL;
@@ -6957,6 +7005,9 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
* flow->in_port is the ultimate input port of the packet.) */
struct xport *in_port = get_ofp_port(xbridge,
ctx.base_flow.in_port.ofp_port);
+ if (in_port && !in_port->peer) {
+ ctx.xin->xport_uuid = in_port->uuid;
+ }
if (flow->packet_type != htonl(PT_ETH) && in_port &&
in_port->pt_mode == NETDEV_PT_LEGACY_L3 && ctx.table_id == 0) {
@@ -7196,6 +7247,7 @@ xlate_resume(struct ofproto_dpif *ofproto,
.stack_size = pin->stack_size,
.mirrors = pin->mirrors,
.conntracked = pin->conntracked,
+ .xport_uuid = UUID_ZERO,
/* When there are no actions, xlate_actions() will search the flow
* table. We don't want it to do that (we want it to resume), so