On Mon, 11 Dec 2018, Florian Westphal wrote: ... > diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h > index b1831a5ca173..d715736eb734 100644 > --- a/include/linux/skbuff.h > +++ b/include/linux/skbuff.h ... > @@ -3896,6 +3906,113 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct) >                 atomic_inc(&nfct->use); >  } >  #endif > + > +#ifdef CONFIG_SKB_EXTENSIONS > +enum skb_ext_id { > +#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) > +       SKB_EXT_BRIDGE_NF, > +#endif > +       SKB_EXT_NUM, /* must be last */ > +}; Could enum skb_ext_id always be defined, with none of the SKB_EXT_* values conditionally excluded? In combination with some alternate function definitions below (see later comments) I think this could reduce the need for CONFIG_SKB_EXTENSIONS preprocessor conditionals throughout the net code. > + > +/** > + *     struct skb_ext - sk_buff extensions > + *     @refcnt: 1 on allocation, deallocated on 0 > + *     @offset: offset to add to @data to obtain extension address > + *     @chunks: size currently allocated, stored in SKB_EXT_ALIGN_SHIFT units > + *     @data: start of extension data, variable sized > + * > + *     Note: offsets/lengths are stored in chunks of 8 bytes, this allows > + *     to use 'u8' types while allowing up to 2kb worth of extension data. > + */ > +struct skb_ext { > +       refcount_t refcnt; > +       u8 offset[SKB_EXT_NUM]; /* in chunks of 8 bytes */ > +       u8 chunks;              /* same */ > +       char data[0] __aligned(8); > +}; > + > +void *skb_ext_add(struct sk_buff *skb, enum skb_ext_id id); > +void __skb_ext_del(struct sk_buff *skb, enum skb_ext_id id); > +void __skb_ext_free(struct skb_ext *ext); > + > +static inline void __skb_ext_put(struct skb_ext *ext) > +{ > +       if (ext && refcount_dec_and_test(&ext->refcnt)) > +               __skb_ext_free(ext); > +} > + > +static inline void skb_ext_put(struct sk_buff *skb) > +{ > +       if (skb->active_extensions) > +               __skb_ext_put(skb->extensions); > +} > + > +static inline void skb_ext_get(struct sk_buff *skb) > +{ > +       if (skb->active_extensions) { > +               struct skb_ext *ext = skb->extensions; > + > +               if (ext) > +                       refcount_inc(&ext->refcnt); > +       } > +} > + > +static inline void __skb_ext_copy(struct sk_buff *dst, > +                                 const struct sk_buff *src) > +{ > +       dst->active_extensions = src->active_extensions; > + > +       if (src->active_extensions) { > +               struct skb_ext *ext = src->extensions; > + > +               if (ext) > +                       refcount_inc(&ext->refcnt); > +               dst->extensions = ext; > +       } > +} > + > +static inline void skb_ext_copy(struct sk_buff *dst, const struct sk_buff *src) > +{ > +       skb_ext_put(dst); > +       __skb_ext_copy(dst, src); > +} > + > +static inline bool __skb_ext_exist(const struct skb_ext *ext, enum skb_ext_id i) > +{ > +       return !!ext->offset[i]; > +} > + > +static inline bool skb_ext_exist(const struct sk_buff *skb, enum skb_ext_id id) > +{ > +       return skb->active_extensions & (1 << id); > +} > + > +static inline void skb_ext_del(struct sk_buff *skb, enum skb_ext_id id) > +{ > +       if (skb_ext_exist(skb, id)) > +               __skb_ext_del(skb, id); > +} > + > +static inline void *skb_ext_find(const struct sk_buff *skb, enum skb_ext_id id) > +{ > +       if (skb_ext_exist(skb, id)) { > +               struct skb_ext *ext = skb->extensions; > + > +               if (ext && __skb_ext_exist(ext, id)) > +                       return (void *)ext + (ext->offset[id] << 3); > +       } > + > +       return NULL; > +} > +#else > +static inline void skb_ext_put(struct sk_buff *skb) {} > +static inline void skb_ext_get(struct sk_buff *skb) {} > +static inline void skb_ext_del(struct sk_buff *skb, int unused) {} > +static inline void __skb_ext_copy(struct sk_buff *d, const struct sk_buff *s) {} > +static inline void skb_ext_copy(struct sk_buff *dst, const struct sk_buff *s) {} For the !CONFIG_SKB_EXTENSIONS case, an alternate definition of skb_ext_exist() that always returns false would be useful to reduce the need for preprocessor conditionals. A similar skb_ext_find() that always returns NULL might also be helpful. > +#endif /* CONFIG_SKB_EXTENSIONS */ > + >  #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) >  static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) >  { Thanks,