Blame view

net/netfilter/nft_meta.c 19.7 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
96518518c   Patrick McHardy   netfilter: add nf...
2
  /*
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
3
   * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
bd2bbdb49   Florian Westphal   netfilter: merge ...
4
5
   * Copyright (c) 2014 Intel Corporation
   * Author: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
96518518c   Patrick McHardy   netfilter: add nf...
6
   *
96518518c   Patrick McHardy   netfilter: add nf...
7
8
9
10
   * Development of this code funded by Astaro AG (http://www.astaro.com/)
   */
  
  #include <linux/kernel.h>
96518518c   Patrick McHardy   netfilter: add nf...
11
12
13
  #include <linux/netlink.h>
  #include <linux/netfilter.h>
  #include <linux/netfilter/nf_tables.h>
e2a093ff0   Ana Rey   netfilter: nft_me...
14
15
16
  #include <linux/in.h>
  #include <linux/ip.h>
  #include <linux/ipv6.h>
afc5be307   Ana Rey   netfilter: nft_me...
17
  #include <linux/smp.h>
e639f7ab0   Florian Westphal   netfilter: nf_tab...
18
  #include <linux/static_key.h>
96518518c   Patrick McHardy   netfilter: add nf...
19
  #include <net/dst.h>
c14ceb0ec   Florian Westphal   netfilter: nft_me...
20
  #include <net/ip.h>
96518518c   Patrick McHardy   netfilter: add nf...
21
22
23
  #include <net/sock.h>
  #include <net/tcp_states.h> /* for TCP_TIME_WAIT */
  #include <net/netfilter/nf_tables.h>
e639f7ab0   Florian Westphal   netfilter: nf_tab...
24
  #include <net/netfilter/nf_tables_core.h>
30e103fe2   wenxu   netfilter: nft_me...
25
  #include <net/netfilter/nft_meta.h>
c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
26
  #include <net/netfilter/nf_tables_offload.h>
96518518c   Patrick McHardy   netfilter: add nf...
27

b4aae759c   Florian Westphal   netfilter: meta: ...
28
  #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
63d10e12b   Ander Juaristi   netfilter: nft_me...
29
30
31
32
  #define NFT_META_SECS_PER_MINUTE	60
  #define NFT_META_SECS_PER_HOUR		3600
  #define NFT_META_SECS_PER_DAY		86400
  #define NFT_META_DAYS_PER_WEEK		7
b07edbe1c   Florian Westphal   netfilter: meta: ...
33
  static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
db8f6f5c8   Florian Westphal   netfilter: nft_me...
34
  static u8 nft_meta_weekday(void)
63d10e12b   Ander Juaristi   netfilter: nft_me...
35
  {
db8f6f5c8   Florian Westphal   netfilter: nft_me...
36
  	time64_t secs = ktime_get_real_seconds();
63d10e12b   Ander Juaristi   netfilter: nft_me...
37
38
39
40
  	unsigned int dse;
  	u8 wday;
  
  	secs -= NFT_META_SECS_PER_MINUTE * sys_tz.tz_minuteswest;
6408c40c3   Arnd Bergmann   netfilter: nft_me...
41
  	dse = div_u64(secs, NFT_META_SECS_PER_DAY);
63d10e12b   Ander Juaristi   netfilter: nft_me...
42
43
44
45
  	wday = (4 + dse) % NFT_META_DAYS_PER_WEEK;
  
  	return wday;
  }
6408c40c3   Arnd Bergmann   netfilter: nft_me...
46
  static u32 nft_meta_hour(time64_t secs)
63d10e12b   Ander Juaristi   netfilter: nft_me...
47
48
49
50
51
52
53
54
55
  {
  	struct tm tm;
  
  	time64_to_tm(secs, 0, &tm);
  
  	return tm.tm_hour * NFT_META_SECS_PER_HOUR
  		+ tm.tm_min * NFT_META_SECS_PER_MINUTE
  		+ tm.tm_sec;
  }
db8f6f5c8   Florian Westphal   netfilter: nft_me...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  static noinline_for_stack void
  nft_meta_get_eval_time(enum nft_meta_keys key,
  		       u32 *dest)
  {
  	switch (key) {
  	case NFT_META_TIME_NS:
  		nft_reg_store64(dest, ktime_get_real_ns());
  		break;
  	case NFT_META_TIME_DAY:
  		nft_reg_store8(dest, nft_meta_weekday());
  		break;
  	case NFT_META_TIME_HOUR:
  		*dest = nft_meta_hour(ktime_get_real_seconds());
  		break;
  	default:
  		break;
  	}
  }
4a54594ab   Florian Westphal   netfilter: nft_me...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  static noinline bool
  nft_meta_get_eval_pkttype_lo(const struct nft_pktinfo *pkt,
  			     u32 *dest)
  {
  	const struct sk_buff *skb = pkt->skb;
  
  	switch (nft_pf(pkt)) {
  	case NFPROTO_IPV4:
  		if (ipv4_is_multicast(ip_hdr(skb)->daddr))
  			nft_reg_store8(dest, PACKET_MULTICAST);
  		else
  			nft_reg_store8(dest, PACKET_BROADCAST);
  		break;
  	case NFPROTO_IPV6:
  		nft_reg_store8(dest, PACKET_MULTICAST);
  		break;
  	case NFPROTO_NETDEV:
  		switch (skb->protocol) {
  		case htons(ETH_P_IP): {
  			int noff = skb_network_offset(skb);
  			struct iphdr *iph, _iph;
  
  			iph = skb_header_pointer(skb, noff,
  						 sizeof(_iph), &_iph);
  			if (!iph)
  				return false;
  
  			if (ipv4_is_multicast(iph->daddr))
  				nft_reg_store8(dest, PACKET_MULTICAST);
  			else
  				nft_reg_store8(dest, PACKET_BROADCAST);
  
  			break;
  		}
  		case htons(ETH_P_IPV6):
  			nft_reg_store8(dest, PACKET_MULTICAST);
  			break;
  		default:
  			WARN_ON_ONCE(1);
  			return false;
  		}
  		break;
  	default:
  		WARN_ON_ONCE(1);
  		return false;
  	}
  
  	return true;
  }
