1 // SPDX-License-Identifier: GPL-2.0-only
4 * Generic part shared by ipv4 and ipv6 backends.
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>
17 #define NFTA_FIB_F_ALL (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR | \
18 NFTA_FIB_F_MARK | NFTA_FIB_F_IIF | NFTA_FIB_F_OIF | \
21 const struct nla_policy nft_fib_policy
[NFTA_FIB_MAX
+ 1] = {
22 [NFTA_FIB_DREG
] = { .type
= NLA_U32
},
23 [NFTA_FIB_RESULT
] = { .type
= NLA_U32
},
25 NLA_POLICY_MASK(NLA_BE32
, NFTA_FIB_F_ALL
),
27 EXPORT_SYMBOL(nft_fib_policy
);
29 int nft_fib_validate(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
30 const struct nft_data
**data
)
32 const struct nft_fib
*priv
= nft_expr_priv(expr
);
35 switch (priv
->result
) {
36 case NFT_FIB_RESULT_OIF
:
37 case NFT_FIB_RESULT_OIFNAME
:
38 hooks
= (1 << NF_INET_PRE_ROUTING
);
39 if (priv
->flags
& NFTA_FIB_F_IIF
) {
40 hooks
|= (1 << NF_INET_LOCAL_IN
) |
41 (1 << NF_INET_FORWARD
);
44 case NFT_FIB_RESULT_ADDRTYPE
:
45 if (priv
->flags
& NFTA_FIB_F_IIF
)
46 hooks
= (1 << NF_INET_PRE_ROUTING
) |
47 (1 << NF_INET_LOCAL_IN
) |
48 (1 << NF_INET_FORWARD
);
49 else if (priv
->flags
& NFTA_FIB_F_OIF
)
50 hooks
= (1 << NF_INET_LOCAL_OUT
) |
51 (1 << NF_INET_POST_ROUTING
) |
52 (1 << NF_INET_FORWARD
);
54 hooks
= (1 << NF_INET_LOCAL_IN
) |
55 (1 << NF_INET_LOCAL_OUT
) |
56 (1 << NF_INET_FORWARD
) |
57 (1 << NF_INET_PRE_ROUTING
) |
58 (1 << NF_INET_POST_ROUTING
);
65 return nft_chain_validate_hooks(ctx
->chain
, hooks
);
67 EXPORT_SYMBOL_GPL(nft_fib_validate
);
69 int nft_fib_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
70 const struct nlattr
* const tb
[])
72 struct nft_fib
*priv
= nft_expr_priv(expr
);
76 if (!tb
[NFTA_FIB_DREG
] || !tb
[NFTA_FIB_RESULT
] || !tb
[NFTA_FIB_FLAGS
])
79 priv
->flags
= ntohl(nla_get_be32(tb
[NFTA_FIB_FLAGS
]));
84 if ((priv
->flags
& (NFTA_FIB_F_SADDR
| NFTA_FIB_F_DADDR
)) ==
85 (NFTA_FIB_F_SADDR
| NFTA_FIB_F_DADDR
))
87 if ((priv
->flags
& (NFTA_FIB_F_IIF
| NFTA_FIB_F_OIF
)) ==
88 (NFTA_FIB_F_IIF
| NFTA_FIB_F_OIF
))
90 if ((priv
->flags
& (NFTA_FIB_F_SADDR
| NFTA_FIB_F_DADDR
)) == 0)
93 priv
->result
= ntohl(nla_get_be32(tb
[NFTA_FIB_RESULT
]));
95 switch (priv
->result
) {
96 case NFT_FIB_RESULT_OIF
:
97 if (priv
->flags
& NFTA_FIB_F_OIF
)
101 case NFT_FIB_RESULT_OIFNAME
:
102 if (priv
->flags
& NFTA_FIB_F_OIF
)
106 case NFT_FIB_RESULT_ADDRTYPE
:
113 err
= nft_parse_register_store(ctx
, tb
[NFTA_FIB_DREG
], &priv
->dreg
,
114 NULL
, NFT_DATA_VALUE
, len
);
120 EXPORT_SYMBOL_GPL(nft_fib_init
);
122 int nft_fib_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
, bool reset
)
124 const struct nft_fib
*priv
= nft_expr_priv(expr
);
126 if (nft_dump_register(skb
, NFTA_FIB_DREG
, priv
->dreg
))
129 if (nla_put_be32(skb
, NFTA_FIB_RESULT
, htonl(priv
->result
)))
132 if (nla_put_be32(skb
, NFTA_FIB_FLAGS
, htonl(priv
->flags
)))
137 EXPORT_SYMBOL_GPL(nft_fib_dump
);
139 void nft_fib_store_result(void *reg
, const struct nft_fib
*priv
,
140 const struct net_device
*dev
)
145 switch (priv
->result
) {
146 case NFT_FIB_RESULT_OIF
:
147 index
= dev
? dev
->ifindex
: 0;
148 *dreg
= (priv
->flags
& NFTA_FIB_F_PRESENT
) ? !!index
: index
;
150 case NFT_FIB_RESULT_OIFNAME
:
151 if (priv
->flags
& NFTA_FIB_F_PRESENT
)
154 strscpy_pad(reg
, dev
? dev
->name
: "", IFNAMSIZ
);
162 EXPORT_SYMBOL_GPL(nft_fib_store_result
);
164 bool nft_fib_reduce(struct nft_regs_track
*track
,
165 const struct nft_expr
*expr
)
167 const struct nft_fib
*priv
= nft_expr_priv(expr
);
168 unsigned int len
= NFT_REG32_SIZE
;
169 const struct nft_fib
*fib
;
171 switch (priv
->result
) {
172 case NFT_FIB_RESULT_OIF
:
174 case NFT_FIB_RESULT_OIFNAME
:
175 if (priv
->flags
& NFTA_FIB_F_PRESENT
)
176 len
= NFT_REG32_SIZE
;
180 case NFT_FIB_RESULT_ADDRTYPE
:
187 if (!nft_reg_track_cmp(track
, expr
, priv
->dreg
)) {
188 nft_reg_track_update(track
, expr
, priv
->dreg
, len
);
192 fib
= nft_expr_priv(track
->regs
[priv
->dreg
].selector
);
193 if (priv
->result
!= fib
->result
||
194 priv
->flags
!= fib
->flags
) {
195 nft_reg_track_update(track
, expr
, priv
->dreg
, len
);
199 if (!track
->regs
[priv
->dreg
].bitwise
)
204 EXPORT_SYMBOL_GPL(nft_fib_reduce
);
206 MODULE_LICENSE("GPL");
207 MODULE_DESCRIPTION("Query routing table from nftables");
208 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");