linux/net/bridge/netfilter/nft_meta_bridge.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/kernel.h>
   3#include <linux/init.h>
   4#include <linux/module.h>
   5#include <linux/netlink.h>
   6#include <linux/netfilter.h>
   7#include <linux/netfilter/nf_tables.h>
   8#include <net/netfilter/nf_tables.h>
   9#include <net/netfilter/nft_meta.h>
  10#include <linux/if_bridge.h>
  11
  12static const struct net_device *
  13nft_meta_get_bridge(const struct net_device *dev)
  14{
  15        if (dev && netif_is_bridge_port(dev))
  16                return netdev_master_upper_dev_get_rcu((struct net_device *)dev);
  17
  18        return NULL;
  19}
  20
  21static void nft_meta_bridge_get_eval(const struct nft_expr *expr,
  22                                     struct nft_regs *regs,
  23                                     const struct nft_pktinfo *pkt)
  24{
  25        const struct nft_meta *priv = nft_expr_priv(expr);
  26        const struct net_device *in = nft_in(pkt), *out = nft_out(pkt);
  27        u32 *dest = &regs->data[priv->dreg];
  28        const struct net_device *br_dev;
  29
  30        switch (priv->key) {
  31        case NFT_META_BRI_IIFNAME:
  32                br_dev = nft_meta_get_bridge(in);
  33                break;
  34        case NFT_META_BRI_OIFNAME:
  35                br_dev = nft_meta_get_bridge(out);
  36                break;
  37        case NFT_META_BRI_IIFPVID: {
  38                u16 p_pvid;
  39
  40                br_dev = nft_meta_get_bridge(in);
  41                if (!br_dev || !br_vlan_enabled(br_dev))
  42                        goto err;
  43
  44                br_vlan_get_pvid_rcu(in, &p_pvid);
  45                nft_reg_store16(dest, p_pvid);
  46                return;
  47        }
  48        case NFT_META_BRI_IIFVPROTO: {
  49                u16 p_proto;
  50
  51                br_dev = nft_meta_get_bridge(in);
  52                if (!br_dev || !br_vlan_enabled(br_dev))
  53                        goto err;
  54
  55                br_vlan_get_proto(br_dev, &p_proto);
  56                nft_reg_store16(dest, htons(p_proto));
  57                return;
  58        }
  59        default:
  60                return nft_meta_get_eval(expr, regs, pkt);
  61        }
  62
  63        strncpy((char *)dest, br_dev ? br_dev->name : "", IFNAMSIZ);
  64        return;
  65err:
  66        regs->verdict.code = NFT_BREAK;
  67}
  68
  69static int nft_meta_bridge_get_init(const struct nft_ctx *ctx,
  70                                    const struct nft_expr *expr,
  71                                    const struct nlattr * const tb[])
  72{
  73        struct nft_meta *priv = nft_expr_priv(expr);
  74        unsigned int len;
  75
  76        priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
  77        switch (priv->key) {
  78        case NFT_META_BRI_IIFNAME:
  79        case NFT_META_BRI_OIFNAME:
  80                len = IFNAMSIZ;
  81                break;
  82        case NFT_META_BRI_IIFPVID:
  83        case NFT_META_BRI_IIFVPROTO:
  84                len = sizeof(u16);
  85                break;
  86        default:
  87                return nft_meta_get_init(ctx, expr, tb);
  88        }
  89
  90        priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
  91        return nft_validate_register_store(ctx, priv->dreg, NULL,
  92                                           NFT_DATA_VALUE, len);
  93}
  94
  95static struct nft_expr_type nft_meta_bridge_type;
  96static const struct nft_expr_ops nft_meta_bridge_get_ops = {
  97        .type           = &nft_meta_bridge_type,
  98        .size           = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
  99        .eval           = nft_meta_bridge_get_eval,
 100        .init           = nft_meta_bridge_get_init,
 101        .dump           = nft_meta_get_dump,
 102};
 103
 104static const struct nft_expr_ops nft_meta_bridge_set_ops = {
 105        .type           = &nft_meta_bridge_type,
 106        .size           = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
 107        .eval           = nft_meta_set_eval,
 108        .init           = nft_meta_set_init,
 109        .destroy        = nft_meta_set_destroy,
 110        .dump           = nft_meta_set_dump,
 111        .validate       = nft_meta_set_validate,
 112};
 113
 114static const struct nft_expr_ops *
 115nft_meta_bridge_select_ops(const struct nft_ctx *ctx,
 116                           const struct nlattr * const tb[])
 117{
 118        if (tb[NFTA_META_KEY] == NULL)
 119                return ERR_PTR(-EINVAL);
 120
 121        if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
 122                return ERR_PTR(-EINVAL);
 123
 124        if (tb[NFTA_META_DREG])
 125                return &nft_meta_bridge_get_ops;
 126
 127        if (tb[NFTA_META_SREG])
 128                return &nft_meta_bridge_set_ops;
 129
 130        return ERR_PTR(-EINVAL);
 131}
 132
 133static struct nft_expr_type nft_meta_bridge_type __read_mostly = {
 134        .family         = NFPROTO_BRIDGE,
 135        .name           = "meta",
 136        .select_ops     = nft_meta_bridge_select_ops,
 137        .policy         = nft_meta_policy,
 138        .maxattr        = NFTA_META_MAX,
 139        .owner          = THIS_MODULE,
 140};
 141
 142static int __init nft_meta_bridge_module_init(void)
 143{
 144        return nft_register_expr(&nft_meta_bridge_type);
 145}
 146
 147static void __exit nft_meta_bridge_module_exit(void)
 148{
 149        nft_unregister_expr(&nft_meta_bridge_type);
 150}
 151
 152module_init(nft_meta_bridge_module_init);
 153module_exit(nft_meta_bridge_module_exit);
 154
 155MODULE_LICENSE("GPL");
 156MODULE_AUTHOR("wenxu <wenxu@ucloud.cn>");
 157MODULE_ALIAS_NFT_AF_EXPR(AF_BRIDGE, "meta");
 158