]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
fib: Support existence check
authorPhil Sutter <phil@nwl.cc>
Sat, 11 Mar 2017 13:31:39 +0000 (14:31 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 13 Mar 2017 11:13:43 +0000 (12:13 +0100)
This allows to check whether a FIB entry exists for a given packet by
comparing the expression with a boolean keyword like so:

| fib daddr oif exists

The implementation requires introduction of a generic expression flag
EXPR_F_BOOLEAN which allows relational expression to signal it's LHS
that a boolean comparison is being done (indicated by boolean type on
RHS). In contrast to exthdr existence checks, fib expression can't know
this in beforehand because the LHS syntax is absolutely identical to a
non-boolean comparison.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/expression.h
include/linux/netfilter/nf_tables.h
src/evaluate.c
src/expression.c
src/fib.c
tests/py/inet/fib.t
tests/py/inet/fib.t.payload

index 423eae7128f5c82ee30e63338bc6ebfef50467bd..94573de087ad7ad3a5f0907a04ffddb4c6eb9ce7 100644 (file)
@@ -171,12 +171,14 @@ struct expr_ops {
  * @EXPR_F_SINGLETON:          singleton (implies primary and constant)
  * @EXPR_F_PROTOCOL:           expressions describes upper layer protocol
  * @EXPR_F_INTERVAL_END:       set member ends an open interval
+ * @EXPR_F_BOOLEAN:            expression is boolean (set by relational expr on LHS)
  */
 enum expr_flags {
        EXPR_F_CONSTANT         = 0x1,
        EXPR_F_SINGLETON        = 0x2,
        EXPR_F_PROTOCOL         = 0x4,
        EXPR_F_INTERVAL_END     = 0x8,
+       EXPR_F_BOOLEAN          = 0x10,
 };
 
 #include <payload.h>
index 4f7d75682c5917cf9b26e70d9ac09b2e02d8ed7c..a9280a6541ac6104586e4c86c90466a087b13db6 100644 (file)
@@ -1257,6 +1257,7 @@ enum nft_fib_flags {
        NFTA_FIB_F_MARK         = 1 << 2,       /* use skb->mark */
        NFTA_FIB_F_IIF          = 1 << 3,       /* restrict to iif */
        NFTA_FIB_F_OIF          = 1 << 4,       /* restrict to oif */
+       NFTA_FIB_F_PRESENT      = 1 << 5,       /* check existence only */
 };
 
 #define NFT_OBJECT_UNSPEC      0
index 7c039cbab5ec37832ee63d542ade6ee2b2f19168..7ddbb658f96fa72c21a8479172a6487e1f98dd00 100644 (file)
@@ -1658,6 +1658,17 @@ range:
        return 0;
 }
 
+static int expr_evaluate_fib(struct eval_ctx *ctx, struct expr **exprp)
+{
+       struct expr *expr = *exprp;
+
+       if (expr->flags & EXPR_F_BOOLEAN) {
+               expr->fib.flags |= NFTA_FIB_F_PRESENT;
+               expr->dtype = &boolean_type;
+       }
+       return expr_evaluate_primary(ctx, exprp);
+}
+
 static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
 {
 #ifdef DEBUG
@@ -1680,8 +1691,9 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
                return expr_evaluate_exthdr(ctx, expr);
        case EXPR_VERDICT:
        case EXPR_META:
-       case EXPR_FIB:
                return expr_evaluate_primary(ctx, expr);
+       case EXPR_FIB:
+               return expr_evaluate_fib(ctx, expr);
        case EXPR_PAYLOAD:
                return expr_evaluate_payload(ctx, expr);
        case EXPR_RT:
index da94b79f1d913bb9b84ee039bcb6fd57e04d1a54..a6065524f8be8afd9f4ee7ff10b13e454ff35164 100644 (file)
@@ -592,6 +592,10 @@ struct expr *relational_expr_alloc(const struct location *loc, enum ops op,
        expr->left  = left;
        expr->op    = op;
        expr->right = right;
+
+       if (right->dtype == &boolean_type)
+               left->flags |= EXPR_F_BOOLEAN;
+
        return expr;
 }
 
index c65677c811abce374cb8176e9b9ef71f8ef2b8c2..28ef4b50b3ea3f748e169da62d24462ee88d3253 100644 (file)
--- a/src/fib.c
+++ b/src/fib.c
@@ -73,7 +73,7 @@ static void __fib_expr_print_f(unsigned int *flags, unsigned int f, const char *
 
 static void fib_expr_print(const struct expr *expr)
 {
-       unsigned int flags = expr->fib.flags;
+       unsigned int flags = expr->fib.flags & ~NFTA_FIB_F_PRESENT;
 
        printf("fib ");
        __fib_expr_print_f(&flags, NFTA_FIB_F_SADDR, "saddr");
@@ -130,6 +130,9 @@ struct expr *fib_expr_alloc(const struct location *loc,
                BUG("Unknown result %d\n", result);
        }
 
+       if (flags & NFTA_FIB_F_PRESENT)
+               type = &boolean_type;
+
        expr = expr_alloc(loc, &fib_expr_ops, type,
                          BYTEORDER_HOST_ENDIAN, len);
 
index 9ee282ab1c93d65ba5623c6f992777d56d9d8a1d..dbe45d95b4cfe057f3b9c9a5b150d30bfcddd8ef 100644 (file)
@@ -12,3 +12,6 @@ fib saddr . iif oifname "lo";ok
 fib daddr . iif type local;ok
 fib daddr . iif type vmap { blackhole : drop, prohibit : drop, unicast : accept };ok
 fib daddr . oif type local;fail
+
+fib daddr oif exists;ok
+fib daddr oif missing;ok
index f5258165384dccf029f52316317567382e62c6b5..1d4c3d94aa0bf25af9f401865654b2d5256abb68 100644 (file)
@@ -20,3 +20,13 @@ __map%d test-ip 0
 ip test-ip prerouting
   [ fib daddr . iif type => reg 1 ]
   [ lookup reg 1 set __map%d dreg 0 ]
+
+# fib daddr oif exists
+ip test-ip prerouting
+  [ fib daddr oif present => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# fib daddr oif missing
+ip test-ip prerouting
+  [ fib daddr oif present => reg 1 ]
+  [ cmp eq reg 1 0x00000000 ]