]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/ipvs/ip_vs_lblc.c
rt2x00: rt2800pci: use module_pci_driver macro
[karo-tx-linux.git] / net / netfilter / ipvs / ip_vs_lblc.c
1 /*
2  * IPVS:        Locality-Based Least-Connection scheduling module
3  *
4  * Authors:     Wensong Zhang <wensong@gnuchina.org>
5  *
6  *              This program is free software; you can redistribute it and/or
7  *              modify it under the terms of the GNU General Public License
8  *              as published by the Free Software Foundation; either version
9  *              2 of the License, or (at your option) any later version.
10  *
11  * Changes:
12  *     Martin Hamilton         :    fixed the terrible locking bugs
13  *                                   *lock(tbl->lock) ==> *lock(&tbl->lock)
14  *     Wensong Zhang           :    fixed the uninitialized tbl->lock bug
15  *     Wensong Zhang           :    added doing full expiration check to
16  *                                   collect stale entries of 24+ hours when
17  *                                   no partial expire check in a half hour
18  *     Julian Anastasov        :    replaced del_timer call with del_timer_sync
19  *                                   to avoid the possible race between timer
20  *                                   handler and del_timer thread in SMP
21  *
22  */
23
24 /*
25  * The lblc algorithm is as follows (pseudo code):
26  *
27  *       if cachenode[dest_ip] is null then
28  *               n, cachenode[dest_ip] <- {weighted least-conn node};
29  *       else
30  *               n <- cachenode[dest_ip];
31  *               if (n is dead) OR
32  *                  (n.conns>n.weight AND
33  *                   there is a node m with m.conns<m.weight/2) then
34  *                 n, cachenode[dest_ip] <- {weighted least-conn node};
35  *
36  *       return n;
37  *
38  * Thanks must go to Wenzhuo Zhang for talking WCCP to me and pushing
39  * me to write this module.
40  */
41
42 #define KMSG_COMPONENT "IPVS"
43 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
44
45 #include <linux/ip.h>
46 #include <linux/slab.h>
47 #include <linux/module.h>
48 #include <linux/kernel.h>
49 #include <linux/skbuff.h>
50 #include <linux/jiffies.h>
51
52 /* for sysctl */
53 #include <linux/fs.h>
54 #include <linux/sysctl.h>
55
56 #include <net/ip_vs.h>
57
58
59 /*
60  *    It is for garbage collection of stale IPVS lblc entries,
61  *    when the table is full.
62  */
63 #define CHECK_EXPIRE_INTERVAL   (60*HZ)
64 #define ENTRY_TIMEOUT           (6*60*HZ)
65
66 #define DEFAULT_EXPIRATION      (24*60*60*HZ)
67
68 /*
69  *    It is for full expiration check.
70  *    When there is no partial expiration check (garbage collection)
71  *    in a half hour, do a full expiration check to collect stale
72  *    entries that haven't been touched for a day.
73  */
74 #define COUNT_FOR_FULL_EXPIRATION   30
75
76
77 /*
78  *     for IPVS lblc entry hash table
79  */
80 #ifndef CONFIG_IP_VS_LBLC_TAB_BITS
81 #define CONFIG_IP_VS_LBLC_TAB_BITS      10
82 #endif
83 #define IP_VS_LBLC_TAB_BITS     CONFIG_IP_VS_LBLC_TAB_BITS
84 #define IP_VS_LBLC_TAB_SIZE     (1 << IP_VS_LBLC_TAB_BITS)
85 #define IP_VS_LBLC_TAB_MASK     (IP_VS_LBLC_TAB_SIZE - 1)
86
87
88 /*
89  *      IPVS lblc entry represents an association between destination
90  *      IP address and its destination server
91  */
92 struct ip_vs_lblc_entry {
93         struct hlist_node       list;
94         int                     af;             /* address family */
95         union nf_inet_addr      addr;           /* destination IP address */
96         struct ip_vs_dest __rcu *dest;          /* real server (cache) */
97         unsigned long           lastuse;        /* last used time */
98         struct rcu_head         rcu_head;
99 };
100
101
102 /*
103  *      IPVS lblc hash table
104  */
105 struct ip_vs_lblc_table {
106         struct rcu_head         rcu_head;
107         struct hlist_head       bucket[IP_VS_LBLC_TAB_SIZE];  /* hash bucket */
108         struct timer_list       periodic_timer; /* collect stale entries */
109         atomic_t                entries;        /* number of entries */
110         int                     max_size;       /* maximum size of entries */
111         int                     rover;          /* rover for expire check */
112         int                     counter;        /* counter for no expire */
113         bool                    dead;
114 };
115
116
117 /*
118  *      IPVS LBLC sysctl table
119  */
120 #ifdef CONFIG_SYSCTL
121 static struct ctl_table vs_vars_table[] = {
122         {
123                 .procname       = "lblc_expiration",
124                 .data           = NULL,
125                 .maxlen         = sizeof(int),
126                 .mode           = 0644,
127                 .proc_handler   = proc_dointvec_jiffies,
128         },
129         { }
130 };
131 #endif
132
133 static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
134 {
135         struct ip_vs_dest *dest;
136
137         hlist_del_rcu(&en->list);
138         /*
139          * We don't kfree dest because it is referred either by its service
140          * or the trash dest list.
141          */
142         dest = rcu_dereference_protected(en->dest, 1);
143         ip_vs_dest_put(dest);
144         kfree_rcu(en, rcu_head);
145 }
146
147
148 /*
149  *      Returns hash value for IPVS LBLC entry
150  */
151 static inline unsigned int
152 ip_vs_lblc_hashkey(int af, const union nf_inet_addr *addr)
153 {
154         __be32 addr_fold = addr->ip;
155
156 #ifdef CONFIG_IP_VS_IPV6
157         if (af == AF_INET6)
158                 addr_fold = addr->ip6[0]^addr->ip6[1]^
159                             addr->ip6[2]^addr->ip6[3];
160 #endif
161         return (ntohl(addr_fold)*2654435761UL) & IP_VS_LBLC_TAB_MASK;
162 }
163
164
165 /*
166  *      Hash an entry in the ip_vs_lblc_table.
167  *      returns bool success.
168  */
169 static void
170 ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en)
171 {
172         unsigned int hash = ip_vs_lblc_hashkey(en->af, &en->addr);
173
174         hlist_add_head_rcu(&en->list, &tbl->bucket[hash]);
175         atomic_inc(&tbl->entries);
176 }
177
178
179 /* Get ip_vs_lblc_entry associated with supplied parameters. */
180 static inline struct ip_vs_lblc_entry *
181 ip_vs_lblc_get(int af, struct ip_vs_lblc_table *tbl,
182                const union nf_inet_addr *addr)
183 {
184         unsigned int hash = ip_vs_lblc_hashkey(af, addr);
185         struct ip_vs_lblc_entry *en;
186
187         hlist_for_each_entry_rcu(en, &tbl->bucket[hash], list)
188                 if (ip_vs_addr_equal(af, &en->addr, addr))
189                         return en;
190
191         return NULL;
192 }
193
194
195 /*
196  * Create or update an ip_vs_lblc_entry, which is a mapping of a destination IP
197  * address to a server. Called under spin lock.
198  */
199 static inline struct ip_vs_lblc_entry *
200 ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
201                struct ip_vs_dest *dest)
202 {
203         struct ip_vs_lblc_entry *en;
204
205         en = ip_vs_lblc_get(dest->af, tbl, daddr);
206         if (!en) {
207                 en = kmalloc(sizeof(*en), GFP_ATOMIC);
208                 if (!en)
209                         return NULL;
210
211                 en->af = dest->af;
212                 ip_vs_addr_copy(dest->af, &en->addr, daddr);
213                 en->lastuse = jiffies;
214
215                 ip_vs_dest_hold(dest);
216                 RCU_INIT_POINTER(en->dest, dest);
217
218                 ip_vs_lblc_hash(tbl, en);
219         } else {
220                 struct ip_vs_dest *old_dest;
221
222                 old_dest = rcu_dereference_protected(en->dest, 1);
223                 if (old_dest != dest) {
224                         ip_vs_dest_put(old_dest);
225                         ip_vs_dest_hold(dest);
226                         /* No ordering constraints for refcnt */
227                         RCU_INIT_POINTER(en->dest, dest);
228                 }
229         }
230
231         return en;
232 }
233
234
235 /*
236  *      Flush all the entries of the specified table.
237  */
238 static void ip_vs_lblc_flush(struct ip_vs_service *svc)
239 {
240         struct ip_vs_lblc_table *tbl = svc->sched_data;
241         struct ip_vs_lblc_entry *en;
242         struct hlist_node *next;
243         int i;
244
245         spin_lock_bh(&svc->sched_lock);
246         tbl->dead = 1;
247         for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
248                 hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) {
249                         ip_vs_lblc_free(en);
250                         atomic_dec(&tbl->entries);
251                 }
252         }
253         spin_unlock_bh(&svc->sched_lock);
254 }
255
256 static int sysctl_lblc_expiration(struct ip_vs_service *svc)
257 {
258 #ifdef CONFIG_SYSCTL
259         struct netns_ipvs *ipvs = net_ipvs(svc->net);
260         return ipvs->sysctl_lblc_expiration;
261 #else
262         return DEFAULT_EXPIRATION;
263 #endif
264 }
265
266 static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
267 {
268         struct ip_vs_lblc_table *tbl = svc->sched_data;
269         struct ip_vs_lblc_entry *en;
270         struct hlist_node *next;
271         unsigned long now = jiffies;
272         int i, j;
273
274         for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
275                 j = (j + 1) & IP_VS_LBLC_TAB_MASK;
276
277                 spin_lock(&svc->sched_lock);
278                 hlist_for_each_entry_safe(en, next, &tbl->bucket[j], list) {
279                         if (time_before(now,
280                                         en->lastuse +
281                                         sysctl_lblc_expiration(svc)))
282                                 continue;
283
284                         ip_vs_lblc_free(en);
285                         atomic_dec(&tbl->entries);
286                 }
287                 spin_unlock(&svc->sched_lock);
288         }
289         tbl->rover = j;
290 }
291
292
293 /*
294  *      Periodical timer handler for IPVS lblc table
295  *      It is used to collect stale entries when the number of entries
296  *      exceeds the maximum size of the table.
297  *
298  *      Fixme: we probably need more complicated algorithm to collect
299  *             entries that have not been used for a long time even
300  *             if the number of entries doesn't exceed the maximum size
301  *             of the table.
302  *      The full expiration check is for this purpose now.
303  */
304 static void ip_vs_lblc_check_expire(unsigned long data)
305 {
306         struct ip_vs_service *svc = (struct ip_vs_service *) data;
307         struct ip_vs_lblc_table *tbl = svc->sched_data;
308         unsigned long now = jiffies;
309         int goal;
310         int i, j;
311         struct ip_vs_lblc_entry *en;
312         struct hlist_node *next;
313
314         if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) {
315                 /* do full expiration check */
316                 ip_vs_lblc_full_check(svc);
317                 tbl->counter = 1;
318                 goto out;
319         }
320
321         if (atomic_read(&tbl->entries) <= tbl->max_size) {
322                 tbl->counter++;
323                 goto out;
324         }
325
326         goal = (atomic_read(&tbl->entries) - tbl->max_size)*4/3;
327         if (goal > tbl->max_size/2)
328                 goal = tbl->max_size/2;
329
330         for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
331                 j = (j + 1) & IP_VS_LBLC_TAB_MASK;
332
333                 spin_lock(&svc->sched_lock);
334                 hlist_for_each_entry_safe(en, next, &tbl->bucket[j], list) {
335                         if (time_before(now, en->lastuse + ENTRY_TIMEOUT))
336                                 continue;
337
338                         ip_vs_lblc_free(en);
339                         atomic_dec(&tbl->entries);
340                         goal--;
341                 }
342                 spin_unlock(&svc->sched_lock);
343                 if (goal <= 0)
344                         break;
345         }
346         tbl->rover = j;
347
348   out:
349         mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL);
350 }
351
352
353 static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
354 {
355         int i;
356         struct ip_vs_lblc_table *tbl;
357
358         /*
359          *    Allocate the ip_vs_lblc_table for this service
360          */
361         tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
362         if (tbl == NULL)
363                 return -ENOMEM;
364
365         svc->sched_data = tbl;
366         IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) allocated for "
367                   "current service\n", sizeof(*tbl));
368
369         /*
370          *    Initialize the hash buckets
371          */
372         for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
373                 INIT_HLIST_HEAD(&tbl->bucket[i]);
374         }
375         tbl->max_size = IP_VS_LBLC_TAB_SIZE*16;
376         tbl->rover = 0;
377         tbl->counter = 1;
378         tbl->dead = 0;
379
380         /*
381          *    Hook periodic timer for garbage collection
382          */
383         setup_timer(&tbl->periodic_timer, ip_vs_lblc_check_expire,
384                         (unsigned long)svc);
385         mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL);
386
387         return 0;
388 }
389
390
391 static void ip_vs_lblc_done_svc(struct ip_vs_service *svc)
392 {
393         struct ip_vs_lblc_table *tbl = svc->sched_data;
394
395         /* remove periodic timer */
396         del_timer_sync(&tbl->periodic_timer);
397
398         /* got to clean up table entries here */
399         ip_vs_lblc_flush(svc);
400
401         /* release the table itself */
402         kfree_rcu(tbl, rcu_head);
403         IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) released\n",
404                   sizeof(*tbl));
405 }
406
407
408 static inline struct ip_vs_dest *
409 __ip_vs_lblc_schedule(struct ip_vs_service *svc)
410 {
411         struct ip_vs_dest *dest, *least;
412         int loh, doh;
413
414         /*
415          * We use the following formula to estimate the load:
416          *                (dest overhead) / dest->weight
417          *
418          * Remember -- no floats in kernel mode!!!
419          * The comparison of h1*w2 > h2*w1 is equivalent to that of
420          *                h1/w1 > h2/w2
421          * if every weight is larger than zero.
422          *
423          * The server with weight=0 is quiesced and will not receive any
424          * new connection.
425          */
426         list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
427                 if (dest->flags & IP_VS_DEST_F_OVERLOAD)
428                         continue;
429                 if (atomic_read(&dest->weight) > 0) {
430                         least = dest;
431                         loh = ip_vs_dest_conn_overhead(least);
432                         goto nextstage;
433                 }
434         }
435         return NULL;
436
437         /*
438          *    Find the destination with the least load.
439          */
440   nextstage:
441         list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
442                 if (dest->flags & IP_VS_DEST_F_OVERLOAD)
443                         continue;
444
445                 doh = ip_vs_dest_conn_overhead(dest);
446                 if (loh * atomic_read(&dest->weight) >
447                     doh * atomic_read(&least->weight)) {
448                         least = dest;
449                         loh = doh;
450                 }
451         }
452
453         IP_VS_DBG_BUF(6, "LBLC: server %s:%d "
454                       "activeconns %d refcnt %d weight %d overhead %d\n",
455                       IP_VS_DBG_ADDR(least->af, &least->addr),
456                       ntohs(least->port),
457                       atomic_read(&least->activeconns),
458                       atomic_read(&least->refcnt),
459                       atomic_read(&least->weight), loh);
460
461         return least;
462 }
463
464
465 /*
466  *   If this destination server is overloaded and there is a less loaded
467  *   server, then return true.
468  */
469 static inline int
470 is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
471 {
472         if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
473                 struct ip_vs_dest *d;
474
475                 list_for_each_entry_rcu(d, &svc->destinations, n_list) {
476                         if (atomic_read(&d->activeconns)*2
477                             < atomic_read(&d->weight)) {
478                                 return 1;
479                         }
480                 }
481         }
482         return 0;
483 }
484
485
486 /*
487  *    Locality-Based (weighted) Least-Connection scheduling
488  */
489 static struct ip_vs_dest *
490 ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
491                     struct ip_vs_iphdr *iph)
492 {
493         struct ip_vs_lblc_table *tbl = svc->sched_data;
494         struct ip_vs_dest *dest = NULL;
495         struct ip_vs_lblc_entry *en;
496
497         IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
498
499         /* First look in our cache */
500         en = ip_vs_lblc_get(svc->af, tbl, &iph->daddr);
501         if (en) {
502                 /* We only hold a read lock, but this is atomic */
503                 en->lastuse = jiffies;
504
505                 /*
506                  * If the destination is not available, i.e. it's in the trash,
507                  * we must ignore it, as it may be removed from under our feet,
508                  * if someone drops our reference count. Our caller only makes
509                  * sure that destinations, that are not in the trash, are not
510                  * moved to the trash, while we are scheduling. But anyone can
511                  * free up entries from the trash at any time.
512                  */
513
514                 dest = rcu_dereference(en->dest);
515                 if ((dest->flags & IP_VS_DEST_F_AVAILABLE) &&
516                     atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc))
517                         goto out;
518         }
519
520         /* No cache entry or it is invalid, time to schedule */
521         dest = __ip_vs_lblc_schedule(svc);
522         if (!dest) {
523                 ip_vs_scheduler_err(svc, "no destination available");
524                 return NULL;
525         }
526
527         /* If we fail to create a cache entry, we'll just use the valid dest */
528         spin_lock_bh(&svc->sched_lock);
529         if (!tbl->dead)
530                 ip_vs_lblc_new(tbl, &iph->daddr, dest);
531         spin_unlock_bh(&svc->sched_lock);
532
533 out:
534         IP_VS_DBG_BUF(6, "LBLC: destination IP address %s --> server %s:%d\n",
535                       IP_VS_DBG_ADDR(svc->af, &iph->daddr),
536                       IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port));
537
538         return dest;
539 }
540
541
542 /*
543  *      IPVS LBLC Scheduler structure
544  */
545 static struct ip_vs_scheduler ip_vs_lblc_scheduler =
546 {
547         .name =                 "lblc",
548         .refcnt =               ATOMIC_INIT(0),
549         .module =               THIS_MODULE,
550         .n_list =               LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list),
551         .init_service =         ip_vs_lblc_init_svc,
552         .done_service =         ip_vs_lblc_done_svc,
553         .schedule =             ip_vs_lblc_schedule,
554 };
555
556 /*
557  *  per netns init.
558  */
559 #ifdef CONFIG_SYSCTL
560 static int __net_init __ip_vs_lblc_init(struct net *net)
561 {
562         struct netns_ipvs *ipvs = net_ipvs(net);
563
564         if (!ipvs)
565                 return -ENOENT;
566
567         if (!net_eq(net, &init_net)) {
568                 ipvs->lblc_ctl_table = kmemdup(vs_vars_table,
569                                                 sizeof(vs_vars_table),
570                                                 GFP_KERNEL);
571                 if (ipvs->lblc_ctl_table == NULL)
572                         return -ENOMEM;
573
574                 /* Don't export sysctls to unprivileged users */
575                 if (net->user_ns != &init_user_ns)
576                         ipvs->lblc_ctl_table[0].procname = NULL;
577
578         } else
579                 ipvs->lblc_ctl_table = vs_vars_table;
580         ipvs->sysctl_lblc_expiration = DEFAULT_EXPIRATION;
581         ipvs->lblc_ctl_table[0].data = &ipvs->sysctl_lblc_expiration;
582
583         ipvs->lblc_ctl_header =
584                 register_net_sysctl(net, "net/ipv4/vs", ipvs->lblc_ctl_table);
585         if (!ipvs->lblc_ctl_header) {
586                 if (!net_eq(net, &init_net))
587                         kfree(ipvs->lblc_ctl_table);
588                 return -ENOMEM;
589         }
590
591         return 0;
592 }
593
594 static void __net_exit __ip_vs_lblc_exit(struct net *net)
595 {
596         struct netns_ipvs *ipvs = net_ipvs(net);
597
598         unregister_net_sysctl_table(ipvs->lblc_ctl_header);
599
600         if (!net_eq(net, &init_net))
601                 kfree(ipvs->lblc_ctl_table);
602 }
603
604 #else
605
606 static int __net_init __ip_vs_lblc_init(struct net *net) { return 0; }
607 static void __net_exit __ip_vs_lblc_exit(struct net *net) { }
608
609 #endif
610
611 static struct pernet_operations ip_vs_lblc_ops = {
612         .init = __ip_vs_lblc_init,
613         .exit = __ip_vs_lblc_exit,
614 };
615
616 static int __init ip_vs_lblc_init(void)
617 {
618         int ret;
619
620         ret = register_pernet_subsys(&ip_vs_lblc_ops);
621         if (ret)
622                 return ret;
623
624         ret = register_ip_vs_scheduler(&ip_vs_lblc_scheduler);
625         if (ret)
626                 unregister_pernet_subsys(&ip_vs_lblc_ops);
627         return ret;
628 }
629
630 static void __exit ip_vs_lblc_cleanup(void)
631 {
632         unregister_ip_vs_scheduler(&ip_vs_lblc_scheduler);
633         unregister_pernet_subsys(&ip_vs_lblc_ops);
634         synchronize_rcu();
635 }
636
637
638 module_init(ip_vs_lblc_init);
639 module_exit(ip_vs_lblc_cleanup);
640 MODULE_LICENSE("GPL");