git: 6baea3312d92 - main - LinuxKPI: skbuff updates

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Wed, 16 Feb 2022 02:21:10 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=6baea3312d92cd7eb25f5b9e0e474132636f62d9

commit 6baea3312d92cd7eb25f5b9e0e474132636f62d9
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2022-02-16 02:10:10 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2022-02-16 02:10:10 +0000

    LinuxKPI: skbuff updates
    
    Various updates to skbuff for new/updated drivers and some housekeeping:
    - update types and struct members, add new (stub) functions
    - improve freeing of frags.
    - fix an issue with sleeping during alloc for dev_alloc_skb().
    - Adjust a KASSERT for skb_reserve() which apparently can be called
      multiple times if no data was put into the skb yet.
    - move the sysctl from linux_8022.c (which may be in a different module)
      to linux_skbuff.c so in case we turn debugging on we do not run into
      unresolved symbols.  Rename the sysctl variable to be less conflicting
      and update debugging macros along with that; also add IMPROVE().
    - add DDB support to show an skbuff.
    - adjust comments/whitespace.
    
    No functional changes intended for iwlwifi.
    
    Sponsored by:   The FreeBSD Foundation (partially)
    MFC after:      3 days
---
 sys/compat/linuxkpi/common/include/linux/skbuff.h | 151 ++++++++++++++++++----
 sys/compat/linuxkpi/common/src/linux_80211.c      |   8 --
 sys/compat/linuxkpi/common/src/linux_skbuff.c     | 104 +++++++++++++--
 3 files changed, 220 insertions(+), 43 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h
index 37fb6109c784..f5954a9c33cf 100644
--- a/sys/compat/linuxkpi/common/include/linux/skbuff.h
+++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 2020-2021 The FreeBSD Foundation
- * Copyright (c) 2021 Bjoern A. Zeeb
+ * Copyright (c) 2020-2022 The FreeBSD Foundation
+ * Copyright (c) 2021-2022 Bjoern A. Zeeb
  *
  * This software was developed by Björn Zeeb under sponsorship from
  * the FreeBSD Foundation.
@@ -43,28 +43,39 @@
 #include <linux/netdev_features.h>
 #include <linux/list.h>
 #include <linux/gfp.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
 
 /* #define	SKB_DEBUG */
 #ifdef SKB_DEBUG
-
 #define	DSKB_TODO	0x01
-#define	DSKB_TRACE	0x02
-#define	DSKB_TRACEX	0x04
-extern int debug_skb;
-
-#define	SKB_TRACE(_s)		if (debug_skb & DSKB_TRACE)		\
-    printf("SKB_TRACE %s:%d %p\n", __func__, __LINE__, _s)
-#define	SKB_TRACE2(_s, _p)	if (debug_skb & DSKB_TRACE)		\
-    printf("SKB_TRACE %s:%d %p, %p\n", __func__, __LINE__, _s, _p)
-#define	SKB_TRACE_FMT(_s, _fmt, ...)	if (debug_skb & DSKB_TRACE)	\
-    printf("SKB_TRACE %s:%d %p" _fmt "\n", __func__, __LINE__, _s, __VA_ARGS__)
-#define	SKB_TODO()		if (debug_skb & DSKB_TODO)		\
-    printf("SKB_TODO %s:%d\n", __func__, __LINE__)
+#define	DSKB_IMPROVE	0x02
+#define	DSKB_TRACE	0x10
+#define	DSKB_TRACEX	0x20
+extern int linuxkpi_debug_skb;
+
+#define	SKB_TODO()							\
+    if (linuxkpi_debug_skb & DSKB_TODO)					\
+	printf("SKB_TODO %s:%d\n", __func__, __LINE__)
+#define	SKB_IMPROVE(...)						\
+    if (linuxkpi_debug_skb & DSKB_IMPROVE)				\
+	printf("SKB_IMPROVE %s:%d\n", __func__, __LINE__)
+#define	SKB_TRACE(_s)							\
+    if (linuxkpi_debug_skb & DSKB_TRACE)				\
+	printf("SKB_TRACE %s:%d %p\n", __func__, __LINE__, _s)
+#define	SKB_TRACE2(_s, _p)						\
+    if (linuxkpi_debug_skb & DSKB_TRACE)				\
+	printf("SKB_TRACE %s:%d %p, %p\n", __func__, __LINE__, _s, _p)
+#define	SKB_TRACE_FMT(_s, _fmt, ...)					\
+   if (linuxkpi_debug_skb & DSKB_TRACE)					\
+	printf("SKB_TRACE %s:%d %p " _fmt "\n", __func__, __LINE__, _s,	\
+	    __VA_ARGS__)
 #else
