diff options
| -rw-r--r-- | include/net/netfilter/nf_tables.h | 6 | ||||
| -rw-r--r-- | include/net/netns/nftables.h | 2 | ||||
| -rw-r--r-- | net/netfilter/nf_tables_api.c | 140 | ||||
| -rw-r--r-- | net/netfilter/nf_tables_core.c | 10 |
4 files changed, 100 insertions, 58 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 713b0b88bd5a..c4d86198d3d6 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <linux/netfilter/nfnetlink.h> | 6 | #include <linux/netfilter/nfnetlink.h> |
| 7 | #include <linux/netfilter/x_tables.h> | 7 | #include <linux/netfilter/x_tables.h> |
| 8 | #include <linux/netfilter/nf_tables.h> | 8 | #include <linux/netfilter/nf_tables.h> |
| 9 | #include <linux/u64_stats_sync.h> | ||
| 9 | #include <net/netlink.h> | 10 | #include <net/netlink.h> |
| 10 | 11 | ||
| 11 | #define NFT_JUMP_STACK_SIZE 16 | 12 | #define NFT_JUMP_STACK_SIZE 16 |
| @@ -528,8 +529,9 @@ enum nft_chain_type { | |||
| 528 | }; | 529 | }; |
| 529 | 530 | ||
| 530 | struct nft_stats { | 531 | struct nft_stats { |
| 531 | u64 bytes; | 532 | u64 bytes; |
| 532 | u64 pkts; | 533 | u64 pkts; |
| 534 | struct u64_stats_sync syncp; | ||
| 533 | }; | 535 | }; |
| 534 | 536 | ||
| 535 | #define NFT_HOOK_OPS_MAX 2 | 537 | #define NFT_HOOK_OPS_MAX 2 |
diff --git a/include/net/netns/nftables.h b/include/net/netns/nftables.h index 26a394cb91a8..eee608b12cc9 100644 --- a/include/net/netns/nftables.h +++ b/include/net/netns/nftables.h | |||
| @@ -13,8 +13,8 @@ struct netns_nftables { | |||
| 13 | struct nft_af_info *inet; | 13 | struct nft_af_info *inet; |
| 14 | struct nft_af_info *arp; | 14 | struct nft_af_info *arp; |
| 15 | struct nft_af_info *bridge; | 15 | struct nft_af_info *bridge; |
| 16 | unsigned int base_seq; | ||
| 16 | u8 gencursor; | 17 | u8 gencursor; |
| 17 | u8 genctr; | ||
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | #endif | 20 | #endif |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index ab4566cfcbe4..8746ff9a8357 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
| @@ -35,7 +35,7 @@ int nft_register_afinfo(struct net *net, struct nft_af_info *afi) | |||
| 35 | { | 35 | { |
| 36 | INIT_LIST_HEAD(&afi->tables); | 36 | INIT_LIST_HEAD(&afi->tables); |
| 37 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 37 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 38 | list_add_tail(&afi->list, &net->nft.af_info); | 38 | list_add_tail_rcu(&afi->list, &net->nft.af_info); |
| 39 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 39 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 40 | return 0; | 40 | return 0; |
| 41 | } | 41 | } |
| @@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(nft_register_afinfo); | |||
| 51 | void nft_unregister_afinfo(struct nft_af_info *afi) | 51 | void nft_unregister_afinfo(struct nft_af_info *afi) |
| 52 | { | 52 | { |
| 53 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 53 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 54 | list_del(&afi->list); | 54 | list_del_rcu(&afi->list); |
| 55 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 55 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 56 | } | 56 | } |
| 57 | EXPORT_SYMBOL_GPL(nft_unregister_afinfo); | 57 | EXPORT_SYMBOL_GPL(nft_unregister_afinfo); |
| @@ -277,11 +277,14 @@ static int nf_tables_dump_tables(struct sk_buff *skb, | |||
| 277 | struct net *net = sock_net(skb->sk); | 277 | struct net *net = sock_net(skb->sk); |
| 278 | int family = nfmsg->nfgen_family; | 278 | int family = nfmsg->nfgen_family; |
| 279 | 279 | ||
| 280 | list_for_each_entry(afi, &net->nft.af_info, list) { | 280 | rcu_read_lock(); |
| 281 | cb->seq = net->nft.base_seq; | ||
| 282 | |||
| 283 | list_for_each_entry_rcu(afi, &net->nft.af_info, list) { | ||
| 281 | if (family != NFPROTO_UNSPEC && family != afi->family) | 284 | if (family != NFPROTO_UNSPEC && family != afi->family) |
| 282 | continue; | 285 | continue; |
| 283 | 286 | ||
| 284 | list_for_each_entry(table, &afi->tables, list) { | 287 | list_for_each_entry_rcu(table, &afi->tables, list) { |
| 285 | if (idx < s_idx) | 288 | if (idx < s_idx) |
| 286 | goto cont; | 289 | goto cont; |
| 287 | if (idx > s_idx) | 290 | if (idx > s_idx) |
| @@ -294,11 +297,14 @@ static int nf_tables_dump_tables(struct sk_buff *skb, | |||
| 294 | NLM_F_MULTI, | 297 | NLM_F_MULTI, |
| 295 | afi->family, table) < 0) | 298 | afi->family, table) < 0) |
| 296 | goto done; | 299 | goto done; |
| 300 | |||
| 301 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
| 297 | cont: | 302 | cont: |
| 298 | idx++; | 303 | idx++; |
| 299 | } | 304 | } |
| 300 | } | 305 | } |
| 301 | done: | 306 | done: |
| 307 | rcu_read_unlock(); | ||
| 302 | cb->args[0] = idx; | 308 | cb->args[0] = idx; |
| 303 | return skb->len; | 309 | return skb->len; |
| 304 | } | 310 | } |
| @@ -407,6 +413,9 @@ static int nf_tables_updtable(struct nft_ctx *ctx) | |||
| 407 | if (flags & ~NFT_TABLE_F_DORMANT) | 413 | if (flags & ~NFT_TABLE_F_DORMANT) |
| 408 | return -EINVAL; | 414 | return -EINVAL; |
| 409 | 415 | ||
| 416 | if (flags == ctx->table->flags) | ||
| 417 | return 0; | ||
| 418 | |||
| 410 | trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE, | 419 | trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE, |
| 411 | sizeof(struct nft_trans_table)); | 420 | sizeof(struct nft_trans_table)); |
| 412 | if (trans == NULL) | 421 | if (trans == NULL) |
| @@ -514,7 +523,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, | |||
| 514 | module_put(afi->owner); | 523 | module_put(afi->owner); |
| 515 | return err; | 524 | return err; |
| 516 | } | 525 | } |
| 517 | list_add_tail(&table->list, &afi->tables); | 526 | list_add_tail_rcu(&table->list, &afi->tables); |
| 518 | return 0; | 527 | return 0; |
| 519 | } | 528 | } |
| 520 | 529 | ||
| @@ -546,7 +555,7 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb, | |||
| 546 | if (err < 0) | 555 | if (err < 0) |
| 547 | return err; | 556 | return err; |
| 548 | 557 | ||
| 549 | list_del(&table->list); | 558 | list_del_rcu(&table->list); |
| 550 | return 0; | 559 | return 0; |
| 551 | } | 560 | } |
| 552 | 561 | ||
| @@ -635,13 +644,20 @@ static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats) | |||
| 635 | { | 644 | { |
| 636 | struct nft_stats *cpu_stats, total; | 645 | struct nft_stats *cpu_stats, total; |
| 637 | struct nlattr *nest; | 646 | struct nlattr *nest; |
| 647 | unsigned int seq; | ||
| 648 | u64 pkts, bytes; | ||
| 638 | int cpu; | 649 | int cpu; |
| 639 | 650 | ||
| 640 | memset(&total, 0, sizeof(total)); | 651 | memset(&total, 0, sizeof(total)); |
| 641 | for_each_possible_cpu(cpu) { | 652 | for_each_possible_cpu(cpu) { |
| 642 | cpu_stats = per_cpu_ptr(stats, cpu); | 653 | cpu_stats = per_cpu_ptr(stats, cpu); |
| 643 | total.pkts += cpu_stats->pkts; | 654 | do { |
| 644 | total.bytes += cpu_stats->bytes; | 655 | seq = u64_stats_fetch_begin_irq(&cpu_stats->syncp); |
| 656 | pkts = cpu_stats->pkts; | ||
| 657 | bytes = cpu_stats->bytes; | ||
| 658 | } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, seq)); | ||
| 659 | total.pkts += pkts; | ||
| 660 | total.bytes += bytes; | ||
| 645 | } | 661 | } |
| 646 | nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS); | 662 | nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS); |
| 647 | if (nest == NULL) | 663 | if (nest == NULL) |
| @@ -761,12 +777,15 @@ static int nf_tables_dump_chains(struct sk_buff *skb, | |||
| 761 | struct net *net = sock_net(skb->sk); | 777 | struct net *net = sock_net(skb->sk); |
| 762 | int family = nfmsg->nfgen_family; | 778 | int family = nfmsg->nfgen_family; |
| 763 | 779 | ||
| 764 | list_for_each_entry(afi, &net->nft.af_info, list) { | 780 | rcu_read_lock(); |
| 781 | cb->seq = net->nft.base_seq; | ||
| 782 | |||
| 783 | list_for_each_entry_rcu(afi, &net->nft.af_info, list) { | ||
| 765 | if (family != NFPROTO_UNSPEC && family != afi->family) | 784 | if (family != NFPROTO_UNSPEC && family != afi->family) |
| 766 | continue; | 785 | continue; |
| 767 | 786 | ||
| 768 | list_for_each_entry(table, &afi->tables, list) { | 787 | list_for_each_entry_rcu(table, &afi->tables, list) { |
| 769 | list_for_each_entry(chain, &table->chains, list) { | 788 | list_for_each_entry_rcu(chain, &table->chains, list) { |
| 770 | if (idx < s_idx) | 789 | if (idx < s_idx) |
| 771 | goto cont; | 790 | goto cont; |
| 772 | if (idx > s_idx) | 791 | if (idx > s_idx) |
| @@ -778,17 +797,19 @@ static int nf_tables_dump_chains(struct sk_buff *skb, | |||
| 778 | NLM_F_MULTI, | 797 | NLM_F_MULTI, |
| 779 | afi->family, table, chain) < 0) | 798 | afi->family, table, chain) < 0) |
| 780 | goto done; | 799 | goto done; |
| 800 | |||
| 801 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
| 781 | cont: | 802 | cont: |
| 782 | idx++; | 803 | idx++; |
| 783 | } | 804 | } |
| 784 | } | 805 | } |
| 785 | } | 806 | } |
| 786 | done: | 807 | done: |
| 808 | rcu_read_unlock(); | ||
| 787 | cb->args[0] = idx; | 809 | cb->args[0] = idx; |
| 788 | return skb->len; | 810 | return skb->len; |
| 789 | } | 811 | } |
| 790 | 812 | ||
| 791 | |||
| 792 | static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb, | 813 | static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb, |
| 793 | const struct nlmsghdr *nlh, | 814 | const struct nlmsghdr *nlh, |
| 794 | const struct nlattr * const nla[]) | 815 | const struct nlattr * const nla[]) |
| @@ -861,7 +882,7 @@ static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr) | |||
| 861 | if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS]) | 882 | if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS]) |
| 862 | return ERR_PTR(-EINVAL); | 883 | return ERR_PTR(-EINVAL); |
| 863 | 884 | ||
| 864 | newstats = alloc_percpu(struct nft_stats); | 885 | newstats = netdev_alloc_pcpu_stats(struct nft_stats); |
| 865 | if (newstats == NULL) | 886 | if (newstats == NULL) |
| 866 | return ERR_PTR(-ENOMEM); | 887 | return ERR_PTR(-ENOMEM); |
| 867 | 888 | ||
| @@ -1077,7 +1098,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 1077 | } | 1098 | } |
| 1078 | basechain->stats = stats; | 1099 | basechain->stats = stats; |
| 1079 | } else { | 1100 | } else { |
| 1080 | stats = alloc_percpu(struct nft_stats); | 1101 | stats = netdev_alloc_pcpu_stats(struct nft_stats); |
| 1081 | if (IS_ERR(stats)) { | 1102 | if (IS_ERR(stats)) { |
| 1082 | module_put(type->owner); | 1103 | module_put(type->owner); |
| 1083 | kfree(basechain); | 1104 | kfree(basechain); |
| @@ -1130,7 +1151,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 1130 | goto err2; | 1151 | goto err2; |
| 1131 | 1152 | ||
| 1132 | table->use++; | 1153 | table->use++; |
| 1133 | list_add_tail(&chain->list, &table->chains); | 1154 | list_add_tail_rcu(&chain->list, &table->chains); |
| 1134 | return 0; | 1155 | return 0; |
| 1135 | err2: | 1156 | err2: |
| 1136 | if (!(table->flags & NFT_TABLE_F_DORMANT) && | 1157 | if (!(table->flags & NFT_TABLE_F_DORMANT) && |
| @@ -1180,7 +1201,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb, | |||
| 1180 | return err; | 1201 | return err; |
| 1181 | 1202 | ||
| 1182 | table->use--; | 1203 | table->use--; |
| 1183 | list_del(&chain->list); | 1204 | list_del_rcu(&chain->list); |
| 1184 | return 0; | 1205 | return 0; |
| 1185 | } | 1206 | } |
| 1186 | 1207 | ||
| @@ -1199,9 +1220,9 @@ int nft_register_expr(struct nft_expr_type *type) | |||
| 1199 | { | 1220 | { |
| 1200 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 1221 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 1201 | if (type->family == NFPROTO_UNSPEC) | 1222 | if (type->family == NFPROTO_UNSPEC) |
| 1202 | list_add_tail(&type->list, &nf_tables_expressions); | 1223 | list_add_tail_rcu(&type->list, &nf_tables_expressions); |
| 1203 | else | 1224 | else |
| 1204 | list_add(&type->list, &nf_tables_expressions); | 1225 | list_add_rcu(&type->list, &nf_tables_expressions); |
| 1205 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 1226 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 1206 | return 0; | 1227 | return 0; |
| 1207 | } | 1228 | } |
| @@ -1216,7 +1237,7 @@ EXPORT_SYMBOL_GPL(nft_register_expr); | |||
| 1216 | void nft_unregister_expr(struct nft_expr_type *type) | 1237 | void nft_unregister_expr(struct nft_expr_type *type) |
| 1217 | { | 1238 | { |
| 1218 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 1239 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 1219 | list_del(&type->list); | 1240 | list_del_rcu(&type->list); |
| 1220 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 1241 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 1221 | } | 1242 | } |
| 1222 | EXPORT_SYMBOL_GPL(nft_unregister_expr); | 1243 | EXPORT_SYMBOL_GPL(nft_unregister_expr); |
| @@ -1549,16 +1570,17 @@ static int nf_tables_dump_rules(struct sk_buff *skb, | |||
| 1549 | unsigned int idx = 0, s_idx = cb->args[0]; | 1570 | unsigned int idx = 0, s_idx = cb->args[0]; |
| 1550 | struct net *net = sock_net(skb->sk); | 1571 | struct net *net = sock_net(skb->sk); |
| 1551 | int family = nfmsg->nfgen_family; | 1572 | int family = nfmsg->nfgen_family; |
| 1552 | u8 genctr = ACCESS_ONCE(net->nft.genctr); | ||
| 1553 | u8 gencursor = ACCESS_ONCE(net->nft.gencursor); | ||
| 1554 | 1573 | ||
| 1555 | list_for_each_entry(afi, &net->nft.af_info, list) { | 1574 | rcu_read_lock(); |
| 1575 | cb->seq = net->nft.base_seq; | ||
| 1576 | |||
| 1577 | list_for_each_entry_rcu(afi, &net->nft.af_info, list) { | ||
| 1556 | if (family != NFPROTO_UNSPEC && family != afi->family) | 1578 | if (family != NFPROTO_UNSPEC && family != afi->family) |
| 1557 | continue; | 1579 | continue; |
| 1558 | 1580 | ||
| 1559 | list_for_each_entry(table, &afi->tables, list) { | 1581 | list_for_each_entry_rcu(table, &afi->tables, list) { |
| 1560 | list_for_each_entry(chain, &table->chains, list) { | 1582 | list_for_each_entry_rcu(chain, &table->chains, list) { |
| 1561 | list_for_each_entry(rule, &chain->rules, list) { | 1583 | list_for_each_entry_rcu(rule, &chain->rules, list) { |
| 1562 | if (!nft_rule_is_active(net, rule)) | 1584 | if (!nft_rule_is_active(net, rule)) |
| 1563 | goto cont; | 1585 | goto cont; |
| 1564 | if (idx < s_idx) | 1586 | if (idx < s_idx) |
| @@ -1572,6 +1594,8 @@ static int nf_tables_dump_rules(struct sk_buff *skb, | |||
| 1572 | NLM_F_MULTI | NLM_F_APPEND, | 1594 | NLM_F_MULTI | NLM_F_APPEND, |
| 1573 | afi->family, table, chain, rule) < 0) | 1595 | afi->family, table, chain, rule) < 0) |
| 1574 | goto done; | 1596 | goto done; |
| 1597 | |||
| 1598 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
| 1575 | cont: | 1599 | cont: |
| 1576 | idx++; | 1600 | idx++; |
| 1577 | } | 1601 | } |
| @@ -1579,9 +1603,7 @@ cont: | |||
| 1579 | } | 1603 | } |
| 1580 | } | 1604 | } |
| 1581 | done: | 1605 | done: |
| 1582 | /* Invalidate this dump, a transition to the new generation happened */ | 1606 | rcu_read_unlock(); |
| 1583 | if (gencursor != net->nft.gencursor || genctr != net->nft.genctr) | ||
| 1584 | return -EBUSY; | ||
| 1585 | 1607 | ||
| 1586 | cb->args[0] = idx; | 1608 | cb->args[0] = idx; |
| 1587 | return skb->len; | 1609 | return skb->len; |
| @@ -1932,7 +1954,7 @@ static LIST_HEAD(nf_tables_set_ops); | |||
| 1932 | int nft_register_set(struct nft_set_ops *ops) | 1954 | int nft_register_set(struct nft_set_ops *ops) |
| 1933 | { | 1955 | { |
| 1934 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 1956 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 1935 | list_add_tail(&ops->list, &nf_tables_set_ops); | 1957 | list_add_tail_rcu(&ops->list, &nf_tables_set_ops); |
| 1936 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 1958 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 1937 | return 0; | 1959 | return 0; |
| 1938 | } | 1960 | } |
| @@ -1941,7 +1963,7 @@ EXPORT_SYMBOL_GPL(nft_register_set); | |||
| 1941 | void nft_unregister_set(struct nft_set_ops *ops) | 1963 | void nft_unregister_set(struct nft_set_ops *ops) |
| 1942 | { | 1964 | { |
| 1943 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 1965 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
| 1944 | list_del(&ops->list); | 1966 | list_del_rcu(&ops->list); |
| 1945 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 1967 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
| 1946 | } | 1968 | } |
| 1947 | EXPORT_SYMBOL_GPL(nft_unregister_set); | 1969 | EXPORT_SYMBOL_GPL(nft_unregister_set); |
| @@ -2234,7 +2256,10 @@ static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2234 | if (cb->args[1]) | 2256 | if (cb->args[1]) |
| 2235 | return skb->len; | 2257 | return skb->len; |
| 2236 | 2258 | ||
| 2237 | list_for_each_entry(set, &ctx->table->sets, list) { | 2259 | rcu_read_lock(); |
| 2260 | cb->seq = ctx->net->nft.base_seq; | ||
| 2261 | |||
| 2262 | list_for_each_entry_rcu(set, &ctx->table->sets, list) { | ||
| 2238 | if (idx < s_idx) | 2263 | if (idx < s_idx) |
| 2239 | goto cont; | 2264 | goto cont; |
| 2240 | if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET, | 2265 | if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET, |
| @@ -2242,11 +2267,13 @@ static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2242 | cb->args[0] = idx; | 2267 | cb->args[0] = idx; |
| 2243 | goto done; | 2268 | goto done; |
| 2244 | } | 2269 | } |
| 2270 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
| 2245 | cont: | 2271 | cont: |
| 2246 | idx++; | 2272 | idx++; |
| 2247 | } | 2273 | } |
| 2248 | cb->args[1] = 1; | 2274 | cb->args[1] = 1; |
| 2249 | done: | 2275 | done: |
| 2276 | rcu_read_unlock(); | ||
| 2250 | return skb->len; | 2277 | return skb->len; |
| 2251 | } | 2278 | } |
| 2252 | 2279 | ||
| @@ -2260,7 +2287,10 @@ static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2260 | if (cb->args[1]) | 2287 | if (cb->args[1]) |
| 2261 | return skb->len; | 2288 | return skb->len; |
| 2262 | 2289 | ||
| 2263 | list_for_each_entry(table, &ctx->afi->tables, list) { | 2290 | rcu_read_lock(); |
| 2291 | cb->seq = ctx->net->nft.base_seq; | ||
| 2292 | |||
| 2293 | list_for_each_entry_rcu(table, &ctx->afi->tables, list) { | ||
| 2264 | if (cur_table) { | 2294 | if (cur_table) { |
| 2265 | if (cur_table != table) | 2295 | if (cur_table != table) |
| 2266 | continue; | 2296 | continue; |
| @@ -2269,7 +2299,7 @@ static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2269 | } | 2299 | } |
| 2270 | ctx->table = table; | 2300 | ctx->table = table; |
| 2271 | idx = 0; | 2301 | idx = 0; |
| 2272 | list_for_each_entry(set, &ctx->table->sets, list) { | 2302 | list_for_each_entry_rcu(set, &ctx->table->sets, list) { |
| 2273 | if (idx < s_idx) | 2303 | if (idx < s_idx) |
| 2274 | goto cont; | 2304 | goto cont; |
| 2275 | if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET, | 2305 | if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET, |
| @@ -2278,12 +2308,14 @@ static int nf_tables_dump_sets_family(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2278 | cb->args[2] = (unsigned long) table; | 2308 | cb->args[2] = (unsigned long) table; |
| 2279 | goto done; | 2309 | goto done; |
| 2280 | } | 2310 | } |
| 2311 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
| 2281 | cont: | 2312 | cont: |
| 2282 | idx++; | 2313 | idx++; |
| 2283 | } | 2314 | } |
| 2284 | } | 2315 | } |
| 2285 | cb->args[1] = 1; | 2316 | cb->args[1] = 1; |
| 2286 | done: | 2317 | done: |
| 2318 | rcu_read_unlock(); | ||
| 2287 | return skb->len; | 2319 | return skb->len; |
| 2288 | } | 2320 | } |
| 2289 | 2321 | ||
| @@ -2300,7 +2332,10 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2300 | if (cb->args[1]) | 2332 | if (cb->args[1]) |
| 2301 | return skb->len; | 2333 | return skb->len; |
| 2302 | 2334 | ||
| 2303 | list_for_each_entry(afi, &net->nft.af_info, list) { | 2335 | rcu_read_lock(); |
| 2336 | cb->seq = net->nft.base_seq; | ||
| 2337 | |||
| 2338 | list_for_each_entry_rcu(afi, &net->nft.af_info, list) { | ||
| 2304 | if (cur_family) { | 2339 | if (cur_family) { |
| 2305 | if (afi->family != cur_family) | 2340 | if (afi->family != cur_family) |
| 2306 | continue; | 2341 | continue; |
| @@ -2308,7 +2343,7 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2308 | cur_family = 0; | 2343 | cur_family = 0; |
| 2309 | } | 2344 | } |
| 2310 | 2345 | ||
| 2311 | list_for_each_entry(table, &afi->tables, list) { | 2346 | list_for_each_entry_rcu(table, &afi->tables, list) { |
| 2312 | if (cur_table) { | 2347 | if (cur_table) { |
| 2313 | if (cur_table != table) | 2348 | if (cur_table != table) |
| 2314 | continue; | 2349 | continue; |
| @@ -2319,7 +2354,7 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2319 | ctx->table = table; | 2354 | ctx->table = table; |
| 2320 | ctx->afi = afi; | 2355 | ctx->afi = afi; |
| 2321 | idx = 0; | 2356 | idx = 0; |
| 2322 | list_for_each_entry(set, &ctx->table->sets, list) { | 2357 | list_for_each_entry_rcu(set, &ctx->table->sets, list) { |
| 2323 | if (idx < s_idx) | 2358 | if (idx < s_idx) |
| 2324 | goto cont; | 2359 | goto cont; |
| 2325 | if (nf_tables_fill_set(skb, ctx, set, | 2360 | if (nf_tables_fill_set(skb, ctx, set, |
| @@ -2330,6 +2365,7 @@ static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb, | |||
| 2330 | cb->args[3] = afi->family; | 2365 | cb->args[3] = afi->family; |
| 2331 | goto done; | 2366 | goto done; |
| 2332 | } | 2367 | } |
| 2368 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||
| 2333 | cont: | 2369 | cont: |
| 2334 | idx++; | 2370 | idx++; |
| 2335 | } | 2371 | } |
| @@ -2339,6 +2375,7 @@ cont: | |||
| 2339 | } | 2375 | } |
| 2340 | cb->args[1] = 1; | 2376 | cb->args[1] = 1; |
| 2341 | done: | 2377 | done: |
| 2378 | rcu_read_unlock(); | ||
| 2342 | return skb->len; | 2379 | return skb->len; |
| 2343 | } | 2380 | } |
| 2344 | 2381 | ||
| @@ -2597,7 +2634,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, | |||
| 2597 | if (err < 0) | 2634 | if (err < 0) |
| 2598 | goto err2; | 2635 | goto err2; |
| 2599 | 2636 | ||
| 2600 | list_add_tail(&set->list, &table->sets); | 2637 | list_add_tail_rcu(&set->list, &table->sets); |
| 2601 | table->use++; | 2638 | table->use++; |
| 2602 | return 0; | 2639 | return 0; |
| 2603 | 2640 | ||
| @@ -2617,7 +2654,7 @@ static void nft_set_destroy(struct nft_set *set) | |||
| 2617 | 2654 | ||
| 2618 | static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) | 2655 | static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set) |
| 2619 | { | 2656 | { |
| 2620 | list_del(&set->list); | 2657 | list_del_rcu(&set->list); |
| 2621 | nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, GFP_ATOMIC); | 2658 | nf_tables_set_notify(ctx, set, NFT_MSG_DELSET, GFP_ATOMIC); |
| 2622 | nft_set_destroy(set); | 2659 | nft_set_destroy(set); |
| 2623 | } | 2660 | } |
| @@ -2652,7 +2689,7 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb, | |||
| 2652 | if (err < 0) | 2689 | if (err < 0) |
| 2653 | return err; | 2690 | return err; |
| 2654 | 2691 | ||
| 2655 | list_del(&set->list); | 2692 | list_del_rcu(&set->list); |
| 2656 | ctx.table->use--; | 2693 | ctx.table->use--; |
| 2657 | return 0; | 2694 | return 0; |
| 2658 | } | 2695 | } |
| @@ -2704,14 +2741,14 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, | |||
| 2704 | } | 2741 | } |
| 2705 | bind: | 2742 | bind: |
| 2706 | binding->chain = ctx->chain; | 2743 | binding->chain = ctx->chain; |
| 2707 | list_add_tail(&binding->list, &set->bindings); | 2744 | list_add_tail_rcu(&binding->list, &set->bindings); |
| 2708 | return 0; | 2745 | return 0; |
| 2709 | } | 2746 | } |
| 2710 | 2747 | ||
| 2711 | void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, | 2748 | void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, |
| 2712 | struct nft_set_binding *binding) | 2749 | struct nft_set_binding *binding) |
| 2713 | { | 2750 | { |
| 2714 | list_del(&binding->list); | 2751 | list_del_rcu(&binding->list); |
| 2715 | 2752 | ||
| 2716 | if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS && | 2753 | if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS && |
| 2717 | !(set->flags & NFT_SET_INACTIVE)) | 2754 | !(set->flags & NFT_SET_INACTIVE)) |
| @@ -3346,7 +3383,7 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
| 3346 | struct nft_set *set; | 3383 | struct nft_set *set; |
| 3347 | 3384 | ||
| 3348 | /* Bump generation counter, invalidate any dump in progress */ | 3385 | /* Bump generation counter, invalidate any dump in progress */ |
| 3349 | net->nft.genctr++; | 3386 | while (++net->nft.base_seq == 0); |
| 3350 | 3387 | ||
| 3351 | /* A new generation has just started */ | 3388 | /* A new generation has just started */ |
| 3352 | net->nft.gencursor = gencursor_next(net); | 3389 | net->nft.gencursor = gencursor_next(net); |
| @@ -3491,12 +3528,12 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
| 3491 | } | 3528 | } |
| 3492 | nft_trans_destroy(trans); | 3529 | nft_trans_destroy(trans); |
| 3493 | } else { | 3530 | } else { |
| 3494 | list_del(&trans->ctx.table->list); | 3531 | list_del_rcu(&trans->ctx.table->list); |
| 3495 | } | 3532 | } |
| 3496 | break; | 3533 | break; |
| 3497 | case NFT_MSG_DELTABLE: | 3534 | case NFT_MSG_DELTABLE: |
| 3498 | list_add_tail(&trans->ctx.table->list, | 3535 | list_add_tail_rcu(&trans->ctx.table->list, |
| 3499 | &trans->ctx.afi->tables); | 3536 | &trans->ctx.afi->tables); |
| 3500 | nft_trans_destroy(trans); | 3537 | nft_trans_destroy(trans); |
| 3501 | break; | 3538 | break; |
| 3502 | case NFT_MSG_NEWCHAIN: | 3539 | case NFT_MSG_NEWCHAIN: |
| @@ -3507,7 +3544,7 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
| 3507 | nft_trans_destroy(trans); | 3544 | nft_trans_destroy(trans); |
| 3508 | } else { | 3545 | } else { |
| 3509 | trans->ctx.table->use--; | 3546 | trans->ctx.table->use--; |
| 3510 | list_del(&trans->ctx.chain->list); | 3547 | list_del_rcu(&trans->ctx.chain->list); |
| 3511 | if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && | 3548 | if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && |
| 3512 | trans->ctx.chain->flags & NFT_BASE_CHAIN) { | 3549 | trans->ctx.chain->flags & NFT_BASE_CHAIN) { |
| 3513 | nf_unregister_hooks(nft_base_chain(trans->ctx.chain)->ops, | 3550 | nf_unregister_hooks(nft_base_chain(trans->ctx.chain)->ops, |
| @@ -3517,8 +3554,8 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
| 3517 | break; | 3554 | break; |
| 3518 | case NFT_MSG_DELCHAIN: | 3555 | case NFT_MSG_DELCHAIN: |
| 3519 | trans->ctx.table->use++; | 3556 | trans->ctx.table->use++; |
| 3520 | list_add_tail(&trans->ctx.chain->list, | 3557 | list_add_tail_rcu(&trans->ctx.chain->list, |
| 3521 | &trans->ctx.table->chains); | 3558 | &trans->ctx.table->chains); |
| 3522 | nft_trans_destroy(trans); | 3559 | nft_trans_destroy(trans); |
| 3523 | break; | 3560 | break; |
| 3524 | case NFT_MSG_NEWRULE: | 3561 | case NFT_MSG_NEWRULE: |
| @@ -3532,12 +3569,12 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
| 3532 | break; | 3569 | break; |
| 3533 | case NFT_MSG_NEWSET: | 3570 | case NFT_MSG_NEWSET: |
| 3534 | trans->ctx.table->use--; | 3571 | trans->ctx.table->use--; |
| 3535 | list_del(&nft_trans_set(trans)->list); | 3572 | list_del_rcu(&nft_trans_set(trans)->list); |
| 3536 | break; | 3573 | break; |
| 3537 | case NFT_MSG_DELSET: | 3574 | case NFT_MSG_DELSET: |
| 3538 | trans->ctx.table->use++; | 3575 | trans->ctx.table->use++; |
| 3539 | list_add_tail(&nft_trans_set(trans)->list, | 3576 | list_add_tail_rcu(&nft_trans_set(trans)->list, |
| 3540 | &trans->ctx.table->sets); | 3577 | &trans->ctx.table->sets); |
| 3541 | nft_trans_destroy(trans); | 3578 | nft_trans_destroy(trans); |
| 3542 | break; | 3579 | break; |
| 3543 | case NFT_MSG_NEWSETELEM: | 3580 | case NFT_MSG_NEWSETELEM: |
| @@ -3951,6 +3988,7 @@ static int nf_tables_init_net(struct net *net) | |||
| 3951 | { | 3988 | { |
| 3952 | INIT_LIST_HEAD(&net->nft.af_info); | 3989 | INIT_LIST_HEAD(&net->nft.af_info); |
| 3953 | INIT_LIST_HEAD(&net->nft.commit_list); | 3990 | INIT_LIST_HEAD(&net->nft.commit_list); |
| 3991 | net->nft.base_seq = 1; | ||
| 3954 | return 0; | 3992 | return 0; |
| 3955 | } | 3993 | } |
| 3956 | 3994 | ||
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index 345acfb1720b..3b90eb2b2c55 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c | |||
| @@ -109,7 +109,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) | |||
| 109 | struct nft_data data[NFT_REG_MAX + 1]; | 109 | struct nft_data data[NFT_REG_MAX + 1]; |
| 110 | unsigned int stackptr = 0; | 110 | unsigned int stackptr = 0; |
| 111 | struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; | 111 | struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; |
| 112 | struct nft_stats __percpu *stats; | 112 | struct nft_stats *stats; |
| 113 | int rulenum; | 113 | int rulenum; |
| 114 | /* | 114 | /* |
| 115 | * Cache cursor to avoid problems in case that the cursor is updated | 115 | * Cache cursor to avoid problems in case that the cursor is updated |
| @@ -205,9 +205,11 @@ next_rule: | |||
| 205 | nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY); | 205 | nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY); |
| 206 | 206 | ||
| 207 | rcu_read_lock_bh(); | 207 | rcu_read_lock_bh(); |
| 208 | stats = rcu_dereference(nft_base_chain(basechain)->stats); | 208 | stats = this_cpu_ptr(rcu_dereference(nft_base_chain(basechain)->stats)); |
| 209 | __this_cpu_inc(stats->pkts); | 209 | u64_stats_update_begin(&stats->syncp); |
| 210 | __this_cpu_add(stats->bytes, pkt->skb->len); | 210 | stats->pkts++; |
| 211 | stats->bytes += pkt->skb->len; | ||
| 212 | u64_stats_update_end(&stats->syncp); | ||
| 211 | rcu_read_unlock_bh(); | 213 | rcu_read_unlock_bh(); |
| 212 | 214 | ||
| 213 | return nft_base_chain(basechain)->policy; | 215 | return nft_base_chain(basechain)->policy; |
