netfilter: conntrack: gre: convert rwlock to rcu
We can use gre. Lock is only needed when a new expectation is added. In case a single spinlock proves to be problematic we can either add one per netns or use an array of locks combined with net_hash_mix() or similar to pick the 'correct' one. But given this is only needed for an expectation rather than per packet a single one should be ok. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
e2e48b4716
commit
202e651cd4
@ -19,6 +19,7 @@ struct nf_conn;
|
|||||||
struct nf_ct_gre_keymap {
|
struct nf_ct_gre_keymap {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
|
struct rcu_head rcu;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum grep_conntrack {
|
enum grep_conntrack {
|
||||||
|
@ -49,6 +49,8 @@ static const unsigned int gre_timeouts[GRE_CT_MAX] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int proto_gre_net_id __read_mostly;
|
static unsigned int proto_gre_net_id __read_mostly;
|
||||||
|
/* used when expectation is added */
|
||||||
|
static DEFINE_SPINLOCK(keymap_lock);
|
||||||
|
|
||||||
static inline struct netns_proto_gre *gre_pernet(struct net *net)
|
static inline struct netns_proto_gre *gre_pernet(struct net *net)
|
||||||
{
|
{
|
||||||
@ -60,12 +62,12 @@ static void nf_ct_gre_keymap_flush(struct net *net)
|
|||||||
struct netns_proto_gre *net_gre = gre_pernet(net);
|
struct netns_proto_gre *net_gre = gre_pernet(net);
|
||||||
struct nf_ct_gre_keymap *km, *tmp;
|
struct nf_ct_gre_keymap *km, *tmp;
|
||||||
|
|
||||||
write_lock_bh(&net_gre->keymap_lock);
|
spin_lock_bh(&keymap_lock);
|
||||||
list_for_each_entry_safe(km, tmp, &net_gre->keymap_list, list) {
|
list_for_each_entry_safe(km, tmp, &net_gre->keymap_list, list) {
|
||||||
list_del(&km->list);
|
list_del_rcu(&km->list);
|
||||||
kfree(km);
|
kfree_rcu(km, rcu);
|
||||||
}
|
}
|
||||||
write_unlock_bh(&net_gre->keymap_lock);
|
spin_unlock_bh(&keymap_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km,
|
static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km,
|
||||||
@ -85,14 +87,12 @@ static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t)
|
|||||||
struct nf_ct_gre_keymap *km;
|
struct nf_ct_gre_keymap *km;
|
||||||
__be16 key = 0;
|
__be16 key = 0;
|
||||||
|
|
||||||
read_lock_bh(&net_gre->keymap_lock);
|
list_for_each_entry_rcu(km, &net_gre->keymap_list, list) {
|
||||||
list_for_each_entry(km, &net_gre->keymap_list, list) {
|
|
||||||
if (gre_key_cmpfn(km, t)) {
|
if (gre_key_cmpfn(km, t)) {
|
||||||
key = km->tuple.src.u.gre.key;
|
key = km->tuple.src.u.gre.key;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read_unlock_bh(&net_gre->keymap_lock);
|
|
||||||
|
|
||||||
pr_debug("lookup src key 0x%x for ", key);
|
pr_debug("lookup src key 0x%x for ", key);
|
||||||
nf_ct_dump_tuple(t);
|
nf_ct_dump_tuple(t);
|
||||||
@ -112,14 +112,10 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
|
|||||||
kmp = &ct_pptp_info->keymap[dir];
|
kmp = &ct_pptp_info->keymap[dir];
|
||||||
if (*kmp) {
|
if (*kmp) {
|
||||||
/* check whether it's a retransmission */
|
/* check whether it's a retransmission */
|
||||||
read_lock_bh(&net_gre->keymap_lock);
|
list_for_each_entry_rcu(km, &net_gre->keymap_list, list) {
|
||||||
list_for_each_entry(km, &net_gre->keymap_list, list) {
|
if (gre_key_cmpfn(km, t) && km == *kmp)
|
||||||
if (gre_key_cmpfn(km, t) && km == *kmp) {
|
|
||||||
read_unlock_bh(&net_gre->keymap_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
read_unlock_bh(&net_gre->keymap_lock);
|
|
||||||
pr_debug("trying to override keymap_%s for ct %p\n",
|
pr_debug("trying to override keymap_%s for ct %p\n",
|
||||||
dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct);
|
dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct);
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
@ -134,9 +130,9 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
|
|||||||
pr_debug("adding new entry %p: ", km);
|
pr_debug("adding new entry %p: ", km);
|
||||||
nf_ct_dump_tuple(&km->tuple);
|
nf_ct_dump_tuple(&km->tuple);
|
||||||
|
|
||||||
write_lock_bh(&net_gre->keymap_lock);
|
spin_lock_bh(&keymap_lock);
|
||||||
list_add_tail(&km->list, &net_gre->keymap_list);
|
list_add_tail(&km->list, &net_gre->keymap_list);
|
||||||
write_unlock_bh(&net_gre->keymap_lock);
|
spin_unlock_bh(&keymap_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -145,24 +141,22 @@ EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add);
|
|||||||
/* destroy the keymap entries associated with specified master ct */
|
/* destroy the keymap entries associated with specified master ct */
|
||||||
void nf_ct_gre_keymap_destroy(struct nf_conn *ct)
|
void nf_ct_gre_keymap_destroy(struct nf_conn *ct)
|
||||||
{
|
{
|
||||||
struct net *net = nf_ct_net(ct);
|
|
||||||
struct netns_proto_gre *net_gre = gre_pernet(net);
|
|
||||||
struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct);
|
struct nf_ct_pptp_master *ct_pptp_info = nfct_help_data(ct);
|
||||||
enum ip_conntrack_dir dir;
|
enum ip_conntrack_dir dir;
|
||||||
|
|
||||||
pr_debug("entering for ct %p\n", ct);
|
pr_debug("entering for ct %p\n", ct);
|
||||||
|
|
||||||
write_lock_bh(&net_gre->keymap_lock);
|
spin_lock_bh(&keymap_lock);
|
||||||
for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) {
|
for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) {
|
||||||
if (ct_pptp_info->keymap[dir]) {
|
if (ct_pptp_info->keymap[dir]) {
|
||||||
pr_debug("removing %p from list\n",
|
pr_debug("removing %p from list\n",
|
||||||
ct_pptp_info->keymap[dir]);
|
ct_pptp_info->keymap[dir]);
|
||||||
list_del(&ct_pptp_info->keymap[dir]->list);
|
list_del_rcu(&ct_pptp_info->keymap[dir]->list);
|
||||||
kfree(ct_pptp_info->keymap[dir]);
|
kfree_rcu(ct_pptp_info->keymap[dir], rcu);
|
||||||
ct_pptp_info->keymap[dir] = NULL;
|
ct_pptp_info->keymap[dir] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_unlock_bh(&net_gre->keymap_lock);
|
spin_unlock_bh(&keymap_lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy);
|
EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy);
|
||||||
|
|
||||||
@ -365,7 +359,6 @@ static int gre_init_net(struct net *net)
|
|||||||
struct nf_proto_net *nf = &net_gre->nf;
|
struct nf_proto_net *nf = &net_gre->nf;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
rwlock_init(&net_gre->keymap_lock);
|
|
||||||
INIT_LIST_HEAD(&net_gre->keymap_list);
|
INIT_LIST_HEAD(&net_gre->keymap_list);
|
||||||
for (i = 0; i < GRE_CT_MAX; i++)
|
for (i = 0; i < GRE_CT_MAX; i++)
|
||||||
net_gre->gre_timeouts[i] = gre_timeouts[i];
|
net_gre->gre_timeouts[i] = gre_timeouts[i];
|
||||||
|
Loading…
Reference in New Issue
Block a user