Skip to content

Commit

Permalink
dpif-netdev: Preserve inner offloads on recirculation.
Browse files Browse the repository at this point in the history
Rather than drop all pending Tx offloads on recirculation,
preserve inner offloads (and mark packet with outer Tx offloads)
when parsing the packet again.

Fixes: c6538b4 ("dpif-netdev: Fix crash due to tunnel offloading on recirculation.")
Fixes: 084c808 ("userspace: Support VXLAN and GENEVE TSO.")
Signed-off-by: David Marchand <[email protected]>
  • Loading branch information
david-marchand committed Jan 23, 2025
1 parent a3c06c3 commit 406dfa6
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 45 deletions.
23 changes: 11 additions & 12 deletions lib/dp-packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ static inline void dp_packet_set_tso_segsz(struct dp_packet *, uint16_t);
void *dp_packet_resize_l2(struct dp_packet *, int increment);
void *dp_packet_resize_l2_5(struct dp_packet *, int increment);
static inline void *dp_packet_eth(const struct dp_packet *);
static inline void dp_packet_reset_outer_offsets(struct dp_packet *);
static inline void dp_packet_reset_offsets(struct dp_packet *);
static inline void dp_packet_reset_offload(struct dp_packet *);
static inline uint16_t dp_packet_l2_pad_size(const struct dp_packet *);
Expand Down Expand Up @@ -433,15 +434,22 @@ dp_packet_eth(const struct dp_packet *b)
? dp_packet_data(b) : NULL;
}

/* Resets all layer offsets. 'l3' offset must be set before 'l2' can be
* retrieved. */
/* Resets all outer layer offsets. */
static inline void
dp_packet_reset_offsets(struct dp_packet *b)
dp_packet_reset_outer_offsets(struct dp_packet *b)
{
b->l2_pad_size = 0;
b->l2_5_ofs = UINT16_MAX;
b->l3_ofs = UINT16_MAX;
b->l4_ofs = UINT16_MAX;
}

/* Resets all layer offsets. 'l3' offset must be set before 'l2' can be
* retrieved. */
static inline void
dp_packet_reset_offsets(struct dp_packet *b)
{
dp_packet_reset_outer_offsets(b);
b->inner_l3_ofs = UINT16_MAX;
b->inner_l4_ofs = UINT16_MAX;
}
Expand Down Expand Up @@ -1316,15 +1324,6 @@ dp_packet_hwol_set_tunnel_gre(struct dp_packet *b)
*dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_TUNNEL_GRE;
}

/* Clears tunnel offloading marks. */
static inline void
dp_packet_hwol_reset_tunnel(struct dp_packet *b)
{
*dp_packet_ol_flags_ptr(b) &= ~(DP_PACKET_OL_TX_TUNNEL_VXLAN |
DP_PACKET_OL_TX_TUNNEL_GRE |
DP_PACKET_OL_TX_TUNNEL_GENEVE);
}

/* Mark packet 'b' as a tunnel packet with outer IPv4 header. */
static inline void
dp_packet_hwol_set_tx_outer_ipv4(struct dp_packet *b)
Expand Down
27 changes: 0 additions & 27 deletions lib/dpif-netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ COVERAGE_DEFINE(datapath_drop_lock_error);
COVERAGE_DEFINE(datapath_drop_userspace_action_error);
COVERAGE_DEFINE(datapath_drop_tunnel_push_error);
COVERAGE_DEFINE(datapath_drop_tunnel_pop_error);
COVERAGE_DEFINE(datapath_drop_tunnel_tso_recirc);
COVERAGE_DEFINE(datapath_drop_recirc_error);
COVERAGE_DEFINE(datapath_drop_invalid_port);
COVERAGE_DEFINE(datapath_drop_invalid_bond);
Expand Down Expand Up @@ -8923,32 +8922,6 @@ static void
dp_netdev_recirculate(struct dp_netdev_pmd_thread *pmd,
struct dp_packet_batch *packets)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
size_t i, size = dp_packet_batch_size(packets);
struct dp_packet *packet;

