git: 5221620a8bf4 - stable/13 - LinuxKPI: skbuff updates
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 20 Feb 2022 18:15:50 UTC
The branch stable/13 has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=5221620a8bf4decd19a176c73b664a16123b88c2 commit 5221620a8bf4decd19a176c73b664a16123b88c2 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-20 16:25:37 +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) (cherry picked from commit 6baea3312d92cd7eb25f5b9e0e474132636f62d9) --- 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 9000c8e62b3b..d6db5dfb6c52 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