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
)
31 const struct nft_fib
*priv
= nft_expr_priv(expr
);
34 switch (priv
->result
) {
35 case NFT_FIB_RESULT_OIF
:
36 case NFT_FIB_RESULT_OIFNAME
:
37 hooks
= (1 << NF_INET_PRE_ROUTING
) |
38 (1 << NF_INET_LOCAL_IN
) |
39 (1 << NF_INET_FORWARD
);
41 case NFT_FIB_RESULT_ADDRTYPE
:
42 if (priv
->flags
& NFTA_FIB_F_IIF
)
43 hooks
= (1 << NF_INET_PRE_ROUTING
) |
44 (1 << NF_INET_LOCAL_IN
) |
45 (1 << NF_INET_FORWARD
);
46 else if (priv
->flags
& NFTA_FIB_F_OIF
)
47 hooks
= (1 << NF_INET_LOCAL_OUT
) |
48 (1 << NF_INET_POST_ROUTING
) |
49 (1 << NF_INET_FORWARD
);
51 hooks
= (1 << NF_INET_LOCAL_IN
) |
52 (1 << NF_INET_LOCAL_OUT
) |
53 (1 << NF_INET_FORWARD
) |
54 (1 << NF_INET_PRE_ROUTING
) |
55 (1 << NF_INET_POST_ROUTING
);
62 return nft_chain_validate_hooks(ctx
->chain
, hooks
);
64 EXPORT_SYMBOL_GPL(nft_fib_validate
);
66 int nft_fib_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
67 const struct nlattr
* const tb
[])
69 struct nft_fib
*priv
= nft_expr_priv(expr
);
73 if (!tb
[NFTA_FIB_DREG
] || !tb
[NFTA_FIB_RESULT
] || !tb
[NFTA_FIB_FLAGS
])
76 priv
->flags
= ntohl(nla_get_be32(tb
[NFTA_FIB_FLAGS
]));
81 if ((priv
->flags
& (NFTA_FIB_F_SADDR
| NFTA_FIB_F_DADDR
)) ==
82 (NFTA_FIB_F_SADDR
| NFTA_FIB_F_DADDR
))
84 if ((priv
->flags
& (NFTA_FIB_F_IIF
| NFTA_FIB_F_OIF
)) ==
85 (NFTA_FIB_F_IIF
| NFTA_FIB_F_OIF
))
87 if ((priv
->flags
& (NFTA_FIB_F_SADDR
| NFTA_FIB_F_DADDR
)) == 0)
90 priv
->result
= ntohl(nla_get_be32(tb
[NFTA_FIB_RESULT
]));
92 switch (priv
->result
) {
93 case NFT_FIB_RESULT_OIF
:
94 if (priv
->flags
& NFTA_FIB_F_OIF
)
98 case NFT_FIB_RESULT_OIFNAME
:
99 if (priv
->flags
& NFTA_FIB_F_OIF
)
103 case NFT_FIB_RESULT_ADDRTYPE
:
110 err
= nft_parse_register_store(ctx
, tb
[NFTA_FIB_DREG
], &priv
->dreg
,
111 NULL
, NFT_DATA_VALUE
, len
);
117 EXPORT_SYMBOL_GPL(nft_fib_init
);
119 int nft_fib_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
, bool reset
)
121 const struct nft_fib
*priv
= nft_expr_priv(expr
);
123 if (nft_dump_register(skb
, NFTA_FIB_DREG
, priv
->dreg
))
126 if (nla_put_be32(skb
, NFTA_FIB_RESULT
, htonl(priv
->result
)))
129 if (nla_put_be32(skb
, NFTA_FIB_FLAGS
, htonl(priv
->flags
)))
134 EXPORT_SYMBOL_GPL(nft_fib_dump
);
136 void nft_fib_store_result(void *reg
, const struct nft_fib
*priv
,
137 const struct net_device
*dev
)
142 switch (priv
->result
) {
143 case NFT_FIB_RESULT_OIF
:
144 index
= dev
? dev
->ifindex
: 0;
145 if (priv
->flags
& NFTA_FIB_F_PRESENT
)
146 nft_reg_store8(dreg
, !!index
);
151 case NFT_FIB_RESULT_OIFNAME
:
152 if (priv
->flags
& NFTA_FIB_F_PRESENT
)
153 nft_reg_store8(dreg
, !!dev
);
155 strscpy_pad(reg
, dev
? dev
->name
: "", IFNAMSIZ
);
163 EXPORT_SYMBOL_GPL(nft_fib_store_result
);
165 bool nft_fib_reduce(struct nft_regs_track
*track
,
166 const struct nft_expr
*expr
)
168 const struct nft_fib
*priv
= nft_expr_priv(expr
);
169 unsigned int len
= NFT_REG32_SIZE
;
170 const struct nft_fib
*fib
;
172 switch (priv
->result
) {
173 case NFT_FIB_RESULT_OIF
:
175 case NFT_FIB_RESULT_OIFNAME
:
176 if (priv
->flags
& NFTA_FIB_F_PRESENT
)
177 len
= NFT_REG32_SIZE
;
181 case NFT_FIB_RESULT_ADDRTYPE
:
188 if (!nft_reg_track_cmp(track
, expr
, priv
->dreg
)) {
189 nft_reg_track_update(track
, expr
, priv
->dreg
, len
);
193 fib
= nft_expr_priv(track
->regs
[priv
->dreg
].selector
);
194 if (priv
->result
!= fib
->result
||
195 priv
->flags
!= fib
->flags
) {
196 nft_reg_track_update(track
, expr
, priv
->dreg
, len
);
200 if (!track
->regs
[priv
->dreg
].bitwise
)
205 EXPORT_SYMBOL_GPL(nft_fib_reduce
);
207 MODULE_LICENSE("GPL");
208 MODULE_DESCRIPTION("Query routing table from nftables");
209 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");