Skip to contentSkip to conversation

packet mmap related oops (with reproducer)

DISCUSSION Dave Jones 2 participants 2 messages Jan 22, 2014 2 messages not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

Dave Jones

author
#2 lore raw

We had a Fedora user report this bug, with a reproducer (below).

Quoted 11 lines · On Fri, Jan 17, 2014 at 06:52:06AM +0000, [email protected] wrote:

https://bugzilla.redhat.com/show_bug.cgi?id=1054537

--- Comment #2 from Karl Auerbach <[email protected]> ---
--> https://bugzilla.redhat.com/attachment.cgi?id=851413
Simple program to cause this kernel issue

This is a C program that must be run with root privilege. It runs fine on older kernels but causes a kernel problem on the most recent one.

Quoted 8 lines

The code creates a raw socket with transmit and receive ring buffers.

The rings are then made visible via mmap().

When munmap() is called things go awry.

The code in this example was quickly lifted from a larger body of code that has been running for several years.

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>

#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/user.h>

#include <features.h> /* for the glibc version number */
#include <net/ethernet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>

#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/if_tun.h>

#define NIL 0

typedef int SOCKET;

int main(int argc, char *argv)
{

size_t              RxMmap_Size;
size_t              TxMmap_Size;
unsigned int        Ether_Sz;
unsigned int        Block_Sz_Order;
unsigned int        Block_Sz;
unsigned int        Block_Cnt;
unsigned int        Frame_Sz;
unsigned int        Frame_Cnt;
unsigned int        Frames_Per_Block;

void * Mmap_Addr;
size_t Mmap_Size;
size_t TXDataOffset;

SOCKET Socket;

struct tpacket_req ring_req;

Ether_Sz = 1518;
Block_Sz = Ether_Sz;
Block_Sz_Order = 2; // 16384 byte blocks
Block_Cnt = 1000;

Socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (Socket == -1)
{
perror("socket failed");
return 1;
}

Frame_Sz = TPACKET_ALIGN(TPACKET_ALIGN(TPACKET2_HDRLEN) + Ether_Sz); TXDataOffset = TPACKET2_HDRLEN - sizeof(struct sockaddr_ll);

Block_Sz = getpagesize() << Block_Sz_Order;

Frames_Per_Block = Block_Sz / Frame_Sz;
Frame_Cnt = Frames_Per_Block * Block_Cnt;

RxMmap_Size = Block_Sz * Block_Cnt;
TxMmap_Size = RxMmap_Size;

Mmap_Size = RxMmap_Size + TxMmap_Size;

// Establish receive ring
// For convenience we will let it be the same size as the TX ring // The mmap size calculations, far above, assume that the // rings are the same size.
ring_req.tp_block_nr = Block_Cnt; ring_req.tp_frame_size = Frame_Sz; ring_req.tp_block_size = Block_Sz;
ring_req.tp_frame_nr = Frame_Cnt;
if (setsockopt(Socket, SOL_PACKET, PACKET_RX_RING,

               (char *)&ring_req, sizeof(ring_req)) < 0)

{
perror("Setsockopt RX_RING failed");
close(Socket);
return -1;
}

// Establish transmit ring
// For convenience we will let it be the same size as the RX ring // The mmap size calculations, far above, assume that the // rings are the same size.
ring_req.tp_block_nr = Block_Cnt; ring_req.tp_frame_size = Frame_Sz; ring_req.tp_block_size = Block_Sz;
ring_req.tp_frame_nr = Frame_Cnt;
if (setsockopt(Socket, SOL_PACKET, PACKET_TX_RING,

               (char *)&ring_req, sizeof(ring_req)) < 0)

{
perror("Setsockopt TX_RING failed");
close(Socket);
return -1;
}

Mmap_Addr = mmap(NIL, Mmap_Size, PROT_READ | PROT_WRITE,

                 MAP_SHARED | MAP_LOCKED, Socket, 0);

if (Mmap_Addr == MAP_FAILED)
{
perror("mmap failed");
return 1;
}

if (Mmap_Addr != MAP_FAILED)
{
(void)munmap(Mmap_Addr, Mmap_Size);
}

close(Socket);
return 0;
}

#3 lore raw

Hi Dave,

Quoted 22 lines · Dave Jones

