diff options
author | Florian Westphal <fw@strlen.de> | 2016-04-12 16:14:24 (GMT) |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2016-04-18 18:39:44 (GMT) |
commit | 5a8145f7b22269adaf9e98b160a20486d1ad5669 (patch) | |
tree | e72bf329e46bc1514eec4fd1db893008842feb32 /net/netfilter/nf_conntrack_labels.c | |
parent | b4ef159927150bf1d63f36330bbb5239516ceb69 (diff) | |
download | linux-5a8145f7b22269adaf9e98b160a20486d1ad5669.tar.xz |
netfilter: labels: don't emit ct event if labels were not changed
make the replace function only send a ctnetlink event if the contents
of the new set is different.
Otherwise 'ct label set ct label | bar'
will cause netlink event storm since we "replace" labels for each packet.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter/nf_conntrack_labels.c')
-rw-r--r-- | net/netfilter/nf_conntrack_labels.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c index 3a30900..bd7f26b 100644 --- a/net/netfilter/nf_conntrack_labels.c +++ b/net/netfilter/nf_conntrack_labels.c @@ -33,14 +33,18 @@ int nf_connlabel_set(struct nf_conn *ct, u16 bit) } EXPORT_SYMBOL_GPL(nf_connlabel_set); -static void replace_u32(u32 *address, u32 mask, u32 new) +static int replace_u32(u32 *address, u32 mask, u32 new) { u32 old, tmp; do { old = *address; tmp = (old & mask) ^ new; + if (old == tmp) + return 0; } while (cmpxchg(address, old, tmp) != old); + + return 1; } int nf_connlabels_replace(struct nf_conn *ct, @@ -49,6 +53,7 @@ int nf_connlabels_replace(struct nf_conn *ct, { struct nf_conn_labels *labels; unsigned int size, i; + int changed = 0; u32 *dst; labels = nf_ct_labels_find(ct); @@ -60,16 +65,15 @@ int nf_connlabels_replace(struct nf_conn *ct, words32 = size / sizeof(u32); dst = (u32 *) labels->bits; - if (words32) { - for (i = 0; i < words32; i++) - replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]); - } + for (i = 0; i < words32; i++) + changed |= replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]); size /= sizeof(u32); for (i = words32; i < size; i++) /* pad */ replace_u32(&dst[i], 0, 0); - nf_conntrack_event_cache(IPCT_LABEL, ct); + if (changed) + nf_conntrack_event_cache(IPCT_LABEL, ct); return 0; } EXPORT_SYMBOL_GPL(nf_connlabels_replace); |