726b44f04   Florian Westphal   netfilter: nft_me...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  static noinline bool
  nft_meta_get_eval_skugid(enum nft_meta_keys key,
  			 u32 *dest,
  			 const struct nft_pktinfo *pkt)
  {
  	struct sock *sk = skb_to_full_sk(pkt->skb);
  	struct socket *sock;
  
  	if (!sk || !sk_fullsock(sk) || !net_eq(nft_net(pkt), sock_net(sk)))
  		return false;
  
  	read_lock_bh(&sk->sk_callback_lock);
  	sock = sk->sk_socket;
  	if (!sock || !sock->file) {
  		read_unlock_bh(&sk->sk_callback_lock);
  		return false;
  	}
  
  	switch (key) {
  	case NFT_META_SKUID:
0c92411bb   Pablo Neira Ayuso   netfilter: nft_me...
143
  		*dest = from_kuid_munged(sock_net(sk)->user_ns,
726b44f04   Florian Westphal   netfilter: nft_me...
144
145
146
  					 sock->file->f_cred->fsuid);
  		break;
  	case NFT_META_SKGID:
0c92411bb   Pablo Neira Ayuso   netfilter: nft_me...
147
  		*dest =	from_kgid_munged(sock_net(sk)->user_ns,
726b44f04   Florian Westphal   netfilter: nft_me...
148
149
150
151
152
153
154
155
156
  					 sock->file->f_cred->fsgid);
  		break;
  	default:
  		break;
  	}
  
  	read_unlock_bh(&sk->sk_callback_lock);
  	return true;
  }
b1327fbc2   Florian Westphal   netfilter: nft_me...
157
158
159
160
161
162
163
164
165
166
167
168
169
  #ifdef CONFIG_CGROUP_NET_CLASSID
  static noinline bool
  nft_meta_get_eval_cgroup(u32 *dest, const struct nft_pktinfo *pkt)
  {
  	struct sock *sk = skb_to_full_sk(pkt->skb);
  
  	if (!sk || !sk_fullsock(sk) || !net_eq(nft_net(pkt), sock_net(sk)))
  		return false;
  
  	*dest = sock_cgroup_classid(&sk->sk_cgrp_data);
  	return true;
  }
  #endif
a4150a1fa   Florian Westphal   netfilter: nft_me...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
  static noinline bool nft_meta_get_eval_kind(enum nft_meta_keys key,
  					    u32 *dest,
  					    const struct nft_pktinfo *pkt)
  {
  	const struct net_device *in = nft_in(pkt), *out = nft_out(pkt);
  
  	switch (key) {
  	case NFT_META_IIFKIND:
  		if (!in || !in->rtnl_link_ops)
  			return false;
  		strncpy((char *)dest, in->rtnl_link_ops->kind, IFNAMSIZ);
  		break;
  	case NFT_META_OIFKIND:
  		if (!out || !out->rtnl_link_ops)
  			return false;
  		strncpy((char *)dest, out->rtnl_link_ops->kind, IFNAMSIZ);
  		break;
  	default:
  		return false;
  	}
  
  	return true;
  }
8724e819c   Florian Westphal   netfilter: nft_me...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  static void nft_meta_store_ifindex(u32 *dest, const struct net_device *dev)
  {
  	*dest = dev ? dev->ifindex : 0;
  }
  
  static void nft_meta_store_ifname(u32 *dest, const struct net_device *dev)
  {
  	strncpy((char *)dest, dev ? dev->name : "", IFNAMSIZ);
  }
  
  static bool nft_meta_store_iftype(u32 *dest, const struct net_device *dev)
  {
  	if (!dev)
  		return false;
  
  	nft_reg_store16(dest, dev->type);
  	return true;
  }
  
  static bool nft_meta_store_ifgroup(u32 *dest, const struct net_device *dev)
  {
  	if (!dev)
  		return false;
  
  	*dest = dev->group;
  	return true;
  }
  
  static bool nft_meta_get_eval_ifname(enum nft_meta_keys key, u32 *dest,
  				     const struct nft_pktinfo *pkt)
  {
  	switch (key) {
  	case NFT_META_IIFNAME:
  		nft_meta_store_ifname(dest, nft_in(pkt));
  		break;
  	case NFT_META_OIFNAME:
  		nft_meta_store_ifname(dest, nft_out(pkt));
  		break;
  	case NFT_META_IIF:
  		nft_meta_store_ifindex(dest, nft_in(pkt));
  		break;
  	case NFT_META_OIF:
  		nft_meta_store_ifindex(dest, nft_out(pkt));
  		break;
  	case NFT_META_IIFTYPE:
  		if (!nft_meta_store_iftype(dest, nft_in(pkt)))
  			return false;
  		break;
  	case NFT_META_OIFTYPE:
  		if (!nft_meta_store_iftype(dest, nft_out(pkt)))
  			return false;
  		break;
  	case NFT_META_IIFGROUP:
78470d9d0   Florian Westphal   netfilter: nft_me...
246
  		if (!nft_meta_store_ifgroup(dest, nft_in(pkt)))
8724e819c   Florian Westphal   netfilter: nft_me...
247
248
249
250
251
252
253
254
255
256
257
258
  			return false;
  		break;
  	case NFT_META_OIFGROUP:
  		if (!nft_meta_store_ifgroup(dest, nft_out(pkt)))
  			return false;
  		break;
  	default:
  		return false;
  	}
  
  	return true;
  }
