Commit 574b238f authored by David S. Miller's avatar David S. Miller

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

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes:

1) Perform garbage collection from workqueue to fix rcu detected
   stall in ipset hash set types, from Jozsef Kadlecsik.

2) Fix the forceadd evaluation path, also from Jozsef.

3) Fix nft_set_pipapo selftest, from Stefano Brivio.

4) Crash when add-flush-add element in pipapo set, also from Stefano.
   Add test to cover this crash.

5) Remove sysctl entry under mutex in hashlimit, from Cong Wang.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9a005c38 99b79c39
...@@ -121,6 +121,7 @@ struct ip_set_ext { ...@@ -121,6 +121,7 @@ struct ip_set_ext {
u32 timeout; u32 timeout;
u8 packets_op; u8 packets_op;
u8 bytes_op; u8 bytes_op;
bool target;
}; };
struct ip_set; struct ip_set;
...@@ -187,6 +188,14 @@ struct ip_set_type_variant { ...@@ -187,6 +188,14 @@ struct ip_set_type_variant {
/* Return true if "b" set is the same as "a" /* Return true if "b" set is the same as "a"
* according to the create set parameters */ * according to the create set parameters */
bool (*same_set)(const struct ip_set *a, const struct ip_set *b); bool (*same_set)(const struct ip_set *a, const struct ip_set *b);
/* Region-locking is used */
bool region_lock;
};
struct ip_set_region {
spinlock_t lock; /* Region lock */
size_t ext_size; /* Size of the dynamic extensions */
u32 elements; /* Number of elements vs timeout */
}; };
/* The core set type structure */ /* The core set type structure */
...@@ -501,7 +510,7 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo, ...@@ -501,7 +510,7 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo,
} }
#define IP_SET_INIT_KEXT(skb, opt, set) \ #define IP_SET_INIT_KEXT(skb, opt, set) \
{ .bytes = (skb)->len, .packets = 1, \ { .bytes = (skb)->len, .packets = 1, .target = true,\
.timeout = ip_set_adt_opt_timeout(opt, set) } .timeout = ip_set_adt_opt_timeout(opt, set) }
#define IP_SET_INIT_UEXT(set) \ #define IP_SET_INIT_UEXT(set) \
......
...@@ -723,6 +723,20 @@ ip_set_rcu_get(struct net *net, ip_set_id_t index) ...@@ -723,6 +723,20 @@ ip_set_rcu_get(struct net *net, ip_set_id_t index)
return set; return set;
} }
static inline void
ip_set_lock(struct ip_set *set)
{
if (!set->variant->region_lock)
spin_lock_bh(&set->lock);
}
static inline void
ip_set_unlock(struct ip_set *set)
{
if (!set->variant->region_lock)
spin_unlock_bh(&set->lock);
}
int int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, struct ip_set_adt_opt *opt) const struct xt_action_param *par, struct ip_set_adt_opt *opt)
...@@ -744,9 +758,9 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ...@@ -744,9 +758,9 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
/* Type requests element to be completed */ /* Type requests element to be completed */
pr_debug("element must be completed, ADD is triggered\n"); pr_debug("element must be completed, ADD is triggered\n");
spin_lock_bh(&set->lock); ip_set_lock(set);
set->variant->kadt(set, skb, par, IPSET_ADD, opt); set->variant->kadt(set, skb, par, IPSET_ADD, opt);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
ret = 1; ret = 1;
} else { } else {
/* --return-nomatch: invert matched element */ /* --return-nomatch: invert matched element */
...@@ -775,9 +789,9 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb, ...@@ -775,9 +789,9 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
!(opt->family == set->family || set->family == NFPROTO_UNSPEC)) !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
return -IPSET_ERR_TYPE_MISMATCH; return -IPSET_ERR_TYPE_MISMATCH;
spin_lock_bh(&set->lock); ip_set_lock(set);
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt); ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
return ret; return ret;
} }
...@@ -797,9 +811,9 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb, ...@@ -797,9 +811,9 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
!(opt->family == set->family || set->family == NFPROTO_UNSPEC)) !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
return -IPSET_ERR_TYPE_MISMATCH; return -IPSET_ERR_TYPE_MISMATCH;
spin_lock_bh(&set->lock); ip_set_lock(set);
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt); ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
return ret; return ret;
} }
...@@ -1264,9 +1278,9 @@ ip_set_flush_set(struct ip_set *set) ...@@ -1264,9 +1278,9 @@ ip_set_flush_set(struct ip_set *set)
{ {
pr_debug("set: %s\n", set->name); pr_debug("set: %s\n", set->name);
spin_lock_bh(&set->lock); ip_set_lock(set);
set->variant->flush(set); set->variant->flush(set);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
} }
static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb, static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
...@@ -1713,9 +1727,9 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, ...@@ -1713,9 +1727,9 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
bool eexist = flags & IPSET_FLAG_EXIST, retried = false; bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
do { do {
spin_lock_bh(&set->lock); ip_set_lock(set);
ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried); ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
spin_unlock_bh(&set->lock); ip_set_unlock(set);
retried = true; retried = true;
} while (ret == -EAGAIN && } while (ret == -EAGAIN &&
set->variant->resize && set->variant->resize &&
......
This diff is collapsed.
...@@ -1766,11 +1766,13 @@ static bool pipapo_match_field(struct nft_pipapo_field *f, ...@@ -1766,11 +1766,13 @@ static bool pipapo_match_field(struct nft_pipapo_field *f,
static void nft_pipapo_remove(const struct net *net, const struct nft_set *set, static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem) const struct nft_set_elem *elem)
{ {
const u8 *data = (const u8 *)elem->key.val.data;
struct nft_pipapo *priv = nft_set_priv(set); struct nft_pipapo *priv = nft_set_priv(set);
struct nft_pipapo_match *m = priv->clone; struct nft_pipapo_match *m = priv->clone;
struct nft_pipapo_elem *e = elem->priv;
int rules_f0, first_rule = 0; int rules_f0, first_rule = 0;
struct nft_pipapo_elem *e; const u8 *data;
data = (const u8 *)nft_set_ext_key(&e->ext);
e = pipapo_get(net, set, data, 0); e = pipapo_get(net, set, data, 0);
if (IS_ERR(e)) if (IS_ERR(e))
......
...@@ -402,15 +402,6 @@ static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo) ...@@ -402,15 +402,6 @@ static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo)
remove_proc_entry(hinfo->name, parent); remove_proc_entry(hinfo->name, parent);
} }
static void htable_destroy(struct xt_hashlimit_htable *hinfo)
{
cancel_delayed_work_sync(&hinfo->gc_work);
htable_remove_proc_entry(hinfo);
htable_selective_cleanup(hinfo, true);
kfree(hinfo->name);
vfree(hinfo);
}
static struct xt_hashlimit_htable *htable_find_get(struct net *net, static struct xt_hashlimit_htable *htable_find_get(struct net *net,
const char *name, const char *name,
u_int8_t family) u_int8_t family)
...@@ -432,8 +423,13 @@ static void htable_put(struct xt_hashlimit_htable *hinfo) ...@@ -432,8 +423,13 @@ static void htable_put(struct xt_hashlimit_htable *hinfo)
{ {
if (refcount_dec_and_mutex_lock(&hinfo->use, &hashlimit_mutex)) { if (refcount_dec_and_mutex_lock(&hinfo->use, &hashlimit_mutex)) {
hlist_del(&hinfo->node); hlist_del(&hinfo->node);
htable_remove_proc_entry(hinfo);
mutex_unlock(&hashlimit_mutex); mutex_unlock(&hashlimit_mutex);
htable_destroy(hinfo);
cancel_delayed_work_sync(&hinfo->gc_work);
htable_selective_cleanup(hinfo, true);
kfree(hinfo->name);
vfree(hinfo);
} }
} }
......
...@@ -13,11 +13,12 @@ ...@@ -13,11 +13,12 @@
KSELFTEST_SKIP=4 KSELFTEST_SKIP=4
# Available test groups: # Available test groups:
# - reported_issues: check for issues that were reported in the past
# - correctness: check that packets match given entries, and only those # - correctness: check that packets match given entries, and only those
# - concurrency: attempt races between insertion, deletion and lookup # - concurrency: attempt races between insertion, deletion and lookup
# - timeout: check that packets match entries until they expire # - timeout: check that packets match entries until they expire
# - performance: estimate matching rate, compare with rbtree and hash baselines # - performance: estimate matching rate, compare with rbtree and hash baselines
TESTS="correctness concurrency timeout" TESTS="reported_issues correctness concurrency timeout"
[ "${quicktest}" != "1" ] && TESTS="${TESTS} performance" [ "${quicktest}" != "1" ] && TESTS="${TESTS} performance"
# Set types, defined by TYPE_ variables below # Set types, defined by TYPE_ variables below
...@@ -25,6 +26,9 @@ TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto ...@@ -25,6 +26,9 @@ TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
net_port_net net_mac net_mac_icmp net6_mac_icmp net6_port_net6_port net_port_net net_mac net_mac_icmp net6_mac_icmp net6_port_net6_port
net_port_mac_proto_net" net_port_mac_proto_net"
# Reported bugs, also described by TYPE_ variables below
BUGS="flush_remove_add"
# List of possible paths to pktgen script from kernel tree for performance tests # List of possible paths to pktgen script from kernel tree for performance tests
PKTGEN_SCRIPT_PATHS=" PKTGEN_SCRIPT_PATHS="
../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh ../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
...@@ -327,6 +331,12 @@ flood_spec ip daddr . tcp dport . meta l4proto . ip saddr ...@@ -327,6 +331,12 @@ flood_spec ip daddr . tcp dport . meta l4proto . ip saddr
perf_duration 0 perf_duration 0
" "
# Definition of tests for bugs reported in the past:
# display display text for test report
TYPE_flush_remove_add="
display Add two elements, flush, re-add
"
# Set template for all tests, types and rules are filled in depending on test # Set template for all tests, types and rules are filled in depending on test
set_template=' set_template='
flush ruleset flush ruleset
...@@ -440,6 +450,8 @@ setup_set() { ...@@ -440,6 +450,8 @@ setup_set() {
# Check that at least one of the needed tools is available # Check that at least one of the needed tools is available
check_tools() { check_tools() {
[ -z "${tools}" ] && return 0
__tools= __tools=
for tool in ${tools}; do for tool in ${tools}; do
if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \ if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \
...@@ -1025,7 +1037,7 @@ format_noconcat() { ...@@ -1025,7 +1037,7 @@ format_noconcat() {
add() { add() {
if ! nft add element inet filter test "${1}"; then if ! nft add element inet filter test "${1}"; then
err "Failed to add ${1} given ruleset:" err "Failed to add ${1} given ruleset:"
err "$(nft list ruleset -a)" err "$(nft -a list ruleset)"
return 1 return 1
fi fi
} }
...@@ -1045,7 +1057,7 @@ add_perf() { ...@@ -1045,7 +1057,7 @@ add_perf() {
add_perf_norange() { add_perf_norange() {
if ! nft add element netdev perf norange "${1}"; then if ! nft add element netdev perf norange "${1}"; then
err "Failed to add ${1} given ruleset:" err "Failed to add ${1} given ruleset:"
err "$(nft list ruleset -a)" err "$(nft -a list ruleset)"
return 1 return 1
fi fi
} }
...@@ -1054,7 +1066,7 @@ add_perf_norange() { ...@@ -1054,7 +1066,7 @@ add_perf_norange() {
add_perf_noconcat() { add_perf_noconcat() {
if ! nft add element netdev perf noconcat "${1}"; then if ! nft add element netdev perf noconcat "${1}"; then
err "Failed to add ${1} given ruleset:" err "Failed to add ${1} given ruleset:"
err "$(nft list ruleset -a)" err "$(nft -a list ruleset)"
return 1 return 1
fi fi
} }
...@@ -1063,7 +1075,7 @@ add_perf_noconcat() { ...@@ -1063,7 +1075,7 @@ add_perf_noconcat() {
del() { del() {
if ! nft delete element inet filter test "${1}"; then if ! nft delete element inet filter test "${1}"; then
err "Failed to delete ${1} given ruleset:" err "Failed to delete ${1} given ruleset:"
err "$(nft list ruleset -a)" err "$(nft -a list ruleset)"
return 1 return 1
fi fi
} }
...@@ -1134,7 +1146,7 @@ send_match() { ...@@ -1134,7 +1146,7 @@ send_match() {
err " $(for f in ${src}; do err " $(for f in ${src}; do
eval format_\$f "${2}"; printf ' '; done)" eval format_\$f "${2}"; printf ' '; done)"
err "should have matched ruleset:" err "should have matched ruleset:"
err "$(nft list ruleset -a)" err "$(nft -a list ruleset)"
return 1 return 1
fi fi
nft reset counter inet filter test >/dev/null nft reset counter inet filter test >/dev/null
...@@ -1160,7 +1172,7 @@ send_nomatch() { ...@@ -1160,7 +1172,7 @@ send_nomatch() {
err " $(for f in ${src}; do err " $(for f in ${src}; do
eval format_\$f "${2}"; printf ' '; done)" eval format_\$f "${2}"; printf ' '; done)"
err "should not have matched ruleset:" err "should not have matched ruleset:"
err "$(nft list ruleset -a)" err "$(nft -a list ruleset)"
return 1 return 1
fi fi
} }
...@@ -1430,6 +1442,23 @@ test_performance() { ...@@ -1430,6 +1442,23 @@ test_performance() {
kill "${perf_pid}" kill "${perf_pid}"
} }
test_bug_flush_remove_add() {
set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }'
elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }'
elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }'
for i in `seq 1 100`; do
nft add table t ${set_cmd} || return ${KSELFTEST_SKIP}
nft add element t s ${elem1} 2>/dev/null || return 1
nft flush set t s 2>/dev/null || return 1
nft add element t s ${elem2} 2>/dev/null || return 1
done
nft flush ruleset
}
test_reported_issues() {
eval test_bug_"${subtest}"
}
# Run everything in a separate network namespace # Run everything in a separate network namespace
[ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; } [ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; }
tmp="$(mktemp)" tmp="$(mktemp)"
...@@ -1438,9 +1467,15 @@ trap cleanup EXIT ...@@ -1438,9 +1467,15 @@ trap cleanup EXIT
# Entry point for test runs # Entry point for test runs
passed=0 passed=0
for name in ${TESTS}; do for name in ${TESTS}; do
printf "TEST: %s\n" "${name}" printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')"
for type in ${TYPES}; do if [ "${name}" = "reported_issues" ]; then
eval desc=\$TYPE_"${type}" SUBTESTS="${BUGS}"
else
SUBTESTS="${TYPES}"
fi
for subtest in ${SUBTESTS}; do
eval desc=\$TYPE_"${subtest}"
IFS=' IFS='
' '
for __line in ${desc}; do for __line in ${desc}; do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment