packet mmap related oops (with reproducer)
Subsystems (2)
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]
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 issueThis 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 blocksBlock_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;
}
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 issueThis 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_tMmap_Size;size_tTXDataOffset;SOCKET Socket;
struct
tpacket_reqring_req;
Ether_Sz= 1518;Block_Sz=Ether_Sz;Block_Sz_Order= 2; // 16384 byte blocksBlock_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