]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
af-packet: make tpacket-v2 block size configurable
authorJason Ish <jason.ish@oisf.net>
Wed, 12 Mar 2025 21:58:43 +0000 (15:58 -0600)
committerVictor Julien <vjulien@oisf.net>
Tue, 18 Mar 2025 10:02:32 +0000 (11:02 +0100)
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

src/runmode-af-packet.c
src/source-af-packet.c
src/source-af-packet.h
suricata.yaml.in

index df91b509c00ee91ac82bbf49afb36b03d0ea4a69..e54ffce73364c752475e7107bd550d1e73f0247a 100644 (file)
@@ -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);
index 4df96ce48b7b1b09b2fce64fcffbaf9ba042d970..140bfd0da00fafaa934e03c3300e3c8a1c81dbf3 100644 (file)
@@ -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;
 
index eb0fa5380e75a8172515fbd6f135075c6846a7e9..c88441a69dbb834506f02017a58bac385632fbb5 100644 (file)
@@ -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;
index d6920396ebf62a4c51d612f4e82434c09f9e9f11..5117b09928d1aeb54f6c5db06aba670a052aad28 100644 (file)
@@ -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