We had a Fedora user report this bug, with a reproducer (below).

Quoted 19 lines · On Fri, Jan 17, 2014 at 06:52:06AM +0000, [email protected] wrote:

https://bugzilla.redhat.com/show_bug.cgi?id=1054537

--- Comment #2 from Karl Auerbach <[email protected]> ---
--> https://bugzilla.redhat.com/attachment.cgi?id=851413
Simple program to cause this kernel issue

This is a C program that must be run with root privilege. It runs fine on older kernels but causes a kernel problem on the most recent one.

The code creates a raw socket with transmit and receive ring buffers.

The rings are then made visible via mmap().

When munmap() is called things go awry.

The code in this example was quickly lifted from a larger body of code that has been running for several years.

It looks to be THP related, you can also use the Linux kernel selftest suite for networking to trigger that, I've reported it here:

https://lkml.org/lkml/2014/1/10/427

Vlastimil seems to have proposed some possibilities, but it seems discussion stalled for now.

Cheers,

Daniel

Quoted 128 lines

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>

#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/user.h>

#include <features.h> /* for the glibc version number */
#include <net/ethernet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>

#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/if_tun.h>

#define NIL 0

typedef int SOCKET;

int main(int argc, char *argv)
{

size_t              RxMmap_Size;
size_t              TxMmap_Size;
unsigned int        Ether_Sz;
unsigned int        Block_Sz_Order;
unsigned int        Block_Sz;
unsigned int        Block_Cnt;
unsigned int        Frame_Sz;
unsigned int        Frame_Cnt;
unsigned int        Frames_Per_Block;

void * Mmap_Addr;
size_t Mmap_Size;
size_t TXDataOffset;

SOCKET Socket;

struct tpacket_req ring_req;

Ether_Sz = 1518;
Block_Sz = Ether_Sz;
Block_Sz_Order = 2; // 16384 byte blocks
Block_Cnt = 1000;

Socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (Socket == -1)

   {
   perror("socket failed");
   return 1;
   }

Frame_Sz = TPACKET_ALIGN(TPACKET_ALIGN(TPACKET2_HDRLEN) + Ether_Sz); TXDataOffset = TPACKET2_HDRLEN - sizeof(struct sockaddr_ll);

Block_Sz = getpagesize() << Block_Sz_Order;

Frames_Per_Block = Block_Sz / Frame_Sz;
Frame_Cnt = Frames_Per_Block * Block_Cnt;

RxMmap_Size = Block_Sz * Block_Cnt;
TxMmap_Size = RxMmap_Size;

Mmap_Size = RxMmap_Size + TxMmap_Size;

// Establish receive ring
// For convenience we will let it be the same size as the TX ring // The mmap size calculations, far above, assume that the // rings are the same size.
ring_req.tp_block_nr = Block_Cnt; ring_req.tp_frame_size = Frame_Sz; ring_req.tp_block_size = Block_Sz;
ring_req.tp_frame_nr = Frame_Cnt;
if (setsockopt(Socket, SOL_PACKET, PACKET_RX_RING,

                (char *)&ring_req, sizeof(ring_req)) < 0)
   {
   perror("Setsockopt RX_RING failed");
   close(Socket);
   return -1;
   }

// Establish transmit ring
// For convenience we will let it be the same size as the RX ring // The mmap size calculations, far above, assume that the // rings are the same size.
ring_req.tp_block_nr = Block_Cnt; ring_req.tp_frame_size = Frame_Sz; ring_req.tp_block_size = Block_Sz;
ring_req.tp_frame_nr = Frame_Cnt;
if (setsockopt(Socket, SOL_PACKET, PACKET_TX_RING,

                (char *)&ring_req, sizeof(ring_req)) < 0)
   {
   perror("Setsockopt TX_RING failed");
   close(Socket);
   return -1;
   }

Mmap_Addr = mmap(NIL, Mmap_Size, PROT_READ | PROT_WRITE,

                  MAP_SHARED | MAP_LOCKED, Socket, 0);

if (Mmap_Addr == MAP_FAILED)

   {
   perror("mmap failed");
   return 1;
   }

if (Mmap_Addr != MAP_FAILED)

   {
   (void)munmap(Mmap_Addr, Mmap_Size);
   }

close(Socket);
return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html