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

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for net-next:

1) Rename 'searched' column to 'clashres' in conntrack /proc/ stats
to amend a recent patch, from Florian Westphal.

2) Remove unused nft_data_debug(), from YueHaibing.

3) Remove unused definitions in IPVS, also from YueHaibing.

4) Fix user data memleak in tables and objects, this is also amending
a recent patch, from Jose M. Guisado.

5) Use nla_memdup() to allocate user data in table and objects, also
from Jose M. Guisado

6) User data support for chains, from Jose M. Guisado

7) Remove unused definition in nf_tables_offload, from YueHaibing.

8) Use kvzalloc() in ip_set_alloc(), from Vasily Averin.

9) Fix false positive reported by lockdep in nfnetlink mutexes,
from Florian Westphal.

10) Extend fast variant of cmp for neq operation, from Phil Sutter.

11) Implement fast bitwise variant, also from Phil Sutter.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+222 -63
+2 -7
include/net/netfilter/nf_tables.h
··· 148 148 memcpy(dst, src, len); 149 149 } 150 150 151 - static inline void nft_data_debug(const struct nft_data *data) 152 - { 153 - pr_debug("data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", 154 - data->data[0], data->data[1], 155 - data->data[2], data->data[3]); 156 - } 157 - 158 151 /** 159 152 * struct nft_ctx - nf_tables rule/set context 160 153 * ··· 945 952 bound:1, 946 953 genmask:2; 947 954 char *name; 955 + u16 udlen; 956 + u8 *udata; 948 957 949 958 /* Only used during control plane commit phase: */ 950 959 struct nft_rule **rules_next;
+11
include/net/netfilter/nf_tables_core.h
··· 23 23 int nf_tables_core_module_init(void); 24 24 void nf_tables_core_module_exit(void); 25 25 26 + struct nft_bitwise_fast_expr { 27 + u32 mask; 28 + u32 xor; 29 + enum nft_registers sreg:8; 30 + enum nft_registers dreg:8; 31 + }; 32 + 26 33 struct nft_cmp_fast_expr { 27 34 u32 data; 35 + u32 mask; 28 36 enum nft_registers sreg:8; 29 37 u8 len; 38 + bool inv; 30 39 }; 31 40 32 41 struct nft_immediate_expr { ··· 74 65 }; 75 66 76 67 extern const struct nft_expr_ops nft_payload_fast_ops; 68 + 69 + extern const struct nft_expr_ops nft_bitwise_fast_ops; 77 70 78 71 extern struct static_key_false nft_counters_enabled; 79 72 extern struct static_key_false nft_trace_enabled;
+2
include/uapi/linux/netfilter/nf_tables.h
··· 208 208 * @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes) 209 209 * @NFTA_CHAIN_FLAGS: chain flags 210 210 * @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32) 211 + * @NFTA_CHAIN_USERDATA: user data (NLA_BINARY) 211 212 */ 212 213 enum nft_chain_attributes { 213 214 NFTA_CHAIN_UNSPEC, ··· 223 222 NFTA_CHAIN_PAD, 224 223 NFTA_CHAIN_FLAGS, 225 224 NFTA_CHAIN_ID, 225 + NFTA_CHAIN_USERDATA, 226 226 __NFTA_CHAIN_MAX 227 227 }; 228 228 #define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
+1 -16
net/netfilter/ipset/ip_set_core.c
··· 250 250 void * 251 251 ip_set_alloc(size_t size) 252 252 { 253 - void *members = NULL; 254 - 255 - if (size < KMALLOC_MAX_SIZE) 256 - members = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); 257 - 258 - if (members) { 259 - pr_debug("%p: allocated with kmalloc\n", members); 260 - return members; 261 - } 262 - 263 - members = vzalloc(size); 264 - if (!members) 265 - return NULL; 266 - pr_debug("%p: allocated with vmalloc\n", members); 267 - 268 - return members; 253 + return kvzalloc(size, GFP_KERNEL_ACCOUNT); 269 254 } 270 255 EXPORT_SYMBOL_GPL(ip_set_alloc); 271 256
-3
net/netfilter/ipvs/ip_vs_sync.c
··· 242 242 | IPVS Sync Connection (1) | 243 243 */ 244 244 245 - #define SYNC_MESG_HEADER_LEN 4 246 - #define MAX_CONNS_PER_SYNCBUFF 255 /* nr_conns in ip_vs_sync_mesg is 8 bit */ 247 - 248 245 /* Version 0 header */ 249 246 struct ip_vs_sync_mesg_v0 { 250 247 __u8 nr_conns;
+2 -2
net/netfilter/nf_conntrack_standalone.c
··· 428 428 const struct ip_conntrack_stat *st = v; 429 429 430 430 if (v == SEQ_START_TOKEN) { 431 - seq_puts(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart\n"); 431 + seq_puts(seq, "entries clashres found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart\n"); 432 432 return 0; 433 433 } 434 434 435 435 seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x " 436 436 "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n", 437 437 nr_conntracks, 438 - st->clash_resolve, /* was: searched */ 438 + st->clash_resolve, 439 439 st->found, 440 440 0, 441 441 st->invalid,
+31 -18
net/netfilter/nf_tables_api.c
··· 997 997 struct nft_table *table; 998 998 struct nft_ctx ctx; 999 999 u32 flags = 0; 1000 - u16 udlen = 0; 1001 1000 int err; 1002 1001 1003 1002 lockdep_assert_held(&net->nft.commit_mutex); ··· 1033 1034 goto err_strdup; 1034 1035 1035 1036 if (nla[NFTA_TABLE_USERDATA]) { 1036 - udlen = nla_len(nla[NFTA_TABLE_USERDATA]); 1037 - table->udata = kzalloc(udlen, GFP_KERNEL); 1037 + table->udata = nla_memdup(nla[NFTA_TABLE_USERDATA], GFP_KERNEL); 1038 1038 if (table->udata == NULL) 1039 1039 goto err_table_udata; 1040 1040 1041 - nla_memcpy(table->udata, nla[NFTA_TABLE_USERDATA], udlen); 1042 - table->udlen = udlen; 1041 + table->udlen = nla_len(nla[NFTA_TABLE_USERDATA]); 1043 1042 } 1044 1043 1045 1044 err = rhltable_init(&table->chains_ht, &nft_chain_ht_params); ··· 1219 1222 1220 1223 rhltable_destroy(&ctx->table->chains_ht); 1221 1224 kfree(ctx->table->name); 1225 + kfree(ctx->table->udata); 1222 1226 kfree(ctx->table); 1223 1227 } 1224 1228 ··· 1315 1317 [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED }, 1316 1318 [NFTA_CHAIN_FLAGS] = { .type = NLA_U32 }, 1317 1319 [NFTA_CHAIN_ID] = { .type = NLA_U32 }, 1320 + [NFTA_CHAIN_USERDATA] = { .type = NLA_BINARY, 1321 + .len = NFT_USERDATA_MAXLEN }, 1318 1322 }; 1319 1323 1320 1324 static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = { ··· 1456 1456 goto nla_put_failure; 1457 1457 1458 1458 if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use))) 1459 + goto nla_put_failure; 1460 + 1461 + if (chain->udata && 1462 + nla_put(skb, NFTA_CHAIN_USERDATA, chain->udlen, chain->udata)) 1459 1463 goto nla_put_failure; 1460 1464 1461 1465 nlmsg_end(skb, nlh); ··· 1698 1694 free_percpu(rcu_dereference_raw(basechain->stats)); 1699 1695 } 1700 1696 kfree(chain->name); 1697 + kfree(chain->udata); 1701 1698 kfree(basechain); 1702 1699 } else { 1703 1700 kfree(chain->name); 1701 + kfree(chain->udata); 1704 1702 kfree(chain); 1705 1703 } 1706 1704 } ··· 2056 2050 } else { 2057 2051 if (!(flags & NFT_CHAIN_BINDING)) { 2058 2052 err = -EINVAL; 2059 - goto err1; 2053 + goto err_destroy_chain; 2060 2054 } 2061 2055 2062 2056 snprintf(name, sizeof(name), "__chain%llu", ++chain_id); ··· 2065 2059 2066 2060 if (!chain->name) { 2067 2061 err = -ENOMEM; 2068 - goto err1; 2062 + goto err_destroy_chain; 2063 + } 2064 + 2065 + if (nla[NFTA_CHAIN_USERDATA]) { 2066 + chain->udata = nla_memdup(nla[NFTA_CHAIN_USERDATA], GFP_KERNEL); 2067 + if (chain->udata == NULL) { 2068 + err = -ENOMEM; 2069 + goto err_destroy_chain; 2070 + } 2071 + chain->udlen = nla_len(nla[NFTA_CHAIN_USERDATA]); 2069 2072 } 2070 2073 2071 2074 rules = nf_tables_chain_alloc_rules(chain, 0); 2072 2075 if (!rules) { 2073 2076 err = -ENOMEM; 2074 - goto err1; 2077 + goto err_destroy_chain; 2075 2078 } 2076 2079 2077 2080 *rules = NULL; ··· 2089 2074 2090 2075 err = nf_tables_register_hook(net, table, chain); 2091 2076 if (err < 0) 2092 - goto err1; 2077 + goto err_destroy_chain; 2093 2078 2094 2079 trans = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN); 2095 2080 if (IS_ERR(trans)) { 2096 2081 err = PTR_ERR(trans); 2097 - goto err2; 2082 + goto err_unregister_hook; 2098 2083 } 2099 2084 2100 2085 nft_trans_chain_policy(trans) = NFT_CHAIN_POLICY_UNSET; ··· 2104 2089 err = nft_chain_add(table, chain); 2105 2090 if (err < 0) { 2106 2091 nft_trans_destroy(trans); 2107 - goto err2; 2092 + goto err_unregister_hook; 2108 2093 } 2109 2094 2110 2095 table->use++; 2111 2096 2112 2097 return 0; 2113 - err2: 2098 + err_unregister_hook: 2114 2099 nf_tables_unregister_hook(net, table, chain); 2115 - err1: 2100 + err_destroy_chain: 2116 2101 nf_tables_chain_destroy(ctx); 2117 2102 2118 2103 return err; ··· 5921 5906 struct nft_object *obj; 5922 5907 struct nft_ctx ctx; 5923 5908 u32 objtype; 5924 - u16 udlen; 5925 5909 int err; 5926 5910 5927 5911 if (!nla[NFTA_OBJ_TYPE] || ··· 5977 5963 } 5978 5964 5979 5965 if (nla[NFTA_OBJ_USERDATA]) { 5980 - udlen = nla_len(nla[NFTA_OBJ_USERDATA]); 5981 - obj->udata = kzalloc(udlen, GFP_KERNEL); 5966 + obj->udata = nla_memdup(nla[NFTA_OBJ_USERDATA], GFP_KERNEL); 5982 5967 if (obj->udata == NULL) 5983 5968 goto err_userdata; 5984 5969 5985 - nla_memcpy(obj->udata, nla[NFTA_OBJ_USERDATA], udlen); 5986 - obj->udlen = udlen; 5970 + obj->udlen = nla_len(nla[NFTA_OBJ_USERDATA]); 5987 5971 } 5988 5972 5989 5973 err = nft_trans_obj_add(&ctx, NFT_MSG_NEWOBJ, obj); ··· 6250 6238 6251 6239 module_put(obj->ops->type->owner); 6252 6240 kfree(obj->key.name); 6241 + kfree(obj->udata); 6253 6242 kfree(obj); 6254 6243 } 6255 6244
+13 -2
net/netfilter/nf_tables_core.c
··· 47 47 } 48 48 } 49 49 50 + static void nft_bitwise_fast_eval(const struct nft_expr *expr, 51 + struct nft_regs *regs) 52 + { 53 + const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr); 54 + u32 *src = &regs->data[priv->sreg]; 55 + u32 *dst = &regs->data[priv->dreg]; 56 + 57 + *dst = (*src & priv->mask) ^ priv->xor; 58 + } 59 + 50 60 static void nft_cmp_fast_eval(const struct nft_expr *expr, 51 61 struct nft_regs *regs) 52 62 { 53 63 const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr); 54 - u32 mask = nft_cmp_fast_mask(priv->len); 55 64 56 - if ((regs->data[priv->sreg] & mask) == priv->data) 65 + if (((regs->data[priv->sreg] & priv->mask) == priv->data) ^ priv->inv) 57 66 return; 58 67 regs->verdict.code = NFT_BREAK; 59 68 } ··· 185 176 nft_rule_for_each_expr(expr, last, rule) { 186 177 if (expr->ops == &nft_cmp_fast_ops) 187 178 nft_cmp_fast_eval(expr, &regs); 179 + else if (expr->ops == &nft_bitwise_fast_ops) 180 + nft_bitwise_fast_eval(expr, &regs); 188 181 else if (expr->ops != &nft_payload_fast_ops || 189 182 !nft_payload_fast_eval(expr, &regs, pkt)) 190 183 expr_call_ops_eval(expr, &regs, pkt);
-2
net/netfilter/nf_tables_offload.c
··· 323 323 return nft_block_setup(basechain, &bo, cmd); 324 324 } 325 325 326 - #define FLOW_SETUP_BLOCK TC_SETUP_BLOCK 327 - 328 326 static int nft_chain_offload_cmd(struct nft_base_chain *basechain, 329 327 struct net_device *dev, 330 328 enum flow_block_command cmd)
+18 -1
net/netfilter/nfnetlink.c
··· 46 46 const struct nfnetlink_subsystem __rcu *subsys; 47 47 } table[NFNL_SUBSYS_COUNT]; 48 48 49 + static struct lock_class_key nfnl_lockdep_keys[NFNL_SUBSYS_COUNT]; 50 + 51 + static const char *const nfnl_lockdep_names[NFNL_SUBSYS_COUNT] = { 52 + [NFNL_SUBSYS_NONE] = "nfnl_subsys_none", 53 + [NFNL_SUBSYS_CTNETLINK] = "nfnl_subsys_ctnetlink", 54 + [NFNL_SUBSYS_CTNETLINK_EXP] = "nfnl_subsys_ctnetlink_exp", 55 + [NFNL_SUBSYS_QUEUE] = "nfnl_subsys_queue", 56 + [NFNL_SUBSYS_ULOG] = "nfnl_subsys_ulog", 57 + [NFNL_SUBSYS_OSF] = "nfnl_subsys_osf", 58 + [NFNL_SUBSYS_IPSET] = "nfnl_subsys_ipset", 59 + [NFNL_SUBSYS_ACCT] = "nfnl_subsys_acct", 60 + [NFNL_SUBSYS_CTNETLINK_TIMEOUT] = "nfnl_subsys_cttimeout", 61 + [NFNL_SUBSYS_CTHELPER] = "nfnl_subsys_cthelper", 62 + [NFNL_SUBSYS_NFTABLES] = "nfnl_subsys_nftables", 63 + [NFNL_SUBSYS_NFT_COMPAT] = "nfnl_subsys_nftcompat", 64 + }; 65 + 49 66 static const int nfnl_group2type[NFNLGRP_MAX+1] = { 50 67 [NFNLGRP_CONNTRACK_NEW] = NFNL_SUBSYS_CTNETLINK, 51 68 [NFNLGRP_CONNTRACK_UPDATE] = NFNL_SUBSYS_CTNETLINK, ··· 649 632 BUG_ON(nfnl_group2type[i] == NFNL_SUBSYS_NONE); 650 633 651 634 for (i=0; i<NFNL_SUBSYS_COUNT; i++) 652 - mutex_init(&table[i].mutex); 635 + __mutex_init(&table[i].mutex, nfnl_lockdep_names[i], &nfnl_lockdep_keys[i]); 653 636 654 637 return register_pernet_subsys(&nfnetlink_net_ops); 655 638 }
+135 -6
net/netfilter/nft_bitwise.c
··· 163 163 u32 len; 164 164 int err; 165 165 166 - if (!tb[NFTA_BITWISE_SREG] || 167 - !tb[NFTA_BITWISE_DREG] || 168 - !tb[NFTA_BITWISE_LEN]) 169 - return -EINVAL; 170 - 171 166 err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len); 172 167 if (err < 0) 173 168 return err; ··· 287 292 .offload = nft_bitwise_offload, 288 293 }; 289 294 295 + static int 296 + nft_bitwise_extract_u32_data(const struct nlattr * const tb, u32 *out) 297 + { 298 + struct nft_data_desc desc; 299 + struct nft_data data; 300 + int err = 0; 301 + 302 + err = nft_data_init(NULL, &data, sizeof(data), &desc, tb); 303 + if (err < 0) 304 + return err; 305 + 306 + if (desc.type != NFT_DATA_VALUE || desc.len != sizeof(u32)) { 307 + err = -EINVAL; 308 + goto err; 309 + } 310 + *out = data.data[0]; 311 + err: 312 + nft_data_release(&data, desc.type); 313 + return err; 314 + } 315 + 316 + static int nft_bitwise_fast_init(const struct nft_ctx *ctx, 317 + const struct nft_expr *expr, 318 + const struct nlattr * const tb[]) 319 + { 320 + struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr); 321 + int err; 322 + 323 + priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]); 324 + err = nft_validate_register_load(priv->sreg, sizeof(u32)); 325 + if (err < 0) 326 + return err; 327 + 328 + priv->dreg = nft_parse_register(tb[NFTA_BITWISE_DREG]); 329 + err = nft_validate_register_store(ctx, priv->dreg, NULL, 330 + NFT_DATA_VALUE, sizeof(u32)); 331 + if (err < 0) 332 + return err; 333 + 334 + if (tb[NFTA_BITWISE_DATA]) 335 + return -EINVAL; 336 + 337 + if (!tb[NFTA_BITWISE_MASK] || 338 + !tb[NFTA_BITWISE_XOR]) 339 + return -EINVAL; 340 + 341 + err = nft_bitwise_extract_u32_data(tb[NFTA_BITWISE_MASK], &priv->mask); 342 + if (err < 0) 343 + return err; 344 + 345 + err = nft_bitwise_extract_u32_data(tb[NFTA_BITWISE_XOR], &priv->xor); 346 + if (err < 0) 347 + return err; 348 + 349 + return 0; 350 + } 351 + 352 + static int 353 + nft_bitwise_fast_dump(struct sk_buff *skb, const struct nft_expr *expr) 354 + { 355 + const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr); 356 + struct nft_data data; 357 + 358 + if (nft_dump_register(skb, NFTA_BITWISE_SREG, priv->sreg)) 359 + return -1; 360 + if (nft_dump_register(skb, NFTA_BITWISE_DREG, priv->dreg)) 361 + return -1; 362 + if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(sizeof(u32)))) 363 + return -1; 364 + if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(NFT_BITWISE_BOOL))) 365 + return -1; 366 + 367 + data.data[0] = priv->mask; 368 + if (nft_data_dump(skb, NFTA_BITWISE_MASK, &data, 369 + NFT_DATA_VALUE, sizeof(u32)) < 0) 370 + return -1; 371 + 372 + data.data[0] = priv->xor; 373 + if (nft_data_dump(skb, NFTA_BITWISE_XOR, &data, 374 + NFT_DATA_VALUE, sizeof(u32)) < 0) 375 + return -1; 376 + 377 + return 0; 378 + } 379 + 380 + static int nft_bitwise_fast_offload(struct nft_offload_ctx *ctx, 381 + struct nft_flow_rule *flow, 382 + const struct nft_expr *expr) 383 + { 384 + const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr); 385 + struct nft_offload_reg *reg = &ctx->regs[priv->dreg]; 386 + 387 + if (priv->xor || priv->sreg != priv->dreg || reg->len != sizeof(u32)) 388 + return -EOPNOTSUPP; 389 + 390 + reg->mask.data[0] = priv->mask; 391 + return 0; 392 + } 393 + 394 + const struct nft_expr_ops nft_bitwise_fast_ops = { 395 + .type = &nft_bitwise_type, 396 + .size = NFT_EXPR_SIZE(sizeof(struct nft_bitwise_fast_expr)), 397 + .eval = NULL, /* inlined */ 398 + .init = nft_bitwise_fast_init, 399 + .dump = nft_bitwise_fast_dump, 400 + .offload = nft_bitwise_fast_offload, 401 + }; 402 + 403 + static const struct nft_expr_ops * 404 + nft_bitwise_select_ops(const struct nft_ctx *ctx, 405 + const struct nlattr * const tb[]) 406 + { 407 + int err; 408 + u32 len; 409 + 410 + if (!tb[NFTA_BITWISE_LEN] || 411 + !tb[NFTA_BITWISE_SREG] || 412 + !tb[NFTA_BITWISE_DREG]) 413 + return ERR_PTR(-EINVAL); 414 + 415 + err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len); 416 + if (err < 0) 417 + return ERR_PTR(err); 418 + 419 + if (len != sizeof(u32)) 420 + return &nft_bitwise_ops; 421 + 422 + if (tb[NFTA_BITWISE_OP] && 423 + ntohl(nla_get_be32(tb[NFTA_BITWISE_OP])) != NFT_BITWISE_BOOL) 424 + return &nft_bitwise_ops; 425 + 426 + return &nft_bitwise_fast_ops; 427 + } 428 + 290 429 struct nft_expr_type nft_bitwise_type __read_mostly = { 291 430 .name = "bitwise", 292 - .ops = &nft_bitwise_ops, 431 + .select_ops = nft_bitwise_select_ops, 293 432 .policy = nft_bitwise_policy, 294 433 .maxattr = NFTA_BITWISE_MAX, 295 434 .owner = THIS_MODULE,
+7 -6
net/netfilter/nft_cmp.c
··· 167 167 struct nft_cmp_fast_expr *priv = nft_expr_priv(expr); 168 168 struct nft_data_desc desc; 169 169 struct nft_data data; 170 - u32 mask; 171 170 int err; 172 171 173 172 err = nft_data_init(NULL, &data, sizeof(data), &desc, ··· 180 181 return err; 181 182 182 183 desc.len *= BITS_PER_BYTE; 183 - mask = nft_cmp_fast_mask(desc.len); 184 184 185 - priv->data = data.data[0] & mask; 185 + priv->mask = nft_cmp_fast_mask(desc.len); 186 + priv->data = data.data[0] & priv->mask; 186 187 priv->len = desc.len; 188 + priv->inv = ntohl(nla_get_be32(tb[NFTA_CMP_OP])) != NFT_CMP_EQ; 187 189 return 0; 188 190 } 189 191 ··· 201 201 }, 202 202 .sreg = priv->sreg, 203 203 .len = priv->len / BITS_PER_BYTE, 204 - .op = NFT_CMP_EQ, 204 + .op = priv->inv ? NFT_CMP_NEQ : NFT_CMP_EQ, 205 205 }; 206 206 207 207 return __nft_cmp_offload(ctx, flow, &cmp); ··· 210 210 static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr) 211 211 { 212 212 const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr); 213 + enum nft_cmp_ops op = priv->inv ? NFT_CMP_NEQ : NFT_CMP_EQ; 213 214 struct nft_data data; 214 215 215 216 if (nft_dump_register(skb, NFTA_CMP_SREG, priv->sreg)) 216 217 goto nla_put_failure; 217 - if (nla_put_be32(skb, NFTA_CMP_OP, htonl(NFT_CMP_EQ))) 218 + if (nla_put_be32(skb, NFTA_CMP_OP, htonl(op))) 218 219 goto nla_put_failure; 219 220 220 221 data.data[0] = priv->data; ··· 273 272 goto err1; 274 273 } 275 274 276 - if (desc.len <= sizeof(u32) && op == NFT_CMP_EQ) 275 + if (desc.len <= sizeof(u32) && (op == NFT_CMP_EQ || op == NFT_CMP_NEQ)) 277 276 return &nft_cmp_fast_ops; 278 277 279 278 return &nft_cmp_ops;