6b2faee0c   Florian Westphal   netfilter: nft_me...
259
260
261
262
263
264
  static noinline u32 nft_prandom_u32(void)
  {
  	struct rnd_state *state = this_cpu_ptr(&nft_prandom_state);
  
  	return prandom_u32_state(state);
  }
01a0fc822   Florian Westphal   netfilter: nft_me...
265
266
267
268
269
270
271
272
273
274
275
276
277
  #ifdef CONFIG_IP_ROUTE_CLASSID
  static noinline bool
  nft_meta_get_eval_rtclassid(const struct sk_buff *skb, u32 *dest)
  {
  	const struct dst_entry *dst = skb_dst(skb);
  
  	if (!dst)
  		return false;
  
  	*dest = dst->tclassid;
  	return true;
  }
  #endif
c14ceb0ec   Florian Westphal   netfilter: nft_me...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  static noinline u32 nft_meta_get_eval_sdif(const struct nft_pktinfo *pkt)
  {
  	switch (nft_pf(pkt)) {
  	case NFPROTO_IPV4:
  		return inet_sdif(pkt->skb);
  	case NFPROTO_IPV6:
  		return inet6_sdif(pkt->skb);
  	}
  
  	return 0;
  }
  
  static noinline void
  nft_meta_get_eval_sdifname(u32 *dest, const struct nft_pktinfo *pkt)
  {
  	u32 sdif = nft_meta_get_eval_sdif(pkt);
  	const struct net_device *dev;
  
  	dev = sdif ? dev_get_by_index_rcu(nft_net(pkt), sdif) : NULL;
  	nft_meta_store_ifname(dest, dev);
  }
222440b4e   Florian Westphal   netfilter: nf_tab...
299
300
301
  void nft_meta_get_eval(const struct nft_expr *expr,
  		       struct nft_regs *regs,
  		       const struct nft_pktinfo *pkt)
96518518c   Patrick McHardy   netfilter: add nf...
302
303
304
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
  	const struct sk_buff *skb = pkt->skb;
49499c3e6   Patrick McHardy   netfilter: nf_tab...
305
  	u32 *dest = &regs->data[priv->dreg];
