Merge tag 'for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
[linux-block.git] / net / netfilter / nf_tables_core.c
index 2d298dccb6dd3fc5589be16021c843d741a4c025..f153b07073afba0f544889eb01312a57414f74a6 100644 (file)
@@ -8,6 +8,7 @@
  * Development of this code funded by Astaro AG (http://www.astaro.com/)
  */
 
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <net/netfilter/nf_tables.h>
 #include <net/netfilter/nf_log.h>
 
+enum nft_trace {
+       NFT_TRACE_RULE,
+       NFT_TRACE_RETURN,
+       NFT_TRACE_POLICY,
+};
+
+static const char *const comments[] = {
+       [NFT_TRACE_RULE]        = "rule",
+       [NFT_TRACE_RETURN]      = "return",
+       [NFT_TRACE_POLICY]      = "policy",
+};
+
+static struct nf_loginfo trace_loginfo = {
+       .type = NF_LOG_TYPE_LOG,
+       .u = {
+               .log = {
+                       .level = LOGLEVEL_WARNING,
+                       .logflags = NF_LOG_MASK,
+               },
+       },
+};
+
+static void __nft_trace_packet(const struct nft_pktinfo *pkt,
+                              const struct nft_chain *chain,
+                              int rulenum, enum nft_trace type)
+{
+       struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
+
+       nf_log_trace(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
+                    pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
+                    chain->table->name, chain->name, comments[type],
+                    rulenum);
+}
+
+static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
+                                   const struct nft_chain *chain,
+                                   int rulenum, enum nft_trace type)
+{
+       if (unlikely(pkt->skb->nf_trace))
+               __nft_trace_packet(pkt, chain, rulenum, type);
+}
+
 static void nft_cmp_fast_eval(const struct nft_expr *expr,
-                             struct nft_data data[NFT_REG_MAX + 1])
+                             struct nft_regs *regs)
 {
        const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
        u32 mask = nft_cmp_fast_mask(priv->len);
 
-       if ((data[priv->sreg].data[0] & mask) == priv->data)
+       if ((regs->data[priv->sreg] & mask) == priv->data)
                return;
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 
 static bool nft_payload_fast_eval(const struct nft_expr *expr,
-                                 struct nft_data data[NFT_REG_MAX + 1],
+                                 struct nft_regs *regs,
                                  const struct nft_pktinfo *pkt)
 {
        const struct nft_payload *priv = nft_expr_priv(expr);
        const struct sk_buff *skb = pkt->skb;
-       struct nft_data *dest = &data[priv->dreg];
+       u32 *dest = &regs->data[priv->dreg];
        unsigned char *ptr;
 
        if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
@@ -51,12 +94,13 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
        if (unlikely(ptr + priv->len >= skb_tail_pointer(skb)))
                return false;
 
+       *dest = 0;
        if (priv->len == 2)
-               *(u16 *)dest->data = *(u16 *)ptr;
+               *(u16 *)dest = *(u16 *)ptr;
        else if (priv->len == 4)
-               *(u32 *)dest->data = *(u32 *)ptr;
+               *(u32 *)dest = *(u32 *)ptr;
        else
-               *(u8 *)dest->data = *(u8 *)ptr;
+               *(u8 *)dest = *(u8 *)ptr;
        return true;
 }
 
@@ -66,62 +110,25 @@ struct nft_jumpstack {
        int                     rulenum;
 };
 
-enum nft_trace {
-       NFT_TRACE_RULE,
-       NFT_TRACE_RETURN,
-       NFT_TRACE_POLICY,
-};
-
-static const char *const comments[] = {
-       [NFT_TRACE_RULE]        = "rule",
-       [NFT_TRACE_RETURN]      = "return",
-       [NFT_TRACE_POLICY]      = "policy",
-};
-
-static struct nf_loginfo trace_loginfo = {
-       .type = NF_LOG_TYPE_LOG,
-       .u = {
-               .log = {
-                       .level = 4,
-                       .logflags = NF_LOG_MASK,
-               },
-       },
-};
-
-static void nft_trace_packet(const struct nft_pktinfo *pkt,
-                            const struct nft_chain *chain,
-                            int rulenum, enum nft_trace type)
-{
-       struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
-
-       nf_log_trace(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
-                    pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
-                    chain->table->name, chain->name, comments[type],
-                    rulenum);
-}
-
 unsigned int
 nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
 {
        const struct nft_chain *chain = ops->priv, *basechain = chain;
+       const struct net *net = read_pnet(&nft_base_chain(basechain)->pnet);
        const struct nft_rule *rule;
        const struct nft_expr *expr, *last;
-       struct nft_data data[NFT_REG_MAX + 1];
+       struct nft_regs regs;
        unsigned int stackptr = 0;
        struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
        struct nft_stats *stats;
        int rulenum;
-       /*
-        * Cache cursor to avoid problems in case that the cursor is updated
-        * while traversing the ruleset.
-        */
-       unsigned int gencursor = ACCESS_ONCE(chain->net->nft.gencursor);
+       unsigned int gencursor = nft_genmask_cur(net);
 
 do_chain:
        rulenum = 0;
        rule = list_entry(&chain->rules, struct nft_rule, list);
 next_rule:
-       data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
+       regs.verdict.code = NFT_CONTINUE;
        list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
 
                /* This rule is not active, skip. */
@@ -132,62 +139,52 @@ next_rule:
 
                nft_rule_for_each_expr(expr, last, rule) {
                        if (expr->ops == &nft_cmp_fast_ops)
-                               nft_cmp_fast_eval(expr, data);
+                               nft_cmp_fast_eval(expr, &regs);
                        else if (expr->ops != &nft_payload_fast_ops ||
-                                !nft_payload_fast_eval(expr, data, pkt))
-                               expr->ops->eval(expr, data, pkt);
+                                !nft_payload_fast_eval(expr, &regs, pkt))
+                               expr->ops->eval(expr, &regs, pkt);
 
-                       if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)
+                       if (regs.verdict.code != NFT_CONTINUE)
                                break;
                }
 
