[PATCH v3 11/17] net,l2tp: use new hashtable implementation
Switch l2tp to use the new hashtable implementation. This reduces the amount of generic unrelated code in l2tp. Signed-off-by: Sasha Levin --- net/l2tp/l2tp_core.c| 134 +- net/l2tp/l2tp_core.h|8 ++-- net/l2tp/l2tp_debugfs.c | 19 +++ 3 files changed, 61 insertions(+), 100 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 393355d..1d395ce 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -107,8 +108,8 @@ static unsigned int l2tp_net_id; struct l2tp_net { struct list_head l2tp_tunnel_list; spinlock_t l2tp_tunnel_list_lock; - struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2]; - spinlock_t l2tp_session_hlist_lock; + DEFINE_HASHTABLE(l2tp_session_hash, L2TP_HASH_BITS_2) + spinlock_t l2tp_session_hash_lock; }; static void l2tp_session_set_header_len(struct l2tp_session *session, int version); @@ -156,30 +157,17 @@ do { \ #define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t) #endif -/* Session hash global list for L2TPv3. - * The session_id SHOULD be random according to RFC3931, but several - * L2TP implementations use incrementing session_ids. So we do a real - * hash on the session_id, rather than a simple bitmask. - */ -static inline struct hlist_head * -l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) -{ - return >l2tp_session_hlist[hash_32(session_id, L2TP_HASH_BITS_2)]; - -} - /* Lookup a session by id in the global session list */ static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id) { struct l2tp_net *pn = l2tp_pernet(net); - struct hlist_head *session_list = - l2tp_session_id_hash_2(pn, session_id); struct l2tp_session *session; struct hlist_node *walk; rcu_read_lock_bh(); - hlist_for_each_entry_rcu(session, walk, session_list, global_hlist) { + hash_for_each_possible_rcu(pn->l2tp_session_hash, session, walk, + global_hlist, session_id) { if (session->session_id == session_id) { rcu_read_unlock_bh(); return session; @@ -190,23 +178,10 @@ static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id) return NULL; } -/* Session hash list. - * The session_id SHOULD be random according to RFC2661, but several - * L2TP implementations (Cisco and Microsoft) use incrementing - * session_ids. So we do a real hash on the session_id, rather than a - * simple bitmask. - */ -static inline struct hlist_head * -l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id) -{ - return >session_hlist[hash_32(session_id, L2TP_HASH_BITS)]; -} - /* Lookup a session by id */ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id) { - struct hlist_head *session_list; struct l2tp_session *session; struct hlist_node *walk; @@ -217,15 +192,14 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn if (tunnel == NULL) return l2tp_session_find_2(net, session_id); - session_list = l2tp_session_id_hash(tunnel, session_id); - read_lock_bh(>hlist_lock); - hlist_for_each_entry(session, walk, session_list, hlist) { + read_lock_bh(>hash_lock); + hash_for_each_possible(tunnel->session_hash, session, walk, hlist, session_id) { if (session->session_id == session_id) { - read_unlock_bh(>hlist_lock); + read_unlock_bh(>hash_lock); return session; } } - read_unlock_bh(>hlist_lock); + read_unlock_bh(>hash_lock); return NULL; } @@ -238,17 +212,15 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) struct l2tp_session *session; int count = 0; - read_lock_bh(>hlist_lock); - for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { - hlist_for_each_entry(session, walk, >session_hlist[hash], hlist) { - if (++count > nth) { - read_unlock_bh(>hlist_lock); - return session; - } + read_lock_bh(>hash_lock); + hash_for_each(tunnel->session_hash, hash, walk, session, hlist) { + if (++count > nth) { + read_unlock_bh(>hash_lock); + return session; } } - read_unlock_bh(>hlist_lock); + read_unlock_bh(>hash_lock); return NULL; } @@ -265,12 +237,10 @@ struct l2tp_session
[PATCH v3 11/17] net,l2tp: use new hashtable implementation
Switch l2tp to use the new hashtable implementation. This reduces the amount of generic unrelated code in l2tp. Signed-off-by: Sasha Levin levinsasha...@gmail.com --- net/l2tp/l2tp_core.c| 134 +- net/l2tp/l2tp_core.h|8 ++-- net/l2tp/l2tp_debugfs.c | 19 +++ 3 files changed, 61 insertions(+), 100 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 393355d..1d395ce 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -44,6 +44,7 @@ #include linux/udp.h #include linux/l2tp.h #include linux/hash.h +#include linux/hashtable.h #include linux/sort.h #include linux/file.h #include linux/nsproxy.h @@ -107,8 +108,8 @@ static unsigned int l2tp_net_id; struct l2tp_net { struct list_head l2tp_tunnel_list; spinlock_t l2tp_tunnel_list_lock; - struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2]; - spinlock_t l2tp_session_hlist_lock; + DEFINE_HASHTABLE(l2tp_session_hash, L2TP_HASH_BITS_2) + spinlock_t l2tp_session_hash_lock; }; static void l2tp_session_set_header_len(struct l2tp_session *session, int version); @@ -156,30 +157,17 @@ do { \ #define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t) #endif -/* Session hash global list for L2TPv3. - * The session_id SHOULD be random according to RFC3931, but several - * L2TP implementations use incrementing session_ids. So we do a real - * hash on the session_id, rather than a simple bitmask. - */ -static inline struct hlist_head * -l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id) -{ - return pn-l2tp_session_hlist[hash_32(session_id, L2TP_HASH_BITS_2)]; - -} - /* Lookup a session by id in the global session list */ static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id) { struct l2tp_net *pn = l2tp_pernet(net); - struct hlist_head *session_list = - l2tp_session_id_hash_2(pn, session_id); struct l2tp_session *session; struct hlist_node *walk; rcu_read_lock_bh(); - hlist_for_each_entry_rcu(session, walk, session_list, global_hlist) { + hash_for_each_possible_rcu(pn-l2tp_session_hash, session, walk, + global_hlist, session_id) { if (session-session_id == session_id) { rcu_read_unlock_bh(); return session; @@ -190,23 +178,10 @@ static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id) return NULL; } -/* Session hash list. - * The session_id SHOULD be random according to RFC2661, but several - * L2TP implementations (Cisco and Microsoft) use incrementing - * session_ids. So we do a real hash on the session_id, rather than a - * simple bitmask. - */ -static inline struct hlist_head * -l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id) -{ - return tunnel-session_hlist[hash_32(session_id, L2TP_HASH_BITS)]; -} - /* Lookup a session by id */ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id) { - struct hlist_head *session_list; struct l2tp_session *session; struct hlist_node *walk; @@ -217,15 +192,14 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn if (tunnel == NULL) return l2tp_session_find_2(net, session_id); - session_list = l2tp_session_id_hash(tunnel, session_id); - read_lock_bh(tunnel-hlist_lock); - hlist_for_each_entry(session, walk, session_list, hlist) { + read_lock_bh(tunnel-hash_lock); + hash_for_each_possible(tunnel-session_hash, session, walk, hlist, session_id) { if (session-session_id == session_id) { - read_unlock_bh(tunnel-hlist_lock); + read_unlock_bh(tunnel-hash_lock); return session; } } - read_unlock_bh(tunnel-hlist_lock); + read_unlock_bh(tunnel-hash_lock); return NULL; } @@ -238,17 +212,15 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) struct l2tp_session *session; int count = 0; - read_lock_bh(tunnel-hlist_lock); - for (hash = 0; hash L2TP_HASH_SIZE; hash++) { - hlist_for_each_entry(session, walk, tunnel-session_hlist[hash], hlist) { - if (++count nth) { - read_unlock_bh(tunnel-hlist_lock); - return session; - } + read_lock_bh(tunnel-hash_lock); + hash_for_each(tunnel-session_hash, hash, walk, session, hlist) { + if (++count nth) { + read_unlock_bh(tunnel-hash_lock); + return session; }