96518518c   Patrick McHardy   netfilter: add nf...
306
307
308
  
  	switch (priv->key) {
  	case NFT_META_LEN:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
309
  		*dest = skb->len;
96518518c   Patrick McHardy   netfilter: add nf...
310
311
  		break;
  	case NFT_META_PROTOCOL:
10596608c   Liping Zhang   netfilter: nf_tab...
312
  		nft_reg_store16(dest, (__force u16)skb->protocol);
96518518c   Patrick McHardy   netfilter: add nf...
313
  		break;
124edfa9e   Patrick McHardy   netfilter: nf_tab...
314
  	case NFT_META_NFPROTO:
10596608c   Liping Zhang   netfilter: nf_tab...
315
  		nft_reg_store8(dest, nft_pf(pkt));
124edfa9e   Patrick McHardy   netfilter: nf_tab...
316
  		break;
4566bf270   Patrick McHardy   netfilter: nft_me...
317
  	case NFT_META_L4PROTO:
beac5afa2   Pablo Neira Ayuso   netfilter: nf_tab...
318
319
  		if (!pkt->tprot_set)
  			goto err;
10596608c   Liping Zhang   netfilter: nf_tab...
320
  		nft_reg_store8(dest, pkt->tprot);
4566bf270   Patrick McHardy   netfilter: nft_me...
321
  		break;
96518518c   Patrick McHardy   netfilter: add nf...
322
  	case NFT_META_PRIORITY:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
323
  		*dest = skb->priority;
96518518c   Patrick McHardy   netfilter: add nf...
324
325
  		break;
  	case NFT_META_MARK:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
326
  		*dest = skb->mark;
96518518c   Patrick McHardy   netfilter: add nf...
327
328
  		break;
  	case NFT_META_IIF:
96518518c   Patrick McHardy   netfilter: add nf...
329
  	case NFT_META_OIF:
96518518c   Patrick McHardy   netfilter: add nf...
330
  	case NFT_META_IIFNAME:
96518518c   Patrick McHardy   netfilter: add nf...
331
  	case NFT_META_OIFNAME:
96518518c   Patrick McHardy   netfilter: add nf...
332
  	case NFT_META_IIFTYPE:
96518518c   Patrick McHardy   netfilter: add nf...
333
  	case NFT_META_OIFTYPE:
8724e819c   Florian Westphal   netfilter: nft_me...
334
335
336
  	case NFT_META_IIFGROUP:
  	case NFT_META_OIFGROUP:
  		if (!nft_meta_get_eval_ifname(priv->key, dest, pkt))
96518518c   Patrick McHardy   netfilter: add nf...
337
  			goto err;
96518518c   Patrick McHardy   netfilter: add nf...
338
339
  		break;
  	case NFT_META_SKUID:
96518518c   Patrick McHardy   netfilter: add nf...
340
  	case NFT_META_SKGID:
726b44f04   Florian Westphal   netfilter: nft_me...
341
  		if (!nft_meta_get_eval_skugid(priv->key, dest, pkt))
96518518c   Patrick McHardy   netfilter: add nf...
342
  			goto err;
96518518c   Patrick McHardy   netfilter: add nf...
343
  		break;
06efbd6d5   Paul Bolle   netfilter: nft_me...
344
  #ifdef CONFIG_IP_ROUTE_CLASSID
01a0fc822   Florian Westphal   netfilter: nft_me...
345
346
  	case NFT_META_RTCLASSID:
  		if (!nft_meta_get_eval_rtclassid(skb, dest))
96518518c   Patrick McHardy   netfilter: add nf...
347
  			goto err;
96518518c   Patrick McHardy   netfilter: add nf...
348
  		break;
96518518c   Patrick McHardy   netfilter: add nf...
349
350
351
  #endif
  #ifdef CONFIG_NETWORK_SECMARK
  	case NFT_META_SECMARK:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
352
  		*dest = skb->secmark;
96518518c   Patrick McHardy   netfilter: add nf...
353
354
  		break;
  #endif
e2a093ff0   Ana Rey   netfilter: nft_me...
355
356
  	case NFT_META_PKTTYPE:
  		if (skb->pkt_type != PACKET_LOOPBACK) {
10596608c   Liping Zhang   netfilter: nf_tab...
357
  			nft_reg_store8(dest, skb->pkt_type);
e2a093ff0   Ana Rey   netfilter: nft_me...
358
359
  			break;
  		}
4a54594ab   Florian Westphal   netfilter: nft_me...
360
  		if (!nft_meta_get_eval_pkttype_lo(pkt, dest))
e2a093ff0   Ana Rey   netfilter: nft_me...
361
  			goto err;
e2a093ff0   Ana Rey   netfilter: nft_me...
362
  		break;
afc5be307   Ana Rey   netfilter: nft_me...
363
  	case NFT_META_CPU:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
364
  		*dest = raw_smp_processor_id();
afc5be307   Ana Rey   netfilter: nft_me...
365
  		break;
e181a5430   Mathias Krause   net: #ifdefify sk...
366
  #ifdef CONFIG_CGROUP_NET_CLASSID
ce674173e   Ana Rey   netfilter: nft_me...
367
  	case NFT_META_CGROUP:
b1327fbc2   Florian Westphal   netfilter: nft_me...
368
  		if (!nft_meta_get_eval_cgroup(dest, pkt))
c5035c77f   Pablo Neira Ayuso   netfilter: nft_me...
369
  			goto err;
ce674173e   Ana Rey   netfilter: nft_me...
370
  		break;
e181a5430   Mathias Krause   net: #ifdefify sk...
371
  #endif
6b2faee0c   Florian Westphal   netfilter: nft_me...
372
373
  	case NFT_META_PRANDOM:
  		*dest = nft_prandom_u32();
b07edbe1c   Florian Westphal   netfilter: meta: ...
374
  		break;
f6931f5f5   Florian Westphal   netfilter: meta: ...
375
376
  #ifdef CONFIG_XFRM
  	case NFT_META_SECPATH:
7af8f4ca3   Florian Westphal   net: move secpath...
377
  		nft_reg_store8(dest, secpath_exists(skb));
f6931f5f5   Florian Westphal   netfilter: meta: ...
378
379
  		break;
  #endif
0fb4d2195   wenxu   netfilter: nft_me...
380
  	case NFT_META_IIFKIND:
0fb4d2195   wenxu   netfilter: nft_me...
381
  	case NFT_META_OIFKIND:
a4150a1fa   Florian Westphal   netfilter: nft_me...
382
  		if (!nft_meta_get_eval_kind(priv->key, dest, pkt))
0fb4d2195   wenxu   netfilter: nft_me...
383
  			goto err;
0fb4d2195   wenxu   netfilter: nft_me...
384
  		break;
63d10e12b   Ander Juaristi   netfilter: nft_me...
385
  	case NFT_META_TIME_NS:
63d10e12b   Ander Juaristi   netfilter: nft_me...
386
  	case NFT_META_TIME_DAY:
63d10e12b   Ander Juaristi   netfilter: nft_me...
387
  	case NFT_META_TIME_HOUR:
db8f6f5c8   Florian Westphal   netfilter: nft_me...
388
  		nft_meta_get_eval_time(priv->key, dest);
63d10e12b   Ander Juaristi   netfilter: nft_me...
389
  		break;
c14ceb0ec   Florian Westphal   netfilter: nft_me...
390
391
392
393
394
395
  	case NFT_META_SDIF:
  		*dest = nft_meta_get_eval_sdif(pkt);
  		break;
  	case NFT_META_SDIFNAME:
  		nft_meta_get_eval_sdifname(dest, pkt);
  		break;
96518518c   Patrick McHardy   netfilter: add nf...
396
397
398
399
400
401
402
  	default:
  		WARN_ON(1);
  		goto err;
  	}
  	return;
  
  err:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
403
  	regs->verdict.code = NFT_BREAK;
96518518c   Patrick McHardy   netfilter: add nf...
404
  }
30e103fe2   wenxu   netfilter: nft_me...
405
  EXPORT_SYMBOL_GPL(nft_meta_get_eval);
96518518c   Patrick McHardy   netfilter: add nf...
406

30e103fe2   wenxu   netfilter: nft_me...
407
408
409
  void nft_meta_set_eval(const struct nft_expr *expr,
  		       struct nft_regs *regs,
  		       const struct nft_pktinfo *pkt)
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
410
411
412
  {
  	const struct nft_meta *meta = nft_expr_priv(expr);
  	struct sk_buff *skb = pkt->skb;
10596608c   Liping Zhang   netfilter: nf_tab...
413
414
  	u32 *sreg = &regs->data[meta->sreg];
  	u32 value = *sreg;
97a0549b1   Taehee Yoo   netfilter: nft_me...
415
  	u8 value8;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
416
417
418
419
420
421
422
423
  
  	switch (meta->key) {
  	case NFT_META_MARK:
  		skb->mark = value;
  		break;
  	case NFT_META_PRIORITY:
  		skb->priority = value;
  		break;
b4aae759c   Florian Westphal   netfilter: meta: ...
424
  	case NFT_META_PKTTYPE:
97a0549b1   Taehee Yoo   netfilter: nft_me...
425
  		value8 = nft_reg_load8(sreg);
10596608c   Liping Zhang   netfilter: nf_tab...
426

97a0549b1   Taehee Yoo   netfilter: nft_me...
427
428
  		if (skb->pkt_type != value8 &&
  		    skb_pkt_type_ok(value8) &&
10596608c   Liping Zhang   netfilter: nf_tab...
429
  		    skb_pkt_type_ok(skb->pkt_type))
97a0549b1   Taehee Yoo   netfilter: nft_me...
430
  			skb->pkt_type = value8;
b4aae759c   Florian Westphal   netfilter: meta: ...
431
  		break;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
432
  	case NFT_META_NFTRACE:
97a0549b1   Taehee Yoo   netfilter: nft_me...
433
434
435
  		value8 = nft_reg_load8(sreg);
  
  		skb->nf_trace = !!value8;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
436
  		break;
b473a1f5d   Christian Göttsche   netfilter: nf_tab...
437
438
439
440
441
  #ifdef CONFIG_NETWORK_SECMARK
  	case NFT_META_SECMARK:
  		skb->secmark = value;
  		break;
  #endif
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
442
443
444
445
  	default:
  		WARN_ON(1);
  	}
  }
