1 // SPDX-License-Identifier: GPL-2.0-only
6 #include <linux/kernel.h>
7 #include <linux/if_vlan.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_meta.h>
16 #include <net/netfilter/nf_tables_offload.h>
17 #include <linux/tcp.h>
18 #include <linux/udp.h>
20 #include <net/geneve.h>
22 #include <linux/icmpv6.h>
24 #include <linux/ipv6.h>
26 static DEFINE_PER_CPU(struct nft_inner_tun_ctx, nft_pcpu_tun_ctx);
28 /* Same layout as nft_expr but it embeds the private expression data area. */
30 const struct nft_expr_ops *ops;
32 struct nft_payload payload;
34 } __attribute__((aligned(__alignof__(u64))));
38 NFT_INNER_EXPR_PAYLOAD,
48 struct __nft_expr expr;
51 static int nft_inner_parse_l2l3(const struct nft_inner *priv,
52 const struct nft_pktinfo *pkt,
53 struct nft_inner_tun_ctx *ctx, u32 off)
55 __be16 llproto, outer_llproto;
58 if (priv->flags & NFT_INNER_LL) {
59 struct vlan_ethhdr *veth, _veth;
60 struct ethhdr *eth, _eth;
63 eth = skb_header_pointer(pkt->skb, off, sizeof(_eth), &_eth);
67 switch (eth->h_proto) {
69 case htons(ETH_P_IPV6):
70 llproto = eth->h_proto;
71 hdrsize = sizeof(_eth);
73 case htons(ETH_P_8021Q):
74 veth = skb_header_pointer(pkt->skb, off, sizeof(_veth), &_veth);
78 outer_llproto = veth->h_vlan_encapsulated_proto;
79 llproto = veth->h_vlan_proto;
80 hdrsize = sizeof(_veth);
86 ctx->inner_lloff = off;
87 ctx->flags |= NFT_PAYLOAD_CTX_INNER_LL;
93 iph = skb_header_pointer(pkt->skb, off, sizeof(_version), &_version);
97 switch (iph->version) {
99 llproto = htons(ETH_P_IP);
102 llproto = htons(ETH_P_IPV6);
109 ctx->llproto = llproto;
110 if (llproto == htons(ETH_P_8021Q))
111 llproto = outer_llproto;
116 case htons(ETH_P_IP): {
117 struct iphdr *iph, _iph;
119 iph = skb_header_pointer(pkt->skb, nhoff, sizeof(_iph), &_iph);
123 if (iph->ihl < 5 || iph->version != 4)
126 ctx->inner_nhoff = nhoff;
127 ctx->flags |= NFT_PAYLOAD_CTX_INNER_NH;
129 thoff = nhoff + (iph->ihl * 4);
130 if ((ntohs(iph->frag_off) & IP_OFFSET) == 0) {
131 ctx->flags |= NFT_PAYLOAD_CTX_INNER_TH;
132 ctx->inner_thoff = thoff;
133 ctx->l4proto = iph->protocol;
137 case htons(ETH_P_IPV6): {
138 struct ipv6hdr *ip6h, _ip6h;
139 int fh_flags = IP6_FH_F_AUTH;
140 unsigned short fragoff;
143 ip6h = skb_header_pointer(pkt->skb, nhoff, sizeof(_ip6h), &_ip6h);
147 if (ip6h->version != 6)
150 ctx->inner_nhoff = nhoff;
151 ctx->flags |= NFT_PAYLOAD_CTX_INNER_NH;
154 l4proto = ipv6_find_hdr(pkt->skb, &thoff, -1, &fragoff, &fh_flags);
155 if (l4proto < 0 || thoff > U16_MAX)
159 thoff = nhoff + sizeof(_ip6h);
160 ctx->flags |= NFT_PAYLOAD_CTX_INNER_TH;
161 ctx->inner_thoff = thoff;
162 ctx->l4proto = l4proto;
173 static int nft_inner_parse_tunhdr(const struct nft_inner *priv,
174 const struct nft_pktinfo *pkt,
175 struct nft_inner_tun_ctx *ctx, u32 *off)
177 if (pkt->tprot == IPPROTO_GRE) {
178 ctx->inner_tunoff = pkt->thoff;
179 ctx->flags |= NFT_PAYLOAD_CTX_INNER_TUN;
183 if (pkt->tprot != IPPROTO_UDP)
186 ctx->inner_tunoff = *off;
187 ctx->flags |= NFT_PAYLOAD_CTX_INNER_TUN;
188 *off += priv->hdrsize;
190 switch (priv->type) {
191 case NFT_INNER_GENEVE: {
192 struct genevehdr *gnvh, _gnvh;
194 gnvh = skb_header_pointer(pkt->skb, pkt->inneroff,
195 sizeof(_gnvh), &_gnvh);
199 *off += gnvh->opt_len * 4;
209 static int nft_inner_parse(const struct nft_inner *priv,
210 struct nft_pktinfo *pkt,
211 struct nft_inner_tun_ctx *tun_ctx)
213 struct nft_inner_tun_ctx ctx = {};
214 u32 off = pkt->inneroff;
216 if (priv->flags & NFT_INNER_HDRSIZE &&
217 nft_inner_parse_tunhdr(priv, pkt, &ctx, &off) < 0)
220 if (priv->flags & (NFT_INNER_LL | NFT_INNER_NH)) {
221 if (nft_inner_parse_l2l3(priv, pkt, &ctx, off) < 0)
223 } else if (priv->flags & NFT_INNER_TH) {
224 ctx.inner_thoff = off;
225 ctx.flags |= NFT_PAYLOAD_CTX_INNER_TH;
229 tun_ctx->type = priv->type;
230 pkt->flags |= NFT_PKTINFO_INNER_FULL;
235 static bool nft_inner_parse_needed(const struct nft_inner *priv,
236 const struct nft_pktinfo *pkt,
237 const struct nft_inner_tun_ctx *tun_ctx)
239 if (!(pkt->flags & NFT_PKTINFO_INNER_FULL))
242 if (priv->type != tun_ctx->type)
248 static void nft_inner_eval(const struct nft_expr *expr, struct nft_regs *regs,
249 const struct nft_pktinfo *pkt)
251 struct nft_inner_tun_ctx *tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx);
252 const struct nft_inner *priv = nft_expr_priv(expr);
254 if (nft_payload_inner_offset(pkt) < 0)
257 if (nft_inner_parse_needed(priv, pkt, tun_ctx) &&
258 nft_inner_parse(priv, (struct nft_pktinfo *)pkt, tun_ctx) < 0)
261 switch (priv->expr_type) {
262 case NFT_INNER_EXPR_PAYLOAD:
263 nft_payload_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, tun_ctx);
265 case NFT_INNER_EXPR_META:
266 nft_meta_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, tun_ctx);
274 regs->verdict.code = NFT_BREAK;
277 static const struct nla_policy nft_inner_policy[NFTA_INNER_MAX + 1] = {
278 [NFTA_INNER_NUM] = { .type = NLA_U32 },
279 [NFTA_INNER_FLAGS] = { .type = NLA_U32 },
280 [NFTA_INNER_HDRSIZE] = { .type = NLA_U32 },
281 [NFTA_INNER_TYPE] = { .type = NLA_U32 },
282 [NFTA_INNER_EXPR] = { .type = NLA_NESTED },
285 struct nft_expr_info {
286 const struct nft_expr_ops *ops;
287 const struct nlattr *attr;
288 struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
291 static int nft_inner_init(const struct nft_ctx *ctx,
292 const struct nft_expr *expr,
293 const struct nlattr * const tb[])
295 struct nft_inner *priv = nft_expr_priv(expr);
296 u32 flags, hdrsize, type, num;
297 struct nft_expr_info expr_info;
300 if (!tb[NFTA_INNER_FLAGS] ||
301 !tb[NFTA_INNER_HDRSIZE] ||
302 !tb[NFTA_INNER_TYPE] ||
303 !tb[NFTA_INNER_EXPR])
306 flags = ntohl(nla_get_be32(tb[NFTA_INNER_FLAGS]));
307 if (flags & ~NFT_INNER_MASK)
310 num = ntohl(nla_get_be32(tb[NFTA_INNER_NUM]));
314 hdrsize = ntohl(nla_get_be32(tb[NFTA_INNER_HDRSIZE]));
315 type = ntohl(nla_get_be32(tb[NFTA_INNER_TYPE]));
320 if (flags & NFT_INNER_HDRSIZE) {
321 if (hdrsize == 0 || hdrsize > 64)
326 priv->hdrsize = hdrsize;
329 err = nft_expr_inner_parse(ctx, tb[NFTA_INNER_EXPR], &expr_info);
333 priv->expr.ops = expr_info.ops;
335 if (!strcmp(expr_info.ops->type->name, "payload"))
336 priv->expr_type = NFT_INNER_EXPR_PAYLOAD;
337 else if (!strcmp(expr_info.ops->type->name, "meta"))
338 priv->expr_type = NFT_INNER_EXPR_META;
342 err = expr_info.ops->init(ctx, (struct nft_expr *)&priv->expr,
343 (const struct nlattr * const*)expr_info.tb);
350 static int nft_inner_dump(struct sk_buff *skb,
351 const struct nft_expr *expr, bool reset)
353 const struct nft_inner *priv = nft_expr_priv(expr);
355 if (nla_put_be32(skb, NFTA_INNER_NUM, htonl(0)) ||
356 nla_put_be32(skb, NFTA_INNER_TYPE, htonl(priv->type)) ||
357 nla_put_be32(skb, NFTA_INNER_FLAGS, htonl(priv->flags)) ||
358 nla_put_be32(skb, NFTA_INNER_HDRSIZE, htonl(priv->hdrsize)))
359 goto nla_put_failure;
361 if (nft_expr_dump(skb, NFTA_INNER_EXPR,
362 (struct nft_expr *)&priv->expr, reset) < 0)
363 goto nla_put_failure;
371 static const struct nft_expr_ops nft_inner_ops = {
372 .type = &nft_inner_type,
373 .size = NFT_EXPR_SIZE(sizeof(struct nft_inner)),
374 .eval = nft_inner_eval,
375 .init = nft_inner_init,
376 .dump = nft_inner_dump,
379 struct nft_expr_type nft_inner_type __read_mostly = {
381 .ops = &nft_inner_ops,
382 .policy = nft_inner_policy,
383 .maxattr = NFTA_INNER_MAX,
384 .owner = THIS_MODULE,