*     @handle: rule handle
  *     @genmask: generation mask
  *     @dlen: length of expression data
+ *     @ulen: length of user data (used for comments)
  *     @data: expression data
  */
 struct nft_rule {
        struct list_head                list;
-       u64                             handle:46,
+       u64                             handle:42,
                                        genmask:2,
-                                       dlen:16;
+                                       dlen:12,
+                                       ulen:8;
        unsigned char                   data[]
                __attribute__((aligned(__alignof__(struct nft_expr))));
 };
        return (struct nft_expr *)&rule->data[rule->dlen];
 }
 
+static inline void *nft_userdata(const struct nft_rule *rule)
+{
+       return (void *)&rule->data[rule->dlen];
+}
+
 /*
  * The last pointer isn't really necessary, but the compiler isn't able to
  * determine that the result of nft_expr_last() is always the same since it
 
 #ifndef _LINUX_NF_TABLES_H
 #define _LINUX_NF_TABLES_H
 
-#define NFT_CHAIN_MAXNAMELEN 32
+#define NFT_CHAIN_MAXNAMELEN   32
+#define NFT_USERDATA_MAXLEN    256
 
 enum nft_registers {
        NFT_REG_VERDICT,
  * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
  * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes)
  * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
+ * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
  */
 enum nft_rule_attributes {
        NFTA_RULE_UNSPEC,
        NFTA_RULE_EXPRESSIONS,
        NFTA_RULE_COMPAT,
        NFTA_RULE_POSITION,
+       NFTA_RULE_USERDATA,
        __NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX          (__NFTA_RULE_MAX - 1)
 
        [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
        [NFTA_RULE_COMPAT]      = { .type = NLA_NESTED },
        [NFTA_RULE_POSITION]    = { .type = NLA_U64 },
+       [NFTA_RULE_USERDATA]    = { .type = NLA_BINARY,
+                                   .len = NFT_USERDATA_MAXLEN },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
        }
        nla_nest_end(skb, list);
 
+       if (rule->ulen &&
+           nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule)))
+               goto nla_put_failure;
+
        return nlmsg_end(skb, nlh);
 
 nla_put_failure:
        struct nft_expr *expr;
        struct nft_ctx ctx;
        struct nlattr *tmp;
-       unsigned int size, i, n;
+       unsigned int size, i, n, ulen = 0;
        int err, rem;
        bool create;
        u64 handle, pos_handle;
                }
        }
 
+       if (nla[NFTA_RULE_USERDATA])
+               ulen = nla_len(nla[NFTA_RULE_USERDATA]);
+
        err = -ENOMEM;
-       rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
+       rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL);
        if (rule == NULL)
                goto err1;
 
 
        rule->handle = handle;
        rule->dlen   = size;
+       rule->ulen   = ulen;
+
+       if (ulen)
+               nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen);
 
        expr = nft_expr_first(rule);
        for (i = 0; i < n; i++) {