30e103fe2   wenxu   netfilter: nft_me...
446
  EXPORT_SYMBOL_GPL(nft_meta_set_eval);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
447

30e103fe2   wenxu   netfilter: nft_me...
448
  const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
96518518c   Patrick McHardy   netfilter: add nf...
449
450
  	[NFTA_META_DREG]	= { .type = NLA_U32 },
  	[NFTA_META_KEY]		= { .type = NLA_U32 },
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
451
  	[NFTA_META_SREG]	= { .type = NLA_U32 },
96518518c   Patrick McHardy   netfilter: add nf...
452
  };
30e103fe2   wenxu   netfilter: nft_me...
453
  EXPORT_SYMBOL_GPL(nft_meta_policy);
96518518c   Patrick McHardy   netfilter: add nf...
454

30e103fe2   wenxu   netfilter: nft_me...
455
456
457
  int nft_meta_get_init(const struct nft_ctx *ctx,
  		      const struct nft_expr *expr,
  		      const struct nlattr * const tb[])
96518518c   Patrick McHardy   netfilter: add nf...
458
  {
d2caa696a   Patrick McHardy   netfilter: nft_me...
459
  	struct nft_meta *priv = nft_expr_priv(expr);
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
460
  	unsigned int len;
96518518c   Patrick McHardy   netfilter: add nf...
461

d2caa696a   Patrick McHardy   netfilter: nft_me...
462
463
  	priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
  	switch (priv->key) {
96518518c   Patrick McHardy   netfilter: add nf...
464
  	case NFT_META_PROTOCOL:
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
465
466
467
468
  	case NFT_META_IIFTYPE:
  	case NFT_META_OIFTYPE:
  		len = sizeof(u16);
  		break;
124edfa9e   Patrick McHardy   netfilter: nf_tab...
469
  	case NFT_META_NFPROTO:
4566bf270   Patrick McHardy   netfilter: nft_me...
470
  	case NFT_META_L4PROTO:
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
471
  	case NFT_META_LEN:
96518518c   Patrick McHardy   netfilter: add nf...
472
473
474
475
  	case NFT_META_PRIORITY:
  	case NFT_META_MARK:
  	case NFT_META_IIF:
  	case NFT_META_OIF:
c14ceb0ec   Florian Westphal   netfilter: nft_me...
476
  	case NFT_META_SDIF:
96518518c   Patrick McHardy   netfilter: add nf...
477
478
  	case NFT_META_SKUID:
  	case NFT_META_SKGID:
06efbd6d5   Paul Bolle   netfilter: nft_me...
479
  #ifdef CONFIG_IP_ROUTE_CLASSID
96518518c   Patrick McHardy   netfilter: add nf...
480
481
482
483
484
  	case NFT_META_RTCLASSID:
  #endif
  #ifdef CONFIG_NETWORK_SECMARK
  	case NFT_META_SECMARK:
  #endif
e2a093ff0   Ana Rey   netfilter: nft_me...
485
  	case NFT_META_PKTTYPE:
afc5be307   Ana Rey   netfilter: nft_me...
486
  	case NFT_META_CPU:
3045d7607   Ana Rey   netfilter: nf_tab...
487
488
  	case NFT_META_IIFGROUP:
  	case NFT_META_OIFGROUP:
e181a5430   Mathias Krause   net: #ifdefify sk...
489
  #ifdef CONFIG_CGROUP_NET_CLASSID
ce674173e   Ana Rey   netfilter: nft_me...
490
  	case NFT_META_CGROUP:
e181a5430   Mathias Krause   net: #ifdefify sk...
491
  #endif
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
492
493
494
495
  		len = sizeof(u32);
  		break;
  	case NFT_META_IIFNAME:
  	case NFT_META_OIFNAME:
0fb4d2195   wenxu   netfilter: nft_me...
496
497
  	case NFT_META_IIFKIND:
  	case NFT_META_OIFKIND:
c14ceb0ec   Florian Westphal   netfilter: nft_me...
498
  	case NFT_META_SDIFNAME:
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
499
  		len = IFNAMSIZ;
d2caa696a   Patrick McHardy   netfilter: nft_me...
500
  		break;
b07edbe1c   Florian Westphal   netfilter: meta: ...
501
502
503
504
  	case NFT_META_PRANDOM:
  		prandom_init_once(&nft_prandom_state);
  		len = sizeof(u32);
  		break;
f6931f5f5   Florian Westphal   netfilter: meta: ...
505
506
507
508
509
  #ifdef CONFIG_XFRM
  	case NFT_META_SECPATH:
  		len = sizeof(u8);
  		break;
  #endif
63d10e12b   Ander Juaristi   netfilter: nft_me...
510
511
512
513
514
515
516
517
518
  	case NFT_META_TIME_NS:
  		len = sizeof(u64);
  		break;
  	case NFT_META_TIME_DAY:
  		len = sizeof(u8);
  		break;
  	case NFT_META_TIME_HOUR:
  		len = sizeof(u32);
  		break;
96518518c   Patrick McHardy   netfilter: add nf...
519
520
521
  	default:
  		return -EOPNOTSUPP;
  	}
b1c96ed37   Patrick McHardy   netfilter: nf_tab...
522
  	priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
27e6d2017   Patrick McHardy   netfilter: nf_tab...
523
524
  	return nft_validate_register_store(ctx, priv->dreg, NULL,
  					   NFT_DATA_VALUE, len);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
525
  }
