mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 23:22:31 +02:00
netfilter pull request 26-05-16
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEjF9xRqF1emXiQiqU1w0aZmrPKyEFAmoIV2cACgkQ1w0aZmrP
KyGYYg//TAfAeQbuVfui3eZLCyKg/J9QyPpyoTMC2X+Waow4Ui+t+PJyez59tjT2
xtuNBI6PSwbEQj7oXU0Yz7J6f2e6wkSn6VtcSBe0ACOshVQ40tVWdtOh3RHOrtUI
tPf4HiZZayM6uLz2abWW7mIAWRt7uSAj6PTTe1X5E1GeIY+rnebjo/iNE912wHGs
HbeshARbiPXofo3D0TzEV90/Kc4Xx98Js4FeNUP7328pP2MdqErSbM96QVmgbqpQ
/eY2+wUSJeIJ1jfVQxhkBG0qJf1LRCXAYvmXD5adU3mq4v450DRzquzWwW5e5vuO
PHLvbyfaB49tmuitAlrAWmouY8LQ6IeOYegh50RAAzlRSy0/+tLRLI85ny1MH8IV
y30B4XCId9NL2A61J8P3jUcnjEpnKl8548Qnr2Ql2Mn3mKM3cXT2LI0uFobBNl+0
67oefbuhDiQbLVRahpUKKskeu/dpFVeiEzG4QNIjjXgcwc0LPZr20WUQdZORrSob
dq5oJ9rBK6phIR6JK5lfGMyE1Uy7TZp+K18YkyvGsAwNz/YSqMgqPpsE/2nsJxlL
1ifmcCdCr1zhU4jd+b3dUR7Bjob08dcE5/kXPWKr6Bir/74hisZoYrYQti09De0l
d2secQ5O7iTRvjD4z4vjQjgaIqN2OlcpWouxnljrTx18B82H7Ps=
=rsHV
-----END PGP SIGNATURE-----
Merge tag 'nf-26-05-16' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says:
====================
Netfilter/IPVS fixes for net
The following patchset contains Netfilter/IPVS fixes for net:
1) Fix small race windows in nf_ct_helper_log() when accessing helper,
from Florian Westphal.
2) Fix potential infinite loop and race conditions in IPVS caused by
frequent user-triggered service table changes, from Julia Anastasov.
3) Fix a race condition when dumping ipsets for restore,
from Jozsef Kadlecsik.
4) Fix inner transport offset in IPv6 in nft_inner when extension
headers come before the layer 4 transport header, from Yizhou Zhao.
5) Fix incorrect iteration over IPv4 ranges in several hash set types,
from Nan Li.
6) Fix incorrect order when restoring BH in nft_inner_restore_tun_ctx(),
from Florian Westphal.
7) Validate option array from ip6t_hbh checkpath() to fix an off-by-one
access, from Zhengchuan Liang.
8) Fix race condition between ipset list -terse and concurrent updates,
from Jozsef Kadlecisk.
9) Fix race condition when inserting elements into a hash bucket, also
from Jozsef.
10) Annotate access to first free slot in hashtable, from Jozsef Kadlecsik.
11) Ensure sufficient headroom in br_netfilter neigh transmission,
from Lorenzo Bianconi.
12) Hold reference on skb->dev in nfqueue exit path, bridge local input
is speciall since skb->dev != state->indev, allowing for net_device
to go away while packet is sitting in nfqueue. From Haoze Xie.
* tag 'nf-26-05-16' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
netfilter: nf_queue: hold bridge skb->dev while queued
netfilter: br_netfilter: Reallocate headroom if necessary in neigh_hh_bridge()
netfilter: ipset: annotate "pos" for concurrent readers/writers
netfilter: ipset: Fix data race between add and dump in all hash types
netfilter: ipset: Fix data race between add and list header in all hash types
netfilter: ip6t_hbh: reject oversized option lists
netfilter: nft_inner: release local_lock before re-enabling softirqs
netfilter: ipset: stop hash:* range iteration at end
netfilter: nft_inner: Fix IPv6 inner_thoff desync
netfilter: ipset: fix a potential dump-destroy race
ipvs: avoid possible loop in ip_vs_dst_event on resizing
netfilter: nf_conntrack_helper: fix possible null deref during error log
====================
Link: https://patch.msgid.link/20260516115627.967773-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
317bbe5301
|
|
@ -1186,8 +1186,9 @@ struct netns_ipvs {
|
|||
struct timer_list dest_trash_timer; /* expiration timer */
|
||||
struct mutex service_mutex; /* service reconfig */
|
||||
struct rw_semaphore svc_resize_sem; /* svc_table resizing */
|
||||
struct rw_semaphore svc_replace_sem; /* svc_table replace */
|
||||
struct delayed_work svc_resize_work; /* resize svc_table */
|
||||
atomic_t svc_table_changes;/* ++ on new table */
|
||||
atomic_t svc_table_changes;/* ++ on table changes */
|
||||
/* Service counters */
|
||||
atomic_t num_services[IP_VS_AF_MAX]; /* Services */
|
||||
atomic_t fwm_services[IP_VS_AF_MAX]; /* Services */
|
||||
|
|
|
|||
|
|
@ -489,11 +489,15 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
|
|||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
|
||||
{
|
||||
unsigned int seq, hh_alen;
|
||||
unsigned int seq, hh_alen = HH_DATA_ALIGN(ETH_HLEN);
|
||||
int err;
|
||||
|
||||
err = skb_cow_head(skb, hh_alen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
do {
|
||||
seq = read_seqbegin(&hh->hh_lock);
|
||||
hh_alen = HH_DATA_ALIGN(ETH_HLEN);
|
||||
memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN);
|
||||
} while (read_seqretry(&hh->hh_lock, seq));
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ struct nf_queue_entry {
|
|||
struct list_head list;
|
||||
struct rhash_head hash_node;
|
||||
struct sk_buff *skb;
|
||||
struct net_device *skb_dev;
|
||||
unsigned int id;
|
||||
unsigned int hook_index; /* index in hook_entries->hook[] */
|
||||
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
|
||||
|
|
|
|||
|
|
@ -297,7 +297,11 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_
|
|||
goto free_skb;
|
||||
}
|
||||
|
||||
neigh_hh_bridge(&neigh->hh, skb);
|
||||
if (neigh_hh_bridge(&neigh->hh, skb)) {
|
||||
neigh_release(neigh);
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
skb->dev = br_indev;
|
||||
|
||||
ret = br_handle_frame_finish(net, sk, skb);
|
||||
|
|
|
|||
|
|
@ -168,6 +168,10 @@ static int hbh_mt6_check(const struct xt_mtchk_param *par)
|
|||
pr_debug("unknown flags %X\n", optsinfo->invflags);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (optsinfo->optsnr > IP6T_OPTS_OPTSNR) {
|
||||
pr_debug("too many supported opts specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (optsinfo->flags & IP6T_OPTS_NSTRICT) {
|
||||
pr_debug("Not strict - not implemented");
|
||||
|
|
|
|||
|
|
@ -1613,6 +1613,7 @@ ip_set_dump_do(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
((dump_type == DUMP_ALL) ==
|
||||
!!(set->type->features & IPSET_DUMP_LAST))) {
|
||||
write_unlock_bh(&ip_set_ref_lock);
|
||||
set = NULL;
|
||||
continue;
|
||||
}
|
||||
pr_debug("List set: %s\n", set->name);
|
||||
|
|
@ -1648,13 +1649,13 @@ ip_set_dump_do(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
if (cb->args[IPSET_CB_PROTO] > IPSET_PROTOCOL_MIN &&
|
||||
nla_put_net16(skb, IPSET_ATTR_INDEX, htons(index)))
|
||||
goto nla_put_failure;
|
||||
if (set->variant->uref)
|
||||
set->variant->uref(set, cb, true);
|
||||
ret = set->variant->head(set, skb);
|
||||
if (ret < 0)
|
||||
goto release_refcount;
|
||||
if (dump_flags & IPSET_FLAG_LIST_HEADER)
|
||||
goto next_set;
|
||||
if (set->variant->uref)
|
||||
set->variant->uref(set, cb, true);
|
||||
fallthrough;
|
||||
default:
|
||||
ret = set->variant->list(set, skb, cb);
|
||||
|
|
|
|||
|
|
@ -386,8 +386,9 @@ static void
|
|||
mtype_ext_cleanup(struct ip_set *set, struct hbucket *n)
|
||||
{
|
||||
int i;
|
||||
u8 pos = smp_load_acquire(&n->pos);
|
||||
|
||||
for (i = 0; i < n->pos; i++)
|
||||
for (i = 0; i < pos; i++)
|
||||
if (test_bit(i, n->used))
|
||||
ip_set_ext_destroy(set, ahash_data(n, i, set->dsize));
|
||||
}
|
||||
|
|
@ -490,7 +491,7 @@ mtype_gc_do(struct ip_set *set, struct htype *h, struct htable *t, u32 r)
|
|||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
u8 k;
|
||||
#endif
|
||||
u8 htable_bits = t->htable_bits;
|
||||
u8 pos, htable_bits = t->htable_bits;
|
||||
|
||||
spin_lock_bh(&t->hregion[r].lock);
|
||||
for (i = ahash_bucket_start(r, htable_bits);
|
||||
|
|
@ -498,7 +499,8 @@ mtype_gc_do(struct ip_set *set, struct htype *h, struct htable *t, u32 r)
|
|||
n = __ipset_dereference(hbucket(t, i));
|
||||
if (!n)
|
||||
continue;
|
||||
for (j = 0, d = 0; j < n->pos; j++) {
|
||||
pos = smp_load_acquire(&n->pos);
|
||||
for (j = 0, d = 0; j < pos; j++) {
|
||||
if (!test_bit(j, n->used)) {
|
||||
d++;
|
||||
continue;
|
||||
|
|
@ -534,7 +536,7 @@ mtype_gc_do(struct ip_set *set, struct htype *h, struct htable *t, u32 r)
|
|||
/* Still try to delete expired elements. */
|
||||
continue;
|
||||
tmp->size = n->size - AHASH_INIT_SIZE;
|
||||
for (j = 0, d = 0; j < n->pos; j++) {
|
||||
for (j = 0, d = 0; j < pos; j++) {
|
||||
if (!test_bit(j, n->used))
|
||||
continue;
|
||||
data = ahash_data(n, j, dsize);
|
||||
|
|
@ -623,7 +625,7 @@ mtype_resize(struct ip_set *set, bool retried)
|
|||
{
|
||||
struct htype *h = set->data;
|
||||
struct htable *t, *orig;
|
||||
u8 htable_bits;
|
||||
u8 pos, htable_bits;
|
||||
size_t hsize, dsize = set->dsize;
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
u8 flags;
|
||||
|
|
@ -685,7 +687,8 @@ mtype_resize(struct ip_set *set, bool retried)
|
|||
n = __ipset_dereference(hbucket(orig, i));
|
||||
if (!n)
|
||||
continue;
|
||||
for (j = 0; j < n->pos; j++) {
|
||||
pos = smp_load_acquire(&n->pos);
|
||||
for (j = 0; j < pos; j++) {
|
||||
if (!test_bit(j, n->used))
|
||||
continue;
|
||||
data = ahash_data(n, j, dsize);
|
||||
|
|
@ -809,9 +812,10 @@ mtype_ext_size(struct ip_set *set, u32 *elements, size_t *ext_size)
|
|||
{
|
||||
struct htype *h = set->data;
|
||||
const struct htable *t;
|
||||
u32 i, j, r;
|
||||
struct hbucket *n;
|
||||
struct mtype_elem *data;
|
||||
u32 i, j, r;
|
||||
u8 pos;
|
||||
|
||||
t = rcu_dereference_bh(h->table);
|
||||
for (r = 0; r < ahash_numof_locks(t->htable_bits); r++) {
|
||||
|
|
@ -820,7 +824,8 @@ mtype_ext_size(struct ip_set *set, u32 *elements, size_t *ext_size)
|
|||
n = rcu_dereference_bh(hbucket(t, i));
|
||||
if (!n)
|
||||
continue;
|
||||
for (j = 0; j < n->pos; j++) {
|
||||
pos = smp_load_acquire(&n->pos);
|
||||
for (j = 0; j < pos; j++) {
|
||||
if (!test_bit(j, n->used))
|
||||
continue;
|
||||
data = ahash_data(n, j, set->dsize);
|
||||
|
|
@ -848,6 +853,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||
bool deleted = false, forceadd = false, reuse = false;
|
||||
u32 r, key, multi = 0, elements, maxelem;
|
||||
u8 npos = 0;
|
||||
|
||||
rcu_read_lock_bh();
|
||||
t = rcu_dereference_bh(h->table);
|
||||
|
|
@ -889,7 +895,8 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
ext_size(AHASH_INIT_SIZE, set->dsize);
|
||||
goto copy_elem;
|
||||
}
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
npos = smp_load_acquire(&n->pos);
|
||||
for (i = 0; i < npos; i++) {
|
||||
if (!test_bit(i, n->used)) {
|
||||
/* Reuse first deleted entry */
|
||||
if (j == -1) {
|
||||
|
|
@ -933,7 +940,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
if (elements >= maxelem)
|
||||
goto set_full;
|
||||
/* Create a new slot */
|
||||
if (n->pos >= n->size) {
|
||||
if (npos >= n->size) {
|
||||
#ifdef IP_SET_HASH_WITH_MULTI
|
||||
if (h->bucketsize >= AHASH_MAX_TUNED)
|
||||
goto set_full;
|
||||
|
|
@ -962,7 +969,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
}
|
||||
|
||||
copy_elem:
|
||||
j = n->pos++;
|
||||
j = npos++;
|
||||
data = ahash_data(n, j, set->dsize);
|
||||
copy_data:
|
||||
t->hregion[r].elements++;
|
||||
|
|
@ -985,6 +992,8 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
if (SET_WITH_TIMEOUT(set))
|
||||
ip_set_timeout_set(ext_timeout(data, set), ext->timeout);
|
||||
smp_mb__before_atomic();
|
||||
/* Ensure all data writes are visible before updating position */
|
||||
smp_store_release(&n->pos, npos);
|
||||
set_bit(j, n->used);
|
||||
if (old != ERR_PTR(-ENOENT)) {
|
||||
rcu_assign_pointer(hbucket(t, key), n);
|
||||
|
|
@ -1043,6 +1052,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
int i, j, k, r, ret = -IPSET_ERR_EXIST;
|
||||
u32 key, multi = 0;
|
||||
size_t dsize = set->dsize;
|
||||
u8 pos;
|
||||
|
||||
/* Userspace add and resize is excluded by the mutex.
|
||||
* Kernespace add does not trigger resize.
|
||||
|
|
@ -1058,7 +1068,8 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
n = rcu_dereference_bh(hbucket(t, key));
|
||||
if (!n)
|
||||
goto out;
|
||||
for (i = 0, k = 0; i < n->pos; i++) {
|
||||
pos = smp_load_acquire(&n->pos);
|
||||
for (i = 0, k = 0; i < pos; i++) {
|
||||
if (!test_bit(i, n->used)) {
|
||||
k++;
|
||||
continue;
|
||||
|
|
@ -1072,8 +1083,8 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
ret = 0;
|
||||
clear_bit(i, n->used);
|
||||
smp_mb__after_atomic();
|
||||
if (i + 1 == n->pos)
|
||||
n->pos--;
|
||||
if (i + 1 == pos)
|
||||
smp_store_release(&n->pos, --pos);
|
||||
t->hregion[r].elements--;
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
for (j = 0; j < IPSET_NET_COUNT; j++)
|
||||
|
|
@ -1094,11 +1105,11 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
x->flags = flags;
|
||||
}
|
||||
}
|
||||
for (; i < n->pos; i++) {
|
||||
for (; i < pos; i++) {
|
||||
if (!test_bit(i, n->used))
|
||||
k++;
|
||||
}
|
||||
if (k == n->pos) {
|
||||
if (k == pos) {
|
||||
t->hregion[r].ext_size -= ext_size(n->size, dsize);
|
||||
rcu_assign_pointer(hbucket(t, key), NULL);
|
||||
kfree_rcu(n, rcu);
|
||||
|
|
@ -1109,7 +1120,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
if (!tmp)
|
||||
goto out;
|
||||
tmp->size = n->size - AHASH_INIT_SIZE;
|
||||
for (j = 0, k = 0; j < n->pos; j++) {
|
||||
for (j = 0, k = 0; j < pos; j++) {
|
||||
if (!test_bit(j, n->used))
|
||||
continue;
|
||||
data = ahash_data(n, j, dsize);
|
||||
|
|
@ -1170,6 +1181,7 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
|
|||
int ret, i, j = 0;
|
||||
#endif
|
||||
u32 key, multi = 0;
|
||||
u8 pos;
|
||||
|
||||
pr_debug("test by nets\n");
|
||||
for (; j < NLEN && h->nets[j].cidr[0] && !multi; j++) {
|
||||
|
|
@ -1187,7 +1199,8 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
|
|||
n = rcu_dereference_bh(hbucket(t, key));
|
||||
if (!n)
|
||||
continue;
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
pos = smp_load_acquire(&n->pos);
|
||||
for (i = 0; i < pos; i++) {
|
||||
if (!test_bit(i, n->used))
|
||||
continue;
|
||||
data = ahash_data(n, i, set->dsize);
|
||||
|
|
@ -1221,6 +1234,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
struct mtype_elem *data;
|
||||
int i, ret = 0;
|
||||
u32 key, multi = 0;
|
||||
u8 pos;
|
||||
|
||||
rcu_read_lock_bh();
|
||||
t = rcu_dereference_bh(h->table);
|
||||
|
|
@ -1243,7 +1257,8 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
pos = smp_load_acquire(&n->pos);
|
||||
for (i = 0; i < pos; i++) {
|
||||
if (!test_bit(i, n->used))
|
||||
continue;
|
||||
data = ahash_data(n, i, set->dsize);
|
||||
|
|
@ -1360,6 +1375,7 @@ mtype_list(const struct ip_set *set,
|
|||
/* We assume that one hash bucket fills into one page */
|
||||
void *incomplete;
|
||||
int i, ret = 0;
|
||||
u8 pos;
|
||||
|
||||
atd = nla_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
|
|
@ -1378,7 +1394,8 @@ mtype_list(const struct ip_set *set,
|
|||
cb->args[IPSET_CB_ARG0], t, n);
|
||||
if (!n)
|
||||
continue;
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
pos = smp_load_acquire(&n->pos);
|
||||
for (i = 0; i < pos; i++) {
|
||||
if (!test_bit(i, n->used))
|
||||
continue;
|
||||
e = ahash_data(n, i, set->dsize);
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
|
||||
if (retried)
|
||||
ip = ntohl(h->next.ip);
|
||||
for (; ip <= ip_to; ip++, i++) {
|
||||
for (; ip <= ip_to; i++) {
|
||||
e.ip = htonl(ip);
|
||||
if (i > IPSET_MAX_RANGE) {
|
||||
hash_ipmark4_data_next(&h->next, &e);
|
||||
|
|
@ -162,6 +162,10 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
return ret;
|
||||
|
||||
ret = 0;
|
||||
|
||||
if (ip == ip_to)
|
||||
break;
|
||||
ip++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
|
||||
if (retried)
|
||||
ip = ntohl(h->next.ip);
|
||||
for (; ip <= ip_to; ip++) {
|
||||
for (; ip <= ip_to;) {
|
||||
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
|
||||
: port;
|
||||
for (; p <= port_to; p++, i++) {
|
||||
|
|
@ -203,6 +203,9 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
|
||||
ret = 0;
|
||||
}
|
||||
if (ip == ip_to)
|
||||
break;
|
||||
ip++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
|
||||
if (retried)
|
||||
ip = ntohl(h->next.ip);
|
||||
for (; ip <= ip_to; ip++) {
|
||||
for (; ip <= ip_to;) {
|
||||
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
|
||||
: port;
|
||||
for (; p <= port_to; p++, i++) {
|
||||
|
|
@ -199,6 +199,9 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
|
||||
ret = 0;
|
||||
}
|
||||
if (ip == ip_to)
|
||||
break;
|
||||
ip++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
p = port;
|
||||
ip2 = ip2_from;
|
||||
}
|
||||
for (; ip <= ip_to; ip++) {
|
||||
for (; ip <= ip_to;) {
|
||||
e.ip = htonl(ip);
|
||||
for (; p <= port_to; p++) {
|
||||
e.port = htons(p);
|
||||
|
|
@ -298,6 +298,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
ip2 = ip2_from;
|
||||
}
|
||||
p = port;
|
||||
if (ip == ip_to)
|
||||
break;
|
||||
ip++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,18 +327,22 @@ ip_vs_use_count_dec(void)
|
|||
/* Service hashing:
|
||||
* Operation Locking order
|
||||
* ---------------------------------------------------------------------------
|
||||
* add table service_mutex, svc_resize_sem(W)
|
||||
* del table service_mutex
|
||||
* move between tables svc_resize_sem(W), seqcount_t(W), bit lock
|
||||
* add/del service service_mutex, bit lock
|
||||
* add first table service_mutex
|
||||
* attach new table service_mutex
|
||||
* add/del service service_mutex, RCU, bit lock
|
||||
* move between tables (rehash) svc_resize_sem(W), seqcount_t(W), bit lock
|
||||
* replace old with attached svc_resize_sem(W), svc_replace_sem(W)
|
||||
* find service RCU, seqcount_t(R)
|
||||
* walk services(blocking) service_mutex, svc_resize_sem(R)
|
||||
* walk services(non-blocking) RCU, seqcount_t(R)
|
||||
* walk services(non-blocking) svc_resize_sem(R), RCU, seqcount_t(R)
|
||||
* walk services(non-blocking) svc_replace_sem(R), RCU, seqcount_t(R)
|
||||
* del table service_mutex after stopped work
|
||||
*
|
||||
* - new tables are linked/unlinked under service_mutex and svc_resize_sem
|
||||
* - new table is linked on resizing and all operations can run in parallel
|
||||
* in 2 tables until the new table is registered as current one
|
||||
* - two contexts can modify buckets: config and table resize, both in
|
||||
* - new table is attached on resizing under service_mutex and all operations
|
||||
* can run in parallel in 2 tables until the new table is registered as current
|
||||
* one
|
||||
* - two contexts can modify buckets: config and table resize (work), both in
|
||||
* process context
|
||||
* - only table resizer can move entries, so we do not protect t->seqc[]
|
||||
* items with t->lock[]
|
||||
|
|
@ -346,9 +350,13 @@ ip_vs_use_count_dec(void)
|
|||
* services are moved to new table
|
||||
* - move operations may disturb readers: find operation will not miss entries
|
||||
* but walkers may see same entry twice if they are forced to retry chains
|
||||
* - walkers using cond_resched_rcu() on !PREEMPT_RCU may need to hold
|
||||
* service_mutex to disallow new tables to be installed or to check
|
||||
* or to walk the newly attached second table
|
||||
* - walkers using cond_resched_rcu() on !PREEMPT_RCU may need to check
|
||||
* svc_table_changes and repeat the RCU read section if new table is installed
|
||||
* - walkers may serialize with the whole resizing process (svc_resize_sem)
|
||||
* to prevent seeing same service twice or just with the svc_table
|
||||
* replace (svc_replace_sem) when we can see entries twice but we
|
||||
* prefer to run concurrently with the rehashing.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
@ -387,9 +395,16 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc)
|
|||
/* increase its refcnt because it is referenced by the svc table */
|
||||
atomic_inc(&svc->refcnt);
|
||||
|
||||
/* We know if new table is attached under service_mutex but rely on
|
||||
* RCU to hold the old table to be freed in resizer
|
||||
*/
|
||||
rcu_read_lock();
|
||||
|
||||
/* This can be the old or the new table */
|
||||
t = rcu_dereference(ipvs->svc_table);
|
||||
|
||||
/* New entries go into recent table */
|
||||
t = rcu_dereference_protected(ipvs->svc_table, 1);
|
||||
t = rcu_dereference_protected(t->new_tbl, 1);
|
||||
t = rcu_dereference(t->new_tbl);
|
||||
|
||||
if (svc->fwmark == 0) {
|
||||
/*
|
||||
|
|
@ -410,6 +425,8 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc)
|
|||
hlist_bl_add_head_rcu(&svc->s_list, head);
|
||||
hlist_bl_unlock(head);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -432,7 +449,13 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
t = rcu_dereference_protected(ipvs->svc_table, 1);
|
||||
/* We know if new table is attached under service_mutex but rely on
|
||||
* RCU to hold the old table to be freed in resizer
|
||||
*/
|
||||
rcu_read_lock();
|
||||
|
||||
/* This can be the old or the new table */
|
||||
t = rcu_dereference(ipvs->svc_table);
|
||||
hash_key = READ_ONCE(svc->hash_key);
|
||||
/* We need to lock the bucket in the right table */
|
||||
if (ip_vs_rht_same_table(t, hash_key)) {
|
||||
|
|
@ -443,13 +466,13 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc)
|
|||
/* Moved to new table ? */
|
||||
if (hash_key != hash_key2) {
|
||||
hlist_bl_unlock(head);
|
||||
t = rcu_dereference_protected(t->new_tbl, 1);
|
||||
t = rcu_dereference(t->new_tbl);
|
||||
head = t->buckets + (hash_key2 & t->mask);
|
||||
hlist_bl_lock(head);
|
||||
}
|
||||
} else {
|
||||
/* It is already moved to new table */
|
||||
t = rcu_dereference_protected(t->new_tbl, 1);
|
||||
t = rcu_dereference(t->new_tbl);
|
||||
head = t->buckets + (hash_key & t->mask);
|
||||
hlist_bl_lock(head);
|
||||
}
|
||||
|
|
@ -459,6 +482,8 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc)
|
|||
svc->flags &= ~IP_VS_SVC_F_HASHED;
|
||||
atomic_dec(&svc->refcnt);
|
||||
hlist_bl_unlock(head);
|
||||
|
||||
rcu_read_unlock();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -666,15 +691,14 @@ static void svc_resize_work_handler(struct work_struct *work)
|
|||
goto unlock_sem;
|
||||
more_work = false;
|
||||
clear_bit(IP_VS_WORK_SVC_RESIZE, &ipvs->work_flags);
|
||||
if (!READ_ONCE(ipvs->enable) ||
|
||||
test_bit(IP_VS_WORK_SVC_NORESIZE, &ipvs->work_flags))
|
||||
if (!READ_ONCE(ipvs->enable))
|
||||
goto unlock_m;
|
||||
t = rcu_dereference_protected(ipvs->svc_table, 1);
|
||||
/* Do nothing if table is removed */
|
||||
if (!t)
|
||||
goto unlock_m;
|
||||
/* New table needs to be registered? BUG! */
|
||||
if (t != rcu_dereference_protected(t->new_tbl, 1))
|
||||
/* New table already attached? BUG! */
|
||||
if (t != rcu_access_pointer(t->new_tbl))
|
||||
goto unlock_m;
|
||||
|
||||
lfactor = sysctl_svc_lfactor(ipvs);
|
||||
|
|
@ -691,6 +715,7 @@ static void svc_resize_work_handler(struct work_struct *work)
|
|||
/* Flip the table_id */
|
||||
t_new->table_id = t->table_id ^ IP_VS_RHT_TABLE_ID_MASK;
|
||||
|
||||
/* Attach new table */
|
||||
rcu_assign_pointer(t->new_tbl, t_new);
|
||||
/* Allow add/del to new_tbl while moving from old table */
|
||||
mutex_unlock(&ipvs->service_mutex);
|
||||
|
|
@ -698,8 +723,8 @@ static void svc_resize_work_handler(struct work_struct *work)
|
|||
ip_vs_rht_for_each_bucket(t, bucket, head) {
|
||||
same_bucket:
|
||||
if (++limit >= 16) {
|
||||
if (!READ_ONCE(ipvs->enable) ||
|
||||
test_bit(IP_VS_WORK_SVC_NORESIZE,
|
||||
/* Check if work is stopped */
|
||||
if (test_bit(IP_VS_WORK_SVC_NORESIZE,
|
||||
&ipvs->work_flags))
|
||||
goto unlock_sem;
|
||||
if (resched_score >= 100) {
|
||||
|
|
@ -764,16 +789,12 @@ static void svc_resize_work_handler(struct work_struct *work)
|
|||
goto same_bucket;
|
||||
}
|
||||
|
||||
/* Tables can be switched only under service_mutex */
|
||||
while (!mutex_trylock(&ipvs->service_mutex)) {
|
||||
cond_resched();
|
||||
if (!READ_ONCE(ipvs->enable) ||
|
||||
test_bit(IP_VS_WORK_SVC_NORESIZE, &ipvs->work_flags))
|
||||
goto unlock_sem;
|
||||
}
|
||||
if (!READ_ONCE(ipvs->enable) ||
|
||||
test_bit(IP_VS_WORK_SVC_NORESIZE, &ipvs->work_flags))
|
||||
goto unlock_m;
|
||||
/* Serialize with readers that don't like svc_table changes */
|
||||
down_write(&ipvs->svc_replace_sem);
|
||||
|
||||
/* Check if work is stopped to avoid synchronize_rcu() */
|
||||
if (test_bit(IP_VS_WORK_SVC_NORESIZE, &ipvs->work_flags))
|
||||
goto unlock_repl;
|
||||
|
||||
rcu_assign_pointer(ipvs->svc_table, t_new);
|
||||
/* Inform readers that new table is installed */
|
||||
|
|
@ -781,8 +802,8 @@ static void svc_resize_work_handler(struct work_struct *work)
|
|||
atomic_inc(&ipvs->svc_table_changes);
|
||||
t_free = t;
|
||||
|
||||
unlock_m:
|
||||
mutex_unlock(&ipvs->service_mutex);
|
||||
unlock_repl:
|
||||
up_write(&ipvs->svc_replace_sem);
|
||||
|
||||
unlock_sem:
|
||||
up_write(&ipvs->svc_resize_sem);
|
||||
|
|
@ -801,6 +822,11 @@ static void svc_resize_work_handler(struct work_struct *work)
|
|||
test_bit(IP_VS_WORK_SVC_NORESIZE, &ipvs->work_flags))
|
||||
return;
|
||||
queue_delayed_work(system_unbound_wq, &ipvs->svc_resize_work, 1);
|
||||
return;
|
||||
|
||||
unlock_m:
|
||||
mutex_unlock(&ipvs->service_mutex);
|
||||
goto unlock_sem;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -1691,6 +1717,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u,
|
|||
struct ip_vs_pe *pe = NULL;
|
||||
int ret_hooks = -1;
|
||||
int ret = 0;
|
||||
bool grow;
|
||||
|
||||
/* increase the module use count */
|
||||
if (!ip_vs_use_count_inc())
|
||||
|
|
@ -1732,16 +1759,25 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u,
|
|||
}
|
||||
#endif
|
||||
|
||||
t = rcu_dereference_protected(ipvs->svc_table, 1);
|
||||
/* The old table can be freed, protect it with RCU */
|
||||
rcu_read_lock();
|
||||
t = rcu_dereference(ipvs->svc_table);
|
||||
if (!t) {
|
||||
int lfactor = sysctl_svc_lfactor(ipvs);
|
||||
int new_size = ip_vs_svc_desired_size(ipvs, NULL, lfactor);
|
||||
|
||||
rcu_read_unlock();
|
||||
t_new = ip_vs_svc_table_alloc(ipvs, new_size, lfactor);
|
||||
if (!t_new) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
grow = false;
|
||||
} else {
|
||||
/* Even the currently attached new table may need to grow */
|
||||
t = rcu_dereference(t->new_tbl);
|
||||
grow = ip_vs_get_num_services(ipvs) + 1 > t->u_thresh;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
if (!rcu_dereference_protected(ipvs->conn_tab, 1)) {
|
||||
|
|
@ -1800,6 +1836,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u,
|
|||
goto out_err;
|
||||
|
||||
if (t_new) {
|
||||
/* Add table for first time */
|
||||
clear_bit(IP_VS_WORK_SVC_NORESIZE, &ipvs->work_flags);
|
||||
rcu_assign_pointer(ipvs->svc_table, t_new);
|
||||
t_new = NULL;
|
||||
|
|
@ -1831,8 +1868,7 @@ ip_vs_add_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *u,
|
|||
ip_vs_svc_hash(svc);
|
||||
|
||||
/* Schedule resize work */
|
||||
if (t && ip_vs_get_num_services(ipvs) > t->u_thresh &&
|
||||
!test_and_set_bit(IP_VS_WORK_SVC_RESIZE, &ipvs->work_flags))
|
||||
if (grow && !test_and_set_bit(IP_VS_WORK_SVC_RESIZE, &ipvs->work_flags))
|
||||
queue_delayed_work(system_unbound_wq, &ipvs->svc_resize_work,
|
||||
1);
|
||||
|
||||
|
|
@ -2054,7 +2090,6 @@ static int ip_vs_del_service(struct ip_vs_service *svc)
|
|||
return -EEXIST;
|
||||
ipvs = svc->ipvs;
|
||||
ip_vs_unlink_service(svc, false);
|
||||
t = rcu_dereference_protected(ipvs->svc_table, 1);
|
||||
|
||||
/* Drop the table if no more services */
|
||||
ns = ip_vs_get_num_services(ipvs);
|
||||
|
|
@ -2062,6 +2097,7 @@ static int ip_vs_del_service(struct ip_vs_service *svc)
|
|||
/* Stop the resizer and drop the tables */
|
||||
set_bit(IP_VS_WORK_SVC_NORESIZE, &ipvs->work_flags);
|
||||
cancel_delayed_work_sync(&ipvs->svc_resize_work);
|
||||
t = rcu_dereference_protected(ipvs->svc_table, 1);
|
||||
if (t) {
|
||||
rcu_assign_pointer(ipvs->svc_table, NULL);
|
||||
/* Inform readers that table is removed */
|
||||
|
|
@ -2075,11 +2111,19 @@ static int ip_vs_del_service(struct ip_vs_service *svc)
|
|||
t = p;
|
||||
}
|
||||
}
|
||||
} else if (ns <= t->l_thresh &&
|
||||
!test_and_set_bit(IP_VS_WORK_SVC_RESIZE,
|
||||
&ipvs->work_flags)) {
|
||||
queue_delayed_work(system_unbound_wq, &ipvs->svc_resize_work,
|
||||
1);
|
||||
} else {
|
||||
bool shrink;
|
||||
|
||||
rcu_read_lock();
|
||||
t = rcu_dereference(ipvs->svc_table);
|
||||
/* Even the currently attached new table may need to shrink */
|
||||
t = rcu_dereference(t->new_tbl);
|
||||
shrink = ns <= t->l_thresh;
|
||||
rcu_read_unlock();
|
||||
if (shrink && !test_and_set_bit(IP_VS_WORK_SVC_RESIZE,
|
||||
&ipvs->work_flags))
|
||||
queue_delayed_work(system_unbound_wq,
|
||||
&ipvs->svc_resize_work, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2184,17 +2228,21 @@ static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,
|
|||
struct ip_vs_service *svc;
|
||||
struct hlist_bl_node *e;
|
||||
struct ip_vs_dest *dest;
|
||||
int old_gen, new_gen;
|
||||
int old_gen;
|
||||
|
||||
if (event != NETDEV_DOWN || !ipvs)
|
||||
return NOTIFY_DONE;
|
||||
IP_VS_DBG(3, "%s() dev=%s\n", __func__, dev->name);
|
||||
|
||||
/* Allow concurrent rehashing on resize but to avoid loop
|
||||
* serialize with installing the new table.
|
||||
*/
|
||||
down_read(&ipvs->svc_replace_sem);
|
||||
|
||||
old_gen = atomic_read(&ipvs->svc_table_changes);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
repeat:
|
||||
smp_rmb(); /* ipvs->svc_table and svc_table_changes */
|
||||
ip_vs_rht_walk_buckets_rcu(ipvs->svc_table, head) {
|
||||
hlist_bl_for_each_entry_rcu(svc, e, head, s_list) {
|
||||
|
|
@ -2207,17 +2255,17 @@ static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,
|
|||
}
|
||||
resched_score++;
|
||||
if (resched_score >= 100) {
|
||||
resched_score = 0;
|
||||
cond_resched_rcu();
|
||||
new_gen = atomic_read(&ipvs->svc_table_changes);
|
||||
/* New table installed ? */
|
||||
if (old_gen != new_gen) {
|
||||
old_gen = new_gen;
|
||||
goto repeat;
|
||||
}
|
||||
/* Flushed? So no more dev refs */
|
||||
if (atomic_read(&ipvs->svc_table_changes) != old_gen)
|
||||
goto done;
|
||||
resched_score = 0;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
rcu_read_unlock();
|
||||
up_read(&ipvs->svc_replace_sem);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
|
@ -2244,6 +2292,10 @@ static int ip_vs_zero_all(struct netns_ipvs *ipvs)
|
|||
struct ip_vs_service *svc;
|
||||
struct hlist_bl_node *e;
|
||||
|
||||
/* svc_table can not be replaced (svc_replace_sem) or
|
||||
* removed (service_mutex)
|
||||
*/
|
||||
down_read(&ipvs->svc_replace_sem);
|
||||
rcu_read_lock();
|
||||
|
||||
ip_vs_rht_walk_buckets_rcu(ipvs->svc_table, head) {
|
||||
|
|
@ -2259,6 +2311,7 @@ static int ip_vs_zero_all(struct netns_ipvs *ipvs)
|
|||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
up_read(&ipvs->svc_replace_sem);
|
||||
|
||||
ip_vs_zero_stats(&ipvs->tot_stats->s);
|
||||
return 0;
|
||||
|
|
@ -3062,6 +3115,7 @@ static int ip_vs_status_show(struct seq_file *seq, void *v)
|
|||
u32 sum;
|
||||
int i;
|
||||
|
||||
/* Info for conns */
|
||||
rcu_read_lock();
|
||||
|
||||
t = rcu_dereference(ipvs->conn_tab);
|
||||
|
|
@ -3123,6 +3177,12 @@ static int ip_vs_status_show(struct seq_file *seq, void *v)
|
|||
}
|
||||
|
||||
after_conns:
|
||||
rcu_read_unlock();
|
||||
|
||||
/* Info for services */
|
||||
down_read(&ipvs->svc_replace_sem);
|
||||
rcu_read_lock();
|
||||
|
||||
t = rcu_dereference(ipvs->svc_table);
|
||||
|
||||
count = ip_vs_get_num_services(ipvs);
|
||||
|
|
@ -3133,9 +3193,7 @@ static int ip_vs_status_show(struct seq_file *seq, void *v)
|
|||
if (!count)
|
||||
goto after_svc;
|
||||
old_gen = atomic_read(&ipvs->svc_table_changes);
|
||||
loops = 0;
|
||||
|
||||
repeat_svc:
|
||||
smp_rmb(); /* ipvs->svc_table and svc_table_changes */
|
||||
memset(counts, 0, sizeof(counts));
|
||||
ip_vs_rht_for_each_table_rcu(ipvs->svc_table, t, pt) {
|
||||
|
|
@ -3157,15 +3215,10 @@ static int ip_vs_status_show(struct seq_file *seq, void *v)
|
|||
if (resched_score >= 100) {
|
||||
resched_score = 0;
|
||||
cond_resched_rcu();
|
||||
new_gen = atomic_read(&ipvs->svc_table_changes);
|
||||
/* New table installed ? */
|
||||
if (old_gen != new_gen) {
|
||||
/* Too many changes? */
|
||||
if (++loops >= 5)
|
||||
goto after_svc;
|
||||
old_gen = new_gen;
|
||||
goto repeat_svc;
|
||||
}
|
||||
/* Flushed? */
|
||||
if (atomic_read(&ipvs->svc_table_changes) !=
|
||||
old_gen)
|
||||
goto after_svc;
|
||||
}
|
||||
counts[count]++;
|
||||
}
|
||||
|
|
@ -3184,6 +3237,9 @@ static int ip_vs_status_show(struct seq_file *seq, void *v)
|
|||
}
|
||||
|
||||
after_svc:
|
||||
rcu_read_unlock();
|
||||
up_read(&ipvs->svc_replace_sem);
|
||||
|
||||
seq_printf(seq, "Stats thread slots:\t%d (max %lu)\n",
|
||||
ipvs->est_kt_count, ipvs->est_max_threads);
|
||||
seq_printf(seq, "Stats chain max len:\t%d\n", ipvs->est_chain_max);
|
||||
|
|
@ -3191,7 +3247,6 @@ static int ip_vs_status_show(struct seq_file *seq, void *v)
|
|||
ipvs->est_chain_max * IPVS_EST_CHAIN_FACTOR *
|
||||
IPVS_EST_NTICKS);
|
||||
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3503,7 +3558,7 @@ __ip_vs_get_service_entries(struct netns_ipvs *ipvs,
|
|||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&ipvs->svc_resize_sem);
|
||||
/* All service modifications are disabled, go ahead */
|
||||
/* All svc_table modifications are disabled, go ahead */
|
||||
ip_vs_rht_walk_buckets(ipvs->svc_table, head) {
|
||||
hlist_bl_for_each_entry(svc, e, head, s_list) {
|
||||
/* Only expose IPv4 entries to old interface */
|
||||
|
|
@ -3687,7 +3742,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
|
|||
pr_err("length: %u != %zu\n", *len, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Protect against table resizer moving the entries.
|
||||
/* Prevent modifications to the list with services.
|
||||
* Try reverse locking, so that we do not hold the mutex
|
||||
* while waiting for semaphore.
|
||||
*/
|
||||
|
|
@ -4029,6 +4084,7 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb,
|
|||
int start = cb->args[0];
|
||||
int idx = 0;
|
||||
|
||||
/* Make sure we do not see same service twice during resize */
|
||||
down_read(&ipvs->svc_resize_sem);
|
||||
rcu_read_lock();
|
||||
ip_vs_rht_walk_buckets_safe_rcu(ipvs->svc_table, head) {
|
||||
|
|
@ -5072,6 +5128,7 @@ int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)
|
|||
/* Initialize service_mutex, svc_table per netns */
|
||||
__mutex_init(&ipvs->service_mutex, "ipvs->service_mutex", &__ipvs_service_key);
|
||||
init_rwsem(&ipvs->svc_resize_sem);
|
||||
init_rwsem(&ipvs->svc_replace_sem);
|
||||
INIT_DELAYED_WORK(&ipvs->svc_resize_work, svc_resize_work_handler);
|
||||
atomic_set(&ipvs->svc_table_changes, 0);
|
||||
RCU_INIT_POINTER(ipvs->svc_table, NULL);
|
||||
|
|
|
|||
|
|
@ -321,8 +321,8 @@ __printf(3, 4)
|
|||
void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
const char *helper_name = "(null)";
|
||||
const struct nf_conn_help *help;
|
||||
const struct nf_conntrack_helper *helper;
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
|
|
@ -331,14 +331,17 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
|
|||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
/* Called from the helper function, this call never fails */
|
||||
help = nfct_help(ct);
|
||||
if (help) {
|
||||
const struct nf_conntrack_helper *helper;
|
||||
|
||||
/* rcu_read_lock()ed by nf_hook_thresh */
|
||||
helper = rcu_dereference(help->helper);
|
||||
helper = rcu_dereference(help->helper);
|
||||
if (helper)
|
||||
helper_name = helper->name;
|
||||
}
|
||||
|
||||
nf_log_packet(nf_ct_net(ct), nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL,
|
||||
"nf_ct_%s: dropping packet: %pV ", helper->name, &vaf);
|
||||
"helper %s dropping packet: %pV ", helper_name, &vaf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
|
|||
struct nf_hook_state *state = &entry->state;
|
||||
|
||||
/* Release those devices we held, or Alexey will kill me. */
|
||||
dev_put(entry->skb_dev);
|
||||
dev_put(state->in);
|
||||
dev_put(state->out);
|
||||
if (state->sk)
|
||||
|
|
@ -102,6 +103,7 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
|
|||
if (state->sk && !refcount_inc_not_zero(&state->sk->sk_refcnt))
|
||||
return false;
|
||||
|
||||
dev_hold(entry->skb_dev);
|
||||
dev_hold(state->in);
|
||||
dev_hold(state->out);
|
||||
|
||||
|
|
@ -202,11 +204,11 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
|
|||
|
||||
*entry = (struct nf_queue_entry) {
|
||||
.skb = skb,
|
||||
.skb_dev = skb->dev,
|
||||
.state = *state,
|
||||
.hook_index = index,
|
||||
.size = sizeof(*entry) + route_key_size,
|
||||
};
|
||||
|
||||
__nf_queue_entry_init_physdevs(entry);
|
||||
|
||||
if (!nf_queue_entry_get_refs(entry)) {
|
||||
|
|
|
|||
|
|
@ -1212,6 +1212,8 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
|
|||
if (physinif == ifindex || physoutif == ifindex)
|
||||
return 1;
|
||||
#endif
|
||||
if (entry->skb_dev && entry->skb_dev->ifindex == ifindex)
|
||||
return 1;
|
||||
if (entry->state.in)
|
||||
if (entry->state.in->ifindex == ifindex)
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -163,7 +163,6 @@ static int nft_inner_parse_l2l3(const struct nft_inner *priv,
|
|||
return -1;
|
||||
|
||||
if (fragoff == 0) {
|
||||
thoff = nhoff + sizeof(_ip6h);
|
||||
ctx->flags |= NFT_PAYLOAD_CTX_INNER_TH;
|
||||
ctx->inner_thoff = thoff;
|
||||
ctx->l4proto = l4proto;
|
||||
|
|
@ -247,8 +246,8 @@ static bool nft_inner_restore_tun_ctx(const struct nft_pktinfo *pkt,
|
|||
local_lock_nested_bh(&nft_pcpu_tun_ctx.bh_lock);
|
||||
this_cpu_tun_ctx = this_cpu_ptr(&nft_pcpu_tun_ctx.ctx);
|
||||
if (this_cpu_tun_ctx->cookie != (unsigned long)pkt->skb) {
|
||||
local_bh_enable();
|
||||
local_unlock_nested_bh(&nft_pcpu_tun_ctx.bh_lock);
|
||||
local_bh_enable();
|
||||
return false;
|
||||
}
|
||||
*tun_ctx = *this_cpu_tun_ctx;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user