+#define	SKB_TODO()		do { } while(0)
+#define	SKB_IMPROVE(...)	do { } while(0)
 #define	SKB_TRACE(_s)		do { } while(0)
 #define	SKB_TRACE2(_s, _p)	do { } while(0)
 #define	SKB_TRACE_FMT(_s, ...)	do { } while(0)
-#define	SKB_TODO()		do { } while(0)
 #endif
 
 enum sk_buff_pkt_type {
@@ -80,7 +91,7 @@ struct sk_buff_head {
 	struct sk_buff		*next;
 	struct sk_buff		*prev;
 	size_t			qlen;
-	int			lock;	/* XXX TYPE */
+	spinlock_t		lock;
 };
 
 enum sk_checksum_flags {
@@ -107,6 +118,7 @@ struct skb_shared_info {
 	enum skb_shared_info_gso_type	gso_type;
 	uint16_t			gso_size;
 	uint16_t			nr_frags;
+	struct sk_buff			*frag_list;
 	skb_frag_t			frags[64];	/* XXX TODO, 16xpage? */
 };
 
@@ -170,13 +182,24 @@ alloc_skb(size_t size, gfp_t gfp)
 	return (skb);
 }
 
+static inline struct sk_buff *
+__dev_alloc_skb(size_t len, gfp_t gfp)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(len, gfp);
+	SKB_IMPROVE();
+	SKB_TRACE(skb);
+	return (skb);
+}
+
 static inline struct sk_buff *
 dev_alloc_skb(size_t len)
 {
 	struct sk_buff *skb;
 
-	skb = alloc_skb(len, GFP_KERNEL);
-	/* XXX TODO */
+	skb = alloc_skb(len, GFP_NOWAIT);
+	SKB_IMPROVE();
 	SKB_TRACE(skb);
 	return (skb);
 }
@@ -220,8 +243,15 @@ static inline void
 skb_reserve(struct sk_buff *skb, size_t len)
 {
 	SKB_TRACE(skb);
+#if 0
+	/* Apparently it is allowed to call skb_reserve multiple times in a row. */
 	KASSERT(skb->data == skb->head, ("%s: skb %p not empty head %p data %p "
 	    "tail %p\n", __func__, skb, skb->head, skb->data, skb->tail));
+#else
+	KASSERT(skb->len == 0 && skb->data == skb->tail, ("%s: skb %p not "
+	    "empty head %p data %p tail %p len %u\n", __func__, skb,
+	    skb->head, skb->data, skb->tail, skb->len));
+#endif
 	skb->data += len;
 	skb->tail += len;
 }
@@ -302,9 +332,9 @@ skb_put(struct sk_buff *skb, size_t len)
 	skb->tail += len;
 	skb->len += len;
 #ifdef SKB_DEBUG
-	if (debug_skb & DSKB_TRACEX)
+	if (linuxkpi_debug_skb & DSKB_TRACEX)
 	printf("%s: skb %p (%u) head %p data %p tail %p end %p, s %p len %zu\n",
-	    __func__, skb,skb->len, skb->head, skb->data, skb->tail, skb->end,
+	    __func__, skb, skb->len, skb->head, skb->data, skb->tail, skb->end,
 	    s, len);
 #endif
 	return (s);
@@ -392,7 +422,7 @@ skb_add_rx_frag(struct sk_buff *skb, int fragno, struct page *page,
 
 	SKB_TRACE(skb);
 #ifdef SKB_DEBUG
-	if (debug_skb & DSKB_TRACEX)
+	if (linuxkpi_debug_skb & DSKB_TRACEX)
 	printf("%s: skb %p head %p data %p tail %p end %p len %u fragno %d "
 	    "page %#jx offset %ju size %zu truesize %u\n", __func__,
 	    skb, skb->head, skb->data, skb->tail, skb->end, skb->len, fragno,
@@ -567,6 +597,14 @@ skb_dequeue_tail(struct sk_buff_head *q)
 	return (skb);
 }
 
+static inline void
+__skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb)
+{
+
+	SKB_TRACE2(q, skb);
+	__skb_queue_after(q, (struct sk_buff *)q, skb);
+}
+
 static inline void
 skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb)
 {
@@ -578,10 +616,19 @@ skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb)
 static inline uint32_t
 skb_queue_len(struct sk_buff_head *head)
 {
+
 	SKB_TRACE(head);
 	return (head->qlen);
 }
 
+static inline uint32_t
+skb_queue_len_lockless(const struct sk_buff_head *head)
+{
+
+	SKB_TRACE(head);
+	return (READ_ONCE(head->qlen));
+}
+
 static inline void
 __skb_queue_purge(struct sk_buff_head *q)
 {
@@ -715,10 +762,26 @@ skb_mark_not_on_list(struct sk_buff *skb)
 }
 
 static inline void