30e103fe2   wenxu   netfilter: nft_me...
526
  EXPORT_SYMBOL_GPL(nft_meta_get_init);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
527

c14ceb0ec   Florian Westphal   netfilter: nft_me...
528
  static int nft_meta_get_validate_sdif(const struct nft_ctx *ctx)
f6931f5f5   Florian Westphal   netfilter: meta: ...
529
  {
f6931f5f5   Florian Westphal   netfilter: meta: ...
530
  	unsigned int hooks;
c14ceb0ec   Florian Westphal   netfilter: nft_me...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
  	switch (ctx->family) {
  	case NFPROTO_IPV4:
  	case NFPROTO_IPV6:
  	case NFPROTO_INET:
  		hooks = (1 << NF_INET_LOCAL_IN) |
  			(1 << NF_INET_FORWARD);
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	return nft_chain_validate_hooks(ctx->chain, hooks);
  }
  
  static int nft_meta_get_validate_xfrm(const struct nft_ctx *ctx)
  {
  #ifdef CONFIG_XFRM
  	unsigned int hooks;
f6931f5f5   Florian Westphal   netfilter: meta: ...
549

36596dadf   Pablo Neira Ayuso   netfilter: nf_tab...
550
  	switch (ctx->family) {
f6931f5f5   Florian Westphal   netfilter: meta: ...
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  	case NFPROTO_NETDEV:
  		hooks = 1 << NF_NETDEV_INGRESS;
  		break;
  	case NFPROTO_IPV4:
  	case NFPROTO_IPV6:
  	case NFPROTO_INET:
  		hooks = (1 << NF_INET_PRE_ROUTING) |
  			(1 << NF_INET_LOCAL_IN) |
  			(1 << NF_INET_FORWARD);
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	return nft_chain_validate_hooks(ctx->chain, hooks);
  #else
  	return 0;
  #endif
  }
c14ceb0ec   Florian Westphal   netfilter: nft_me...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
  static int nft_meta_get_validate(const struct nft_ctx *ctx,
  				 const struct nft_expr *expr,
  				 const struct nft_data **data)
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
  
  	switch (priv->key) {
  	case NFT_META_SECPATH:
  		return nft_meta_get_validate_xfrm(ctx);
  	case NFT_META_SDIF:
  	case NFT_META_SDIFNAME:
  		return nft_meta_get_validate_sdif(ctx);
  	default:
  		break;
  	}
  
  	return 0;
  }
30e103fe2   wenxu   netfilter: nft_me...
588
589
590
  int nft_meta_set_validate(const struct nft_ctx *ctx,
  			  const struct nft_expr *expr,
  			  const struct nft_data **data)
b4aae759c   Florian Westphal   netfilter: meta: ...
591
  {
960fa72f6   Liping Zhang   netfilter: nft_me...
592
  	struct nft_meta *priv = nft_expr_priv(expr);
b4aae759c   Florian Westphal   netfilter: meta: ...
593
  	unsigned int hooks;
960fa72f6   Liping Zhang   netfilter: nft_me...
594
595
  	if (priv->key != NFT_META_PKTTYPE)
  		return 0;
36596dadf   Pablo Neira Ayuso   netfilter: nf_tab...
596
  	switch (ctx->family) {
b4aae759c   Florian Westphal   netfilter: meta: ...
597
598
599
600
601
602
  	case NFPROTO_BRIDGE:
  		hooks = 1 << NF_BR_PRE_ROUTING;
  		break;
  	case NFPROTO_NETDEV:
  		hooks = 1 << NF_NETDEV_INGRESS;
  		break;
96d9f2a72   Liping Zhang   netfilter: nft_me...
603
604
605
606
607
  	case NFPROTO_IPV4:
  	case NFPROTO_IPV6:
  	case NFPROTO_INET:
  		hooks = 1 << NF_INET_PRE_ROUTING;
  		break;
b4aae759c   Florian Westphal   netfilter: meta: ...
608
609
610
611
612
613
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	return nft_chain_validate_hooks(ctx->chain, hooks);
  }
30e103fe2   wenxu   netfilter: nft_me...
614
  EXPORT_SYMBOL_GPL(nft_meta_set_validate);
b4aae759c   Florian Westphal   netfilter: meta: ...
615

30e103fe2   wenxu   netfilter: nft_me...
616
617
618
  int nft_meta_set_init(const struct nft_ctx *ctx,
  		      const struct nft_expr *expr,
  		      const struct nlattr * const tb[])
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
619
620
  {
  	struct nft_meta *priv = nft_expr_priv(expr);
d07db9884   Patrick McHardy   netfilter: nf_tab...
621
  	unsigned int len;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
622
623
624
  	int err;
  
  	priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
d2caa696a   Patrick McHardy   netfilter: nft_me...
625
626
627
  	switch (priv->key) {
  	case NFT_META_MARK:
  	case NFT_META_PRIORITY:
b473a1f5d   Christian Göttsche   netfilter: nf_tab...
628
629
630
  #ifdef CONFIG_NETWORK_SECMARK
  	case NFT_META_SECMARK:
  #endif
d07db9884   Patrick McHardy   netfilter: nf_tab...
631
632
  		len = sizeof(u32);
  		break;
d2caa696a   Patrick McHardy   netfilter: nft_me...
633
  	case NFT_META_NFTRACE:
d07db9884   Patrick McHardy   netfilter: nf_tab...
634
  		len = sizeof(u8);
d2caa696a   Patrick McHardy   netfilter: nft_me...
635
  		break;
b4aae759c   Florian Westphal   netfilter: meta: ...
636
  	case NFT_META_PKTTYPE:
b4aae759c   Florian Westphal   netfilter: meta: ...
637
638
  		len = sizeof(u8);
  		break;
d2caa696a   Patrick McHardy   netfilter: nft_me...
639
640
  	default:
  		return -EOPNOTSUPP;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
641
  	}
b1c96ed37   Patrick McHardy   netfilter: nf_tab...
642
  	priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
d07db9884   Patrick McHardy   netfilter: nf_tab...
643
  	err = nft_validate_register_load(priv->sreg, len);
b38895c57   Pablo Neira Ayuso   netfilter: nft_me...
644
645
  	if (err < 0)
  		return err;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
646

e639f7ab0   Florian Westphal   netfilter: nf_tab...
647
648
  	if (priv->key == NFT_META_NFTRACE)
  		static_branch_inc(&nft_trace_enabled);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
649
  	return 0;
96518518c   Patrick McHardy   netfilter: add nf...
650
  }
30e103fe2   wenxu   netfilter: nft_me...
651
  EXPORT_SYMBOL_GPL(nft_meta_set_init);
96518518c   Patrick McHardy   netfilter: add nf...
652

30e103fe2   wenxu   netfilter: nft_me...
653
654
  int nft_meta_get_dump(struct sk_buff *skb,
  		      const struct nft_expr *expr)
96518518c   Patrick McHardy   netfilter: add nf...
655
656
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
657
658
  	if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
  		goto nla_put_failure;
b1c96ed37   Patrick McHardy   netfilter: nf_tab...
659
  	if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg))