-               switch (data[NFT_REG_VERDICT].verdict) {
+               switch (regs.verdict.code) {
                case NFT_BREAK:
-                       data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
+                       regs.verdict.code = NFT_CONTINUE;
                        continue;
                case NFT_CONTINUE:
-                       if (unlikely(pkt->skb->nf_trace))
-                               nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
+                       nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
                        continue;
                }
                break;
        }
 
-       switch (data[NFT_REG_VERDICT].verdict & NF_VERDICT_MASK) {
+       switch (regs.verdict.code & NF_VERDICT_MASK) {
        case NF_ACCEPT:
        case NF_DROP:
        case NF_QUEUE:
-               if (unlikely(pkt->skb->nf_trace))
-                       nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
-
-               return data[NFT_REG_VERDICT].verdict;
+               nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
+               return regs.verdict.code;
        }
 
-       switch (data[NFT_REG_VERDICT].verdict) {
+       switch (regs.verdict.code) {
        case NFT_JUMP:
-               if (unlikely(pkt->skb->nf_trace))
-                       nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
-
                BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
                jumpstack[stackptr].chain = chain;
                jumpstack[stackptr].rule  = rule;
                jumpstack[stackptr].rulenum = rulenum;
                stackptr++;
-               chain = data[NFT_REG_VERDICT].chain;
-               goto do_chain;
+               /* fall through */
        case NFT_GOTO:
-               if (unlikely(pkt->skb->nf_trace))
-                       nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
+               nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
 
-               chain = data[NFT_REG_VERDICT].chain;
+               chain = regs.verdict.chain;
                goto do_chain;
-       case NFT_RETURN:
-               if (unlikely(pkt->skb->nf_trace))
-                       nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
-               break;
        case NFT_CONTINUE:
-               if (unlikely(pkt->skb->nf_trace && !(chain->flags & NFT_BASE_CHAIN)))
-                       nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);
+               rulenum++;
+               /* fall through */
+       case NFT_RETURN:
+               nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
                break;
        default:
                WARN_ON(1);
@@ -201,8 +198,7 @@ next_rule:
                goto next_rule;
        }
 
-       if (unlikely(pkt->skb->nf_trace))
-               nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY);
+       nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY);
 
        rcu_read_lock_bh();
        stats = this_cpu_ptr(rcu_dereference(nft_base_chain(basechain)->stats));
@@ -244,8 +240,14 @@ int __init nf_tables_core_module_init(void)
        if (err < 0)
                goto err6;
 
+       err = nft_dynset_module_init();
+       if (err < 0)
+               goto err7;
+
        return 0;
 
+err7:
+       nft_payload_module_exit();
 err6:
        nft_byteorder_module_exit();
 err5:
@@ -262,6 +264,7 @@ err1:
 
 void nf_tables_core_module_exit(void)
 {
+       nft_dynset_module_exit();
        nft_payload_module_exit();
        nft_byteorder_module_exit();
        nft_bitwise_module_exit();