blob: cec8dc0e5e6f2479527fd1dc1d3ee981d58b85e6 [file] [log] [blame]
Patrick McHardy96518512013-10-14 11:00:02 +02001/*
Patrick McHardyef1f7df2013-10-10 11:41:20 +02002 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
Patrick McHardy96518512013-10-14 11:00:02 +02003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/netlink.h>
15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h>
Ana Reye2a093f2014-08-06 13:52:49 +020017#include <linux/in.h>
18#include <linux/ip.h>
19#include <linux/ipv6.h>
Ana Reyafc5be302014-08-24 14:08:36 +020020#include <linux/smp.h>
Florian Westphale639f7a2015-11-28 21:53:05 +010021#include <linux/static_key.h>
Patrick McHardy96518512013-10-14 11:00:02 +020022#include <net/dst.h>
23#include <net/sock.h>
24#include <net/tcp_states.h> /* for TCP_TIME_WAIT */
25#include <net/netfilter/nf_tables.h>
Florian Westphale639f7a2015-11-28 21:53:05 +010026#include <net/netfilter/nf_tables_core.h>
Tomasz Bursztykaaa456602014-04-14 15:41:27 +030027#include <net/netfilter/nft_meta.h>
Patrick McHardy96518512013-10-14 11:00:02 +020028
Florian Westphalb4aae752015-12-10 18:04:07 +010029#include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
30
Florian Westphalb07edbe2016-02-16 17:24:08 +010031static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
32
Tomasz Bursztykaaa456602014-04-14 15:41:27 +030033void nft_meta_get_eval(const struct nft_expr *expr,
Patrick McHardya55e22e2015-04-11 02:27:31 +010034 struct nft_regs *regs,
Tomasz Bursztykaaa456602014-04-14 15:41:27 +030035 const struct nft_pktinfo *pkt)
Patrick McHardy96518512013-10-14 11:00:02 +020036{
37 const struct nft_meta *priv = nft_expr_priv(expr);
38 const struct sk_buff *skb = pkt->skb;
39 const struct net_device *in = pkt->in, *out = pkt->out;
Eric Dumazet3aed8222015-11-08 10:54:12 -080040 struct sock *sk;
Patrick McHardy49499c32015-04-11 02:27:37 +010041 u32 *dest = &regs->data[priv->dreg];
Patrick McHardy96518512013-10-14 11:00:02 +020042
43 switch (priv->key) {
44 case NFT_META_LEN:
Patrick McHardyfad136e2015-04-11 02:27:33 +010045 *dest = skb->len;
Patrick McHardy96518512013-10-14 11:00:02 +020046 break;
47 case NFT_META_PROTOCOL:
Liping Zhang1894d7c2017-03-08 22:54:18 +080048 nft_reg_store16(dest, (__force u16)skb->protocol);
Patrick McHardy96518512013-10-14 11:00:02 +020049 break;
Patrick McHardy124edfa2014-01-03 12:16:17 +000050 case NFT_META_NFPROTO:
Liping Zhang1894d7c2017-03-08 22:54:18 +080051 nft_reg_store8(dest, pkt->pf);
Patrick McHardy124edfa2014-01-03 12:16:17 +000052 break;
Patrick McHardy4566bf22014-01-03 12:16:18 +000053 case NFT_META_L4PROTO:
Pablo Neira Ayusobeac5af2016-09-09 12:42:49 +020054 if (!pkt->tprot_set)
55 goto err;
Liping Zhang1894d7c2017-03-08 22:54:18 +080056 nft_reg_store8(dest, pkt->tprot);
Patrick McHardy4566bf22014-01-03 12:16:18 +000057 break;
Patrick McHardy96518512013-10-14 11:00:02 +020058 case NFT_META_PRIORITY:
Patrick McHardyfad136e2015-04-11 02:27:33 +010059 *dest = skb->priority;
Patrick McHardy96518512013-10-14 11:00:02 +020060 break;
61 case NFT_META_MARK:
Patrick McHardyfad136e2015-04-11 02:27:33 +010062 *dest = skb->mark;
Patrick McHardy96518512013-10-14 11:00:02 +020063 break;
64 case NFT_META_IIF:
65 if (in == NULL)
66 goto err;
Patrick McHardyfad136e2015-04-11 02:27:33 +010067 *dest = in->ifindex;
Patrick McHardy96518512013-10-14 11:00:02 +020068 break;
69 case NFT_META_OIF:
70 if (out == NULL)
71 goto err;
Patrick McHardyfad136e2015-04-11 02:27:33 +010072 *dest = out->ifindex;
Patrick McHardy96518512013-10-14 11:00:02 +020073 break;
74 case NFT_META_IIFNAME:
75 if (in == NULL)
76 goto err;
Patrick McHardyfad136e2015-04-11 02:27:33 +010077 strncpy((char *)dest, in->name, IFNAMSIZ);
Patrick McHardy96518512013-10-14 11:00:02 +020078 break;
79 case NFT_META_OIFNAME:
80 if (out == NULL)
81 goto err;
Patrick McHardyfad136e2015-04-11 02:27:33 +010082 strncpy((char *)dest, out->name, IFNAMSIZ);
Patrick McHardy96518512013-10-14 11:00:02 +020083 break;
84 case NFT_META_IIFTYPE:
85 if (in == NULL)
86 goto err;
Liping Zhang1894d7c2017-03-08 22:54:18 +080087 nft_reg_store16(dest, in->type);
Patrick McHardy96518512013-10-14 11:00:02 +020088 break;
89 case NFT_META_OIFTYPE:
90 if (out == NULL)
91 goto err;
Liping Zhang1894d7c2017-03-08 22:54:18 +080092 nft_reg_store16(dest, out->type);
Patrick McHardy96518512013-10-14 11:00:02 +020093 break;
94 case NFT_META_SKUID:
Eric Dumazet3aed8222015-11-08 10:54:12 -080095 sk = skb_to_full_sk(skb);
96 if (!sk || !sk_fullsock(sk))
Patrick McHardy96518512013-10-14 11:00:02 +020097 goto err;
98
Eric Dumazet3aed8222015-11-08 10:54:12 -080099 read_lock_bh(&sk->sk_callback_lock);
100 if (sk->sk_socket == NULL ||
101 sk->sk_socket->file == NULL) {
102 read_unlock_bh(&sk->sk_callback_lock);
Patrick McHardy96518512013-10-14 11:00:02 +0200103 goto err;
104 }
105
Patrick McHardyfad136e2015-04-11 02:27:33 +0100106 *dest = from_kuid_munged(&init_user_ns,
Eric Dumazet3aed8222015-11-08 10:54:12 -0800107 sk->sk_socket->file->f_cred->fsuid);
108 read_unlock_bh(&sk->sk_callback_lock);
Patrick McHardy96518512013-10-14 11:00:02 +0200109 break;
110 case NFT_META_SKGID:
Eric Dumazet3aed8222015-11-08 10:54:12 -0800111 sk = skb_to_full_sk(skb);
112 if (!sk || !sk_fullsock(sk))
Patrick McHardy96518512013-10-14 11:00:02 +0200113 goto err;
114
Eric Dumazet3aed8222015-11-08 10:54:12 -0800115 read_lock_bh(&sk->sk_callback_lock);
116 if (sk->sk_socket == NULL ||
117 sk->sk_socket->file == NULL) {
118 read_unlock_bh(&sk->sk_callback_lock);
Patrick McHardy96518512013-10-14 11:00:02 +0200119 goto err;
120 }
Patrick McHardyfad136e2015-04-11 02:27:33 +0100121 *dest = from_kgid_munged(&init_user_ns,
Eric Dumazet3aed8222015-11-08 10:54:12 -0800122 sk->sk_socket->file->f_cred->fsgid);
123 read_unlock_bh(&sk->sk_callback_lock);
Patrick McHardy96518512013-10-14 11:00:02 +0200124 break;
Paul Bolle06efbd62014-02-12 10:53:01 +0100125#ifdef CONFIG_IP_ROUTE_CLASSID
Patrick McHardy96518512013-10-14 11:00:02 +0200126 case NFT_META_RTCLASSID: {
127 const struct dst_entry *dst = skb_dst(skb);
128
129 if (dst == NULL)
130 goto err;
Patrick McHardyfad136e2015-04-11 02:27:33 +0100131 *dest = dst->tclassid;
Patrick McHardy96518512013-10-14 11:00:02 +0200132 break;
133 }
134#endif
135#ifdef CONFIG_NETWORK_SECMARK
136 case NFT_META_SECMARK:
Patrick McHardyfad136e2015-04-11 02:27:33 +0100137 *dest = skb->secmark;
Patrick McHardy96518512013-10-14 11:00:02 +0200138 break;
139#endif
Ana Reye2a093f2014-08-06 13:52:49 +0200140 case NFT_META_PKTTYPE:
141 if (skb->pkt_type != PACKET_LOOPBACK) {
Liping Zhang1894d7c2017-03-08 22:54:18 +0800142 nft_reg_store8(dest, skb->pkt_type);
Ana Reye2a093f2014-08-06 13:52:49 +0200143 break;
144 }
145
Eric W. Biederman6aa187f2015-09-18 14:32:57 -0500146 switch (pkt->pf) {
Ana Reye2a093f2014-08-06 13:52:49 +0200147 case NFPROTO_IPV4:
148 if (ipv4_is_multicast(ip_hdr(skb)->daddr))
Liping Zhang1894d7c2017-03-08 22:54:18 +0800149 nft_reg_store8(dest, PACKET_MULTICAST);
Ana Reye2a093f2014-08-06 13:52:49 +0200150 else
Liping Zhang1894d7c2017-03-08 22:54:18 +0800151 nft_reg_store8(dest, PACKET_BROADCAST);
Ana Reye2a093f2014-08-06 13:52:49 +0200152 break;
153 case NFPROTO_IPV6:
154 if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF)
Liping Zhang1894d7c2017-03-08 22:54:18 +0800155 nft_reg_store8(dest, PACKET_MULTICAST);
Ana Reye2a093f2014-08-06 13:52:49 +0200156 else
Liping Zhang1894d7c2017-03-08 22:54:18 +0800157 nft_reg_store8(dest, PACKET_BROADCAST);
Ana Reye2a093f2014-08-06 13:52:49 +0200158 break;
Liping Zhangc5493c62017-01-07 21:33:55 +0800159 case NFPROTO_NETDEV:
160 switch (skb->protocol) {
161 case htons(ETH_P_IP): {
162 int noff = skb_network_offset(skb);
163 struct iphdr *iph, _iph;
164
165 iph = skb_header_pointer(skb, noff,
166 sizeof(_iph), &_iph);
167 if (!iph)
168 goto err;
169
170 if (ipv4_is_multicast(iph->daddr))
Liping Zhang1894d7c2017-03-08 22:54:18 +0800171 nft_reg_store8(dest, PACKET_MULTICAST);
Liping Zhangc5493c62017-01-07 21:33:55 +0800172 else
Liping Zhang1894d7c2017-03-08 22:54:18 +0800173 nft_reg_store8(dest, PACKET_BROADCAST);
Liping Zhangc5493c62017-01-07 21:33:55 +0800174
175 break;
176 }
177 case htons(ETH_P_IPV6):
Liping Zhang1894d7c2017-03-08 22:54:18 +0800178 nft_reg_store8(dest, PACKET_MULTICAST);
Liping Zhangc5493c62017-01-07 21:33:55 +0800179 break;
180 default:
181 WARN_ON_ONCE(1);
182 goto err;
183 }
184 break;
Ana Reye2a093f2014-08-06 13:52:49 +0200185 default:
Liping Zhangc5493c62017-01-07 21:33:55 +0800186 WARN_ON_ONCE(1);
Ana Reye2a093f2014-08-06 13:52:49 +0200187 goto err;
188 }
189 break;
Ana Reyafc5be302014-08-24 14:08:36 +0200190 case NFT_META_CPU:
Patrick McHardyfad136e2015-04-11 02:27:33 +0100191 *dest = raw_smp_processor_id();
Ana Reyafc5be302014-08-24 14:08:36 +0200192 break;
Ana Rey3045d762014-09-02 20:36:14 +0200193 case NFT_META_IIFGROUP:
194 if (in == NULL)
195 goto err;
Patrick McHardyfad136e2015-04-11 02:27:33 +0100196 *dest = in->group;
Ana Rey3045d762014-09-02 20:36:14 +0200197 break;
198 case NFT_META_OIFGROUP:
199 if (out == NULL)
200 goto err;
Patrick McHardyfad136e2015-04-11 02:27:33 +0100201 *dest = out->group;
Ana Rey3045d762014-09-02 20:36:14 +0200202 break;
Mathias Krausee181a542015-07-19 22:21:13 +0200203#ifdef CONFIG_CGROUP_NET_CLASSID
Ana Reyce674172014-11-03 18:10:50 +0100204 case NFT_META_CGROUP:
Eric Dumazet3aed8222015-11-08 10:54:12 -0800205 sk = skb_to_full_sk(skb);
206 if (!sk || !sk_fullsock(sk))
Pablo Neira Ayusoc5035c72015-03-27 12:14:13 +0100207 goto err;
Tejun Heo2a56a1f2015-12-07 17:38:52 -0500208 *dest = sock_cgroup_classid(&sk->sk_cgrp_data);
Ana Reyce674172014-11-03 18:10:50 +0100209 break;
Mathias Krausee181a542015-07-19 22:21:13 +0200210#endif
Florian Westphalb07edbe2016-02-16 17:24:08 +0100211 case NFT_META_PRANDOM: {
212 struct rnd_state *state = this_cpu_ptr(&nft_prandom_state);
213 *dest = prandom_u32_state(state);
214 break;
215 }
Patrick McHardy96518512013-10-14 11:00:02 +0200216 default:
217 WARN_ON(1);
218 goto err;
219 }
220 return;
221
222err:
Patrick McHardya55e22e2015-04-11 02:27:31 +0100223 regs->verdict.code = NFT_BREAK;
Patrick McHardy96518512013-10-14 11:00:02 +0200224}
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300225EXPORT_SYMBOL_GPL(nft_meta_get_eval);
Patrick McHardy96518512013-10-14 11:00:02 +0200226
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300227void nft_meta_set_eval(const struct nft_expr *expr,
Patrick McHardya55e22e2015-04-11 02:27:31 +0100228 struct nft_regs *regs,
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300229 const struct nft_pktinfo *pkt)
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100230{
231 const struct nft_meta *meta = nft_expr_priv(expr);
232 struct sk_buff *skb = pkt->skb;
Liping Zhang1894d7c2017-03-08 22:54:18 +0800233 u32 *sreg = &regs->data[meta->sreg];
234 u32 value = *sreg;
235 u8 pkt_type;
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100236
237 switch (meta->key) {
238 case NFT_META_MARK:
239 skb->mark = value;
240 break;
241 case NFT_META_PRIORITY:
242 skb->priority = value;
243 break;
Florian Westphalb4aae752015-12-10 18:04:07 +0100244 case NFT_META_PKTTYPE:
Liping Zhang1894d7c2017-03-08 22:54:18 +0800245 pkt_type = nft_reg_load8(sreg);
246
247 if (skb->pkt_type != pkt_type &&
248 skb_pkt_type_ok(pkt_type) &&
249 skb_pkt_type_ok(skb->pkt_type))
250 skb->pkt_type = pkt_type;
Florian Westphalb4aae752015-12-10 18:04:07 +0100251 break;
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100252 case NFT_META_NFTRACE:
Liping Zhang62131e52016-06-08 20:20:10 +0800253 skb->nf_trace = !!value;
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100254 break;
255 default:
256 WARN_ON(1);
257 }
258}
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300259EXPORT_SYMBOL_GPL(nft_meta_set_eval);
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100260
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300261const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
Patrick McHardy96518512013-10-14 11:00:02 +0200262 [NFTA_META_DREG] = { .type = NLA_U32 },
263 [NFTA_META_KEY] = { .type = NLA_U32 },
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100264 [NFTA_META_SREG] = { .type = NLA_U32 },
Patrick McHardy96518512013-10-14 11:00:02 +0200265};
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300266EXPORT_SYMBOL_GPL(nft_meta_policy);
Patrick McHardy96518512013-10-14 11:00:02 +0200267
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300268int nft_meta_get_init(const struct nft_ctx *ctx,
269 const struct nft_expr *expr,
270 const struct nlattr * const tb[])
Patrick McHardy96518512013-10-14 11:00:02 +0200271{
Patrick McHardyd2caa692014-03-29 10:43:02 +0000272 struct nft_meta *priv = nft_expr_priv(expr);
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100273 unsigned int len;
Patrick McHardy96518512013-10-14 11:00:02 +0200274
Patrick McHardyd2caa692014-03-29 10:43:02 +0000275 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
276 switch (priv->key) {
Patrick McHardy96518512013-10-14 11:00:02 +0200277 case NFT_META_PROTOCOL:
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100278 case NFT_META_IIFTYPE:
279 case NFT_META_OIFTYPE:
280 len = sizeof(u16);
281 break;
Patrick McHardy124edfa2014-01-03 12:16:17 +0000282 case NFT_META_NFPROTO:
Patrick McHardy4566bf22014-01-03 12:16:18 +0000283 case NFT_META_L4PROTO:
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100284 case NFT_META_LEN:
Patrick McHardy96518512013-10-14 11:00:02 +0200285 case NFT_META_PRIORITY:
286 case NFT_META_MARK:
287 case NFT_META_IIF:
288 case NFT_META_OIF:
Patrick McHardy96518512013-10-14 11:00:02 +0200289 case NFT_META_SKUID:
290 case NFT_META_SKGID:
Paul Bolle06efbd62014-02-12 10:53:01 +0100291#ifdef CONFIG_IP_ROUTE_CLASSID
Patrick McHardy96518512013-10-14 11:00:02 +0200292 case NFT_META_RTCLASSID:
293#endif
294#ifdef CONFIG_NETWORK_SECMARK
295 case NFT_META_SECMARK:
296#endif
Ana Reye2a093f2014-08-06 13:52:49 +0200297 case NFT_META_PKTTYPE:
Ana Reyafc5be302014-08-24 14:08:36 +0200298 case NFT_META_CPU:
Ana Rey3045d762014-09-02 20:36:14 +0200299 case NFT_META_IIFGROUP:
300 case NFT_META_OIFGROUP:
Mathias Krausee181a542015-07-19 22:21:13 +0200301#ifdef CONFIG_CGROUP_NET_CLASSID
Ana Reyce674172014-11-03 18:10:50 +0100302 case NFT_META_CGROUP:
Mathias Krausee181a542015-07-19 22:21:13 +0200303#endif
Patrick McHardy45d9bcd2015-04-11 02:27:26 +0100304 len = sizeof(u32);
305 break;
306 case NFT_META_IIFNAME:
307 case NFT_META_OIFNAME:
308 len = IFNAMSIZ;
Patrick McHardyd2caa692014-03-29 10:43:02 +0000309 break;
Florian Westphalb07edbe2016-02-16 17:24:08 +0100310 case NFT_META_PRANDOM:
311 prandom_init_once(&nft_prandom_state);
312 len = sizeof(u32);
313 break;
Patrick McHardy96518512013-10-14 11:00:02 +0200314 default:
315 return -EOPNOTSUPP;
316 }
317
Patrick McHardyb1c96ed2015-04-11 02:27:36 +0100318 priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
Patrick McHardy27e6d202015-04-11 02:27:29 +0100319 return nft_validate_register_store(ctx, priv->dreg, NULL,
320 NFT_DATA_VALUE, len);
Patrick McHardy96518512013-10-14 11:00:02 +0200321}
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300322EXPORT_SYMBOL_GPL(nft_meta_get_init);
Patrick McHardy96518512013-10-14 11:00:02 +0200323
Liping Zhang960fa722016-08-22 22:57:56 +0800324int nft_meta_set_validate(const struct nft_ctx *ctx,
325 const struct nft_expr *expr,
326 const struct nft_data **data)
Florian Westphalb4aae752015-12-10 18:04:07 +0100327{
Liping Zhang960fa722016-08-22 22:57:56 +0800328 struct nft_meta *priv = nft_expr_priv(expr);
Florian Westphalb4aae752015-12-10 18:04:07 +0100329 unsigned int hooks;
330
Liping Zhang960fa722016-08-22 22:57:56 +0800331 if (priv->key != NFT_META_PKTTYPE)
332 return 0;
333
Florian Westphalb4aae752015-12-10 18:04:07 +0100334 switch (ctx->afi->family) {
335 case NFPROTO_BRIDGE:
336 hooks = 1 << NF_BR_PRE_ROUTING;
337 break;
338 case NFPROTO_NETDEV:
339 hooks = 1 << NF_NETDEV_INGRESS;
340 break;
341 default:
342 return -EOPNOTSUPP;
343 }
344
345 return nft_chain_validate_hooks(ctx->chain, hooks);
346}
Liping Zhang960fa722016-08-22 22:57:56 +0800347EXPORT_SYMBOL_GPL(nft_meta_set_validate);
Florian Westphalb4aae752015-12-10 18:04:07 +0100348
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300349int nft_meta_set_init(const struct nft_ctx *ctx,
350 const struct nft_expr *expr,
351 const struct nlattr * const tb[])
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100352{
353 struct nft_meta *priv = nft_expr_priv(expr);
Patrick McHardyd07db982015-04-11 02:27:30 +0100354 unsigned int len;
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100355 int err;
356
357 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
Patrick McHardyd2caa692014-03-29 10:43:02 +0000358 switch (priv->key) {
359 case NFT_META_MARK:
360 case NFT_META_PRIORITY:
Patrick McHardyd07db982015-04-11 02:27:30 +0100361 len = sizeof(u32);
362 break;
Patrick McHardyd2caa692014-03-29 10:43:02 +0000363 case NFT_META_NFTRACE:
Patrick McHardyd07db982015-04-11 02:27:30 +0100364 len = sizeof(u8);
Patrick McHardyd2caa692014-03-29 10:43:02 +0000365 break;
Florian Westphalb4aae752015-12-10 18:04:07 +0100366 case NFT_META_PKTTYPE:
Florian Westphalb4aae752015-12-10 18:04:07 +0100367 len = sizeof(u8);
368 break;
Patrick McHardyd2caa692014-03-29 10:43:02 +0000369 default:
370 return -EOPNOTSUPP;
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100371 }
372
Liping Zhang960fa722016-08-22 22:57:56 +0800373 err = nft_meta_set_validate(ctx, expr, NULL);
374 if (err < 0)
375 return err;
376
Patrick McHardyb1c96ed2015-04-11 02:27:36 +0100377 priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
Patrick McHardyd07db982015-04-11 02:27:30 +0100378 err = nft_validate_register_load(priv->sreg, len);
Pablo Neira Ayusob38895c2014-01-09 20:03:55 +0100379 if (err < 0)
380 return err;
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100381
Florian Westphale639f7a2015-11-28 21:53:05 +0100382 if (priv->key == NFT_META_NFTRACE)
383 static_branch_inc(&nft_trace_enabled);
384
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100385 return 0;
386}
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300387EXPORT_SYMBOL_GPL(nft_meta_set_init);
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100388
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300389int nft_meta_get_dump(struct sk_buff *skb,
390 const struct nft_expr *expr)
Patrick McHardy96518512013-10-14 11:00:02 +0200391{
392 const struct nft_meta *priv = nft_expr_priv(expr);
393
Patrick McHardy96518512013-10-14 11:00:02 +0200394 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
395 goto nla_put_failure;
Patrick McHardyb1c96ed2015-04-11 02:27:36 +0100396 if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg))
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100397 goto nla_put_failure;
Patrick McHardy96518512013-10-14 11:00:02 +0200398 return 0;
399
400nla_put_failure:
401 return -1;
402}
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300403EXPORT_SYMBOL_GPL(nft_meta_get_dump);
Patrick McHardy96518512013-10-14 11:00:02 +0200404
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300405int nft_meta_set_dump(struct sk_buff *skb,
406 const struct nft_expr *expr)
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100407{
408 const struct nft_meta *priv = nft_expr_priv(expr);
409
410 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
411 goto nla_put_failure;
Patrick McHardyb1c96ed2015-04-11 02:27:36 +0100412 if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg))
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100413 goto nla_put_failure;
414
415 return 0;
416
417nla_put_failure:
418 return -1;
419}
Tomasz Bursztykaaa456602014-04-14 15:41:27 +0300420EXPORT_SYMBOL_GPL(nft_meta_set_dump);
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100421
Florian Westphale639f7a2015-11-28 21:53:05 +0100422void nft_meta_set_destroy(const struct nft_ctx *ctx,
423 const struct nft_expr *expr)
424{
425 const struct nft_meta *priv = nft_expr_priv(expr);
426
427 if (priv->key == NFT_META_NFTRACE)
428 static_branch_dec(&nft_trace_enabled);
429}
430EXPORT_SYMBOL_GPL(nft_meta_set_destroy);
431
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200432static struct nft_expr_type nft_meta_type;
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100433static const struct nft_expr_ops nft_meta_get_ops = {
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200434 .type = &nft_meta_type,
Patrick McHardy96518512013-10-14 11:00:02 +0200435 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100436 .eval = nft_meta_get_eval,
Patrick McHardyd2caa692014-03-29 10:43:02 +0000437 .init = nft_meta_get_init,
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100438 .dump = nft_meta_get_dump,
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200439};
440
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100441static const struct nft_expr_ops nft_meta_set_ops = {
442 .type = &nft_meta_type,
443 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
444 .eval = nft_meta_set_eval,
Patrick McHardyd2caa692014-03-29 10:43:02 +0000445 .init = nft_meta_set_init,
Florian Westphale639f7a2015-11-28 21:53:05 +0100446 .destroy = nft_meta_set_destroy,
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100447 .dump = nft_meta_set_dump,
Liping Zhang960fa722016-08-22 22:57:56 +0800448 .validate = nft_meta_set_validate,
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100449};
450
451static const struct nft_expr_ops *
452nft_meta_select_ops(const struct nft_ctx *ctx,
453 const struct nlattr * const tb[])
454{
455 if (tb[NFTA_META_KEY] == NULL)
456 return ERR_PTR(-EINVAL);
457
458 if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
459 return ERR_PTR(-EINVAL);
460
461 if (tb[NFTA_META_DREG])
462 return &nft_meta_get_ops;
463
464 if (tb[NFTA_META_SREG])
465 return &nft_meta_set_ops;
466
467 return ERR_PTR(-EINVAL);
468}
469
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200470static struct nft_expr_type nft_meta_type __read_mostly = {
471 .name = "meta",
Arturo Borrero Gonzaleze035b772013-12-26 16:38:01 +0100472 .select_ops = &nft_meta_select_ops,
Patrick McHardy96518512013-10-14 11:00:02 +0200473 .policy = nft_meta_policy,
474 .maxattr = NFTA_META_MAX,
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200475 .owner = THIS_MODULE,
Patrick McHardy96518512013-10-14 11:00:02 +0200476};
477
478static int __init nft_meta_module_init(void)
479{
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200480 return nft_register_expr(&nft_meta_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200481}
482
483static void __exit nft_meta_module_exit(void)
484{
Patrick McHardyef1f7df2013-10-10 11:41:20 +0200485 nft_unregister_expr(&nft_meta_type);
Patrick McHardy96518512013-10-14 11:00:02 +0200486}
487
488module_init(nft_meta_module_init);
489module_exit(nft_meta_module_exit);
490
491MODULE_LICENSE("GPL");
492MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
493MODULE_ALIAS_NFT_EXPR("meta");