96518518c   Patrick McHardy   netfilter: add nf...
660
  		goto nla_put_failure;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
661
662
663
664
665
  	return 0;
  
  nla_put_failure:
  	return -1;
  }
30e103fe2   wenxu   netfilter: nft_me...
666
  EXPORT_SYMBOL_GPL(nft_meta_get_dump);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
667

30e103fe2   wenxu   netfilter: nft_me...
668
  int nft_meta_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
669
670
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
96518518c   Patrick McHardy   netfilter: add nf...
671
672
  	if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
  		goto nla_put_failure;
b1c96ed37   Patrick McHardy   netfilter: nf_tab...
673
  	if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg))
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
674
  		goto nla_put_failure;
96518518c   Patrick McHardy   netfilter: add nf...
675
676
677
678
679
  	return 0;
  
  nla_put_failure:
  	return -1;
  }
30e103fe2   wenxu   netfilter: nft_me...
680
  EXPORT_SYMBOL_GPL(nft_meta_set_dump);
96518518c   Patrick McHardy   netfilter: add nf...
681

30e103fe2   wenxu   netfilter: nft_me...
682
683
  void nft_meta_set_destroy(const struct nft_ctx *ctx,
  			  const struct nft_expr *expr)
e639f7ab0   Florian Westphal   netfilter: nf_tab...
684
685
686
687
688
689
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
  
  	if (priv->key == NFT_META_NFTRACE)
  		static_branch_dec(&nft_trace_enabled);
  }
30e103fe2   wenxu   netfilter: nft_me...
690
  EXPORT_SYMBOL_GPL(nft_meta_set_destroy);
e639f7ab0   Florian Westphal   netfilter: nf_tab...
691

c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
692
693
694
695
696
697
698
699
700
  static int nft_meta_get_offload(struct nft_offload_ctx *ctx,
  				struct nft_flow_rule *flow,
  				const struct nft_expr *expr)
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
  	struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
  
  	switch (priv->key) {
  	case NFT_META_PROTOCOL:
a5d45bc0d   Pablo Neira Ayuso   netfilter: nftabl...
701
702
  		NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_BASIC, basic, n_proto,
  					sizeof(__u16), reg);
c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
703
704
705
  		nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_NETWORK);
  		break;
  	case NFT_META_L4PROTO:
a5d45bc0d   Pablo Neira Ayuso   netfilter: nftabl...
706
707
  		NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
  					sizeof(__u8), reg);
c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
708
709
  		nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
  		break;
25da5eb32   Pablo Neira Ayuso   netfilter: nft_me...
710
  	case NFT_META_IIF:
a5d45bc0d   Pablo Neira Ayuso   netfilter: nftabl...
711
712
  		NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_META, meta,
  					ingress_ifindex, sizeof(__u32), reg);
25da5eb32   Pablo Neira Ayuso   netfilter: nft_me...
713
  		break;
8819efc94   Pablo Neira Ayuso   netfilter: nf_tab...
714
  	case NFT_META_IIFTYPE:
a5d45bc0d   Pablo Neira Ayuso   netfilter: nftabl...
715
716
  		NFT_OFFLOAD_MATCH_EXACT(FLOW_DISSECTOR_KEY_META, meta,
  					ingress_iftype, sizeof(__u16), reg);
8819efc94   Pablo Neira Ayuso   netfilter: nf_tab...
717
  		break;
