The commit is pushed to "branch-rh7-3.10.0-327.10.1.vz7.12.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git after rh7-3.10.0-327.10.1.vz7.12.3 ------> commit 9d03fb3ebb7064dd2a3c1f5620f3ff6a0808182d Author: Pavel Tikhomirov <ptikhomi...@virtuozzo.com> Date: Thu Mar 24 19:53:35 2016 +0400
vzprivnet: Hash sets for ipv6 privnet changes: 1) remove second loop cursor in hlist_for_each_entry Port diff-vz-privnet6-hashsets vzredir: Hash sets for ipv6 privnet I've recently back-ported the sparse privnets to rhel5 and made (cloned) a stupid support for ipv6 using plain lists. This is an attempt to speed up the v6 filtering since in ipv6 rt cache isn't that good for us as in ipv4. The idea of this patch is to have a set for each prefix configured and lookup in each of them sequentially. According to PMs people need to configure privnets with the same (or close to each oterh) prefixes. Taken from 2.6.18-rh5 Signed-off-by: Pavel Emelyanov <xe...@parallels.com> Signed-off-by: Pavel Tikhomirov <ptikhomi...@virtuozzo.com> --- net/ipv6/netfilter/ip6_vzprivnet.c | 100 ++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 8 deletions(-) diff --git a/net/ipv6/netfilter/ip6_vzprivnet.c b/net/ipv6/netfilter/ip6_vzprivnet.c index ffaf3ad..c9fb1a5 100644 --- a/net/ipv6/netfilter/ip6_vzprivnet.c +++ b/net/ipv6/netfilter/ip6_vzprivnet.c @@ -4,6 +4,8 @@ #include <linux/list.h> #include <linux/seq_file.h> #include <linux/module.h> +#include <linux/jhash.h> +#include <linux/random.h> #include <linux/inet.h> #include <net/ipv6.h> @@ -26,7 +28,23 @@ struct vzprivnet_entry { struct hlist_node hash; }; -static HLIST_HEAD(vzpriv_entries); +struct vzprivnet_hash { + unsigned preflen; + struct hlist_head *hash; +}; + +#define MAX_PREFLEN 128 + +static struct vzprivnet_hash hashes[MAX_PREFLEN]; +static unsigned hash_rnd; + +static noinline unsigned hash_ip_and_prefix(u32 *ip, unsigned preflen) +{ + u32 key[4]; + + ipv6_addr_prefix((struct in6_addr *)key, (struct in6_addr *)ip, preflen); + return jhash2(key, 4, hash_rnd); +} static inline int ip6_match(u32 *net, unsigned plen, u32 *ip) { @@ -38,13 +56,62 @@ static inline int ip6_intersect(u32 *ip1, unsigned len1, u32 *ip2, unsigned len2 return ip6_match(ip1, len1, ip2) || ip6_match(ip2, len2, ip1); } +static struct vzprivnet_hash *vzprivnet6_get_hash(unsigned preflen) +{ + int i; + struct hlist_head *hash = NULL; + + if (preflen == MAX_PREFLEN) + return NULL; + +again: + write_lock_bh(&vzpriv6lock); + for (i = 0; hashes[i].hash != NULL; i++) + if (hashes[i].preflen == preflen) { + write_unlock_bh(&vzpriv6lock); + if (hash != NULL) + free_page((unsigned long)hash); + return hashes + i; + } + + if (i == MAX_PREFLEN) { + write_unlock_bh(&vzpriv6lock); + if (hash != NULL) + free_page((unsigned long)hash); + + WARN_ON_ONCE(1); + return NULL; + } + + if (hash != NULL) { + hashes[i].preflen = preflen; + hashes[i].hash = hash; + write_unlock_bh(&vzpriv6lock); + return hashes + i; + } + + write_unlock_bh(&vzpriv6lock); + + hash = (struct hlist_head *)get_zeroed_page(GFP_KERNEL); + if (hash == NULL) + return NULL; + + goto again; +} + static struct vzprivnet_entry *vzprivnet6_lookup(u32 *ip) { - struct vzprivnet_entry *e; + int i; - hlist_for_each_entry(e, &vzpriv_entries, hash) { - if (ip6_match(e->ip, e->preflen, ip)) - return e; + for (i = 0; hashes[i].hash != NULL; i++) { + struct vzprivnet_entry *pne; + unsigned chain; + + chain = hash_ip_and_prefix(ip, hashes[i].preflen); + hlist_for_each_entry(pne, &hashes[i].hash[chain], hash) + /* hashes[i].preflen == pne->preflen here */ + if (ip6_match(pne->ip, pne->preflen, ip)) + return pne; } return NULL; @@ -65,9 +132,12 @@ static inline struct vzprivnet *vzprivnet6_lookup_net(u32 *ip) return &internet; } -static void vzprivnet6_hash_entry(struct vzprivnet_entry *e) +static void vzprivnet6_hash_entry(struct vzprivnet_entry *e, struct vzprivnet_hash *h) { - hlist_add_head(&e->hash, &vzpriv_entries); + unsigned chain; + + chain = hash_ip_and_prefix(e->ip, e->preflen); + hlist_add_head(&e->hash, &h->hash[chain]); } static void vzprivnet6_unhash_entry(struct vzprivnet_entry *e) @@ -85,8 +155,13 @@ static int sparse6_add(unsigned netid, u32 *ip, unsigned preflen, int weak) int err; struct vzprivnet *pn, *epn = NULL; struct vzprivnet_entry *pne = NULL, *tmp; + struct vzprivnet_hash *hash; err = -ENOMEM; + hash = vzprivnet6_get_hash(preflen); + if (hash == NULL) + goto out; + pn = kzalloc(sizeof(*pn), GFP_KERNEL); if (pn == NULL) goto out; @@ -118,7 +193,7 @@ found_net: pne->preflen = preflen; pne->pn = pn; list_add_tail(&pne->list, &pn->entries); - vzprivnet6_hash_entry(pne); + vzprivnet6_hash_entry(pne, hash); pne = NULL; } else if (weak) { pn->weak = 1; @@ -534,6 +609,13 @@ static struct file_operations proc_classify6_ops = { static void vzprivnet6_show_stat(struct seq_file *f) { + int i; + + for (i = 0; i < MAX_PREFLEN; i++) + if (hashes[i].hash == NULL) + break; + + seq_printf(f, "Hashes6: %d\n", i); } static int __init ip6_vzprivnet_init(void) @@ -541,6 +623,8 @@ static int __init ip6_vzprivnet_init(void) int err = -ENOMEM; struct proc_dir_entry *proc; + get_random_bytes(&hash_rnd, 4); + proc = proc_create("sparse6", 0644, vzpriv_proc_dir, &proc_sparse6_ops); if (proc == NULL) _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel