git: 49ed6e979c3b - main - LinuxKPI: add a work-in-progress skbuff implementation
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 27 Dec 2021 19:11:43 UTC
The branch main has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=49ed6e979c3b327ae466a559884802d901aa5792 commit 49ed6e979c3b327ae466a559884802d901aa5792 Author: Bjoern A. Zeeb <bz@FreeBSD.org> AuthorDate: 2021-12-26 18:26:26 +0000 Commit: Bjoern A. Zeeb <bz@FreeBSD.org> CommitDate: 2021-12-27 18:47:25 +0000 LinuxKPI: add a work-in-progress skbuff implementation This is a work-in-progress implementation of sk_buff compat code used for wireless drivers only currently. Bring in this version of the code as it has proven to be good enough to have packets going for a few months. The current implementation has several drawbacks including the need for us to copy data between sk_buffs and mbufs. Do not rely on the internals of this implementation. They are highly likely to change as we will improve the integration to FreeBSD mbufs. Sponsored by: The FreeBSD Foundation MFC after: 3 days --- sys/compat/linuxkpi/common/include/linux/skbuff.h | 826 ++++++++++++++++++++++ sys/compat/linuxkpi/common/src/linux_skbuff.c | 113 +++ sys/conf/files | 2 + sys/modules/linuxkpi/Makefile | 1 + 4 files changed, 942 insertions(+) diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h new file mode 100644 index 000000000000..37fb6109c784 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h @@ -0,0 +1,826 @@ +/*- + * Copyright (c) 2020-2021 The FreeBSD Foundation + * Copyright (c) 2021 Bjoern A. Zeeb + * + * This software was developed by Björn Zeeb under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * NOTE: this socket buffer compatibility code is highly EXPERIMENTAL. + * Do not rely on the internals of this implementation. They are highly + * likely to change as we will improve the integration to FreeBSD mbufs. + */ + +#ifndef _LINUXKPI_LINUX_SKBUFF_H +#define _LINUXKPI_LINUX_SKBUFF_H + +#include <linux/page.h> +#include <linux/dma-mapping.h> +#include <linux/netdev_features.h> +#include <linux/list.h> +#include <linux/gfp.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__) +#else +#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 { + PACKET_BROADCAST, + PACKET_MULTICAST, + PACKET_OTHERHOST, +}; + +#define NET_SKB_PAD CACHE_LINE_SIZE /* ? */ + +struct sk_buff_head { + /* XXX TODO */ + struct sk_buff *next; + struct sk_buff *prev; + size_t qlen; + int lock; /* XXX TYPE */ +}; + +enum sk_checksum_flags { + CHECKSUM_NONE = 0x00, + CHECKSUM_UNNECESSARY = 0x01, + CHECKSUM_PARTIAL = 0x02, + CHECKSUM_COMPLETE = 0x04, +}; + +struct skb_frag { + /* XXX TODO */ + struct page *page; /* XXX-BZ These three are a wild guess so far! */ + off_t offset; + size_t size; +}; +typedef struct skb_frag skb_frag_t; + +enum skb_shared_info_gso_type { + SKB_GSO_TCPV4, + SKB_GSO_TCPV6, +}; + +struct skb_shared_info { + enum skb_shared_info_gso_type gso_type; + uint16_t gso_size; + uint16_t nr_frags; + skb_frag_t frags[64]; /* XXX TODO, 16xpage? */ +}; + +struct sk_buff { + /* XXX TODO */ + /* struct sk_buff_head */ + struct sk_buff *next; + struct sk_buff *prev; + int list; /* XXX TYPE */ + uint32_t _alloc_len; /* Length of alloc data-buf. XXX-BZ give up for truesize? */ + uint32_t len; /* ? */ + uint32_t data_len; /* ? If we have frags? */ + uint32_t truesize; /* The total size of all buffers, incl. frags. */ + uint16_t mac_len; /* Link-layer header length. */ + __sum16 csum; + uint16_t l3hdroff; /* network header offset from *head */ + uint16_t l4hdroff; /* transport header offset from *head */ + uint32_t priority; + uint16_t qmap; /* queue mapping */ + uint16_t _spareu16_0; + enum sk_buff_pkt_type pkt_type; + + /* "Scratch" area for layers to store metadata. */ + /* ??? I see sizeof() operations so probably an array. */ + uint8_t cb[64] __aligned(CACHE_LINE_SIZE); + + struct net_device *dev; + void *sk; /* XXX net/sock.h? */ + + int csum_offset, csum_start, ip_summed, protocol; + + uint8_t *head; /* Head of buffer. */ + uint8_t *data; /* Head of data. */ + uint8_t *tail; /* End of data. */ + uint8_t *end; /* End of buffer. */ + + struct skb_shared_info *shinfo; + + /* FreeBSD specific bandaid (see linuxkpi_kfree_skb). */ + void *m; + void(*m_free_func)(void *); + + /* Force padding to CACHE_LINE_SIZE. */ + uint8_t __scratch[0] __aligned(CACHE_LINE_SIZE); +}; + +/* -------------------------------------------------------------------------- */ + +struct sk_buff *linuxkpi_alloc_skb(size_t, gfp_t); +void linuxkpi_kfree_skb(struct sk_buff *); + +/* -------------------------------------------------------------------------- */ + +static inline struct sk_buff * +alloc_skb(size_t size, gfp_t gfp) +{ + struct sk_buff *skb; + + skb = linuxkpi_alloc_skb(size, gfp); + 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_TRACE(skb); + return (skb); +} + +static inline void +kfree_skb(struct sk_buff *skb) +{ + SKB_TRACE(skb); + linuxkpi_kfree_skb(skb); +} + +static inline void +dev_kfree_skb(struct sk_buff *skb) +{ + SKB_TRACE(skb); + kfree_skb(skb); +} + +static inline void +dev_kfree_skb_any(struct sk_buff *skb) +{ + SKB_TRACE(skb); + dev_kfree_skb(skb); +} + +static inline void +dev_kfree_skb_irq(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); +} + +/* -------------------------------------------------------------------------- */ + +/* XXX BZ review this one for terminal condition as Linux "queues" are special. */ +#define skb_list_walk_safe(_q, skb, tmp) \ + for ((skb) = (_q)->next; (skb) != NULL && ((tmp) = (skb)->next); (skb) = (tmp)) + +/* Add headroom; cannot do once there is data in there. */ +static inline void +skb_reserve(struct sk_buff *skb, size_t len) +{ + SKB_TRACE(skb); + 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)); + skb->data += len; + skb->tail += len; +} + +/* + * Remove headroom; return new data pointer; basically make space at the + * front to copy data in (manually). + */ +static inline void * +skb_push(struct sk_buff *skb, size_t len) +{ + SKB_TRACE(skb); + KASSERT(((skb->data - len) >= skb->head), ("%s: skb %p (data %p - " + "len %zu) < head %p\n", __func__, skb, skb->data, len, skb->data)); + skb->len += len; + skb->data -= len; + return (skb->data); +} + +/* + * Length of the data on the skb (without any frags)??? + */ +static inline size_t +skb_headlen(struct sk_buff *skb) +{ + + SKB_TRACE(skb); + return (skb->len - skb->data_len); +} + + +/* Return the end of data (tail pointer). */ +static inline uint8_t * +skb_tail_pointer(struct sk_buff *skb) +{ + + SKB_TRACE(skb); + return (skb->tail); +} + +/* Return number of bytes available at end of buffer. */ +static inline unsigned int +skb_tailroom(struct sk_buff *skb) +{ + + SKB_TRACE(skb); + KASSERT((skb->end - skb->tail) >= 0, ("%s: skb %p tailroom < 0, " + "end %p tail %p\n", __func__, skb, skb->end, skb->tail)); + return (skb->end - skb->tail); +} + +/* Return numer of bytes available at the beginning of buffer. */ +static inline unsigned int +skb_headroom(struct sk_buff *skb) +{ + SKB_TRACE(skb); + KASSERT((skb->data - skb->head) >= 0, ("%s: skb %p headroom < 0, " + "data %p head %p\n", __func__, skb, skb->data, skb->head)); + return (skb->data - skb->head); +} + + +/* + * Remove tailroom; return the old tail pointer; basically make space at + * the end to copy data in (manually). See also skb_put_data() below. + */ +static inline void * +skb_put(struct sk_buff *skb, size_t len) +{ + void *s; + + SKB_TRACE(skb); + KASSERT(((skb->tail + len) <= skb->end), ("%s: skb %p (tail %p + " + "len %zu) > end %p, head %p data %p len %u\n", __func__, + skb, skb->tail, len, skb->end, skb->head, skb->data, skb->len)); + + s = skb_tail_pointer(skb); + skb->tail += len; + skb->len += len; +#ifdef SKB_DEBUG + if (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, + s, len); +#endif + return (s); +} + +/* skb_put() + copying data in. */ +static inline void * +skb_put_data(struct sk_buff *skb, const void *buf, size_t len) +{ + void *s; + + SKB_TRACE2(skb, buf); + s = skb_put(skb, len); + memcpy(s, buf, len); + return (s); +} + +/* skb_put() + filling with zeros. */ +static inline void * +skb_put_zero(struct sk_buff *skb, size_t len) +{ + void *s; + + SKB_TRACE(skb); + s = skb_put(skb, len); + memset(s, '\0', len); + return (s); +} + +/* + * Remove len bytes from beginning of data. + * + * XXX-BZ ath10k checks for !NULL conditions so I assume this doesn't panic; + * we return the advanced data pointer so we don't have to keep a temp, correct? + */ +static inline void * +skb_pull(struct sk_buff *skb, size_t len) +{ + + SKB_TRACE(skb); +#if 0 /* Apparently this doesn't barf... */ + KASSERT(skb->len >= len, ("%s: skb %p skb->len %u < len %u, data %p\n", + __func__, skb, skb->len, len, skb->data)); +#endif + if (skb->len < len) + return (NULL); + skb->len -= len; + skb->data += len; + return (skb->data); +} + +/* Reduce skb data to given length or do nothing if smaller already. */ +static inline void +__skb_trim(struct sk_buff *skb, unsigned int len) +{ + + SKB_TRACE(skb); + if (skb->len < len) + return; + + skb->len = len; + skb->tail = skb->data + skb->len; +} + +static inline void +skb_trim(struct sk_buff *skb, unsigned int len) +{ + + return (__skb_trim(skb, len)); +} + +static inline struct skb_shared_info * +skb_shinfo(struct sk_buff *skb) +{ + + SKB_TRACE(skb); + return (skb->shinfo); +} + +static inline void +skb_add_rx_frag(struct sk_buff *skb, int fragno, struct page *page, + off_t offset, size_t size, unsigned int truesize) +{ + struct skb_shared_info *shinfo; + + SKB_TRACE(skb); +#ifdef SKB_DEBUG + if (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, + (uintmax_t)(uintptr_t)linux_page_address(page), (uintmax_t)offset, + size, truesize); +#endif + + shinfo = skb_shinfo(skb); + KASSERT(fragno >= 0 && fragno < nitems(shinfo->frags), ("%s: skb %p " + "fragno %d too big\n", __func__, skb, fragno)); + shinfo->frags[fragno].page = page; + shinfo->frags[fragno].offset = offset; + shinfo->frags[fragno].size = size; + shinfo->nr_frags = fragno + 1; + skb->len += size; + skb->truesize += truesize; + + /* XXX TODO EXTEND truesize? */ +} + +/* -------------------------------------------------------------------------- */ + +/* XXX BZ review this one for terminal condition as Linux "queues" are special. */ +#define skb_queue_walk(_q, skb) \ + for ((skb) = (_q)->next; (skb) != (struct sk_buff *)(_q); \ + (skb) = (skb)->next) + +#define skb_queue_walk_safe(_q, skb, tmp) \ + for ((skb) = (_q)->next, (tmp) = (skb)->next; \ + (skb) != (struct sk_buff *)(_q); (skb) = (tmp), (tmp) = (skb)->next) + +static inline bool +skb_queue_empty(struct sk_buff_head *q) +{ + + SKB_TRACE(q); + return (q->qlen == 0); +} + +static inline void +__skb_queue_head_init(struct sk_buff_head *q) +{ + SKB_TRACE(q); + q->prev = q->next = (struct sk_buff *)q; + q->qlen = 0; +} + +static inline void +skb_queue_head_init(struct sk_buff_head *q) +{ + SKB_TRACE(q); + return (__skb_queue_head_init(q)); +} + +static inline void +__skb_insert(struct sk_buff *new, struct sk_buff *prev, struct sk_buff *next, + struct sk_buff_head *q) +{ + + SKB_TRACE_FMT(new, "prev %p next %p q %p", prev, next, q); + new->prev = prev; + new->next = next; + next->prev = new; + prev->next = new; + q->qlen++; +} + +static inline void +__skb_queue_after(struct sk_buff_head *q, struct sk_buff *skb, + struct sk_buff *new) +{ + + SKB_TRACE_FMT(q, "skb %p new %p", skb, new); + __skb_insert(new, skb, skb->next, q); +} + +static inline void +__skb_queue_before(struct sk_buff_head *q, struct sk_buff *skb, + struct sk_buff *new) +{ + + SKB_TRACE_FMT(q, "skb %p new %p", skb, new); + __skb_insert(new, skb->prev, skb, q); +} + +static inline void +__skb_queue_tail(struct sk_buff_head *q, struct sk_buff *skb) +{ + struct sk_buff *s; + + SKB_TRACE2(q, skb); + q->qlen++; + s = (struct sk_buff *)q; + s->prev->next = skb; + skb->prev = s->prev; + skb->next = s; + s->prev = skb; +} + +static inline void +skb_queue_tail(struct sk_buff_head *q, struct sk_buff *skb) +{ + SKB_TRACE2(q, skb); + return (__skb_queue_tail(q, skb)); +} + +static inline struct sk_buff * +skb_peek_tail(struct sk_buff_head *q) +{ + struct sk_buff *skb; + + skb = q->prev; + SKB_TRACE2(q, skb); + if (skb == (struct sk_buff *)q) + return (NULL); + return (skb); +} + +static inline void +__skb_unlink(struct sk_buff *skb, struct sk_buff_head *head) +{ + SKB_TRACE2(skb, head); + struct sk_buff *p, *n;; + + head->qlen--; + p = skb->prev; + n = skb->next; + p->next = n; + n->prev = p; + skb->prev = skb->next = NULL; +} + +static inline void +skb_unlink(struct sk_buff *skb, struct sk_buff_head *head) +{ + SKB_TRACE2(skb, head); + return (__skb_unlink(skb, head)); +} + +static inline struct sk_buff * +__skb_dequeue(struct sk_buff_head *q) +{ + struct sk_buff *skb; + + SKB_TRACE(q); + skb = q->next; + if (skb == (struct sk_buff *)q) + return (NULL); + if (skb != NULL) + __skb_unlink(skb, q); + SKB_TRACE(skb); + return (skb); +} + +static inline struct sk_buff * +skb_dequeue(struct sk_buff_head *q) +{ + SKB_TRACE(q); + return (__skb_dequeue(q)); +} + +static inline struct sk_buff * +skb_dequeue_tail(struct sk_buff_head *q) +{ + struct sk_buff *skb; + + skb = skb_peek_tail(q); + if (skb != NULL) + __skb_unlink(skb, q); + + SKB_TRACE2(q, skb); + 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 uint32_t +skb_queue_len(struct sk_buff_head *head) +{ + SKB_TRACE(head); + return (head->qlen); +} + +static inline void +__skb_queue_purge(struct sk_buff_head *q) +{ + struct sk_buff *skb; + + SKB_TRACE(q); + while ((skb = __skb_dequeue(q)) != NULL) + kfree_skb(skb); +} + +static inline void +skb_queue_purge(struct sk_buff_head *q) +{ + SKB_TRACE(q); + return (__skb_queue_purge(q)); +} + +static inline struct sk_buff * +skb_queue_prev(struct sk_buff_head *q, struct sk_buff *skb) +{ + + SKB_TRACE2(q, skb); + /* XXX what is the q argument good for? */ + return (skb->prev); +} + +/* -------------------------------------------------------------------------- */ + +static inline struct sk_buff * +skb_copy(struct sk_buff *skb, gfp_t gfp) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (NULL); +} + +static inline void +consume_skb(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); +} + +static inline uint16_t +skb_checksum(struct sk_buff *skb, int offs, size_t len, int x) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (0xffff); +} + +static inline int +skb_checksum_start_offset(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (-1); +} + +static inline dma_addr_t +skb_frag_dma_map(struct device *dev, const skb_frag_t *frag, int x, + size_t fragsz, enum dma_data_direction dir) +{ + SKB_TRACE2(frag, dev); + SKB_TODO(); + return (-1); +} + +static inline size_t +skb_frag_size(const skb_frag_t *frag) +{ + SKB_TRACE(frag); + SKB_TODO(); + return (-1); +} + +static inline bool +skb_is_nonlinear(struct sk_buff *skb) +{ + SKB_TRACE(skb); + return ((skb->data_len > 0) ? true : false); +} + +#define skb_walk_frags(_skb, _frag) \ + for ((_frag) = (_skb); false; (_frag)++) + +static inline void +skb_checksum_help(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); +} + +static inline bool +skb_ensure_writable(struct sk_buff *skb, size_t off) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (false); +} + +static inline void * +skb_frag_address(const skb_frag_t *frag) +{ + SKB_TRACE(frag); + SKB_TODO(); + return (NULL); +} + +static inline struct sk_buff * +skb_gso_segment(struct sk_buff *skb, netdev_features_t netdev_flags) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (NULL); +} + +static inline bool +skb_is_gso(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (false); +} + +static inline void +skb_mark_not_on_list(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); +} + +static inline void +skb_queue_splice_init(struct sk_buff_head *qa, struct sk_buff_head *qb) +{ + SKB_TRACE2(qa, qb); + SKB_TODO(); +} + +static inline void +skb_reset_transport_header(struct sk_buff *skb) +{ + + SKB_TRACE(skb); + skb->l4hdroff = skb->data - skb->head; +} + +static inline uint8_t * +skb_transport_header(struct sk_buff *skb) +{ + + SKB_TRACE(skb); + return (skb->head + skb->l4hdroff); +} + +static inline uint8_t * +skb_network_header(struct sk_buff *skb) +{ + + SKB_TRACE(skb); + return (skb->head + skb->l3hdroff); +} + +static inline int +__skb_linearize(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (ENXIO); +} + +static inline bool +pskb_expand_head(struct sk_buff *skb, int x, int len, gfp_t gfp) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (false); +} + +/* Not really seen this one but need it as symmetric accessor function. */ +static inline void +skb_set_queue_mapping(struct sk_buff *skb, uint16_t qmap) +{ + + SKB_TRACE_FMT(skb, "qmap %u", qmap); + skb->qmap = qmap; +} + +static inline uint16_t +skb_get_queue_mapping(struct sk_buff *skb) +{ + + SKB_TRACE_FMT(skb, "qmap %u", skb->qmap); + return (skb->qmap); +} + +static inline bool +skb_header_cloned(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (false); +} + +static inline uint8_t * +skb_mac_header(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); + return (NULL); +} + +static inline void +skb_orphan(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); +} + +static inline void +skb_reset_mac_header(struct sk_buff *skb) +{ + SKB_TRACE(skb); + SKB_TODO(); +} + +static inline struct sk_buff * +skb_peek(struct sk_buff_head *q) +{ + SKB_TRACE(q); + SKB_TODO(); + return (NULL); +} + +static inline __sum16 +csum_unfold(__sum16 sum) +{ + SKB_TODO(); + return (sum); +} + +#endif /* _LINUXKPI_LINUX_SKBUFF_H */ diff --git a/sys/compat/linuxkpi/common/src/linux_skbuff.c b/sys/compat/linuxkpi/common/src/linux_skbuff.c new file mode 100644 index 000000000000..e9935e65b466 --- /dev/null +++ b/sys/compat/linuxkpi/common/src/linux_skbuff.c @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2020-2021 The FreeBSD Foundation + * Copyright (c) 2021 Bjoern A. Zeeb + * + * This software was developed by Björn Zeeb under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * NOTE: this socket buffer compatibility code is highly EXPERIMENTAL. + * Do not rely on the internals of this implementation. They are highly + * likely to change as we will improve the integration to FreeBSD mbufs. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <linux/skbuff.h> +#include <linux/slab.h> + +static MALLOC_DEFINE(M_LKPISKB, "lkpiskb", "Linux KPI skbuff compat"); + +struct sk_buff * +linuxkpi_alloc_skb(size_t size, gfp_t gfp) +{ + struct sk_buff *skb; + size_t len; + + len = sizeof(*skb) + size + sizeof(struct skb_shared_info); + /* + * Using or 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); + if (skb == NULL) + return (skb); + skb->_alloc_len = size; + skb->truesize = size; + + skb->head = skb->data = skb->tail = (uint8_t *)(skb+1); + skb->end = skb->head + size; + + skb->shinfo = (struct skb_shared_info *)(skb->end); + + SKB_TRACE_FMT(skb, "data %p size %zu", skb->data, size); + return (skb); +} + +void +linuxkpi_kfree_skb(struct sk_buff *skb) +{ + struct skb_shared_info *shinfo; + uint16_t fragno; + + SKB_TRACE(skb); + if (skb == NULL) + return; + + /* + * XXX TODO this will go away once we have skb backed by mbuf. + * currently we allow the mbuf to stay around and use a private + * free function to allow secondary resources to be freed along. + */ + if (skb->m != NULL) { + void *m; + + m = skb->m; + skb->m = NULL; + + KASSERT(skb->m_free_func != NULL, ("%s: skb %p has m %p but no " + "m_free_func %p\n", __func__, skb, m, skb->m_free_func)); + skb->m_free_func(m); + } + KASSERT(skb->m == NULL, + ("%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); + } + + free(skb, M_LKPISKB); +} diff --git a/sys/conf/files b/sys/conf/files index 517168b5a5d5..6a809efe75d1 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -4570,6 +4570,8 @@ compat/linuxkpi/common/src/linux_shmemfs.c optional compat_linuxkpi \ *** 20 LINES SKIPPED ***