git: 6baea3312d92 - main - LinuxKPI: skbuff updates
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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