DP_PACKET_BATCH_REFILL_FOR_EACH (i, size, packet, packets) {
if (dp_packet_hwol_is_tunnel(packet)) {
if (dp_packet_hwol_is_tso(packet)) {
/* Can't perform GSO in the middle of a pipeline. */
COVERAGE_INC(datapath_drop_tunnel_tso_recirc);
dp_packet_delete(packet);
VLOG_WARN_RL(&rl, "Recirculating tunnel packets with "
"TSO is not supported");
continue;
}
/* Have to fix all the checksums before re-parsing, because the
* packet will be treated as having a single set of headers. */
dp_packet_ol_send_prepare(packet, 0);
/* This packet must not be marked with anything tunnel-related. */
dp_packet_hwol_reset_tunnel(packet);
/* Clear inner offsets. Other ones are collateral, but they will
* be re-initialized on re-parsing. */
dp_packet_reset_offsets(packet);
}
dp_packet_batch_refill(packets, packet, i);
}

dp_netdev_input__(pmd, packets, true, 0);
}

Expand Down
34 changes: 28 additions & 6 deletions lib/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,7 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
uint8_t nw_frag, nw_tos, nw_ttl, nw_proto;
uint8_t *ct_nw_proto_p = NULL;
ovs_be16 ct_tp_src = 0, ct_tp_dst = 0;
bool tunneling;

/* Metadata. */
if (flow_tnl_dst_is_set(&md->tunnel)) {
Expand Down Expand Up @@ -857,7 +858,13 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)

/* Initialize packet's layer pointer and offsets. */
frame = data;
dp_packet_reset_offsets(packet);
tunneling = dp_packet_hwol_is_tunnel(packet);
if (tunneling) {
/* Preserve inner offsets from previous circulation. */
dp_packet_reset_outer_offsets(packet);
} else {
dp_packet_reset_offsets(packet);
}

if (packet_type == htonl(PT_ETH)) {
/* Must have full Ethernet header to proceed. */
Expand Down Expand Up @@ -936,9 +943,16 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
nw_proto = nh->ip_proto;
nw_frag = ipv4_get_nw_frag(nh);
data_pull(&data, &size, ip_len);
dp_packet_hwol_set_tx_ipv4(packet);
if (dp_packet_ip_checksum_good(packet)) {
dp_packet_hwol_set_tx_ip_csum(packet);
if (tunneling) {
dp_packet_hwol_set_tx_outer_ipv4(packet);
if (dp_packet_ip_checksum_good(packet)) {
dp_packet_hwol_set_tx_outer_ipv4_csum(packet);
}
} else {
dp_packet_hwol_set_tx_ipv4(packet);
if (dp_packet_ip_checksum_good(packet)) {
dp_packet_hwol_set_tx_ip_csum(packet);
}
}
} else if (dl_type == htons(ETH_TYPE_IPV6)) {
const struct ovs_16aligned_ip6_hdr *nh = data;
Expand All @@ -953,7 +967,11 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
}
data_pull(&data, &size, sizeof *nh);

dp_packet_hwol_set_tx_ipv6(packet);
if (tunneling) {
dp_packet_hwol_set_tx_outer_ipv6(packet);
} else {
dp_packet_hwol_set_tx_ipv6(packet);
}
plen = ntohs(nh->ip6_plen);
dp_packet_set_l2_pad_size(packet, size - plen);
size = plen; /* Never pull padding. */
Expand Down Expand Up @@ -1078,7 +1096,11 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
dp_packet_ol_l4_csum_check_partial(packet);
if (dp_packet_l4_checksum_good(packet)
|| dp_packet_ol_l4_csum_partial(packet)) {
dp_packet_hwol_set_csum_udp(packet);
if (tunneling) {
dp_packet_hwol_set_outer_udp_csum(packet);
} else {
dp_packet_hwol_set_csum_udp(packet);
}
}
}
} else if (OVS_LIKELY(nw_proto == IPPROTO_SCTP)) {
Expand Down

0 comments on commit 406dfa6

Please sign in to comment.