Name: Put skb on a diet using skb_extend Status: Compiles Signed-off-by: Rusty Russell Add an skb_extend structure for adding random crap to skbuffs. Don't use it for anything yet. Index: linux-2.6.10-rc2-bk7-Netfilter/include/linux/skbuff.h =================================================================== --- linux-2.6.10-rc2-bk7-Netfilter.orig/include/linux/skbuff.h 2004-10-19 14:34:22.000000000 +1000 +++ linux-2.6.10-rc2-bk7-Netfilter/include/linux/skbuff.h 2004-11-23 21:00:38.104947816 +1100 @@ -27,6 +27,7 @@ #include #include #include +#include #include #define HAVE_ALLOC_SKB /* For the drivers to know */ @@ -272,6 +273,7 @@ #endif + struct skb_extend *ext; /* These elements must be at the end, see alloc_skb() for details. */ unsigned int truesize; @@ -1137,6 +1139,23 @@ /* Call this if aborting loop before !skb_iter_next */ extern void skb_iter_abort(const struct sk_buff *skb, struct skb_iter *i); +static inline struct skb_extend *skb_find_ext(struct sk_buff *skb, __u8 ext) +{ + struct skb_extend *i; + for (i = skb->ext; i && i->type != ext; i = i->next); + return i; +} + +static inline void skb_unlink_ext(struct sk_buff *skb, struct skb_extend *ext) +{ + struct skb_extend **i; + for (i = &skb->ext; *i != ext; i = &(*i)->next); + *i = ext->next; +} + +void skb_drop_exts(struct sk_buff *skb); +struct skb_extend *skb_copy_exts(const struct sk_buff *skb, int gfp_mask); + #ifdef CONFIG_NETFILTER static inline void nf_conntrack_put(struct nf_conntrack *nfct) { Index: linux-2.6.10-rc2-bk7-Netfilter/include/linux/skb_extend.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.10-rc2-bk7-Netfilter/include/linux/skb_extend.h 2004-11-23 21:08:57.319055736 +1100 @@ -0,0 +1,27 @@ +#ifndef _LINUX_SKB_EXTEND_H +#define _LINUX_SKB_EXTEND_H + +#define MAX_SKB_EXTEND_TYPES 32 + +/* Extensions for an skb: optional stuff which isn't permanently in struct. */ +struct skb_extend { + struct skb_extend *next; + __u8 type; +} __attribute__((packed)); + +struct sk_buff; +struct skb_extend_type +{ + /* Operations. */ + struct skb_extend *(*copy)(const struct sk_buff *skb, + struct skb_extend *ext, + int gfp_flags); + void (*free)(const struct sk_buff *, struct skb_extend *); + + /* For the default copy operation. */ + unsigned int size; +}; + +int register_skb_extend_type(struct skb_extend_type *); +void unregister_skb_extend_type(struct skb_extend_type *); +#endif /* _LINUX_SKB_EXTEND_H */ Index: linux-2.6.10-rc2-bk7-Netfilter/net/core/skbuff.c =================================================================== --- linux-2.6.10-rc2-bk7-Netfilter.orig/net/core/skbuff.c 2004-11-16 15:30:11.000000000 +1100 +++ linux-2.6.10-rc2-bk7-Netfilter/net/core/skbuff.c 2004-11-23 22:02:58.336346216 +1100 @@ -70,6 +70,9 @@ static kmem_cache_t *skbuff_head_cache; +static struct skb_extend_type *skb_extend_types[MAX_SKB_EXTEND_TYPES]; +static spinlock_t skb_extend_type_lock; + /* * Keep out-of-line to prevent kernel bloat. * __builtin_return_address is not used because it is not always @@ -252,10 +255,41 @@ skb->tc_classid = 0; #endif #endif - + skb_drop_exts(skb); kfree_skbmem(skb); } +void skb_drop_exts(struct sk_buff *skb) +{ + while (skb->ext) { + struct skb_extend *tmp = skb->ext->next; + skb_extend_types[skb->ext->type]->free(skb, skb->ext); + skb->ext = tmp; + } +} + +struct skb_extend *skb_copy_exts(const struct sk_buff *skb, int gfp_mask) +{ + struct skb_extend *i, *tmp, *ret = NULL; + + for (i = skb->ext; i; i = i->next) { + tmp = skb_extend_types[i->type]->copy(skb, i, gfp_mask); + if (!tmp) + goto unwind; + tmp->next = ret; + ret = tmp; + } + return ret; + +unwind: + while (ret) { + tmp = ret->next; + skb_extend_types[ret->type]->free(skb, ret); + ret = tmp; + } + return NULL; +} + /** * skb_clone - duplicate an sk_buff * @skb: buffer to clone @@ -277,6 +311,12 @@ if (!n) return NULL; + n->ext = skb_copy_exts(skb, gfp_mask); + if (skb->ext && !n->ext) { + kmem_cache_free(skbuff_head_cache, n); + return NULL; + } + #define C(x) n->x = skb->x n->next = n->prev = NULL; @@ -426,6 +466,12 @@ if (!n) return NULL; + n->ext = skb_copy_exts(skb, gfp_mask); + if (skb->ext && !n->ext) { + kfree_skbmem(n); + return NULL; + } + /* Set the data pointer */ skb_reserve(n, headerlen); /* Set the tail pointer and length */ @@ -464,6 +510,13 @@ if (!n) goto out; + n->ext = skb_copy_exts(skb, gfp_mask); + if (skb->ext && !n->ext) { + kfree_skbmem(n); + n = NULL; + goto out; + } + /* Set the data pointer */ skb_reserve(n, skb->data - skb->head); /* Set the tail pointer and length */ @@ -613,6 +666,12 @@ if (!n) return NULL; + n->ext = skb_copy_exts(skb, gfp_mask); + if (skb->ext && !n->ext) { + kfree_skbmem(n); + return NULL; + } + skb_reserve(n, newheadroom); /* Set the tail pointer and length */ @@ -1425,6 +1484,59 @@ skb_split_no_header(skb, skb1, len, pos); } +static struct skb_extend *flat_copy(const struct sk_buff *skb, + struct skb_extend *ext, + int gfp_mask) +{ + unsigned int size = skb_extend_types[ext->type]->size; + struct skb_extend *new = kmalloc(size, gfp_mask); + if (new) + memcpy(new, ext, size); + return new; +} + +static void flat_free(const struct sk_buff *skb, struct skb_extend *ext) +{ + kfree(ext); +} + +int register_skb_extend_type(struct skb_extend_type *ext) +{ + int i; + + if (!ext->copy) + ext->copy = flat_copy; + if (!ext->free) + ext->free = flat_free; + + spin_lock_irq(&skb_extend_type_lock); + for (i = 0; i < ARRAY_SIZE(skb_extend_types); i++) { + if (!skb_extend_types[i]) { + skb_extend_types[i] = ext; + spin_unlock_irq(&skb_extend_type_lock); + return i; + } + } + spin_unlock_irq(&skb_extend_type_lock); + return -ENOSPC; +} + +void unregister_skb_extend_type(struct skb_extend_type *ext) +{ + int i; + + spin_lock_irq(&skb_extend_type_lock); + for (i = 0; i < ARRAY_SIZE(skb_extend_types); i++) { + if (skb_extend_types[i] == ext) { + skb_extend_types[i] = NULL; + spin_unlock_irq(&skb_extend_type_lock); + return; + } + } + spin_unlock_irq(&skb_extend_type_lock); + BUG(); +} + void __init skb_init(void) { skbuff_head_cache = kmem_cache_create("skbuff_head_cache", @@ -1466,3 +1578,7 @@ EXPORT_SYMBOL(skb_iter_first); EXPORT_SYMBOL(skb_iter_next); EXPORT_SYMBOL(skb_iter_abort); +EXPORT_SYMBOL(skb_copy_exts); +EXPORT_SYMBOL(skb_drop_exts); +EXPORT_SYMBOL_GPL(register_skb_extend_type); +EXPORT_SYMBOL_GPL(unregister_skb_extend_type);