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-7.0.9~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f3d52ef8cfafd22519bcbbb34da76a610680ab29;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 (cherry picked from commit 5871c6458c6696516425f19e8c840663767bf917) --- diff --git a/src/runmode-af-packet.c b/src/runmode-af-packet.c index 9991f108d1..469970cf88 100644 --- a/src/runmode-af-packet.c +++ b/src/runmode-af-packet.c @@ -242,6 +242,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 @@ -655,6 +656,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", (int *)&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 6112cb9d88..0ead90b1ad 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -318,6 +318,7 @@ typedef struct AFPThreadVars_ int socket; int ring_size; + int v2_block_size; int block_size; int block_timeout; /* socket buffer size */ @@ -1602,6 +1603,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) { @@ -1712,29 +1770,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 } @@ -2518,6 +2598,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 7d04704a9d..fabb5202e7 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 02e5865eff..d74b4a27d3 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -661,6 +661,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