Skip to content

Commit

Permalink
ofproto-dpif-xlate: Fix recirculation when in_port is OFPP_CONTROLLER.
Browse files Browse the repository at this point in the history
Recirculation usually requires finding the pre-recirculation input port.
Packets sent by the controller, with in_port of OFPP_CONTROLLER or
OFPP_NONE, do not have a real input port data structure, only a port
number.  The code in xlate_lookup_ofproto_() mishandled this case,
failing to return the ofproto data structure.  This commit fixes the
problem and adds a test to guard against regression.

Reported-by: Numan Siddique <[email protected]>
Reported-at: https://mail.openvswitch.org/pipermail/ovs-dev/2020-March/368642.html
Tested-by: Numan Siddique <[email protected]>
Acked-by: Numan Siddique <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
blp committed Mar 20, 2020
1 parent 9a8a18f commit 323ae1e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 4 deletions.
25 changes: 21 additions & 4 deletions ofproto/ofproto-dpif-xlate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1520,15 +1520,32 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer,
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) {
ofp_port_t in_port = recirc_id_node->state.metadata.in_port;
if (in_port != OFPP_NONE && in_port != OFPP_CONTROLLER) {
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;
}
} else {
/* OFPP_NONE and OFPP_CONTROLLER are not real ports. They indicate
* that the packet originated from the controller via an OpenFlow
* "packet-out". The right thing to do is to find just the
* ofproto. There is no xport, which is OK.
*
* OFPP_NONE can also indicate that a bond caused recirculation. */
struct uuid uuid = recirc_id_node->state.ofproto_uuid;
const struct xbridge *bridge = xbridge_lookup_by_uuid(xcfg, &uuid);
if (bridge && bridge->ofproto) {
if (errorp) {
*errorp = NULL;
}
*xportp = NULL;
if (ofp_in_port) {
*ofp_in_port = in_port;
}
return bridge->ofproto;
}
}
}

Expand Down
30 changes: 30 additions & 0 deletions tests/ofproto-dpif.at
Original file line number Diff line number Diff line change
Expand Up @@ -5171,6 +5171,36 @@ AT_CHECK_UNQUOTED([tail -1 stdout], [0], [Datapath actions: 2
OVS_VSWITCHD_STOP
AT_CLEANUP

# Checks for regression against a bug in which OVS dropped packets
# with in_port=CONTROLLER when they were recirculated (because
# CONTROLLER isn't a real port and could not be looked up).
AT_SETUP([ofproto-dpif - packet-out recirculation])
OVS_VSWITCHD_START
add_of_ports br0 1 2

AT_DATA([flows.txt], [dnl
table=0 ip actions=mod_dl_dst:83:83:83:83:83:83,ct(table=1)
table=1 ip actions=ct(commit),output:2
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])

packet=ffffffffffff00102030405008004500001c00000000401100000a000002ffffffff0035111100080000
AT_CHECK([ovs-ofctl packet-out br0 "in_port=controller packet=$packet actions=table"])

# Dumps out the flow table, extracts the number of packets that have gone
# through the (single) flow in table 1, and returns success if it's exactly 1.
#
# If this remains 0, then the recirculation isn't working properly since the
# packet never goes through flow in table 1.
check_flows () {
n=$(ovs-ofctl dump-flows br0 table=1 | sed -n 's/.*n_packets=\([[0-9]]\{1,\}\).*/\1/p')
echo "n_packets=$n"
test "$n" = 1
}
OVS_WAIT_UNTIL([check_flows], [ovs dump-flows br0])

OVS_VSWITCHD_STOP
AT_CLEANUP

AT_SETUP([ofproto-dpif - debug_slow action])
OVS_VSWITCHD_START
Expand Down

0 comments on commit 323ae1e

Please sign in to comment.