summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Chaudron <echaudro@redhat.com>2021-07-05 07:57:41 -0400
committerIlya Maximets <i.maximets@ovn.org>2021-07-09 21:35:20 +0200
commit1aa1f591422ec3e34ae9becf257081645500de6c (patch)
tree6ce36c8ade72f93bdb50ef19a0b3daeef296960b
parentd127fa6d2bd7b5679cafab1f92b1237f374664bc (diff)
downloadopenvswitch-1aa1f591422ec3e34ae9becf257081645500de6c.tar.gz
netdev-linux: Ignore TSO packets when TSO is not enabled for userspace.
When TSO is disabled from a userspace forwarding datapath perspective, but TSO has been wrongly enabled on the kernel side, log a warning message, and drop the packet. With the current implementation, OVS will crash. [i.maximets]: The call stack looks like this: 0 dp_packet_set_size (b=0x0, b=0x0, v=13028) at lib/dp-packet.h:578 1 netdev_linux_batch_rxq_recv_sock at lib/netdev-linux.c:1310 2 netdev_linux_rxq_recv at lib/netdev-linux.c 3 netdev_rxq_recv at lib/netdev.c 4 dp_netdev_process_rxq_port at lib/dpif-netdev.c The problem is that the code assumes that (mmsgs[i].msg_len > std_len) can only be true if userpace-tso is enabled and additional buffers are provided to the kernel. However, since recvmmsg() is called with MSG_TRUNC, the resulting msg_len reflects the original packet size before truncation, and it can be larger than the buffer if TSO / GRO is enabled on the network interface. If TSO support for user space is not enabled in OVS, the aux_bufs are not allocated and are left NULL, resulting in a crash. Fixes: 73858f9dbe83 ("netdev-linux: Prepend the std packet in the TSO packet") Fixes: 2109841b7984 ("Use batch process recv for tap and raw socket in netdev datapath") Signed-off-by: Eelco Chaudron <echaudro@redhat.com> Acked-by: Flavio Leitner <fbl@sysclose.org> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
-rw-r--r--lib/netdev-linux.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 5a747f73c..557c3f5e9 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -1277,14 +1277,28 @@ netdev_linux_batch_rxq_recv_sock(struct netdev_rxq_linux *rx, int mtu,
for (i = 0; i < retval; i++) {
struct dp_packet *pkt;
- if (mmsgs[i].msg_len < ETH_HEADER_LEN) {
+ if (mmsgs[i].msg_hdr.msg_flags & MSG_TRUNC
+ || mmsgs[i].msg_len < ETH_HEADER_LEN) {
struct netdev *netdev_ = netdev_rxq_get_netdev(&rx->up);
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ /* The rx->aux_bufs[i] will be re-used next time. */
dp_packet_delete(buffers[i]);
netdev->rx_dropped += 1;
- VLOG_WARN_RL(&rl, "%s: Dropped packet: less than ether hdr size",
- netdev_get_name(netdev_));
+ if (mmsgs[i].msg_hdr.msg_flags & MSG_TRUNC) {
+ /* Data is truncated, so the packet is corrupted, and needs
+ * to be dropped. This can happen if TSO/GRO is enabled in
+ * the kernel, but not in userspace, i.e. there is no dp
+ * buffer to store the full packet. */
+ VLOG_WARN_RL(&rl,
+ "%s: Dropped packet: Too big. GRO/TSO enabled?",
+ netdev_get_name(netdev_));
+ } else {
+ VLOG_WARN_RL(&rl,
+ "%s: Dropped packet: less than ether hdr size",
+ netdev_get_name(netdev_));
+ }
+
continue;
}