git: 43ffd0f5c0f9 - main - LinuxKPI: skbuff: switch to using uma for the skb

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Tue, 22 Apr 2025 23:46:18 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=43ffd0f5c0f91237a37736f1d40045b0052b775b

commit 43ffd0f5c0f91237a37736f1d40045b0052b775b
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-04-22 20:41:40 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-04-22 23:45:49 +0000

    LinuxKPI: skbuff: switch to using uma for the skb
    
    Split allocating the skb header and its payload data memory into skb
    header from uma and the data to whatever we used to do for it.
    
    This is a first step which should allow us to one day at least in the
    RX path take the data, attach it to an mbuf and send it up the stack
    and just free the skbuff header.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
---
 sys/compat/linuxkpi/common/src/linux_skbuff.c | 65 ++++++++++++++++++++-------
 1 file changed, 49 insertions(+), 16 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_skbuff.c b/sys/compat/linuxkpi/common/src/linux_skbuff.c
index 4139295fc837..d454e5fc3ab8 100644
--- a/sys/compat/linuxkpi/common/src/linux_skbuff.c
+++ b/sys/compat/linuxkpi/common/src/linux_skbuff.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2020-2022 The FreeBSD Foundation
+ * Copyright (c) 2020-2025 The FreeBSD Foundation
  * Copyright (c) 2021-2022 Bjoern A. Zeeb
  *
  * This software was developed by Björn Zeeb under sponsorship from
@@ -42,6 +42,8 @@
 #include <sys/malloc.h>
 #include <sys/sysctl.h>
 
+#include <vm/uma.h>
+
 #ifdef DDB
 #include <ddb/ddb.h>
 #endif
@@ -63,6 +65,8 @@ SYSCTL_INT(_compat_linuxkpi_skb, OID_AUTO, debug, CTLFLAG_RWTUN,
     &linuxkpi_debug_skb, 0, "SKB debug level");
 #endif
 
+static uma_zone_t skbzone;
+
 #ifdef __LP64__
 /*
  * Realtek wireless drivers (e.g., rtw88) require 32bit DMA in a single segment.
@@ -84,16 +88,28 @@ struct sk_buff *
 linuxkpi_alloc_skb(size_t size, gfp_t gfp)
 {
 	struct sk_buff *skb;
+	void *p;
 	size_t len;
 
-	len = sizeof(*skb) + size + sizeof(struct skb_shared_info);
+	skb = uma_zalloc(skbzone, linux_check_m_flags(gfp) | M_ZERO);
+	if (skb == NULL)
+		return (NULL);
+
+	skb->prev = skb->next = skb;
+	skb->truesize = size;
+	skb->shinfo = (struct skb_shared_info *)(skb + 1);
+
+	if (size == 0)
+		return (skb);
+
+	len = size;
 	/*
 	 * Using our own type here not backing my kmalloc.
 	 * We assume no one calls kfree directly on the skb.
 	 */
 #ifdef __LP64__
 	if (__predict_true(linuxkpi_skb_memlimit == 0)) {
-		skb = malloc(len, M_LKPISKB, linux_check_m_flags(gfp) | M_ZERO);
+		p = malloc(len, M_LKPISKB, linux_check_m_flags(gfp) | M_ZERO);
 	} else {
 		vm_paddr_t high;
 
@@ -107,23 +123,21 @@ linuxkpi_alloc_skb(size_t size, gfp_t gfp)
 			break;
 		}
 		len = roundup_pow_of_two(len);
-		skb = contigmalloc(len, M_LKPISKB,
+		p = contigmalloc(len, M_LKPISKB,
 		    linux_check_m_flags(gfp) | M_ZERO, 0, high, PAGE_SIZE, 0);
 	}
 #else
-	skb = malloc(len, M_LKPISKB, linux_check_m_flags(gfp) | M_ZERO);
+	p = malloc(len, M_LKPISKB, linux_check_m_flags(gfp) | M_ZERO);
 #endif
-	if (skb == NULL)
-		return (skb);
-	skb->truesize = size;
+	if (p == NULL) {
+		uma_zfree(skbzone, skb);
+		return (NULL);
+	}
 
-	skb->head = skb->data = skb->tail = (uint8_t *)(skb+1);
+	skb->head = skb->data = (uint8_t *)p;
+	skb_reset_tail_pointer(skb);
 	skb->end = skb->head + size;
 
-	skb->prev = skb->next = skb;
-
-	skb->shinfo = (struct skb_shared_info *)(skb->end);
-
 	SKB_TRACE_FMT(skb, "data %p size %zu", (skb) ? skb->data : NULL, size);
 	return (skb);
 }
@@ -161,8 +175,8 @@ linuxkpi_build_skb(void *data, size_t fragsz)
 	skb->_flags |= _SKB_FLAGS_SKBEXTFRAG;
 	skb->truesize = fragsz;
 	skb->head = skb->data = data;
-	skb_reset_tail_pointer(skb);	/* XXX is that correct? */
-	skb->end = (void *)((uintptr_t)skb->head + fragsz);
+	skb_reset_tail_pointer(skb);
+	skb->end = skb->head + fragsz;
 
 	return (skb);
 }
@@ -255,10 +269,29 @@ linuxkpi_kfree_skb(struct sk_buff *skb)
 
 		p = skb->head;
 		skb_free_frag(p);
+		skb->head = NULL;
 	}
 
-	free(skb, M_LKPISKB);
+	free(skb->head, M_LKPISKB);
+	uma_zfree(skbzone, skb);
+}
+
+static void
+lkpi_skbuff_init(void *arg __unused)
+{
+	skbzone = uma_zcreate("skbuff",
+	    sizeof(struct sk_buff) + sizeof(struct skb_shared_info),
+	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
+	/* Do we need to apply limits? */
+}
+SYSINIT(linuxkpi_skbuff, SI_SUB_DRIVERS, SI_ORDER_FIRST, lkpi_skbuff_init, NULL);
+
+static void
+lkpi_skbuff_destroy(void *arg __unused)
+{
+	uma_zdestroy(skbzone);
 }
+SYSUNINIT(linuxkpi_skbuff, SI_SUB_DRIVERS, SI_ORDER_SECOND, lkpi_skbuff_destroy, NULL);
 
 #ifdef DDB
 DB_SHOW_COMMAND(skb, db_show_skb)