c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
718
719
720
721
722
723
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	return 0;
  }
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
724
  static const struct nft_expr_ops nft_meta_get_ops = {
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
725
  	.type		= &nft_meta_type,
96518518c   Patrick McHardy   netfilter: add nf...
726
  	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
727
  	.eval		= nft_meta_get_eval,
d2caa696a   Patrick McHardy   netfilter: nft_me...
728
  	.init		= nft_meta_get_init,
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
729
  	.dump		= nft_meta_get_dump,
f6931f5f5   Florian Westphal   netfilter: meta: ...
730
  	.validate	= nft_meta_get_validate,
c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
731
  	.offload	= nft_meta_get_offload,
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
732
  };
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
733
734
735
736
  static const struct nft_expr_ops nft_meta_set_ops = {
  	.type		= &nft_meta_type,
  	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
  	.eval		= nft_meta_set_eval,
d2caa696a   Patrick McHardy   netfilter: nft_me...
737
  	.init		= nft_meta_set_init,
e639f7ab0   Florian Westphal   netfilter: nf_tab...
738
  	.destroy	= nft_meta_set_destroy,
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
739
  	.dump		= nft_meta_set_dump,
960fa72f6   Liping Zhang   netfilter: nft_me...
740
  	.validate	= nft_meta_set_validate,
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
741
742
743
744
745
746
747
748
749
750
751
  };
  
  static const struct nft_expr_ops *
  nft_meta_select_ops(const struct nft_ctx *ctx,
  		    const struct nlattr * const tb[])
  {
  	if (tb[NFTA_META_KEY] == NULL)
  		return ERR_PTR(-EINVAL);
  
  	if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
  		return ERR_PTR(-EINVAL);
dfee0e99b   Arnd Bergmann   netfilter: bridge...
752
  #if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE) && IS_MODULE(CONFIG_NFT_BRIDGE_META)
0ef1efd13   Pablo Neira Ayuso   netfilter: nf_tab...
753
754
755
  	if (ctx->family == NFPROTO_BRIDGE)
  		return ERR_PTR(-EAGAIN);
  #endif
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
756
757
758
759
760
761
762
763
  	if (tb[NFTA_META_DREG])
  		return &nft_meta_get_ops;
  
  	if (tb[NFTA_META_SREG])
  		return &nft_meta_set_ops;
  
  	return ERR_PTR(-EINVAL);
  }
8a22543c8   Florian Westphal   netfilter: nf_tab...
764
  struct nft_expr_type nft_meta_type __read_mostly = {
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
765
  	.name		= "meta",
d4ef38354   Arushi Singhal   netfilter: Remove...
766
  	.select_ops	= nft_meta_select_ops,
96518518c   Patrick McHardy   netfilter: add nf...
767
768
  	.policy		= nft_meta_policy,
  	.maxattr	= NFTA_META_MAX,
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
769
  	.owner		= THIS_MODULE,
96518518c   Patrick McHardy   netfilter: add nf...
770
  };
fb9619454   Christian Göttsche   netfilter: nf_tab...
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
  
  #ifdef CONFIG_NETWORK_SECMARK
  struct nft_secmark {
  	u32 secid;
  	char *ctx;
  };
  
  static const struct nla_policy nft_secmark_policy[NFTA_SECMARK_MAX + 1] = {
  	[NFTA_SECMARK_CTX]     = { .type = NLA_STRING, .len = NFT_SECMARK_CTX_MAXLEN },
  };
  
  static int nft_secmark_compute_secid(struct nft_secmark *priv)
  {
  	u32 tmp_secid = 0;
  	int err;
  
  	err = security_secctx_to_secid(priv->ctx, strlen(priv->ctx), &tmp_secid);
  	if (err)
  		return err;
  
  	if (!tmp_secid)
  		return -ENOENT;
  
  	err = security_secmark_relabel_packet(tmp_secid);
  	if (err)
  		return err;
  
  	priv->secid = tmp_secid;
  	return 0;
  }
  
  static void nft_secmark_obj_eval(struct nft_object *obj, struct nft_regs *regs,
  				 const struct nft_pktinfo *pkt)
  {
  	const struct nft_secmark *priv = nft_obj_data(obj);
  	struct sk_buff *skb = pkt->skb;
  
  	skb->secmark = priv->secid;
  }
  
  static int nft_secmark_obj_init(const struct nft_ctx *ctx,
  				const struct nlattr * const tb[],
  				struct nft_object *obj)
  {
  	struct nft_secmark *priv = nft_obj_data(obj);
  	int err;
  
  	if (tb[NFTA_SECMARK_CTX] == NULL)
  		return -EINVAL;
  
  	priv->ctx = nla_strdup(tb[NFTA_SECMARK_CTX], GFP_KERNEL);
  	if (!priv->ctx)
  		return -ENOMEM;
  
  	err = nft_secmark_compute_secid(priv);
  	if (err) {
  		kfree(priv->ctx);
  		return err;
  	}
  
  	security_secmark_refcount_inc();
  
  	return 0;
  }
  
  static int nft_secmark_obj_dump(struct sk_buff *skb, struct nft_object *obj,
  				bool reset)
  {
  	struct nft_secmark *priv = nft_obj_data(obj);
  	int err;
  
  	if (nla_put_string(skb, NFTA_SECMARK_CTX, priv->ctx))
  		return -1;
  
  	if (reset) {
  		err = nft_secmark_compute_secid(priv);
  		if (err)
  			return err;
  	}
  
  	return 0;
  }
  
  static void nft_secmark_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj)
  {
  	struct nft_secmark *priv = nft_obj_data(obj);
  
  	security_secmark_refcount_dec();
  
  	kfree(priv->ctx);
  }
  
  static const struct nft_object_ops nft_secmark_obj_ops = {
  	.type		= &nft_secmark_obj_type,
  	.size		= sizeof(struct nft_secmark),
  	.init		= nft_secmark_obj_init,
  	.eval		= nft_secmark_obj_eval,
  	.dump		= nft_secmark_obj_dump,
  	.destroy	= nft_secmark_obj_destroy,
  };
  struct nft_object_type nft_secmark_obj_type __read_mostly = {
  	.type		= NFT_OBJECT_SECMARK,
  	.ops		= &nft_secmark_obj_ops,
  	.maxattr	= NFTA_SECMARK_MAX,
  	.policy		= nft_secmark_policy,
  	.owner		= THIS_MODULE,
  };
  #endif /* CONFIG_NETWORK_SECMARK */