netfilter: bridge: introduce broute meta statement
authorSriram Yagnaraman <sriram.yagnaraman@est.tech>
Fri, 24 Feb 2023 09:52:51 +0000 (10:52 +0100)
committerFlorian Westphal <fw@strlen.de>
Wed, 8 Mar 2023 13:21:18 +0000 (14:21 +0100)
nftables equivalent for ebtables -t broute.

Implement broute meta statement to set br_netfilter_broute flag
in skb to force a packet to be routed instead of being bridged.

Signed-off-by: Sriram Yagnaraman <sriram.yagnaraman@est.tech>
Signed-off-by: Florian Westphal <fw@strlen.de>
include/uapi/linux/netfilter/nf_tables.h
net/bridge/netfilter/nft_meta_bridge.c

index ff677f3..9c6f02c 100644 (file)
@@ -931,6 +931,7 @@ enum nft_exthdr_attributes {
  * @NFT_META_TIME_HOUR: hour of day (in seconds)
  * @NFT_META_SDIF: slave device interface index
  * @NFT_META_SDIFNAME: slave device interface name
+ * @NFT_META_BRI_BROUTE: packet br_netfilter_broute bit
  */
 enum nft_meta_keys {
        NFT_META_LEN,
@@ -969,6 +970,7 @@ enum nft_meta_keys {
        NFT_META_TIME_HOUR,
        NFT_META_SDIF,
        NFT_META_SDIFNAME,
+       NFT_META_BRI_BROUTE,
        __NFT_META_IIFTYPE,
 };
 
index c3ecd77..bd4d1b4 100644 (file)
@@ -8,6 +8,9 @@
 #include <net/netfilter/nf_tables.h>
 #include <net/netfilter/nft_meta.h>
 #include <linux/if_bridge.h>
+#include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
+
+#include "../br_private.h"
 
 static const struct net_device *
 nft_meta_get_bridge(const struct net_device *dev)
@@ -102,6 +105,50 @@ static const struct nft_expr_ops nft_meta_bridge_get_ops = {
        .reduce         = nft_meta_get_reduce,
 };
 
+static void nft_meta_bridge_set_eval(const struct nft_expr *expr,
+                                    struct nft_regs *regs,
+                                    const struct nft_pktinfo *pkt)
+{
+       const struct nft_meta *meta = nft_expr_priv(expr);
+       u32 *sreg = &regs->data[meta->sreg];
+       struct sk_buff *skb = pkt->skb;
+       u8 value8;
+
+       switch (meta->key) {
+       case NFT_META_BRI_BROUTE:
+               value8 = nft_reg_load8(sreg);
+               BR_INPUT_SKB_CB(skb)->br_netfilter_broute = !!value8;
+               break;
+       default:
+               nft_meta_set_eval(expr, regs, pkt);
+       }
+}
+
+static int nft_meta_bridge_set_init(const struct nft_ctx *ctx,
+                                   const struct nft_expr *expr,
+                                   const struct nlattr * const tb[])
+{
+       struct nft_meta *priv = nft_expr_priv(expr);
+       unsigned int len;
+       int err;
+
+       priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
+       switch (priv->key) {
+       case NFT_META_BRI_BROUTE:
+               len = sizeof(u8);
+               break;
+       default:
+               return nft_meta_set_init(ctx, expr, tb);
+       }
+
+       priv->len = len;
+       err = nft_parse_register_load(tb[NFTA_META_SREG], &priv->sreg, len);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
 static bool nft_meta_bridge_set_reduce(struct nft_regs_track *track,
                                       const struct nft_expr *expr)
 {
@@ -120,15 +167,33 @@ static bool nft_meta_bridge_set_reduce(struct nft_regs_track *track,
        return false;
 }
 
+static int nft_meta_bridge_set_validate(const struct nft_ctx *ctx,
+                                       const struct nft_expr *expr,
+                                       const struct nft_data **data)
+{
+       struct nft_meta *priv = nft_expr_priv(expr);
+       unsigned int hooks;
+
+       switch (priv->key) {
+       case NFT_META_BRI_BROUTE:
+               hooks = 1 << NF_BR_PRE_ROUTING;
+               break;
+       default:
+               return nft_meta_set_validate(ctx, expr, data);
+       }
+
+       return nft_chain_validate_hooks(ctx->chain, hooks);
+}
+
 static const struct nft_expr_ops nft_meta_bridge_set_ops = {
        .type           = &nft_meta_bridge_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
-       .eval           = nft_meta_set_eval,
-       .init           = nft_meta_set_init,
+       .eval           = nft_meta_bridge_set_eval,
+       .init           = nft_meta_bridge_set_init,
        .destroy        = nft_meta_set_destroy,
        .dump           = nft_meta_set_dump,
        .reduce         = nft_meta_bridge_set_reduce,
-       .validate       = nft_meta_set_validate,
+       .validate       = nft_meta_bridge_set_validate,
 };
 
 static const struct nft_expr_ops *