git: 349b042b9005 - main - LinuxKPI: skbuff: start implementing skb_copy()

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Fri, 15 Apr 2022 15:56:50 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=349b042b90057c1e9dbb64dfdb894fe03ea20a1d

commit 349b042b90057c1e9dbb64dfdb894fe03ea20a1d
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2022-04-15 12:30:51 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2022-04-15 15:54:03 +0000

    LinuxKPI: skbuff: start implementing skb_copy()
    
    Implement skb_copy() with omissions of fragments and possibly other fields
    for now.  Should we hit frags at any point a log message will let us know.
    For the few cases we need this currently this is enough.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
---
 sys/compat/linuxkpi/common/include/linux/skbuff.h | 10 ++++--
 sys/compat/linuxkpi/common/src/linux_skbuff.c     | 38 +++++++++++++++++++++++
 2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h
index 2b1b66844640..3caf7059dd15 100644
--- a/sys/compat/linuxkpi/common/include/linux/skbuff.h
+++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h
@@ -172,6 +172,8 @@ struct sk_buff *linuxkpi_alloc_skb(size_t, gfp_t);
 struct sk_buff *linuxkpi_dev_alloc_skb(size_t, gfp_t);
 void linuxkpi_kfree_skb(struct sk_buff *);
 
+struct sk_buff *linuxkpi_skb_copy(struct sk_buff *, gfp_t);
+
 /* -------------------------------------------------------------------------- */
 
 static inline struct sk_buff *
@@ -667,9 +669,11 @@ skb_queue_prev(struct sk_buff_head *q, struct sk_buff *skb)
 static inline struct sk_buff *
 skb_copy(struct sk_buff *skb, gfp_t gfp)
 {
-	SKB_TRACE(skb);
-	SKB_TODO();
-	return (NULL);
+	struct sk_buff *new;
+
+	new = linuxkpi_skb_copy(skb, gfp);
+	SKB_TRACE2(skb, new);
+	return (new);
 }
 
 static inline void
diff --git a/sys/compat/linuxkpi/common/src/linux_skbuff.c b/sys/compat/linuxkpi/common/src/linux_skbuff.c
index dfa9dfb2ceb4..df1f6439c694 100644
--- a/sys/compat/linuxkpi/common/src/linux_skbuff.c
+++ b/sys/compat/linuxkpi/common/src/linux_skbuff.c
@@ -111,6 +111,44 @@ linuxkpi_dev_alloc_skb(size_t size, gfp_t gfp)
 	return (skb);
 }
 
+struct sk_buff *
+linuxkpi_skb_copy(struct sk_buff *skb, gfp_t gfp)
+{
+	struct sk_buff *new;
+	struct skb_shared_info *shinfo;
+	size_t len;
+	unsigned int headroom;
+
+	/* Full buffer size + any fragments. */
+	len = skb->end - skb->head + skb->data_len;
+
+	new = linuxkpi_alloc_skb(len, gfp);
+	if (new == NULL)
+		return (NULL);
+
+	headroom = skb_headroom(skb);
+	/* Fixup head and end. */
+	skb_reserve(new, headroom);	/* data and tail move headroom forward. */
+	skb_put(new, skb->len);		/* tail and len get adjusted */
+
+	/* Copy data. */
+	memcpy(new->head, skb->data - headroom, headroom + skb->len);
+
+	/* Deal with fragments. */
+	shinfo = skb->shinfo;
+	if (shinfo->nr_frags > 0) {
+		printf("%s:%d: NOT YET SUPPORTED; missing %d frags\n",
+		    __func__, __LINE__, shinfo->nr_frags);
+		SKB_TODO();
+	}
+
+	/* Deal with header fields. */
+	memcpy(new->cb, skb->cb, sizeof(skb->cb));
+	SKB_IMPROVE("more header fields to copy?");
+
+	return (new);
+}
+
 void
 linuxkpi_kfree_skb(struct sk_buff *skb)
 {