*     @cloned: Head may be cloned (check refcnt to be sure)
  *     @ip_summed: Driver fed us an IP checksum
  *     @nohdr: Payload reference only, must not modify header
- *     @nfctinfo: Relationship of this skb to the connection
  *     @pkt_type: Packet class
  *     @fclone: skbuff clone status
  *     @ipvs_property: skbuff is owned by ipvs
  *     @nf_trace: netfilter packet trace flag
  *     @protocol: Packet protocol from driver
  *     @destructor: Destruct function
- *     @nfct: Associated connection, if any
+ *     @_nfct: Associated connection, if any (with nfctinfo bits)
  *     @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
  *     @skb_iif: ifindex of device we arrived on
  *     @tc_index: Traffic control index
        struct  sec_path        *sp;
 #endif
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-       struct nf_conntrack     *nfct;
+       unsigned long            _nfct;
 #endif
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        struct nf_bridge_info   *nf_bridge;
        __u8                    pkt_type:3;
        __u8                    pfmemalloc:1;
        __u8                    ignore_df:1;
-       __u8                    nfctinfo:3;
 
        __u8                    nf_trace:1;
        __u8                    ip_summed:2;
 #define SKB_DST_NOREF  1UL
 #define SKB_DST_PTRMASK        ~(SKB_DST_NOREF)
 
+#define SKB_NFCT_PTRMASK       ~(7UL)
 /**
  * skb_dst - returns skb dst_entry
  * @skb: buffer
 static inline struct nf_conntrack *skb_nfct(const struct sk_buff *skb)
 {
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
-       return skb->nfct;
+       return (void *)(skb->_nfct & SKB_NFCT_PTRMASK);
 #else
        return NULL;
 #endif
 static inline void nf_reset(struct sk_buff *skb)
 {
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-       nf_conntrack_put(skb->nfct);
-       skb->nfct = NULL;
+       nf_conntrack_put(skb_nfct(skb));
+       skb->_nfct = 0;
 #endif
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        nf_bridge_put(skb->nf_bridge);
                             bool copy)
 {
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-       dst->nfct = src->nfct;
-       nf_conntrack_get(src->nfct);
-       if (copy)
-               dst->nfctinfo = src->nfctinfo;
+       dst->_nfct = src->_nfct;
+       nf_conntrack_get(skb_nfct(src));
 #endif
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        dst->nf_bridge  = src->nf_bridge;
 static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
 {
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
-       nf_conntrack_put(dst->nfct);
+       nf_conntrack_put(skb_nfct(dst));
 #endif
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        nf_bridge_put(dst->nf_bridge);
 
        /* Usage count in here is 1 for hash table, 1 per skb,
         * plus 1 for any connection(s) we are `master' for
         *
-        * Hint, SKB address this struct and refcnt via skb->nfct and
+        * Hint, SKB address this struct and refcnt via skb->_nfct and
         * helpers nf_conntrack_get() and nf_conntrack_put().
         * Helper nf_ct_put() equals nf_conntrack_put() by dec refcnt,
         * beware nf_ct_get() is different and don't inc refcnt.
                             const struct nf_conn *ignored_conntrack);
 
 #define NFCT_INFOMASK  7UL
+#define NFCT_PTRMASK   ~(NFCT_INFOMASK)
 
 /* Return conntrack_info and tuple hash for given skb. */
 static inline struct nf_conn *
 nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
 {
-       *ctinfo = skb->nfctinfo;
-       return (struct nf_conn *)skb->nfct;
+       *ctinfo = skb->_nfct & NFCT_INFOMASK;
+
+       return (struct nf_conn *)(skb->_nfct & NFCT_PTRMASK);
 }
 
 /* decrement reference count on a conntrack */
 static inline void
 nf_ct_set(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info info)
 {
-       skb->nfct = &ct->ct_general;
-       skb->nfctinfo = info;
+       skb->_nfct = (unsigned long)ct | info;
 }
 
 #define NF_CT_STAT_INC(net, count)       __this_cpu_inc((net)->ct.stat->count)
 
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
        nf_reset(skb);
        nf_ct_set(skb, nf_ct_untracked_get(), IP_CT_NEW);
-       nf_conntrack_get(skb->nfct);
+       nf_conntrack_get(skb_nfct(skb));
 #endif
        if (hooknum == NF_INET_PRE_ROUTING ||
            hooknum == NF_INET_LOCAL_IN) {
 
 {
        void (*attach)(struct sk_buff *, const struct sk_buff *);
 
-       if (skb->nfct) {
+       if (skb->_nfct) {
                rcu_read_lock();
                attach = rcu_dereference(ip_ct_attach);
                if (attach)
 
        return &ct->tuplehash[IP_CT_DIR_ORIGINAL];
 }
 
-/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
+/* On success, returns conntrack ptr, sets skb->_nfct | ctinfo */
 static inline struct nf_conn *
 resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
                  struct sk_buff *skb,
                        NF_CT_STAT_INC_ATOMIC(net, ignore);
                        return NF_ACCEPT;
                }
-               skb->nfct = NULL;
+               skb->_nfct = 0;
        }
 
        /* rcu_read_lock()ed by nf_hook_thresh */
                        goto out;
                }
                /* ICMP[v6] protocol trackers may assign one conntrack. */
-               if (skb->nfct)
+               if (skb->_nfct)
                        goto out;
        }
 repeat:
                 * the netfilter core what to do */
                pr_debug("nf_conntrack_in: Can't track with proto module\n");
                nf_conntrack_put(&ct->ct_general);
-               skb->nfct = NULL;
+               skb->_nfct = 0;
                NF_CT_STAT_INC_ATOMIC(net, invalid);
                if (ret == -NF_DROP)
                        NF_CT_STAT_INC_ATOMIC(net, drop);
        nf_conntrack_max = max_factor * nf_conntrack_htable_size;
 
        nf_conntrack_cachep = kmem_cache_create("nf_conntrack",
-                                               sizeof(struct nf_conn), 0,
+                                               sizeof(struct nf_conn),
+                                               NFCT_INFOMASK + 1,
                                                SLAB_DESTROY_BY_RCU | SLAB_HWCACHE_ALIGN, NULL);
        if (!nf_conntrack_cachep)
                goto err_cachep;
 
        if (ret < 0)
                goto out_start;
 
+       BUILD_BUG_ON(SKB_NFCT_PTRMASK != NFCT_PTRMASK);
+       BUILD_BUG_ON(NFCT_INFOMASK <= IP_CT_NUMBER);
+
 #ifdef CONFIG_SYSCTL
        nf_ct_netfilter_header =
                register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
 
 static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
 {
        /* Previously seen (loopback)? Ignore. */
-       if (skb->nfct != NULL)
+       if (skb->_nfct != 0)
                return XT_CONTINUE;
 
        /* special case the untracked ct : we want the percpu object */
 notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        /* Previously seen (loopback)? Ignore. */
-       if (skb->nfct != NULL)
+       if (skb->_nfct != 0)
                return XT_CONTINUE;
 
        nf_ct_set(skb, nf_ct_untracked_get(), IP_CT_NEW);