]> 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:33:18 +0000 (11:33 +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
(cherry picked from commit 5871c6458c6696516425f19e8c840663767bf917)

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

index 9991f108d19ac3cb9923b1ea8a6131f1d2f0c513..469970cf88625188e0690c380814da237ae41f80 100644 (file)
@@ -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);
index 6112cb9d8869c97affed0f810bc02aa0e8c7dcdd..0ead90b1ad08d57d24c6c51f11f2cad185adb60f 100644 (file)
@@ -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;
 
index 7d04704a9d00234561bbe57e28d972d1070a0287..fabb5202e773aa5ee4b0d0e68af53df2c539b1a7 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 02e5865effd538b44f37788e463e8f832ea52bb6..d74b4a27d35308a994d5ee58911271c48133f734 100644 (file)
@@ -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