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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
574b238f64
|
@ -121,6 +121,7 @@ struct ip_set_ext {
|
|||
u32 timeout;
|
||||
u8 packets_op;
|
||||
u8 bytes_op;
|
||||
bool target;
|
||||
};
|
||||
|
||||
struct ip_set;
|
||||
|
@ -187,6 +188,14 @@ struct ip_set_type_variant {
|
|||
/* Return true if "b" set is the same as "a"
|
||||
* according to the create set parameters */
|
||||
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 */
|
||||
|
@ -501,7 +510,7 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo,
|
|||
}
|
||||
|
||||
#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) }
|
||||
|
||||
#define IP_SET_INIT_UEXT(set) \
|
||||
|
|
|
@ -723,6 +723,20 @@ ip_set_rcu_get(struct net *net, ip_set_id_t index)
|
|||
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
|
||||
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)
|
||||
|
@ -744,9 +758,9 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
|
|||
if (ret == -EAGAIN) {
|
||||
/* Type requests element to be completed */
|
||||
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);
|
||||
spin_unlock_bh(&set->lock);
|
||||
ip_set_unlock(set);
|
||||
ret = 1;
|
||||
} else {
|
||||
/* --return-nomatch: invert matched element */
|
||||
|
@ -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))
|
||||
return -IPSET_ERR_TYPE_MISMATCH;
|
||||
|
||||
spin_lock_bh(&set->lock);
|
||||
ip_set_lock(set);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
|
||||
spin_unlock_bh(&set->lock);
|
||||
ip_set_unlock(set);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -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))
|
||||
return -IPSET_ERR_TYPE_MISMATCH;
|
||||
|
||||
spin_lock_bh(&set->lock);
|
||||
ip_set_lock(set);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
|
||||
spin_unlock_bh(&set->lock);
|
||||
ip_set_unlock(set);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1264,9 +1278,9 @@ ip_set_flush_set(struct ip_set *set)
|
|||
{
|
||||
pr_debug("set: %s\n", set->name);
|
||||
|
||||
spin_lock_bh(&set->lock);
|
||||
ip_set_lock(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,
|
||||
|
@ -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;
|
||||
|
||||
do {
|
||||
spin_lock_bh(&set->lock);
|
||||
ip_set_lock(set);
|
||||
ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
|
||||
spin_unlock_bh(&set->lock);
|
||||
ip_set_unlock(set);
|
||||
retried = true;
|
||||
} while (ret == -EAGAIN &&
|
||||
set->variant->resize &&
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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,
|
||||
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_match *m = priv->clone;
|
||||
struct nft_pipapo_elem *e = elem->priv;
|
||||
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);
|
||||
if (IS_ERR(e))
|
||||
|
|
|
@ -402,15 +402,6 @@ static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo)
|
|||
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,
|
||||
const char *name,
|
||||
u_int8_t family)
|
||||
|
@ -432,8 +423,13 @@ static void htable_put(struct xt_hashlimit_htable *hinfo)
|
|||
{
|
||||
if (refcount_dec_and_mutex_lock(&hinfo->use, &hashlimit_mutex)) {
|
||||
hlist_del(&hinfo->node);
|
||||
htable_remove_proc_entry(hinfo);
|
||||
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 @@
|
|||
KSELFTEST_SKIP=4
|
||||
|
||||
# Available test groups:
|
||||
# - reported_issues: check for issues that were reported in the past
|
||||
# - correctness: check that packets match given entries, and only those
|
||||
# - concurrency: attempt races between insertion, deletion and lookup
|
||||
# - timeout: check that packets match entries until they expire
|
||||
# - 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"
|
||||
|
||||
# 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
|
|||
net_port_net net_mac net_mac_icmp net6_mac_icmp net6_port_net6_port
|
||||
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
|
||||
PKTGEN_SCRIPT_PATHS="
|
||||
../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
|
||||
|
@ -327,6 +331,12 @@ flood_spec ip daddr . tcp dport . meta l4proto . ip saddr
|
|||
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='
|
||||
flush ruleset
|
||||
|
@ -440,6 +450,8 @@ setup_set() {
|
|||
|
||||
# Check that at least one of the needed tools is available
|
||||
check_tools() {
|
||||
[ -z "${tools}" ] && return 0
|
||||
|
||||
__tools=
|
||||
for tool in ${tools}; do
|
||||
if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \
|
||||
|
@ -1025,7 +1037,7 @@ format_noconcat() {
|
|||
add() {
|
||||
if ! nft add element inet filter test "${1}"; then
|
||||
err "Failed to add ${1} given ruleset:"
|
||||
err "$(nft list ruleset -a)"
|
||||
err "$(nft -a list ruleset)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
@ -1045,7 +1057,7 @@ add_perf() {
|
|||
add_perf_norange() {
|
||||
if ! nft add element netdev perf norange "${1}"; then
|
||||
err "Failed to add ${1} given ruleset:"
|
||||
err "$(nft list ruleset -a)"
|
||||
err "$(nft -a list ruleset)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
@ -1054,7 +1066,7 @@ add_perf_norange() {
|
|||
add_perf_noconcat() {
|
||||
if ! nft add element netdev perf noconcat "${1}"; then
|
||||
err "Failed to add ${1} given ruleset:"
|
||||
err "$(nft list ruleset -a)"
|
||||
err "$(nft -a list ruleset)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
@ -1063,7 +1075,7 @@ add_perf_noconcat() {
|
|||
del() {
|
||||
if ! nft delete element inet filter test "${1}"; then
|
||||
err "Failed to delete ${1} given ruleset:"
|
||||
err "$(nft list ruleset -a)"
|
||||
err "$(nft -a list ruleset)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
@ -1134,7 +1146,7 @@ send_match() {
|
|||
err " $(for f in ${src}; do
|
||||
eval format_\$f "${2}"; printf ' '; done)"
|
||||
err "should have matched ruleset:"
|
||||
err "$(nft list ruleset -a)"
|
||||
err "$(nft -a list ruleset)"
|
||||
return 1
|
||||
fi
|
||||
nft reset counter inet filter test >/dev/null
|
||||
|
@ -1160,7 +1172,7 @@ send_nomatch() {
|
|||
err " $(for f in ${src}; do
|
||||
eval format_\$f "${2}"; printf ' '; done)"
|
||||
err "should not have matched ruleset:"
|
||||
err "$(nft list ruleset -a)"
|
||||
err "$(nft -a list ruleset)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
@ -1430,6 +1442,23 @@ test_performance() {
|
|||
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
|
||||
[ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; }
|
||||
tmp="$(mktemp)"
|
||||
|
@ -1438,9 +1467,15 @@ trap cleanup EXIT
|
|||
# Entry point for test runs
|
||||
passed=0
|
||||
for name in ${TESTS}; do
|
||||
printf "TEST: %s\n" "${name}"
|
||||
for type in ${TYPES}; do
|
||||
eval desc=\$TYPE_"${type}"
|
||||
printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')"
|
||||
if [ "${name}" = "reported_issues" ]; then
|
||||
SUBTESTS="${BUGS}"
|
||||
else
|
||||
SUBTESTS="${TYPES}"
|
||||
fi
|
||||
|
||||
for subtest in ${SUBTESTS}; do
|
||||
eval desc=\$TYPE_"${subtest}"
|
||||
IFS='
|
||||
'
|
||||
for __line in ${desc}; do
|
||||
|
|
Loading…
Reference in New Issue