[NFTA_RULE_HANDLE]      = { .type = NLA_U64 },
        [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
        [NFTA_RULE_COMPAT]      = { .type = NLA_NESTED },
+       [NFTA_RULE_POSITION]    = { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
        struct nfgenmsg *nfmsg;
        const struct nft_expr *expr, *next;
        struct nlattr *list;
+       const struct nft_rule *prule;
+       int type = event | NFNL_SUBSYS_NFTABLES << 8;
 
-       event |= NFNL_SUBSYS_NFTABLES << 8;
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
+       nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
                        flags);
        if (nlh == NULL)
                goto nla_put_failure;
        if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
                goto nla_put_failure;
 
+       if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
+               prule = list_entry(rule->list.prev, struct nft_rule, list);
+               if (nla_put_be64(skb, NFTA_RULE_POSITION,
+                                cpu_to_be64(prule->handle)))
+                       goto nla_put_failure;
+       }
+
        list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
        if (list == NULL)
                goto nla_put_failure;
        unsigned int size, i, n;
        int err, rem;
        bool create;
-       u64 handle;
+       u64 handle, pos_handle;
 
        create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
 
                handle = nf_tables_alloc_handle(table);
        }
 
+       if (nla[NFTA_RULE_POSITION]) {
+               if (!(nlh->nlmsg_flags & NLM_F_CREATE))
+                       return -EOPNOTSUPP;
+
+               pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
+               old_rule = __nf_tables_rule_lookup(chain, pos_handle);
+               if (IS_ERR(old_rule))
+                       return PTR_ERR(old_rule);
+       }
+
        nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
 
        n = 0;
                list_replace_rcu(&old_rule->list, &rule->list);
                nf_tables_rule_destroy(old_rule);
        } else if (nlh->nlmsg_flags & NLM_F_APPEND)
-               list_add_tail_rcu(&rule->list, &chain->rules);
-       else
-               list_add_rcu(&rule->list, &chain->rules);
+               if (old_rule)
+                       list_add_rcu(&rule->list, &old_rule->list);
+               else
+                       list_add_tail_rcu(&rule->list, &chain->rules);
+       else {
+               if (old_rule)
+                       list_add_tail_rcu(&rule->list, &old_rule->list);
+               else
+                       list_add_rcu(&rule->list, &chain->rules);
+       }
 
        nf_tables_rule_notify(skb, nlh, table, chain, rule, NFT_MSG_NEWRULE,
                              nlh->nlmsg_flags & (NLM_F_APPEND | NLM_F_REPLACE),