Warning: This file is not a C or C++ file. It does not have highlighting.
1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
---|---|
2 | /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> |
3 | * Patrick Schaaf <bof@bof.de> |
4 | * Martin Josefsson <gandalf@wlug.westbo.se> |
5 | * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> |
6 | */ |
7 | #ifndef _IP_SET_H |
8 | #define _IP_SET_H |
9 | |
10 | #include <linux/ip.h> |
11 | #include <linux/ipv6.h> |
12 | #include <linux/netlink.h> |
13 | #include <linux/netfilter.h> |
14 | #include <linux/netfilter/x_tables.h> |
15 | #include <linux/stringify.h> |
16 | #include <linux/vmalloc.h> |
17 | #include <net/netlink.h> |
18 | #include <uapi/linux/netfilter/ipset/ip_set.h> |
19 | |
20 | #define _IP_SET_MODULE_DESC(a, b, c) \ |
21 | MODULE_DESCRIPTION(a " type of IP sets, revisions " b "-" c) |
22 | #define IP_SET_MODULE_DESC(a, b, c) \ |
23 | _IP_SET_MODULE_DESC(a, __stringify(b), __stringify(c)) |
24 | |
25 | /* Set features */ |
26 | enum ip_set_feature { |
27 | IPSET_TYPE_IP_FLAG = 0, |
28 | IPSET_TYPE_IP = (1 << IPSET_TYPE_IP_FLAG), |
29 | IPSET_TYPE_PORT_FLAG = 1, |
30 | IPSET_TYPE_PORT = (1 << IPSET_TYPE_PORT_FLAG), |
31 | IPSET_TYPE_MAC_FLAG = 2, |
32 | IPSET_TYPE_MAC = (1 << IPSET_TYPE_MAC_FLAG), |
33 | IPSET_TYPE_IP2_FLAG = 3, |
34 | IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG), |
35 | IPSET_TYPE_NAME_FLAG = 4, |
36 | IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG), |
37 | IPSET_TYPE_IFACE_FLAG = 5, |
38 | IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG), |
39 | IPSET_TYPE_MARK_FLAG = 6, |
40 | IPSET_TYPE_MARK = (1 << IPSET_TYPE_MARK_FLAG), |
41 | IPSET_TYPE_NOMATCH_FLAG = 7, |
42 | IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG), |
43 | /* Strictly speaking not a feature, but a flag for dumping: |
44 | * this settype must be dumped last */ |
45 | IPSET_DUMP_LAST_FLAG = 8, |
46 | IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG), |
47 | }; |
48 | |
49 | /* Set extensions */ |
50 | enum ip_set_extension { |
51 | IPSET_EXT_BIT_TIMEOUT = 0, |
52 | IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT), |
53 | IPSET_EXT_BIT_COUNTER = 1, |
54 | IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER), |
55 | IPSET_EXT_BIT_COMMENT = 2, |
56 | IPSET_EXT_COMMENT = (1 << IPSET_EXT_BIT_COMMENT), |
57 | IPSET_EXT_BIT_SKBINFO = 3, |
58 | IPSET_EXT_SKBINFO = (1 << IPSET_EXT_BIT_SKBINFO), |
59 | /* Mark set with an extension which needs to call destroy */ |
60 | IPSET_EXT_BIT_DESTROY = 7, |
61 | IPSET_EXT_DESTROY = (1 << IPSET_EXT_BIT_DESTROY), |
62 | }; |
63 | |
64 | #define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT) |
65 | #define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER) |
66 | #define SET_WITH_COMMENT(s) ((s)->extensions & IPSET_EXT_COMMENT) |
67 | #define SET_WITH_SKBINFO(s) ((s)->extensions & IPSET_EXT_SKBINFO) |
68 | #define SET_WITH_FORCEADD(s) ((s)->flags & IPSET_CREATE_FLAG_FORCEADD) |
69 | |
70 | /* Extension id, in size order */ |
71 | enum ip_set_ext_id { |
72 | IPSET_EXT_ID_COUNTER = 0, |
73 | IPSET_EXT_ID_TIMEOUT, |
74 | IPSET_EXT_ID_SKBINFO, |
75 | IPSET_EXT_ID_COMMENT, |
76 | IPSET_EXT_ID_MAX, |
77 | }; |
78 | |
79 | struct ip_set; |
80 | |
81 | /* Extension type */ |
82 | struct ip_set_ext_type { |
83 | /* Destroy extension private data (can be NULL) */ |
84 | void (*destroy)(struct ip_set *set, void *ext); |
85 | enum ip_set_extension type; |
86 | enum ipset_cadt_flags flag; |
87 | /* Size and minimal alignment */ |
88 | u8 len; |
89 | u8 align; |
90 | }; |
91 | |
92 | extern const struct ip_set_ext_type ip_set_extensions[]; |
93 | |
94 | struct ip_set_counter { |
95 | atomic64_t bytes; |
96 | atomic64_t packets; |
97 | }; |
98 | |
99 | struct ip_set_comment_rcu { |
100 | struct rcu_head rcu; |
101 | char str[]; |
102 | }; |
103 | |
104 | struct ip_set_comment { |
105 | struct ip_set_comment_rcu __rcu *c; |
106 | }; |
107 | |
108 | struct ip_set_skbinfo { |
109 | u32 skbmark; |
110 | u32 skbmarkmask; |
111 | u32 skbprio; |
112 | u16 skbqueue; |
113 | u16 __pad; |
114 | }; |
115 | |
116 | struct ip_set_ext { |
117 | struct ip_set_skbinfo skbinfo; |
118 | u64 packets; |
119 | u64 bytes; |
120 | char *comment; |
121 | u32 timeout; |
122 | u8 packets_op; |
123 | u8 bytes_op; |
124 | bool target; |
125 | }; |
126 | |
127 | #define ext_timeout(e, s) \ |
128 | ((unsigned long *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_TIMEOUT])) |
129 | #define ext_counter(e, s) \ |
130 | ((struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER])) |
131 | #define ext_comment(e, s) \ |
132 | ((struct ip_set_comment *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COMMENT])) |
133 | #define ext_skbinfo(e, s) \ |
134 | ((struct ip_set_skbinfo *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_SKBINFO])) |
135 | |
136 | typedef int (*ipset_adtfn)(struct ip_set *set, void *value, |
137 | const struct ip_set_ext *ext, |
138 | struct ip_set_ext *mext, u32 cmdflags); |
139 | |
140 | /* Kernel API function options */ |
141 | struct ip_set_adt_opt { |
142 | u8 family; /* Actual protocol family */ |
143 | u8 dim; /* Dimension of match/target */ |
144 | u8 flags; /* Direction and negation flags */ |
145 | u32 cmdflags; /* Command-like flags */ |
146 | struct ip_set_ext ext; /* Extensions */ |
147 | }; |
148 | |
149 | /* Set type, variant-specific part */ |
150 | struct ip_set_type_variant { |
151 | /* Kernelspace: test/add/del entries |
152 | * returns negative error code, |
153 | * zero for no match/success to add/delete |
154 | * positive for matching element */ |
155 | int (*kadt)(struct ip_set *set, const struct sk_buff *skb, |
156 | const struct xt_action_param *par, |
157 | enum ipset_adt adt, struct ip_set_adt_opt *opt); |
158 | |
159 | /* Userspace: test/add/del entries |
160 | * returns negative error code, |
161 | * zero for no match/success to add/delete |
162 | * positive for matching element */ |
163 | int (*uadt)(struct ip_set *set, struct nlattr *tb[], |
164 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried); |
165 | |
166 | /* Low level add/del/test functions */ |
167 | ipset_adtfn adt[IPSET_ADT_MAX]; |
168 | |
169 | /* When adding entries and set is full, try to resize the set */ |
170 | int (*resize)(struct ip_set *set, bool retried); |
171 | /* Destroy the set */ |
172 | void (*destroy)(struct ip_set *set); |
173 | /* Flush the elements */ |
174 | void (*flush)(struct ip_set *set); |
175 | /* Expire entries before listing */ |
176 | void (*expire)(struct ip_set *set); |
177 | /* List set header data */ |
178 | int (*head)(struct ip_set *set, struct sk_buff *skb); |
179 | /* List elements */ |
180 | int (*list)(const struct ip_set *set, struct sk_buff *skb, |
181 | struct netlink_callback *cb); |
182 | /* Keep listing private when resizing runs parallel */ |
183 | void (*uref)(struct ip_set *set, struct netlink_callback *cb, |
184 | bool start); |
185 | |
186 | /* Return true if "b" set is the same as "a" |
187 | * according to the create set parameters */ |
188 | bool (*same_set)(const struct ip_set *a, const struct ip_set *b); |
189 | /* Cancel ongoing garbage collectors before destroying the set*/ |
190 | void (*cancel_gc)(struct ip_set *set); |
191 | /* Region-locking is used */ |
192 | bool region_lock; |
193 | }; |
194 | |
195 | struct ip_set_region { |
196 | spinlock_t lock; /* Region lock */ |
197 | size_t ext_size; /* Size of the dynamic extensions */ |
198 | u32 elements; /* Number of elements vs timeout */ |
199 | }; |
200 | |
201 | /* Max range where every element is added/deleted in one step */ |
202 | #define IPSET_MAX_RANGE (1<<14) |
203 | |
204 | /* The max revision number supported by any set type + 1 */ |
205 | #define IPSET_REVISION_MAX 9 |
206 | |
207 | /* The core set type structure */ |
208 | struct ip_set_type { |
209 | struct list_head list; |
210 | |
211 | /* Typename */ |
212 | char name[IPSET_MAXNAMELEN]; |
213 | /* Protocol version */ |
214 | u8 protocol; |
215 | /* Set type dimension */ |
216 | u8 dimension; |
217 | /* |
218 | * Supported family: may be NFPROTO_UNSPEC for both |
219 | * NFPROTO_IPV4/NFPROTO_IPV6. |
220 | */ |
221 | u8 family; |
222 | /* Type revisions */ |
223 | u8 revision_min, revision_max; |
224 | /* Revision-specific supported (create) flags */ |
225 | u8 create_flags[IPSET_REVISION_MAX+1]; |
226 | /* Set features to control swapping */ |
227 | u16 features; |
228 | |
229 | /* Create set */ |
230 | int (*create)(struct net *net, struct ip_set *set, |
231 | struct nlattr *tb[], u32 flags); |
232 | |
233 | /* Attribute policies */ |
234 | const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1]; |
235 | const struct nla_policy adt_policy[IPSET_ATTR_ADT_MAX + 1]; |
236 | |
237 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ |
238 | struct module *me; |
239 | }; |
240 | |
241 | /* register and unregister set type */ |
242 | extern int ip_set_type_register(struct ip_set_type *set_type); |
243 | extern void ip_set_type_unregister(struct ip_set_type *set_type); |
244 | |
245 | /* A generic IP set */ |
246 | struct ip_set { |
247 | /* For call_cru in destroy */ |
248 | struct rcu_head rcu; |
249 | /* The name of the set */ |
250 | char name[IPSET_MAXNAMELEN]; |
251 | /* Lock protecting the set data */ |
252 | spinlock_t lock; |
253 | /* References to the set */ |
254 | u32 ref; |
255 | /* References to the set for netlink events like dump, |
256 | * ref can be swapped out by ip_set_swap |
257 | */ |
258 | u32 ref_netlink; |
259 | /* The core set type */ |
260 | struct ip_set_type *type; |
261 | /* The type variant doing the real job */ |
262 | const struct ip_set_type_variant *variant; |
263 | /* The actual INET family of the set */ |
264 | u8 family; |
265 | /* The type revision */ |
266 | u8 revision; |
267 | /* Extensions */ |
268 | u8 extensions; |
269 | /* Create flags */ |
270 | u8 flags; |
271 | /* Default timeout value, if enabled */ |
272 | u32 timeout; |
273 | /* Number of elements (vs timeout) */ |
274 | u32 elements; |
275 | /* Size of the dynamic extensions (vs timeout) */ |
276 | size_t ext_size; |
277 | /* Element data size */ |
278 | size_t dsize; |
279 | /* Offsets to extensions in elements */ |
280 | size_t offset[IPSET_EXT_ID_MAX]; |
281 | /* The type specific data */ |
282 | void *data; |
283 | }; |
284 | |
285 | static inline void |
286 | ip_set_ext_destroy(struct ip_set *set, void *data) |
287 | { |
288 | /* Check that the extension is enabled for the set and |
289 | * call it's destroy function for its extension part in data. |
290 | */ |
291 | if (SET_WITH_COMMENT(set)) { |
292 | struct ip_set_comment *c = ext_comment(data, set); |
293 | |
294 | ip_set_extensions[IPSET_EXT_ID_COMMENT].destroy(set, c); |
295 | } |
296 | } |
297 | |
298 | int ip_set_put_flags(struct sk_buff *skb, struct ip_set *set); |
299 | |
300 | /* Netlink CB args */ |
301 | enum { |
302 | IPSET_CB_NET = 0, /* net namespace */ |
303 | IPSET_CB_PROTO, /* ipset protocol */ |
304 | IPSET_CB_DUMP, /* dump single set/all sets */ |
305 | IPSET_CB_INDEX, /* set index */ |
306 | IPSET_CB_PRIVATE, /* set private data */ |
307 | IPSET_CB_ARG0, /* type specific */ |
308 | }; |
309 | |
310 | /* register and unregister set references */ |
311 | extern ip_set_id_t ip_set_get_byname(struct net *net, |
312 | const char *name, struct ip_set **set); |
313 | extern void ip_set_put_byindex(struct net *net, ip_set_id_t index); |
314 | extern void ip_set_name_byindex(struct net *net, ip_set_id_t index, char *name); |
315 | extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index); |
316 | extern void ip_set_nfnl_put(struct net *net, ip_set_id_t index); |
317 | |
318 | /* API for iptables set match, and SET target */ |
319 | |
320 | extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb, |
321 | const struct xt_action_param *par, |
322 | struct ip_set_adt_opt *opt); |
323 | extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb, |
324 | const struct xt_action_param *par, |
325 | struct ip_set_adt_opt *opt); |
326 | extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, |
327 | const struct xt_action_param *par, |
328 | struct ip_set_adt_opt *opt); |
329 | |
330 | /* Utility functions */ |
331 | extern void *ip_set_alloc(size_t size); |
332 | extern void ip_set_free(void *members); |
333 | extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); |
334 | extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); |
335 | extern size_t ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], |
336 | size_t len, size_t align); |
337 | extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], |
338 | struct ip_set_ext *ext); |
339 | extern int ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set, |
340 | const void *e, bool active); |
341 | extern bool ip_set_match_extensions(struct ip_set *set, |
342 | const struct ip_set_ext *ext, |
343 | struct ip_set_ext *mext, |
344 | u32 flags, void *data); |
345 | |
346 | static inline int |
347 | ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr) |
348 | { |
349 | __be32 ip; |
350 | int ret = ip_set_get_ipaddr4(nla, &ip); |
351 | |
352 | if (ret) |
353 | return ret; |
354 | *ipaddr = ntohl(ip); |
355 | return 0; |
356 | } |
357 | |
358 | /* Ignore IPSET_ERR_EXIST errors if asked to do so? */ |
359 | static inline bool |
360 | ip_set_eexist(int ret, u32 flags) |
361 | { |
362 | return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST); |
363 | } |
364 | |
365 | /* Match elements marked with nomatch */ |
366 | static inline bool |
367 | ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt, struct ip_set *set) |
368 | { |
369 | return adt == IPSET_TEST && |
370 | (set->type->features & IPSET_TYPE_NOMATCH) && |
371 | ((flags >> 16) & IPSET_FLAG_NOMATCH) && |
372 | (ret > 0 || ret == -ENOTEMPTY); |
373 | } |
374 | |
375 | /* Check the NLA_F_NET_BYTEORDER flag */ |
376 | static inline bool |
377 | ip_set_attr_netorder(struct nlattr *tb[], int type) |
378 | { |
379 | return tb[type] && (tb[type]->nla_type & NLA_F_NET_BYTEORDER); |
380 | } |
381 | |
382 | static inline bool |
383 | ip_set_optattr_netorder(struct nlattr *tb[], int type) |
384 | { |
385 | return !tb[type] || (tb[type]->nla_type & NLA_F_NET_BYTEORDER); |
386 | } |
387 | |
388 | /* Useful converters */ |
389 | static inline u32 |
390 | ip_set_get_h32(const struct nlattr *attr) |
391 | { |
392 | return ntohl(nla_get_be32(attr)); |
393 | } |
394 | |
395 | static inline u16 |
396 | ip_set_get_h16(const struct nlattr *attr) |
397 | { |
398 | return ntohs(nla_get_be16(attr)); |
399 | } |
400 | |
401 | static inline int nla_put_ipaddr4(struct sk_buff *skb, int type, __be32 ipaddr) |
402 | { |
403 | struct nlattr *__nested = nla_nest_start(skb, type); |
404 | int ret; |
405 | |
406 | if (!__nested) |
407 | return -EMSGSIZE; |
408 | ret = nla_put_in_addr(skb, IPSET_ATTR_IPADDR_IPV4, ipaddr); |
409 | if (!ret) |
410 | nla_nest_end(skb, __nested); |
411 | return ret; |
412 | } |
413 | |
414 | static inline int nla_put_ipaddr6(struct sk_buff *skb, int type, |
415 | const struct in6_addr *ipaddrptr) |
416 | { |
417 | struct nlattr *__nested = nla_nest_start(skb, type); |
418 | int ret; |
419 | |
420 | if (!__nested) |
421 | return -EMSGSIZE; |
422 | ret = nla_put_in6_addr(skb, IPSET_ATTR_IPADDR_IPV6, ipaddrptr); |
423 | if (!ret) |
424 | nla_nest_end(skb, __nested); |
425 | return ret; |
426 | } |
427 | |
428 | /* Get address from skbuff */ |
429 | static inline __be32 |
430 | ip4addr(const struct sk_buff *skb, bool src) |
431 | { |
432 | return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; |
433 | } |
434 | |
435 | static inline void |
436 | ip4addrptr(const struct sk_buff *skb, bool src, __be32 *addr) |
437 | { |
438 | *addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; |
439 | } |
440 | |
441 | static inline void |
442 | ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr) |
443 | { |
444 | memcpy(addr, src ? &ipv6_hdr(skb)->saddr : &ipv6_hdr(skb)->daddr, |
445 | sizeof(*addr)); |
446 | } |
447 | |
448 | /* How often should the gc be run by default */ |
449 | #define IPSET_GC_TIME (3 * 60) |
450 | |
451 | /* Timeout period depending on the timeout value of the given set */ |
452 | #define IPSET_GC_PERIOD(timeout) \ |
453 | ((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1) |
454 | |
455 | /* Entry is set with no timeout value */ |
456 | #define IPSET_ELEM_PERMANENT 0 |
457 | |
458 | /* Set is defined with timeout support: timeout value may be 0 */ |
459 | #define IPSET_NO_TIMEOUT UINT_MAX |
460 | |
461 | /* Max timeout value, see msecs_to_jiffies() in jiffies.h */ |
462 | #define IPSET_MAX_TIMEOUT (UINT_MAX >> 1)/MSEC_PER_SEC |
463 | |
464 | #define ip_set_adt_opt_timeout(opt, set) \ |
465 | ((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (set)->timeout) |
466 | |
467 | static inline unsigned int |
468 | ip_set_timeout_uget(struct nlattr *tb) |
469 | { |
470 | unsigned int timeout = ip_set_get_h32(tb); |
471 | |
472 | /* Normalize to fit into jiffies */ |
473 | if (timeout > IPSET_MAX_TIMEOUT) |
474 | timeout = IPSET_MAX_TIMEOUT; |
475 | |
476 | return timeout; |
477 | } |
478 | |
479 | static inline bool |
480 | ip_set_timeout_expired(const unsigned long *t) |
481 | { |
482 | return *t != IPSET_ELEM_PERMANENT && time_is_before_jiffies(*t); |
483 | } |
484 | |
485 | static inline void |
486 | ip_set_timeout_set(unsigned long *timeout, u32 value) |
487 | { |
488 | unsigned long t; |
489 | |
490 | if (!value) { |
491 | *timeout = IPSET_ELEM_PERMANENT; |
492 | return; |
493 | } |
494 | |
495 | t = msecs_to_jiffies(value * MSEC_PER_SEC) + jiffies; |
496 | if (t == IPSET_ELEM_PERMANENT) |
497 | /* Bingo! :-) */ |
498 | t--; |
499 | *timeout = t; |
500 | } |
501 | |
502 | void ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment, |
503 | const struct ip_set_ext *ext); |
504 | |
505 | static inline void |
506 | ip_set_init_counter(struct ip_set_counter *counter, |
507 | const struct ip_set_ext *ext) |
508 | { |
509 | if (ext->bytes != ULLONG_MAX) |
510 | atomic64_set(&(counter)->bytes, (long long)(ext->bytes)); |
511 | if (ext->packets != ULLONG_MAX) |
512 | atomic64_set(&(counter)->packets, (long long)(ext->packets)); |
513 | } |
514 | |
515 | static inline void |
516 | ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo, |
517 | const struct ip_set_ext *ext) |
518 | { |
519 | *skbinfo = ext->skbinfo; |
520 | } |
521 | |
522 | static inline void |
523 | nf_inet_addr_mask_inplace(union nf_inet_addr *a1, |
524 | const union nf_inet_addr *mask) |
525 | { |
526 | a1->all[0] &= mask->all[0]; |
527 | a1->all[1] &= mask->all[1]; |
528 | a1->all[2] &= mask->all[2]; |
529 | a1->all[3] &= mask->all[3]; |
530 | } |
531 | |
532 | #define IP_SET_INIT_KEXT(skb, opt, set) \ |
533 | { .bytes = (skb)->len, .packets = 1, .target = true,\ |
534 | .timeout = ip_set_adt_opt_timeout(opt, set) } |
535 | |
536 | #define IP_SET_INIT_UEXT(set) \ |
537 | { .bytes = ULLONG_MAX, .packets = ULLONG_MAX, \ |
538 | .timeout = (set)->timeout } |
539 | |
540 | #define IPSET_CONCAT(a, b) a##b |
541 | #define IPSET_TOKEN(a, b) IPSET_CONCAT(a, b) |
542 | |
543 | #endif /*_IP_SET_H */ |
544 |
Warning: This file is not a C or C++ file. It does not have highlighting.