From: Jason Ish Date: Wed, 12 Mar 2025 21:58:43 +0000 (-0600) Subject: af-packet: make tpacket-v2 block size configurable X-Git-Tag: suricata-8.0.0-beta1~270 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5871c6458c6696516425f19e8c840663767bf917;p=thirdparty%2Fsuricata.git af-packet: make tpacket-v2 block size configurable With the change of the default tpacket-v2 block size from 32k to 128k, allow it to be configurable for users who may want to make it larger, or revert it back to the pre 7.0.9 default of 32k. Ticket: #7458 --- diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index df91b509c0..e54ffce733 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -216,6 +216,7 @@ static void *ParseAFPConfig(const char *iface) aconf->copy_mode = AFP_COPY_MODE_NONE; aconf->block_timeout = 10; aconf->block_size = getpagesize() << AFP_BLOCK_SIZE_DEFAULT_ORDER; + aconf->v2_block_size = 0; #ifdef HAVE_PACKET_EBPF aconf->ebpf_t_config.cpus_count = UtilCpuGetNumProcessorsConfigured(); #endif @@ -629,6 +630,15 @@ static void *ParseAFPConfig(const char *iface) aconf->block_timeout = 10; } + if ((ConfGetChildValueIntWithDefault(if_root, if_default, "v2-block-size", &value)) == 1) { + if (value % getpagesize()) { + SCLogWarning("%s: v2-block-size %" PRIuMAX " must be a multiple of pagesize (%u).", + iface, value, getpagesize()); + } else { + aconf->v2_block_size = value; + } + } + (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", &boolval); if (boolval) { SCLogConfig("%s: disabling promiscuous mode", aconf->iface); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 4df96ce48b..140bfd0da0 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -317,6 +317,7 @@ typedef struct AFPThreadVars_ int socket; int ring_size; + int v2_block_size; int block_size; int block_timeout; /* socket buffer size */ @@ -1599,6 +1600,63 @@ sockaddr_ll) + ETH_HLEN) - ETH_HLEN); return 1; } +static int AFPComputeRingParamsWithBlockSize(AFPThreadVars *ptv, unsigned int block_size) +{ + /* Compute structure: + Target is to store all pending packets + with a size equal to MTU + auxdata + And we keep a decent number of block + + To do so: + Compute frame_size (aligned to be able to fit in block + Check which block size we need. Blocksize is a 2^n * pagesize + We then need to get order, big enough to have + frame_size < block size + Find number of frame per block (divide) + Fill in packet_req + + Compute frame size: + described in packet_mmap.txt + dependent on snaplen (need to use a variable ?) +snaplen: MTU ? +tp_hdrlen determine_version in daq_afpacket +in V1: sizeof(struct tpacket_hdr); +in V2: val in getsockopt(instance->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) +frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct +sockaddr_ll) + ETH_HLEN) - ETH_HLEN); + + */ + int tp_hdrlen = sizeof(struct tpacket_hdr); + int snaplen = default_packet_size; + + if (snaplen == 0) { + snaplen = GetIfaceMaxPacketSize(ptv->livedev); + if (snaplen <= 0) { + SCLogWarning("%s: unable to get MTU, setting snaplen default of 1514", ptv->iface); + snaplen = 1514; + } + } + + ptv->req.v2.tp_frame_size = TPACKET_ALIGN( + snaplen + + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - + ETH_HLEN); + ptv->req.v2.tp_block_size = block_size; + int frames_per_block = ptv->req.v2.tp_block_size / ptv->req.v2.tp_frame_size; + if (frames_per_block == 0) { + SCLogError("%s: Frame size bigger than block size", ptv->iface); + return -1; + } + ptv->req.v2.tp_frame_nr = ptv->ring_size; + ptv->req.v2.tp_block_nr = ptv->req.v2.tp_frame_nr / frames_per_block + 1; + /* exact division */ + ptv->req.v2.tp_frame_nr = ptv->req.v2.tp_block_nr * frames_per_block; + SCLogPerf("%s: rx ring: block_size=%d block_nr=%d frame_size=%d frame_nr=%d", ptv->iface, + ptv->req.v2.tp_block_size, ptv->req.v2.tp_block_nr, ptv->req.v2.tp_frame_size, + ptv->req.v2.tp_frame_nr); + return 1; +} + #ifdef HAVE_TPACKET_V3 static int AFPComputeRingParamsV3(AFPThreadVars *ptv) { @@ -1709,29 +1767,51 @@ static int AFPSetupRing(AFPThreadVars *ptv, char *devname) } } else { #endif - for (order = AFP_BLOCK_SIZE_DEFAULT_ORDER; order >= 0; order--) { - if (AFPComputeRingParams(ptv, order) != 1) { + if (ptv->v2_block_size) { + + if (AFPComputeRingParamsWithBlockSize(ptv, ptv->v2_block_size) != 1) { SCLogError("%s: ring parameters are incorrect. Please file a bug report", devname); return AFP_FATAL_ERROR; } - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, - (void *) &ptv->req, sizeof(ptv->req)); + r = setsockopt( + ptv->socket, SOL_PACKET, PACKET_RX_RING, (void *)&ptv->req, sizeof(ptv->req)); if (r < 0) { if (errno == ENOMEM) { - SCLogWarning("%s: memory issue with ring parameters. Retrying", devname); - continue; + SCLogError("%s: memory issue with ring parameters", devname); + return AFP_FATAL_ERROR; } SCLogError("%s: failed to setup RX Ring: %s", devname, strerror(errno)); return AFP_FATAL_ERROR; - } else { - break; } - } - if (order < 0) { - SCLogError("%s: failed to setup RX Ring (order 0 failed)", devname); - return AFP_FATAL_ERROR; + + } else { + for (order = AFP_BLOCK_SIZE_DEFAULT_ORDER; order >= 0; order--) { + if (AFPComputeRingParams(ptv, order) != 1) { + SCLogError( + "%s: ring parameters are incorrect. Please file a bug report", devname); + return AFP_FATAL_ERROR; + } + + r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, (void *)&ptv->req, + sizeof(ptv->req)); + + if (r < 0) { + if (errno == ENOMEM) { + SCLogWarning("%s: memory issue with ring parameters. Retrying", devname); + continue; + } + SCLogError("%s: failed to setup RX Ring: %s", devname, strerror(errno)); + return AFP_FATAL_ERROR; + } else { + break; + } + } + if (order < 0) { + SCLogError("%s: failed to setup RX Ring (order 0 failed)", devname); + return AFP_FATAL_ERROR; + } } #ifdef HAVE_TPACKET_V3 } @@ -2516,6 +2596,7 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data) ptv->buffer_size = afpconfig->buffer_size; ptv->ring_size = afpconfig->ring_size; + ptv->v2_block_size = afpconfig->v2_block_size; ptv->block_size = afpconfig->block_size; ptv->block_timeout = afpconfig->block_timeout; diff --git a/src/source-af-packet.h b/src/source-af-packet.h index eb0fa5380e..c88441a69d 100644 --- a/src/source-af-packet.h +++ b/src/source-af-packet.h @@ -90,6 +90,8 @@ typedef struct AFPIfaceConfig_ int block_size; /* block timeout for tpacket_v3 in milliseconds */ int block_timeout; + /* block size for tpacket v2 */ + int v2_block_size; /* cluster param */ uint16_t cluster_id; int cluster_type; diff --git a/suricata.yaml.in b/suricata.yaml.in index d6920396eb..5117b09928 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -684,6 +684,10 @@ af-packet: # tpacket_v3 block timeout: an open block is passed to userspace if it is not # filled after block-timeout milliseconds. #block-timeout: 10 + # Block size for tpacket-v2. In 7.0.9 the built-in default was + # increased from 32768 to 131072. Uncomment and reset back to + # 32768 if this is a problem with your configuration. + #v2-block-size: 131072 # On busy systems, set it to yes to help recover from a packet drop # phase. This will result in some packets (at max a ring flush) not being inspected. #use-emergency-flush: yes