-skb_queue_splice_init(struct sk_buff_head *qa, struct sk_buff_head *qb)
+skb_queue_splice_init(struct sk_buff_head *q, struct sk_buff_head *h)
 {
-	SKB_TRACE2(qa, qb);
-	SKB_TODO();
+	struct sk_buff *b, *e;
+
+	SKB_TRACE2(q, h);
+
+	if (skb_queue_empty(q))
+		return;
+
+	/* XXX do we need a barrier around this? */
+	b = q->next;
+	e = q->prev;
+
+	b->prev = (struct sk_buff *)h;
+	h->next = b;
+	e->next = h->next;
+	h->next->prev = e;
+
+	h->qlen += q->qlen;
+	__skb_queue_head_init(q);
 }
 
 static inline void
@@ -753,12 +816,12 @@ __skb_linearize(struct sk_buff *skb)
 	return (ENXIO);
 }
 
-static inline bool
+static inline int
 pskb_expand_head(struct sk_buff *skb, int x, int len, gfp_t gfp)
 {
 	SKB_TRACE(skb);
 	SKB_TODO();
-	return (false);
+	return (-ENXIO);
 }
 
 /* Not really seen this one but need it as symmetric accessor function. */
@@ -823,4 +886,38 @@ csum_unfold(__sum16 sum)
 	return (sum);
 }
 
+static inline void
+skb_reset_tail_pointer(struct sk_buff *skb)
+{
+
+	SKB_TRACE(skb);
+	skb->tail = (uint8_t *)(uintptr_t)(skb->data - skb->head);
+	SKB_TRACE(skb);
+}
+
+static inline struct sk_buff *
+skb_get(struct sk_buff *skb)
+{
+
+	SKB_TODO();	/* XXX refcnt? as in get/put_device? */
+	return (skb);
+}
+
+static inline struct sk_buff *
+skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
+{
+
+	SKB_TODO();
+	return (NULL);
+}
+
+static inline void
+skb_copy_from_linear_data(const struct sk_buff *skb, void *dst, size_t len)
+{
+
+	SKB_TRACE(skb);
+	/* Let us just hope the destination has len space ... */
+	memcpy(dst, skb->data, len);
+}
+
 #endif	/* _LINUXKPI_LINUX_SKBUFF_H */
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 8bce01c25f5b..a1010b23f76f 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -72,14 +72,6 @@ __FBSDID("$FreeBSD$");
 
 static MALLOC_DEFINE(M_LKPI80211, "lkpi80211", "Linux KPI 80211 compat");
 
-/* -------------------------------------------------------------------------- */
-/* These are unrelated to 802.11 sysctl bug debugging during 802.11 work so   *
- * keep them here rather than in a more general file.                         */
-
-int debug_skb;
-SYSCTL_INT(_compat_linuxkpi, OID_AUTO, debug_skb, CTLFLAG_RWTUN,
-    &debug_skb, 0, "SKB debug level");
-
 /* -------------------------------------------------------------------------- */
 
 int debug_80211;
diff --git a/sys/compat/linuxkpi/common/src/linux_skbuff.c b/sys/compat/linuxkpi/common/src/linux_skbuff.c
index e9935e65b466..0a4974d74d9d 100644
--- a/sys/compat/linuxkpi/common/src/linux_skbuff.c
+++ b/sys/compat/linuxkpi/common/src/linux_skbuff.c
@@ -1,6 +1,6 @@
 /*-
- * Copyright (c) 2020-2021 The FreeBSD Foundation
- * Copyright (c) 2021 Bjoern A. Zeeb
+ * Copyright (c) 2020-2022 The FreeBSD Foundation
+ * Copyright (c) 2021-2022 Bjoern A. Zeeb
  *
  * This software was developed by Björn Zeeb under sponsorship from
  * the FreeBSD Foundation.
@@ -38,13 +38,31 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_ddb.h"
+
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
+#include <sys/sysctl.h>
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
 
 #include <linux/skbuff.h>
 #include <linux/slab.h>
+#include <linux/gfp.h>
+
+#ifdef SKB_DEBUG
+SYSCTL_DECL(_compat_linuxkpi);
+SYSCTL_NODE(_compat_linuxkpi, OID_AUTO, skb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
+    "LinuxKPI skbuff");
+
+int linuxkpi_debug_skb;
+SYSCTL_INT(_compat_linuxkpi_skb, OID_AUTO, debug, CTLFLAG_RWTUN,
+    &linuxkpi_debug_skb, 0, "SKB debug level");
+#endif
 
 static MALLOC_DEFINE(M_LKPISKB, "lkpiskb", "Linux KPI skbuff compat");
 
@@ -56,7 +74,7 @@ linuxkpi_alloc_skb(size_t size, gfp_t gfp)
 
 	len = sizeof(*skb) + size + sizeof(struct skb_shared_info);
 	/*
-	 * Using or own type here not backing my kmalloc.
+	 * Using our own type here not backing my kmalloc.
 	 * We assume no one calls kfree directly on the skb.
 	 */
 	skb = malloc(len, M_LKPISKB, linux_check_m_flags(gfp) | M_ZERO);
