Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: ipset: set match: add support to match the counters

The new revision of the set match supports to match the counters
and to suppress updating the counters at matching too.

At the set:list types, the updating of the subcounters can be
suppressed as well.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Jozsef Kadlecsik and committed by
Pablo Neira Ayuso
6e01781d de76303c

+120 -9
+7 -2
include/linux/netfilter/ipset/ip_set.h
··· 76 76 77 77 typedef int (*ipset_adtfn)(struct ip_set *set, void *value, 78 78 const struct ip_set_ext *ext, 79 - struct ip_set_ext *mext, u32 flags); 79 + struct ip_set_ext *mext, u32 cmdflags); 80 80 81 81 /* Kernel API function options */ 82 82 struct ip_set_adt_opt { ··· 217 217 const struct ip_set_ext *ext, 218 218 struct ip_set_ext *mext, u32 flags) 219 219 { 220 - if (ext->packets != ULLONG_MAX) { 220 + if (ext->packets != ULLONG_MAX && 221 + !(flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) { 221 222 ip_set_add_bytes(ext->bytes, counter); 222 223 ip_set_add_packets(ext->packets, counter); 224 + } 225 + if (flags & IPSET_FLAG_MATCH_COUNTERS) { 226 + mext->packets = ip_set_get_packets(counter); 227 + mext->bytes = ip_set_get_bytes(counter); 223 228 } 224 229 } 225 230
+27 -4
include/uapi/linux/netfilter/ipset/ip_set.h
··· 145 145 IPSET_ERR_TYPE_SPECIFIC = 4352, 146 146 }; 147 147 148 - /* Flags at command level */ 148 + /* Flags at command level or match/target flags, lower half of cmdattrs*/ 149 149 enum ipset_cmd_flags { 150 150 IPSET_FLAG_BIT_EXIST = 0, 151 151 IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST), ··· 153 153 IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME), 154 154 IPSET_FLAG_BIT_LIST_HEADER = 2, 155 155 IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER), 156 - IPSET_FLAG_CMD_MAX = 15, /* Lower half */ 156 + IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE = 3, 157 + IPSET_FLAG_SKIP_COUNTER_UPDATE = 158 + (1 << IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE), 159 + IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE = 4, 160 + IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE = 161 + (1 << IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE), 162 + IPSET_FLAG_BIT_MATCH_COUNTERS = 5, 163 + IPSET_FLAG_MATCH_COUNTERS = (1 << IPSET_FLAG_BIT_MATCH_COUNTERS), 164 + IPSET_FLAG_BIT_RETURN_NOMATCH = 7, 165 + IPSET_FLAG_RETURN_NOMATCH = (1 << IPSET_FLAG_BIT_RETURN_NOMATCH), 166 + IPSET_FLAG_CMD_MAX = 15, 157 167 }; 158 168 159 - /* Flags at CADT attribute level */ 169 + /* Flags at CADT attribute level, upper half of cmdattrs */ 160 170 enum ipset_cadt_flags { 161 171 IPSET_FLAG_BIT_BEFORE = 0, 162 172 IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), ··· 176 166 IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH), 177 167 IPSET_FLAG_BIT_WITH_COUNTERS = 3, 178 168 IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS), 179 - IPSET_FLAG_CADT_MAX = 15, /* Upper half */ 169 + IPSET_FLAG_CADT_MAX = 15, 180 170 }; 181 171 182 172 /* Commands with settype-specific attributes */ ··· 205 195 * If changed, new revision of iptables match/target is required. 206 196 */ 207 197 IPSET_DIM_MAX = 6, 198 + /* Backward compatibility: set match revision 2 */ 208 199 IPSET_BIT_RETURN_NOMATCH = 7, 209 200 }; 210 201 ··· 218 207 IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH), 219 208 }; 220 209 210 + enum { 211 + IPSET_COUNTER_NONE = 0, 212 + IPSET_COUNTER_EQ, 213 + IPSET_COUNTER_NE, 214 + IPSET_COUNTER_LT, 215 + IPSET_COUNTER_GT, 216 + }; 217 + 218 + struct ip_set_counter_match { 219 + __u8 op; 220 + __u64 value; 221 + }; 221 222 222 223 /* Interface to iptables/ip6tables */ 223 224
+9
include/uapi/linux/netfilter/xt_set.h
··· 62 62 __u32 timeout; 63 63 }; 64 64 65 + /* Revision 3 match */ 66 + 67 + struct xt_set_info_match_v3 { 68 + struct xt_set_info match_set; 69 + struct ip_set_counter_match packets; 70 + struct ip_set_counter_match bytes; 71 + __u32 flags; 72 + }; 73 + 65 74 #endif /*_XT_SET_H*/
+1 -1
net/netfilter/ipset/ip_set_core.c
··· 413 413 ret = 1; 414 414 } else { 415 415 /* --return-nomatch: invert matched element */ 416 - if ((opt->flags & IPSET_RETURN_NOMATCH) && 416 + if ((opt->cmdflags & IPSET_FLAG_RETURN_NOMATCH) && 417 417 (set->type->features & IPSET_TYPE_NOMATCH) && 418 418 (ret > 0 || ret == -ENOTEMPTY)) 419 419 ret = -ret;
+6 -2
net/netfilter/ipset/ip_set_list_set.c
··· 84 84 { 85 85 struct list_set *map = set->data; 86 86 struct set_elem *e; 87 - u32 i; 87 + u32 i, cmdflags = opt->cmdflags; 88 88 int ret; 89 89 90 + /* Don't lookup sub-counters at all */ 91 + opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS; 92 + if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE) 93 + opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE; 90 94 for (i = 0; i < map->size; i++) { 91 95 e = list_set_elem(map, i); 92 96 if (e->id == IPSET_INVALID_ID) ··· 103 99 if (SET_WITH_COUNTER(set)) 104 100 ip_set_update_counter(ext_counter(e, map), 105 101 ext, &opt->ext, 106 - opt->cmdflags); 102 + cmdflags); 107 103 return ret; 108 104 } 109 105 }
+70
net/netfilter/xt_set.c
··· 189 189 ADT_OPT(opt, par->family, info->match_set.dim, 190 190 info->match_set.flags, 0, UINT_MAX); 191 191 192 + if (opt.flags & IPSET_RETURN_NOMATCH) 193 + opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH; 194 + 192 195 return match_set(info->match_set.index, skb, par, &opt, 193 196 info->match_set.flags & IPSET_INV_MATCH); 194 197 } ··· 320 317 #define set_target_v2_checkentry set_target_v1_checkentry 321 318 #define set_target_v2_destroy set_target_v1_destroy 322 319 320 + /* Revision 3 match */ 321 + 322 + static bool 323 + match_counter(u64 counter, const struct ip_set_counter_match *info) 324 + { 325 + switch (info->op) { 326 + case IPSET_COUNTER_NONE: 327 + return true; 328 + case IPSET_COUNTER_EQ: 329 + return counter == info->value; 330 + case IPSET_COUNTER_NE: 331 + return counter != info->value; 332 + case IPSET_COUNTER_LT: 333 + return counter < info->value; 334 + case IPSET_COUNTER_GT: 335 + return counter > info->value; 336 + } 337 + return false; 338 + } 339 + 340 + static bool 341 + set_match_v3(const struct sk_buff *skb, struct xt_action_param *par) 342 + { 343 + const struct xt_set_info_match_v3 *info = par->matchinfo; 344 + ADT_OPT(opt, par->family, info->match_set.dim, 345 + info->match_set.flags, info->flags, UINT_MAX); 346 + int ret; 347 + 348 + if (info->packets.op != IPSET_COUNTER_NONE || 349 + info->bytes.op != IPSET_COUNTER_NONE) 350 + opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS; 351 + 352 + ret = match_set(info->match_set.index, skb, par, &opt, 353 + info->match_set.flags & IPSET_INV_MATCH); 354 + 355 + if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS)) 356 + return ret; 357 + 358 + if (!match_counter(opt.ext.packets, &info->packets)) 359 + return 0; 360 + return match_counter(opt.ext.bytes, &info->bytes); 361 + } 362 + 363 + #define set_match_v3_checkentry set_match_v1_checkentry 364 + #define set_match_v3_destroy set_match_v1_destroy 365 + 323 366 static struct xt_match set_matches[] __read_mostly = { 324 367 { 325 368 .name = "set", ··· 416 367 .matchsize = sizeof(struct xt_set_info_match_v1), 417 368 .checkentry = set_match_v1_checkentry, 418 369 .destroy = set_match_v1_destroy, 370 + .me = THIS_MODULE 371 + }, 372 + /* counters support: update, match */ 373 + { 374 + .name = "set", 375 + .family = NFPROTO_IPV4, 376 + .revision = 3, 377 + .match = set_match_v3, 378 + .matchsize = sizeof(struct xt_set_info_match_v3), 379 + .checkentry = set_match_v3_checkentry, 380 + .destroy = set_match_v3_destroy, 381 + .me = THIS_MODULE 382 + }, 383 + { 384 + .name = "set", 385 + .family = NFPROTO_IPV6, 386 + .revision = 3, 387 + .match = set_match_v3, 388 + .matchsize = sizeof(struct xt_set_info_match_v3), 389 + .checkentry = set_match_v3_checkentry, 390 + .destroy = set_match_v3_destroy, 419 391 .me = THIS_MODULE 420 392 }, 421 393 };