Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-2.6-microblaze.git] / net / netfilter / nf_tables_core.c
index 866cfba..36e73f9 100644 (file)
@@ -38,7 +38,7 @@ static noinline void __nft_trace_packet(struct nft_traceinfo *info,
 
 static inline void nft_trace_packet(struct nft_traceinfo *info,
                                    const struct nft_chain *chain,
-                                   const struct nft_rule *rule,
+                                   const struct nft_rule_dp *rule,
                                    enum nft_trace_types type)
 {
        if (static_branch_unlikely(&nft_trace_enabled)) {
@@ -67,6 +67,36 @@ static void nft_cmp_fast_eval(const struct nft_expr *expr,
        regs->verdict.code = NFT_BREAK;
 }
 
+static noinline void __nft_trace_verdict(struct nft_traceinfo *info,
+                                        const struct nft_chain *chain,
+                                        const struct nft_regs *regs)
+{
+       enum nft_trace_types type;
+
+       switch (regs->verdict.code) {
+       case NFT_CONTINUE:
+       case NFT_RETURN:
+               type = NFT_TRACETYPE_RETURN;
+               break;
+       default:
+               type = NFT_TRACETYPE_RULE;
+               break;
+       }
+
+       __nft_trace_packet(info, chain, type);
+}
+
+static inline void nft_trace_verdict(struct nft_traceinfo *info,
+                                    const struct nft_chain *chain,
+                                    const struct nft_rule_dp *rule,
+                                    const struct nft_regs *regs)
+{
+       if (static_branch_unlikely(&nft_trace_enabled)) {
+               info->rule = rule;
+               __nft_trace_verdict(info, chain, regs);
+       }
+}
+
 static bool nft_payload_fast_eval(const struct nft_expr *expr,
                                  struct nft_regs *regs,
                                  const struct nft_pktinfo *pkt)
@@ -79,7 +109,7 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
        if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
                ptr = skb_network_header(skb);
        else {
-               if (!pkt->tprot_set)
+               if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
                        return false;
                ptr = skb_network_header(skb) + nft_thoff(pkt);
        }
@@ -110,7 +140,6 @@ static noinline void nft_update_chain_stats(const struct nft_chain *chain,
 
        base_chain = nft_base_chain(chain);
 
-       rcu_read_lock();
        pstats = READ_ONCE(base_chain->stats);
        if (pstats) {
                local_bh_disable();
@@ -121,12 +150,12 @@ static noinline void nft_update_chain_stats(const struct nft_chain *chain,
                u64_stats_update_end(&stats->syncp);
                local_bh_enable();
        }
-       rcu_read_unlock();
 }
 
 struct nft_jumpstack {
-       const struct nft_chain  *chain;
-       struct nft_rule *const *rules;
+       const struct nft_chain *chain;
+       const struct nft_rule_dp *rule;
+       const struct nft_rule_dp *last_rule;
 };
 
 static void expr_call_ops_eval(const struct nft_expr *expr,
@@ -141,6 +170,7 @@ static void expr_call_ops_eval(const struct nft_expr *expr,
 
        X(e, nft_payload_eval);
        X(e, nft_cmp_eval);
+       X(e, nft_counter_eval);
        X(e, nft_meta_get_eval);
        X(e, nft_lookup_eval);
        X(e, nft_range_eval);
@@ -154,18 +184,28 @@ static void expr_call_ops_eval(const struct nft_expr *expr,
        expr->ops->eval(expr, regs, pkt);
 }
 
+#define nft_rule_expr_first(rule)      (struct nft_expr *)&rule->data[0]
+#define nft_rule_expr_next(expr)       ((void *)expr) + expr->ops->size
+#define nft_rule_expr_last(rule)       (struct nft_expr *)&rule->data[rule->dlen]
+#define nft_rule_next(rule)            (void *)rule + sizeof(*rule) + rule->dlen
+
+#define nft_rule_dp_for_each_expr(expr, last, rule) \
+        for ((expr) = nft_rule_expr_first(rule), (last) = nft_rule_expr_last(rule); \
+             (expr) != (last); \
+             (expr) = nft_rule_expr_next(expr))
+
 unsigned int
 nft_do_chain(struct nft_pktinfo *pkt, void *priv)
 {
        const struct nft_chain *chain = priv, *basechain = chain;
+       const struct nft_rule_dp *rule, *last_rule;
        const struct net *net = nft_net(pkt);
-       struct nft_rule *const *rules;
-       const struct nft_rule *rule;
        const struct nft_expr *expr, *last;
        struct nft_regs regs;
        unsigned int stackptr = 0;
        struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
        bool genbit = READ_ONCE(net->nft.gencursor);
+       struct nft_rule_blob *blob;
        struct nft_traceinfo info;
 
        info.trace = false;
@@ -173,16 +213,16 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv)
                nft_trace_init(&info, pkt, &regs.verdict, basechain);
 do_chain:
        if (genbit)
-               rules = rcu_dereference(chain->rules_gen_1);
+               blob = rcu_dereference(chain->blob_gen_1);
        else
-               rules = rcu_dereference(chain->rules_gen_0);
+               blob = rcu_dereference(chain->blob_gen_0);
 
+       rule = (struct nft_rule_dp *)blob->data;
+       last_rule = (void *)blob->data + blob->size;
 next_rule:
-       rule = *rules;
        regs.verdict.code = NFT_CONTINUE;
-       for (; *rules ; rules++) {
-               rule = *rules;
-               nft_rule_for_each_expr(expr, last, rule) {
+       for (; rule < last_rule; rule = nft_rule_next(rule)) {
+               nft_rule_dp_for_each_expr(expr, last, rule) {
                        if (expr->ops == &nft_cmp_fast_ops)
                                nft_cmp_fast_eval(expr, &regs);
                        else if (expr->ops == &nft_bitwise_fast_ops)
@@ -207,13 +247,13 @@ next_rule:
                break;
        }
 
+       nft_trace_verdict(&info, chain, rule, &regs);
+
        switch (regs.verdict.code & NF_VERDICT_MASK) {
        case NF_ACCEPT:
        case NF_DROP:
        case NF_QUEUE:
        case NF_STOLEN:
-               nft_trace_packet(&info, chain, rule,
-                                NFT_TRACETYPE_RULE);
                return regs.verdict.code;
        }
 
@@ -222,28 +262,25 @@ next_rule:
                if (WARN_ON_ONCE(stackptr >= NFT_JUMP_STACK_SIZE))
                        return NF_DROP;
                jumpstack[stackptr].chain = chain;
-               jumpstack[stackptr].rules = rules + 1;
+               jumpstack[stackptr].rule = nft_rule_next(rule);
+               jumpstack[stackptr].last_rule = last_rule;
                stackptr++;
                fallthrough;
        case NFT_GOTO:
-               nft_trace_packet(&info, chain, rule,
-                                NFT_TRACETYPE_RULE);
-
                chain = regs.verdict.chain;
                goto do_chain;
        case NFT_CONTINUE:
        case NFT_RETURN:
-               nft_trace_packet(&info, chain, rule,
-                                NFT_TRACETYPE_RETURN);
                break;
        default:
-               WARN_ON(1);
+               WARN_ON_ONCE(1);
        }
 
        if (stackptr > 0) {
                stackptr--;
                chain = jumpstack[stackptr].chain;
-               rules = jumpstack[stackptr].rules;
+               rule = jumpstack[stackptr].rule;
+               last_rule = jumpstack[stackptr].last_rule;
                goto next_rule;
        }
 
@@ -269,18 +306,22 @@ static struct nft_expr_type *nft_basic_types[] = {
        &nft_rt_type,
        &nft_exthdr_type,
        &nft_last_type,
+       &nft_counter_type,
 };
 
 static struct nft_object_type *nft_basic_objects[] = {
 #ifdef CONFIG_NETWORK_SECMARK
        &nft_secmark_obj_type,
 #endif
+       &nft_counter_obj_type,
 };
 
 int __init nf_tables_core_module_init(void)
 {
        int err, i, j = 0;
 
+       nft_counter_init_seqcount();
+
        for (i = 0; i < ARRAY_SIZE(nft_basic_objects); i++) {
                err = nft_register_obj(nft_basic_objects[i]);
                if (err)