cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nft_fib.c (5028B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *
      4 * Generic part shared by ipv4 and ipv6 backends.
      5 */
      6
      7#include <linux/kernel.h>
      8#include <linux/init.h>
      9#include <linux/module.h>
     10#include <linux/netlink.h>
     11#include <linux/netfilter.h>
     12#include <linux/netfilter/nf_tables.h>
     13#include <net/netfilter/nf_tables_core.h>
     14#include <net/netfilter/nf_tables.h>
     15#include <net/netfilter/nft_fib.h>
     16
     17const struct nla_policy nft_fib_policy[NFTA_FIB_MAX + 1] = {
     18	[NFTA_FIB_DREG]		= { .type = NLA_U32 },
     19	[NFTA_FIB_RESULT]	= { .type = NLA_U32 },
     20	[NFTA_FIB_FLAGS]	= { .type = NLA_U32 },
     21};
     22EXPORT_SYMBOL(nft_fib_policy);
     23
     24#define NFTA_FIB_F_ALL (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR | \
     25			NFTA_FIB_F_MARK | NFTA_FIB_F_IIF | NFTA_FIB_F_OIF | \
     26			NFTA_FIB_F_PRESENT)
     27
     28int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
     29		     const struct nft_data **data)
     30{
     31	const struct nft_fib *priv = nft_expr_priv(expr);
     32	unsigned int hooks;
     33
     34	switch (priv->result) {
     35	case NFT_FIB_RESULT_OIF:
     36	case NFT_FIB_RESULT_OIFNAME:
     37		hooks = (1 << NF_INET_PRE_ROUTING);
     38		if (priv->flags & NFTA_FIB_F_IIF) {
     39			hooks |= (1 << NF_INET_LOCAL_IN) |
     40				 (1 << NF_INET_FORWARD);
     41		}
     42		break;
     43	case NFT_FIB_RESULT_ADDRTYPE:
     44		if (priv->flags & NFTA_FIB_F_IIF)
     45			hooks = (1 << NF_INET_PRE_ROUTING) |
     46				(1 << NF_INET_LOCAL_IN) |
     47				(1 << NF_INET_FORWARD);
     48		else if (priv->flags & NFTA_FIB_F_OIF)
     49			hooks = (1 << NF_INET_LOCAL_OUT) |
     50				(1 << NF_INET_POST_ROUTING) |
     51				(1 << NF_INET_FORWARD);
     52		else
     53			hooks = (1 << NF_INET_LOCAL_IN) |
     54				(1 << NF_INET_LOCAL_OUT) |
     55				(1 << NF_INET_FORWARD) |
     56				(1 << NF_INET_PRE_ROUTING) |
     57				(1 << NF_INET_POST_ROUTING);
     58
     59		break;
     60	default:
     61		return -EINVAL;
     62	}
     63
     64	return nft_chain_validate_hooks(ctx->chain, hooks);
     65}
     66EXPORT_SYMBOL_GPL(nft_fib_validate);
     67
     68int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
     69		 const struct nlattr * const tb[])
     70{
     71	struct nft_fib *priv = nft_expr_priv(expr);
     72	unsigned int len;
     73	int err;
     74
     75	if (!tb[NFTA_FIB_DREG] || !tb[NFTA_FIB_RESULT] || !tb[NFTA_FIB_FLAGS])
     76		return -EINVAL;
     77
     78	priv->flags = ntohl(nla_get_be32(tb[NFTA_FIB_FLAGS]));
     79
     80	if (priv->flags == 0 || (priv->flags & ~NFTA_FIB_F_ALL))
     81		return -EINVAL;
     82
     83	if ((priv->flags & (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR)) ==
     84			   (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR))
     85		return -EINVAL;
     86	if ((priv->flags & (NFTA_FIB_F_IIF | NFTA_FIB_F_OIF)) ==
     87			   (NFTA_FIB_F_IIF | NFTA_FIB_F_OIF))
     88		return -EINVAL;
     89	if ((priv->flags & (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR)) == 0)
     90		return -EINVAL;
     91
     92	priv->result = ntohl(nla_get_be32(tb[NFTA_FIB_RESULT]));
     93
     94	switch (priv->result) {
     95	case NFT_FIB_RESULT_OIF:
     96		if (priv->flags & NFTA_FIB_F_OIF)
     97			return -EINVAL;
     98		len = sizeof(int);
     99		break;
    100	case NFT_FIB_RESULT_OIFNAME:
    101		if (priv->flags & NFTA_FIB_F_OIF)
    102			return -EINVAL;
    103		len = IFNAMSIZ;
    104		break;
    105	case NFT_FIB_RESULT_ADDRTYPE:
    106		len = sizeof(u32);
    107		break;
    108	default:
    109		return -EINVAL;
    110	}
    111
    112	err = nft_parse_register_store(ctx, tb[NFTA_FIB_DREG], &priv->dreg,
    113				       NULL, NFT_DATA_VALUE, len);
    114	if (err < 0)
    115		return err;
    116
    117	return 0;
    118}
    119EXPORT_SYMBOL_GPL(nft_fib_init);
    120
    121int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr)
    122{
    123	const struct nft_fib *priv = nft_expr_priv(expr);
    124
    125	if (nft_dump_register(skb, NFTA_FIB_DREG, priv->dreg))
    126		return -1;
    127
    128	if (nla_put_be32(skb, NFTA_FIB_RESULT, htonl(priv->result)))
    129		return -1;
    130
    131	if (nla_put_be32(skb, NFTA_FIB_FLAGS, htonl(priv->flags)))
    132		return -1;
    133
    134	return 0;
    135}
    136EXPORT_SYMBOL_GPL(nft_fib_dump);
    137
    138void nft_fib_store_result(void *reg, const struct nft_fib *priv,
    139			  const struct net_device *dev)
    140{
    141	u32 *dreg = reg;
    142	int index;
    143
    144	switch (priv->result) {
    145	case NFT_FIB_RESULT_OIF:
    146		index = dev ? dev->ifindex : 0;
    147		*dreg = (priv->flags & NFTA_FIB_F_PRESENT) ? !!index : index;
    148		break;
    149	case NFT_FIB_RESULT_OIFNAME:
    150		if (priv->flags & NFTA_FIB_F_PRESENT)
    151			*dreg = !!dev;
    152		else
    153			strncpy(reg, dev ? dev->name : "", IFNAMSIZ);
    154		break;
    155	default:
    156		WARN_ON_ONCE(1);
    157		*dreg = 0;
    158		break;
    159	}
    160}
    161EXPORT_SYMBOL_GPL(nft_fib_store_result);
    162
    163bool nft_fib_reduce(struct nft_regs_track *track,
    164		    const struct nft_expr *expr)
    165{
    166	const struct nft_fib *priv = nft_expr_priv(expr);
    167	unsigned int len = NFT_REG32_SIZE;
    168	const struct nft_fib *fib;
    169
    170	switch (priv->result) {
    171	case NFT_FIB_RESULT_OIF:
    172		break;
    173	case NFT_FIB_RESULT_OIFNAME:
    174		if (priv->flags & NFTA_FIB_F_PRESENT)
    175			len = NFT_REG32_SIZE;
    176		else
    177			len = IFNAMSIZ;
    178		break;
    179	case NFT_FIB_RESULT_ADDRTYPE:
    180	     break;
    181	default:
    182		WARN_ON_ONCE(1);
    183		break;
    184	}
    185
    186	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
    187		nft_reg_track_update(track, expr, priv->dreg, len);
    188		return false;
    189	}
    190
    191	fib = nft_expr_priv(track->regs[priv->dreg].selector);
    192	if (priv->result != fib->result ||
    193	    priv->flags != fib->flags) {
    194		nft_reg_track_update(track, expr, priv->dreg, len);
    195		return false;
    196	}
    197
    198	if (!track->regs[priv->dreg].bitwise)
    199		return true;
    200
    201	return false;
    202}
    203EXPORT_SYMBOL_GPL(nft_fib_reduce);
    204
    205MODULE_LICENSE("GPL");
    206MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");