Update changelog
[l2tpns.git] / grpsess.c
1 /*
2 * Fernando ALVES 2013
3 * Grouped session for load balancing and fail-over
4 * GPL licenced
5 */
6
7 #include <errno.h>
8 #include <ctype.h>
9 #include <string.h>
10 #include <sys/socket.h>
11 #include <linux/rtnetlink.h>
12 #include <netinet/ip6.h>
13
14 #include "dhcp6.h"
15 #include "l2tpns.h"
16 #include "util.h"
17 #include "cluster.h"
18
19 #ifdef BGP
20 #include "bgp.h"
21 #endif
22
23 union grp_iphash {
24 groupidt grp;
25 union grp_iphash *idx;
26 } grp_ip_hash[256]; // Mapping from IP address to group structures.
27
28 struct grp_ipv6radix {
29 groupidt grp;
30 struct grp_ipv6radix *branch;
31 } grp_ipv6_hash[16]; // Mapping from IPv6 address to session structures.
32
33 groupidt gnextgrpid = 0;
34
35 typedef struct
36 {
37 sessionidt sid_loaddist[0x10000];
38 }
39 local_group;
40
41 local_group *grp_local = NULL; // Array of local_group structures.
42
43 // Find gruop by IP, < 1 for not found
44 //
45 // Confusingly enough, this 'ip' must be
46 // in _network_ order. This being the common
47 // case when looking it up from IP packet headers.
48 static groupidt grp_lookup_ipmap(in_addr_t ip)
49 {
50 uint8_t *a = (uint8_t *) &ip;
51 union grp_iphash *h = grp_ip_hash;
52
53 if (!(h = h[*a++].idx)) return 0;
54 if (!(h = h[*a++].idx)) return 0;
55 if (!(h = h[*a++].idx)) return 0;
56
57 return h[*a].grp;
58 }
59
60 //
61 // Take an IP address in HOST byte order and
62 // add it to the grouid by IP cache.
63 //
64 // (It's actually cached in network order)
65 //
66 static void grp_cache_ipmap(in_addr_t ip, groupidt g)
67 {
68 in_addr_t nip = htonl(ip); // MUST be in network order. I.e. MSB must in be ((char *) (&ip))[0]
69 uint8_t *a = (uint8_t *) &nip;
70 union grp_iphash *h = grp_ip_hash;
71 int i;
72
73 for (i = 0; i < 3; i++)
74 {
75 if (!(h[a[i]].idx || (h[a[i]].idx = calloc(256, sizeof(union grp_iphash)))))
76 return;
77
78 h = h[a[i]].idx;
79 }
80
81 h[a[3]].grp = g;
82
83 if (g > 0)
84 LOG(4, 0, 0, "Caching Group:%d ip address %s\n", g, fmtaddr(nip, 0));
85 else if (g == 0)
86 LOG(4, 0, 0, "Un-caching Group ip address %s\n", fmtaddr(nip, 0));
87 }
88
89 groupidt grp_groupbyip(in_addr_t ip)
90 {
91 groupidt g = grp_lookup_ipmap(ip);
92
93 if (g > 0 && g < MAXGROUPE)
94 return g;
95
96 return 0;
97 }
98
99 static void grp_cache_ipv6map(struct in6_addr ip, int prefixlen, groupidt g)
100 {
101 int i;
102 int niblles;
103 struct grp_ipv6radix *curnode;
104 char ipv6addr[INET6_ADDRSTRLEN];
105
106 curnode = &grp_ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
107
108 niblles = prefixlen >> 2;
109 i = 1;
110
111 while (i < niblles)
112 {
113 if (curnode->branch == NULL)
114 {
115 if (!(curnode->branch = calloc(16, sizeof(struct grp_ipv6radix))))
116 return;
117 }
118
119 if (i & 1)
120 curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
121 else
122 curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
123
124 i++;
125 }
126
127 curnode->grp = g;
128
129 if (g > 0)
130 LOG(4, 0, 0, "Caching Group:%d ip address %s/%d\n", g,
131 inet_ntop(AF_INET6, &ip, ipv6addr,
132 INET6_ADDRSTRLEN),
133 prefixlen);
134 else if (g == 0)
135 LOG(4, 0, 0, "Un-caching Group:%d ip address %s/%d\n", g,
136 inet_ntop(AF_INET6, &ip, ipv6addr,
137 INET6_ADDRSTRLEN),
138 prefixlen);
139 }
140
141 static void grp_route6set(groupidt g, struct in6_addr ip, int prefixlen, int add)
142 {
143 struct {
144 struct nlmsghdr nh;
145 struct rtmsg rt;
146 char buf[64];
147 } req;
148 int metric;
149 char ipv6addr[INET6_ADDRSTRLEN];
150
151 if (!config->ipv6_prefix.s6_addr[0])
152 {
153 LOG(0, 0, 0, "Asked to set IPv6 route, but IPv6 not setup.\n");
154 return;
155 }
156
157 memset(&req, 0, sizeof(req));
158
159 if (add)
160 {
161 req.nh.nlmsg_type = RTM_NEWROUTE;
162 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE;
163 }
164 else
165 {
166 req.nh.nlmsg_type = RTM_DELROUTE;
167 req.nh.nlmsg_flags = NLM_F_REQUEST;
168 }
169
170 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt));
171
172 req.rt.rtm_family = AF_INET6;
173 req.rt.rtm_dst_len = prefixlen;
174 req.rt.rtm_table = RT_TABLE_MAIN;
175 req.rt.rtm_protocol = 42;
176 req.rt.rtm_scope = RT_SCOPE_LINK;
177 req.rt.rtm_type = RTN_UNICAST;
178
179 netlink_addattr(&req.nh, RTA_OIF, &tunidx, sizeof(int));
180 netlink_addattr(&req.nh, RTA_DST, &ip, sizeof(ip));
181 metric = 1;
182 netlink_addattr(&req.nh, RTA_METRICS, &metric, sizeof(metric));
183
184 LOG(1, g, 0, "Route Group %s %s/%d\n",
185 add ? "add" : "del",
186 inet_ntop(AF_INET6, &ip, ipv6addr, INET6_ADDRSTRLEN),
187 prefixlen);
188
189 if (netlink_send(&req.nh) < 0)
190 LOG(0, 0, 0, "grp_route6set() error in sending netlink message: %s\n", strerror(errno));
191
192 #ifdef BGP
193 if (add)
194 bgp_add_route6(ip, prefixlen);
195 else
196 bgp_del_route6(ip, prefixlen);
197 #endif /* BGP */
198
199 if (g)
200 {
201 if (!add) // Are we deleting a route?
202 g = 0; // Caching the session as '0' is the same as uncaching.
203
204 grp_cache_ipv6map(ip, prefixlen, g);
205 }
206
207 return;
208 }
209
210 static groupidt grp_lookup_ipv6map(struct in6_addr ip)
211 {
212 struct grp_ipv6radix *curnode;
213 int i;
214 int g;
215 char ipv6addr[INET6_ADDRSTRLEN];
216
217 curnode = &grp_ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
218 i = 1;
219 g = curnode->grp;
220
221 while (g == 0 && i < 32 && curnode->branch != NULL)
222 {
223 if (i & 1)
224 curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
225 else
226 curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
227
228 g = curnode->grp;
229 i++;
230 }
231
232 LOG(4, 0, 0, "Looking up Group address %s and got %d\n",
233 inet_ntop(AF_INET6, &ip, ipv6addr,
234 INET6_ADDRSTRLEN),
235 g);
236
237 return g;
238 }
239
240 groupidt grp_groupbyipv6(struct in6_addr ip)
241 {
242 groupidt g = grp_lookup_ipv6map(ip);
243
244 if (g > 0 && g < MAXGROUPE)
245 return g;
246
247 return 0;
248 }
249
250 // Set all route of a group
251 void grp_setgrouproute6(groupidt g, int add)
252 {
253 int i, j;
254 int ipv6opened = 0;
255
256 if (add)
257 {
258 for (j = 0; j < grpsession[g].nbsession; j++)
259 {
260 if (grpsession[g].sesslist[j].sid != 0)
261 {
262 if (session[grpsession[g].sesslist[j].sid].ppp.ipv6cp == Opened)
263 {
264 // IPv6 opened
265 ipv6opened = 1;
266 break;
267 }
268 }
269 }
270 }
271
272 if (ipv6opened || !add)
273 {
274 for (i = 0; i < grpsession[g].nbroutes6grp; i++)
275 {
276 if (grpsession[g].route6[i].ipv6prefixlen != 0)
277 {
278 grpsession[g].ipv6cp_opened = add;
279 grp_route6set(g, grpsession[g].route6[i].ipv6route, grpsession[g].route6[i].ipv6prefixlen, add);
280 }
281 }
282 }
283 }
284
285 // Add a route
286 //
287 // This adds it to the routing table, advertises it
288 // via BGP if enabled, and stuffs it into the
289 // 'groupbyip' cache.
290 //
291 // 'ip' must be in _host_ order.
292 //
293 static void grp_routeset(groupidt g, in_addr_t ip, int prefixlen, int add)
294 {
295 struct {
296 struct nlmsghdr nh;
297 struct rtmsg rt;
298 char buf[32];
299 } req;
300 int i;
301 in_addr_t n_ip;
302
303 if (!prefixlen) prefixlen = 32;
304
305 ip &= 0xffffffff << (32 - prefixlen);; // Force the ip to be the first one in the route.
306
307 memset(&req, 0, sizeof(req));
308
309 if (add)
310 {
311 req.nh.nlmsg_type = RTM_NEWROUTE;
312 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE;
313 }
314 else
315 {
316 req.nh.nlmsg_type = RTM_DELROUTE;
317 req.nh.nlmsg_flags = NLM_F_REQUEST;
318 }
319
320 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt));
321
322 req.rt.rtm_family = AF_INET;
323 req.rt.rtm_dst_len = prefixlen;
324 req.rt.rtm_table = RT_TABLE_MAIN;
325 req.rt.rtm_protocol = 42;
326 req.rt.rtm_scope = RT_SCOPE_LINK;
327 req.rt.rtm_type = RTN_UNICAST;
328
329 netlink_addattr(&req.nh, RTA_OIF, &tunidx, sizeof(int));
330 n_ip = htonl(ip);
331 netlink_addattr(&req.nh, RTA_DST, &n_ip, sizeof(n_ip));
332
333 LOG(3, 0, 0, "Route (Group) %s %s/%d\n", add ? "add" : "del", fmtaddr(htonl(ip), 0), prefixlen);
334
335 if (netlink_send(&req.nh) < 0)
336 LOG(0, 0, 0, "grp_routeset() error in sending netlink message: %s\n", strerror(errno));
337
338 #ifdef BGP
339 if (add)
340 bgp_add_route(htonl(ip), prefixlen);
341 else
342 bgp_del_route(htonl(ip), prefixlen);
343 #endif /* BGP */
344
345 // Add/Remove the IPs to the 'groupbyip' cache.
346 // Note that we add the zero address in the case of
347 // a network route. Roll on CIDR.
348
349 // Note that 'g == 0' implies this is the address pool.
350 // We still cache it here, because it will pre-fill
351 // the malloc'ed tree.
352 if (g)
353 {
354 if (!add) // Are we deleting a route?
355 g = 0; // Caching the session as '0' is the same as uncaching.
356
357 for (i = ip; i < ip+(1<<(32-prefixlen)) ; ++i)
358 {
359 grp_cache_ipmap(i, g);
360 if (!g) cache_ipmap(i, 0);
361 }
362 }
363 }
364
365 // Set all route of a group
366 void grp_setgrouproute(groupidt g, int add)
367 {
368 int i;
369 for (i = 0; i < grpsession[g].nbroutesgrp; i++)
370 {
371 if (grpsession[g].route[i].ip != 0)
372 {
373 grp_routeset(g, grpsession[g].route[i].ip, grpsession[g].route[i].prefixlen, add);
374 }
375 }
376 }
377
378 // return group id by session
379 groupidt grp_groupbysession(sessionidt s)
380 {
381 groupidt g = 0;
382 int i;
383 for (g = gnextgrpid; g != 0; g = grpsession[g].prev)
384 {
385 for (i = 0; i < grpsession[g].nbsession; i++)
386 {
387 if (grpsession[g].sesslist[i].sid == s)
388 { // session found in group
389 return g;
390 }
391 }
392 }
393
394 return 0;
395 }
396
397 // Remove a session to a group
398 // return 1 if OK
399 void grp_removesession(groupidt g, sessionidt s)
400 {
401 int i;
402
403 if (grpsession[g].nbsession <= 0)
404 return;
405
406 for (i = 0; i < grpsession[g].nbsession; i++)
407 {
408 if (grpsession[g].sesslist[i].sid == s)
409 { // session found on group
410 --grpsession[g].nbsession;
411 if (grpsession[g].nbsession == 0)
412 {
413 // Group is empty, remove it
414
415 // Del all routes
416 grp_setgrouproute(g, 0);
417 grp_setgrouproute6(g, 0);
418
419 if (gnextgrpid == g)
420 {
421 gnextgrpid = grpsession[g].prev;
422 }
423 else
424 {
425 groupidt g2;
426 for (g2 = gnextgrpid; g2 != 0; g2 = grpsession[g2].prev)
427 {
428 if (grpsession[g2].prev == g)
429 {
430 grpsession[g2].prev = grpsession[g].prev;
431 break;
432 }
433 }
434 }
435
436 memset(&grpsession[g], 0, sizeof(grpsession[0]));
437 grpsession[g].state = GROUPEFREE;
438 }
439 else
440 {
441 // remove the session
442 memmove(&grpsession[g].sesslist[i],
443 &grpsession[g].sesslist[i+1],
444 (grpsession[g].nbsession - i) * sizeof(grpsession[g].sesslist[i]));
445 }
446
447 cluster_send_groupe(g);
448 return;
449 }
450 }
451 }
452
453 // Add a session to a group
454 // return 1 if OK
455 static int grp_addsession(groupidt g, sessionidt s, uint8_t weight)
456 {
457 int i;
458
459 for (i = 0; i < grpsession[g].nbsession; i++)
460 {
461 if (grpsession[g].sesslist[i].sid == s)
462 { // already in group
463 if ((!grpsession[g].sesslist[i].weight) || (weight > 1))
464 grpsession[g].sesslist[i].weight = weight; // update Weight session (for load-balancing)
465
466 return 1;
467 }
468 }
469
470 if (i >= MAXSESSINGRP)
471 {
472 LOG(1, s, session[s].tunnel, " Too many session for Group %d\n", g);
473 return 0;
474 }
475 else
476 { // add session id to group
477 if (i == 0)
478 {
479 // it's the first session of the group, set to next group
480 grpsession[g].prev = gnextgrpid;
481 gnextgrpid = g;
482 grpsession[g].state = GROUPEOPEN;
483 }
484 grpsession[g].sesslist[i].sid = s;
485 grpsession[g].sesslist[i].weight = weight;
486 grpsession[g].nbsession++;
487
488 return 1;
489 }
490 return 0;
491 }
492
493 // Add a route to a group
494 // return 1 if OK
495 static int grp_addroute(groupidt g, sessionidt s, in_addr_t ip, int prefixlen)
496 {
497 int i;
498
499 for (i = 0; i < MAXROUTEINGRP; i++)
500 {
501 if ((i >= grpsession[g].nbroutesgrp))
502 {
503 LOG(3, s, session[s].tunnel, " Radius reply Group %d contains route for %s/%d\n",
504 g, fmtaddr(htonl(ip), 0), prefixlen);
505
506 grpsession[g].route[i].ip = ip;
507 grpsession[g].route[i].prefixlen = prefixlen;
508 grpsession[g].nbroutesgrp++;
509 return 1;
510 }
511 else if ((grpsession[g].route[i].ip == ip) && (grpsession[g].route[i].prefixlen == prefixlen))
512 {
513 // route already defined in group
514 LOG(3, s, session[s].tunnel,
515 " Radius reply Group %d contains route for %s/%d (this already defined)\n",
516 g, fmtaddr(htonl(ip), 0), prefixlen);
517
518 return 1;
519 }
520 else if (grpsession[g].route[i].ip == 0)
521 {
522 LOG(3, s, session[s].tunnel, " Radius reply Group %d contains route for %s/%d (find empty on list!!!)\n",
523 g, fmtaddr(htonl(ip), 0), prefixlen);
524
525 grpsession[g].route[i].ip = ip;
526 grpsession[g].route[i].prefixlen = prefixlen;
527 return 1;
528 }
529 }
530
531 if (i >= MAXROUTEINGRP)
532 {
533 LOG(1, s, session[s].tunnel, " Too many routes for Group %d\n", g);
534 }
535 return 0;
536 }
537
538 // Add a route to a group
539 // return 1 if OK
540 static int grp_addroute6(groupidt g, sessionidt s, struct in6_addr ip6, int prefixlen)
541 {
542 int i;
543 char ipv6addr[INET6_ADDRSTRLEN];
544
545 for (i = 0; i < MAXROUTE6INGRP; i++)
546 {
547 if ((i >= grpsession[g].nbroutes6grp))
548 {
549 LOG(3, s, session[s].tunnel, " Radius reply Group %d contains route for %s/%d\n",
550 g, inet_ntop(AF_INET6, &ip6, ipv6addr, INET6_ADDRSTRLEN), prefixlen);
551
552 grpsession[g].route6[i].ipv6route = ip6;
553 grpsession[g].route6[i].ipv6prefixlen = prefixlen;
554 grpsession[g].nbroutes6grp++;
555 return 1;
556 }
557 else if (!memcmp(&grpsession[g].route6[i].ipv6route, &ip6, sizeof(ip6)) && (grpsession[g].route6[i].ipv6prefixlen == prefixlen))
558 {
559 // route already defined in group
560 LOG(3, s, session[s].tunnel,
561 " Radius reply Group %d contains route for %s/%d (this already defined)\n",
562 g, inet_ntop(AF_INET6, &ip6, ipv6addr, INET6_ADDRSTRLEN), prefixlen);
563
564 return 1;
565 }
566 else if (grpsession[g].route6[i].ipv6prefixlen == 0)
567 {
568 LOG(3, s, session[s].tunnel, " Radius reply Group %d contains route for %s/%d (find empty on list!!!)\n",
569 g, inet_ntop(AF_INET6, &ip6, ipv6addr, INET6_ADDRSTRLEN), prefixlen);
570
571 grpsession[g].route6[i].ipv6route = ip6;
572 grpsession[g].route6[i].ipv6prefixlen = prefixlen;
573 return 1;
574 }
575 }
576
577 if (i >= MAXROUTE6INGRP)
578 {
579 LOG(1, s, session[s].tunnel, " Too many IPv6 routes for Group %d\n", g);
580 }
581 return 0;
582 }
583
584 // Process Sames vendor specific attribut radius
585 void grp_processvendorspecific(sessionidt s, uint8_t *pvs)
586 {
587 uint8_t attrib = *pvs;
588 groupidt grpid = 0;
589 uint8_t *n = pvs + 2;
590 uint8_t *e = pvs + pvs[1];
591
592 if ((attrib >= 22) && (attrib <= 24))
593 {
594 while (n < e && isdigit(*n))
595 {
596 grpid = grpid * 10 + *n - '0';
597 n++;
598 }
599 if ((grpid == 0) || (grpid >= MAXGROUPE))
600 {
601 LOG(1, s, session[s].tunnel, " Group Attribute Id %d not allowed\n", grpid);
602 return;
603 }
604 else if (*n != ',')
605 {
606 LOG(1, s, session[s].tunnel, " Group Attribute Id not defined\n");
607 return;
608 }
609
610 if (!grp_addsession(grpid, s, 1))
611 {
612 return;
613 }
614
615 if (grpid > config->cluster_highest_groupeid)
616 config->cluster_highest_groupeid = grpid;
617
618 n++;
619 }
620
621 //process, Sames vendor-specific 64520
622 if (attrib == 22) //SAMES-Group-Framed-Route
623 {
624 in_addr_t ip = 0;
625 uint8_t u = 0;
626 uint8_t bits = 0;
627
628 while (n < e && (isdigit(*n) || *n == '.'))
629 {
630 if (*n == '.')
631 {
632 ip = (ip << 8) + u;
633 u = 0;
634 }
635 else
636 u = u * 10 + *n - '0';
637 n++;
638 }
639 ip = (ip << 8) + u;
640 if (*n == '/')
641 {
642 n++;
643 while (n < e && isdigit(*n))
644 bits = bits * 10 + *n++ - '0';
645 }
646 else if ((ip >> 24) < 128)
647 bits = 8;
648 else if ((ip >> 24) < 192)
649 bits = 16;
650 else
651 bits = 24;
652
653 if (!grp_addroute(grpid, s, ip, bits))
654 return;
655 }
656 else if (attrib == 24)
657 {
658 struct in6_addr r6;
659 int prefixlen;
660 uint8_t *m = memchr(n, '/', e - n);
661
662 *m++ = 0;
663 inet_pton(AF_INET6, (char *) n, &r6);
664
665 prefixlen = 0;
666 while (m < e && isdigit(*m)) {
667 prefixlen = prefixlen * 10 + *m++ - '0';
668 }
669
670 if (prefixlen)
671 {
672 if (!grp_addroute6(grpid, s, r6, prefixlen))
673 return;
674 }
675 }
676 else if (attrib == 23) //SAMES-Group-Session-Weight
677 {
678 uint8_t weight = 0;
679
680 while (n < e && isdigit(*n))
681 weight = weight * 10 + *n++ - '0';
682
683 if (!weight)
684 {
685 LOG(1, s, session[s].tunnel, " Group-Session-Weight 0 GroupId %d not allowed\n", grpid);
686 return;
687 }
688 if (!grp_addsession(grpid, s, weight))
689 {
690 return;
691 }
692 }
693 else
694 {
695 LOG(3, s, session[s].tunnel, " Unknown vendor-specific: 64520, Attrib: %d\n", attrib);
696 }
697 }
698
699 // Init data structures
700 void grp_initdata()
701 {
702 int i;
703
704 // Set default value (10s)
705 config->grp_txrate_average_time = 10;
706
707 if (!(grpsession = shared_malloc(sizeof(groupsesst) * MAXGROUPE)))
708 {
709 LOG(0, 0, 0, "Error doing malloc for grouped session: %s\n", strerror(errno));
710 exit(1);
711 }
712
713 memset(grpsession, 0, sizeof(grpsession[0]) * MAXGROUPE);
714 for (i = 1; i < MAXGROUPE; i++)
715 {
716 grpsession[i].state = GROUPEUNDEF;
717 }
718
719 if (!(grp_local = shared_malloc(sizeof(local_group) * MAXGROUPE)))
720 {
721 LOG(0, 0, 0, "Error doing malloc for grp_local: %s\n", strerror(errno));
722 exit(1);
723 }
724 memset(grp_local, 0, sizeof(grp_local[0]) * MAXGROUPE);
725
726 }
727
728 // Update time_changed of the group
729 void grp_time_changed()
730 {
731 groupidt g;
732
733 for (g = gnextgrpid; g != 0; g = grpsession[g].prev)
734 {
735 grpsession[g].time_changed++;
736 }
737 }
738
739 // Uncache all IP of a session
740 //~ static void grp_uncache_ipsession(groupidt g, sessionidt s)
741 //~ {
742 //~ int i;
743 //~ uint8_t *a;
744 //~ in_addr_t ip;
745 //~ in_addr_t n_ip, j;
746 //~ int prefixlen;
747 //~ union iphash *h;
748 //~
749 //~ for (i = 0; i < grpsession[g].nbroutesgrp; i++)
750 //~ {
751 //~ if (grpsession[g].route[i].ip != 0)
752 //~ {
753 //~ prefixlen = grpsession[g].route[i].prefixlen;
754 //~ ip = grpsession[g].route[i].ip & (0xffffffff << (32 - prefixlen)); // Force the ip to be the first one in the route.
755 //~
756 //~ for (j = ip; j < ip+(1<<(32-prefixlen)) ; ++j)
757 //~ {
758 //~ n_ip = htonl(j); // To network order
759 //~ a = (uint8_t *) &n_ip;
760 //~ h = ip_hash;
761 //~
762 //~ if (!(h = h[*a++].idx)) continue;
763 //~ if (!(h = h[*a++].idx)) continue;
764 //~ if (!(h = h[*a++].idx)) continue;
765 //~
766 //~ if (s == h[*a].sess)
767 //~ {
768 //~ h[*a].sess = 0;
769 //~ //LOG(3, s, session[s].tunnel, "UnCaching ip address %s\n", fmtaddr(n_ip, 0));
770 //~ }
771 //~ }
772 //~ }
773 //~ }
774 //~ }
775
776 uint16_t guint16_index_loadlist;
777 // return the next session can be used on the group
778 sessionidt grp_getnextsession(groupidt g, void *p_ip, void *p_ip_src, int is_ipv6)
779 {
780 in_addr_t *p_ipv4 = p_ip;
781 in_addr_t *p_ipv4_src = p_ip_src;
782 struct in6_addr *p_ipv6 = p_ip;
783 struct in6_addr *p_ipv6_src = p_ip_src;
784 sessionidt s = 0, s2 = 0, s3 = 0;
785 int i;
786 uint32_t ltime_changed = 0, mintxrate = 0xFFFFFFFF, maxtxrate = 0;
787 uint32_t txrate = 0;
788
789 if (g >= MAXGROUPE)
790 return 0;
791
792 if (grpsession[g].time_changed >= config->grp_txrate_average_time)
793 {
794 // recalculation txrate
795 ltime_changed = grpsession[g].time_changed;
796 grpsession[g].time_changed = 0;
797 for (i = 0; i < grpsession[g].nbsession; i++)
798 {
799 if ((s2 = grpsession[g].sesslist[i].sid))
800 {
801 uint32_t coutgrp_delta = 0;
802
803 if (session[s2].cout >= grpsession[g].sesslist[i].prev_coutgrp)
804 coutgrp_delta = session[s2].cout - grpsession[g].sesslist[i].prev_coutgrp;
805 grpsession[g].sesslist[i].prev_coutgrp = session[s2].cout;
806
807 txrate = (txrate + (coutgrp_delta/ltime_changed)) >> 1;
808 grpsession[g].sesslist[i].tx_rate = txrate;
809
810 txrate = grpsession[g].sesslist[i].tx_rate/grpsession[g].sesslist[i].weight;
811 if (txrate < mintxrate)
812 {
813 if ( session[s2].ppp.phase > Establish &&
814 (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
815 {
816 grpsession[g].smin = s2;
817 mintxrate = txrate;
818 }
819 }
820
821 if (txrate > maxtxrate)
822 {
823 if ( session[s2].ppp.phase > Establish &&
824 (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
825 {
826 grpsession[g].smax = s2;
827 maxtxrate = txrate;
828 }
829 }
830 }
831 }
832 }
833
834 if (!is_ipv6)
835 s = sessionbyip(*p_ipv4);
836
837 if (s || is_ipv6)
838 {
839 uint8_t *as;
840 uint8_t *ad;
841 uint16_t ai;
842
843 if (is_ipv6)
844 {
845 as = (uint8_t *) &p_ipv6_src[12];
846 ad = (uint8_t *) &p_ipv6[12];
847 }
848 else
849 {
850 as = (uint8_t *) p_ipv4_src;
851 ad = (uint8_t *) p_ipv4;
852 }
853
854 ai = ad[3];
855 ai <<= 8;
856 ai |= as[3];
857
858 s = grp_local[g].sid_loaddist[ai];
859 if (!s)
860 {
861 s = grpsession[g].smin;
862 grp_local[g].sid_loaddist[ai] = s;
863 }
864
865 if (g != grp_groupbysession(s))
866 {
867 // This session does not belong to this group
868 LOG(3, s, session[s].tunnel, "Warning, the session does not belong to group %d\n", g);
869 s = 0;
870 grp_local[g].sid_loaddist[ai] = 0;
871 }
872 else if ( (session[s].ppp.phase > Establish) &&
873 (time_now - session[s].last_packet <= (config->echo_timeout + 1)) )
874 {
875 grp_local[g].sid_loaddist[guint16_index_loadlist++] = 0;
876 return s;
877 }
878 else
879 {
880 s = 0;
881 grp_local[g].sid_loaddist[ai] = 0;
882 }
883 }
884
885 if (!s)
886 {
887 // random between 0 and nbsession-1
888 uint indexsess = (rand() % grpsession[g].nbsession);
889
890 if (indexsess >= grpsession[g].nbsession)
891 indexsess = 0; //Sanity checks.
892
893 s2 = grpsession[g].sesslist[indexsess].sid;
894 if (s2 &&
895 (session[s2].ppp.phase > Establish) &&
896 (time_now - session[s2].last_packet <= (config->echo_timeout + 1)))
897 {
898 s = s2;
899 }
900 else
901 {
902 for (i = 0; i < grpsession[g].nbsession; i++)
903 {
904 if ((s2 = grpsession[g].sesslist[i].sid))
905 {
906 s3 = s2;
907
908 if ( session[s2].ppp.phase > Establish &&
909 (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
910 {
911 s = s2;
912 break;
913 }
914 }
915 }
916 }
917 }
918
919 if (!s)
920 s = s3;
921
922 if (s && !is_ipv6)
923 {
924 cache_ipmap(ntohl(*p_ipv4), s);
925 }
926
927 return s;
928 }
929
930 // load a groupe receive from master
931 int grp_cluster_load_groupe(groupidt g, groupsesst *new)
932 {
933 int i;
934 int updategroup = 0;
935
936 if (g >= MAXGROUPE)
937 {
938 LOG(0, 0, 0, "ERROR: Received a group id > MAXGROUPE!\n");
939 return 0;
940 }
941
942 if ((grpsession[g].nbroutesgrp != new->nbroutesgrp) ||
943 (grpsession[g].nbroutes6grp != new->nbroutes6grp) ||
944 (grpsession[g].nbsession != new->nbsession))
945 {
946 updategroup = 1;
947 }
948
949 if (!updategroup)
950 {
951 // Check session list
952 for (i = 0; i < grpsession[g].nbsession; i++)
953 {
954 if (grpsession[g].sesslist[i].sid != new->sesslist[i].sid)
955 {
956 updategroup = 1;
957 break;
958 }
959 }
960 }
961
962 if (!updategroup)
963 {
964 // Check routes list
965 for (i = 0; i < grpsession[g].nbroutesgrp; i++)
966 {
967 if (grpsession[g].route[i].ip != new->route[i].ip)
968 {
969 updategroup = 1;
970 break;
971 }
972 }
973 }
974
975 if (!updategroup)
976 {
977 // Check IPv6 routes list
978 for (i = 0; i < grpsession[g].nbroutes6grp; i++)
979 {
980 if ((grpsession[g].route6[i].ipv6prefixlen != new->route6[i].ipv6prefixlen) ||
981 memcmp(&grpsession[g].route6[i].ipv6route, &new->route6[i].ipv6route, sizeof(new->route6[i].ipv6route)))
982 {
983 updategroup = 1;
984 break;
985 }
986 }
987 }
988
989 if (grpsession[g].ipv6cp_opened != new->ipv6cp_opened)
990 {
991 updategroup = 1;
992 }
993
994 // needs update
995 if (updategroup)
996 {
997 // Del all routes
998 grp_setgrouproute(g, 0);
999 grp_setgrouproute6(g, 0);
1000 }
1001
1002 memcpy(&grpsession[g], new, sizeof(grpsession[g])); // Copy over..
1003
1004 // needs update
1005 if (updategroup)
1006 {
1007 // Add all routes
1008 grp_setgrouproute(g, 1);
1009 grp_setgrouproute6(g, 1);
1010 }
1011
1012 return 1;
1013 }