@@ -78,7 +96,7 @@ void
 linuxkpi_kfree_skb(struct sk_buff *skb)
 {
 	struct skb_shared_info *shinfo;
-	uint16_t fragno;
+	uint16_t fragno, count;
 
 	SKB_TRACE(skb);
 	if (skb == NULL)
@@ -103,11 +121,81 @@ linuxkpi_kfree_skb(struct sk_buff *skb)
 	    ("%s: skb %p m %p != NULL\n", __func__, skb, skb->m));
 
 	shinfo = skb->shinfo;
-	for (fragno = 0; fragno < nitems(shinfo->frags); fragno++) {
-
-		if (shinfo->frags[fragno].page != NULL)
-			__free_page(shinfo->frags[fragno].page);
+	for (count = fragno = 0;
+	    count < shinfo->nr_frags && fragno < nitems(shinfo->frags);
+	    fragno++) {
+
+		if (shinfo->frags[fragno].page != NULL) {
+			struct page *p;
+
+			p = shinfo->frags[fragno].page;
+			shinfo->frags[fragno].size = 0;
+			shinfo->frags[fragno].offset = 0;
+			shinfo->frags[fragno].page = NULL;
+			__free_page(p);
+			count++;
+		}
 	}
 
 	free(skb, M_LKPISKB);
 }
+
+#ifdef DDB
+DB_SHOW_COMMAND(skb, db_show_skb)
+{
+	struct sk_buff *skb;
+	int i;
+
+	if (!have_addr) {
+		db_printf("usage: show skb <addr>\n");
+			return;
+	}
+
+	skb = (struct sk_buff *)addr;
+
+	db_printf("skb %p\n", skb);
+	db_printf("\tnext %p prev %p\n", skb->next, skb->prev);
+	db_printf("\tlist %d\n", skb->list);
+	db_printf("\t_alloc_len %u len %u data_len %u truesize %u mac_len %u\n",
+	    skb->_alloc_len, skb->len, skb->data_len, skb->truesize,
+	    skb->mac_len);
+	db_printf("\tcsum %#06x l3hdroff %u l4hdroff %u priority %u qmap %u\n",
+	    skb->csum, skb->l3hdroff, skb->l4hdroff, skb->priority, skb->qmap);
+	db_printf("\tpkt_type %d dev %p sk %p\n",
+	    skb->pkt_type, skb->dev, skb->sk);
+	db_printf("\tcsum_offset %d csum_start %d ip_summed %d protocol %d\n",
+	    skb->csum_offset, skb->csum_start, skb->ip_summed, skb->protocol);
+	db_printf("\thead %p data %p tail %p end %p\n",
+	    skb->head, skb->data, skb->tail, skb->end);
+	db_printf("\tshinfo %p m %p m_free_func %p\n",
+	    skb->shinfo, skb->m, skb->m_free_func);
+
+	if (skb->shinfo != NULL) {
+		struct skb_shared_info *shinfo;
+
+		shinfo = skb->shinfo;
+		db_printf("\t\tgso_type %d gso_size %u nr_frags %u\n",
+		    shinfo->gso_type, shinfo->gso_size, shinfo->nr_frags);
+		for (i = 0; i < nitems(shinfo->frags); i++) {
+			struct skb_frag *frag;
+
+			frag = &shinfo->frags[i];
+			if (frag == NULL || frag->page == NULL)
+				continue;
+			db_printf("\t\t\tfrag %p fragno %d page %p %p "
+			    "offset %ju size %zu\n",
+			    frag, i, frag->page, linux_page_address(frag->page),
+			    (uintmax_t)frag->offset, frag->size);
+		}
+	}
+	db_printf("\tcb[] %p {", skb->cb);
+	for (i = 0; i < nitems(skb->cb); i++) {
+		db_printf("%#04x%s",
+		    skb->cb[i], (i < (nitems(skb->cb)-1)) ? ", " : "");
+	}
+	db_printf("}\n");
+
+	db_printf("\t_spareu16_0 %#06x __scratch[0] %p\n",
+	    skb->_spareu16_0, skb->__scratch);
+};
+#endif