3 * Grouped session for load balancing and fail-over
10 #include <sys/socket.h>
11 #include <linux/rtnetlink.h>
12 #include <netinet/ip6.h>
25 union grp_iphash
*idx
;
26 } grp_ip_hash
[256]; // Mapping from IP address to group structures.
28 struct grp_ipv6radix
{
30 struct grp_ipv6radix
*branch
;
31 } grp_ipv6_hash
[16]; // Mapping from IPv6 address to session structures.
33 groupidt gnextgrpid
= 0;
37 sessionidt sid_loaddist
[0x10000];
41 local_group
*grp_local
= NULL
; // Array of local_group structures.
43 // Find gruop by IP, < 1 for not found
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
)
50 uint8_t *a
= (uint8_t *) &ip
;
51 union grp_iphash
*h
= grp_ip_hash
;
53 if (!(h
= h
[*a
++].idx
)) return 0;
54 if (!(h
= h
[*a
++].idx
)) return 0;
55 if (!(h
= h
[*a
++].idx
)) return 0;
61 // Take an IP address in HOST byte order and
62 // add it to the grouid by IP cache.
64 // (It's actually cached in network order)
66 static void grp_cache_ipmap(in_addr_t ip
, groupidt g
)
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
;
73 for (i
= 0; i
< 3; i
++)
75 if (!(h
[a
[i
]].idx
|| (h
[a
[i
]].idx
= calloc(256, sizeof(union grp_iphash
)))))
84 LOG(4, 0, 0, "Caching Group:%d ip address %s\n", g
, fmtaddr(nip
, 0));
86 LOG(4, 0, 0, "Un-caching Group ip address %s\n", fmtaddr(nip
, 0));
89 groupidt
grp_groupbyip(in_addr_t ip
)
91 groupidt g
= grp_lookup_ipmap(ip
);
93 if (g
> 0 && g
< MAXGROUPE
)
99 static void grp_cache_ipv6map(struct in6_addr ip
, int prefixlen
, groupidt g
)
103 struct grp_ipv6radix
*curnode
;
104 char ipv6addr
[INET6_ADDRSTRLEN
];
106 curnode
= &grp_ipv6_hash
[((ip
.s6_addr
[0]) & 0xF0)>>4];
108 niblles
= prefixlen
>> 2;
113 if (curnode
->branch
== NULL
)
115 if (!(curnode
->branch
= calloc(16, sizeof(struct grp_ipv6radix
))))
120 curnode
= &curnode
->branch
[ip
.s6_addr
[i
>>1] & 0x0F];
122 curnode
= &curnode
->branch
[(ip
.s6_addr
[i
>>1] & 0xF0)>>4];
130 LOG(4, 0, 0, "Caching Group:%d ip address %s/%d\n", g
,
131 inet_ntop(AF_INET6
, &ip
, ipv6addr
,
135 LOG(4, 0, 0, "Un-caching Group:%d ip address %s/%d\n", g
,
136 inet_ntop(AF_INET6
, &ip
, ipv6addr
,
141 static void grp_route6set(groupidt g
, struct in6_addr ip
, int prefixlen
, int add
)
149 char ipv6addr
[INET6_ADDRSTRLEN
];
151 if (!config
->ipv6_prefix
.s6_addr
[0])
153 LOG(0, 0, 0, "Asked to set IPv6 route, but IPv6 not setup.\n");
157 memset(&req
, 0, sizeof(req
));
161 req
.nh
.nlmsg_type
= RTM_NEWROUTE
;
162 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_CREATE
| NLM_F_REPLACE
;
166 req
.nh
.nlmsg_type
= RTM_DELROUTE
;
167 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
;
170 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(req
.rt
));
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
;
179 netlink_addattr(&req
.nh
, RTA_OIF
, &tunidx
, sizeof(int));
180 netlink_addattr(&req
.nh
, RTA_DST
, &ip
, sizeof(ip
));
182 netlink_addattr(&req
.nh
, RTA_METRICS
, &metric
, sizeof(metric
));
184 LOG(1, g
, 0, "Route Group %s %s/%d\n",
186 inet_ntop(AF_INET6
, &ip
, ipv6addr
, INET6_ADDRSTRLEN
),
189 if (netlink_send(&req
.nh
) < 0)
190 LOG(0, 0, 0, "grp_route6set() error in sending netlink message: %s\n", strerror(errno
));
194 bgp_add_route6(ip
, prefixlen
);
196 bgp_del_route6(ip
, prefixlen
);
201 if (!add
) // Are we deleting a route?
202 g
= 0; // Caching the session as '0' is the same as uncaching.
204 grp_cache_ipv6map(ip
, prefixlen
, g
);
210 static groupidt
grp_lookup_ipv6map(struct in6_addr ip
)
212 struct grp_ipv6radix
*curnode
;
215 char ipv6addr
[INET6_ADDRSTRLEN
];
217 curnode
= &grp_ipv6_hash
[((ip
.s6_addr
[0]) & 0xF0)>>4];
221 while (g
== 0 && i
< 32 && curnode
->branch
!= NULL
)
224 curnode
= &curnode
->branch
[ip
.s6_addr
[i
>>1] & 0x0F];
226 curnode
= &curnode
->branch
[(ip
.s6_addr
[i
>>1] & 0xF0)>>4];
232 LOG(4, 0, 0, "Looking up Group address %s and got %d\n",
233 inet_ntop(AF_INET6
, &ip
, ipv6addr
,
240 groupidt
grp_groupbyipv6(struct in6_addr ip
)
242 groupidt g
= grp_lookup_ipv6map(ip
);
244 if (g
> 0 && g
< MAXGROUPE
)
250 // Set all route of a group
251 void grp_setgrouproute6(groupidt g
, int add
)
258 for (j
= 0; j
< grpsession
[g
].nbsession
; j
++)
260 if (grpsession
[g
].sesslist
[j
].sid
!= 0)
262 if (session
[grpsession
[g
].sesslist
[j
].sid
].ppp
.ipv6cp
== Opened
)
272 if (ipv6opened
|| !add
)
274 for (i
= 0; i
< grpsession
[g
].nbroutes6grp
; i
++)
276 if (grpsession
[g
].route6
[i
].ipv6prefixlen
!= 0)
278 grpsession
[g
].ipv6cp_opened
= add
;
279 grp_route6set(g
, grpsession
[g
].route6
[i
].ipv6route
, grpsession
[g
].route6
[i
].ipv6prefixlen
, add
);
287 // This adds it to the routing table, advertises it
288 // via BGP if enabled, and stuffs it into the
289 // 'groupbyip' cache.
291 // 'ip' must be in _host_ order.
293 static void grp_routeset(groupidt g
, in_addr_t ip
, int prefixlen
, int add
)
303 if (!prefixlen
) prefixlen
= 32;
305 ip
&= 0xffffffff << (32 - prefixlen
);; // Force the ip to be the first one in the route.
307 memset(&req
, 0, sizeof(req
));
311 req
.nh
.nlmsg_type
= RTM_NEWROUTE
;
312 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_CREATE
| NLM_F_REPLACE
;
316 req
.nh
.nlmsg_type
= RTM_DELROUTE
;
317 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
;
320 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(req
.rt
));
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
;
329 netlink_addattr(&req
.nh
, RTA_OIF
, &tunidx
, sizeof(int));
331 netlink_addattr(&req
.nh
, RTA_DST
, &n_ip
, sizeof(n_ip
));
333 LOG(3, 0, 0, "Route (Group) %s %s/%d\n", add
? "add" : "del", fmtaddr(htonl(ip
), 0), prefixlen
);
335 if (netlink_send(&req
.nh
) < 0)
336 LOG(0, 0, 0, "grp_routeset() error in sending netlink message: %s\n", strerror(errno
));
340 bgp_add_route(htonl(ip
), prefixlen
);
342 bgp_del_route(htonl(ip
), prefixlen
);
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.
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.
354 if (!add
) // Are we deleting a route?
355 g
= 0; // Caching the session as '0' is the same as uncaching.
357 for (i
= ip
; i
< ip
+(1<<(32-prefixlen
)) ; ++i
)
359 grp_cache_ipmap(i
, g
);
360 if (!g
) cache_ipmap(i
, 0);
365 // Set all route of a group
366 void grp_setgrouproute(groupidt g
, int add
)
369 for (i
= 0; i
< grpsession
[g
].nbroutesgrp
; i
++)
371 if (grpsession
[g
].route
[i
].ip
!= 0)
373 grp_routeset(g
, grpsession
[g
].route
[i
].ip
, grpsession
[g
].route
[i
].prefixlen
, add
);
378 // return group id by session
379 groupidt
grp_groupbysession(sessionidt s
)
383 for (g
= gnextgrpid
; g
!= 0; g
= grpsession
[g
].prev
)
385 for (i
= 0; i
< grpsession
[g
].nbsession
; i
++)
387 if (grpsession
[g
].sesslist
[i
].sid
== s
)
388 { // session found in group
397 // Remove a session to a group
399 void grp_removesession(groupidt g
, sessionidt s
)
403 if (grpsession
[g
].nbsession
<= 0)
406 for (i
= 0; i
< grpsession
[g
].nbsession
; i
++)
408 if (grpsession
[g
].sesslist
[i
].sid
== s
)
409 { // session found on group
410 --grpsession
[g
].nbsession
;
411 if (grpsession
[g
].nbsession
== 0)
413 // Group is empty, remove it
416 grp_setgrouproute(g
, 0);
417 grp_setgrouproute6(g
, 0);
421 gnextgrpid
= grpsession
[g
].prev
;
426 for (g2
= gnextgrpid
; g2
!= 0; g2
= grpsession
[g2
].prev
)
428 if (grpsession
[g2
].prev
== g
)
430 grpsession
[g2
].prev
= grpsession
[g
].prev
;
436 memset(&grpsession
[g
], 0, sizeof(grpsession
[0]));
437 grpsession
[g
].state
= GROUPEFREE
;
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
]));
447 cluster_send_groupe(g
);
453 // Add a session to a group
455 static int grp_addsession(groupidt g
, sessionidt s
, uint8_t weight
)
459 for (i
= 0; i
< grpsession
[g
].nbsession
; i
++)
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)
470 if (i
>= MAXSESSINGRP
)
472 LOG(1, s
, session
[s
].tunnel
, " Too many session for Group %d\n", g
);
476 { // add session id to group
479 // it's the first session of the group, set to next group
480 grpsession
[g
].prev
= gnextgrpid
;
482 grpsession
[g
].state
= GROUPEOPEN
;
484 grpsession
[g
].sesslist
[i
].sid
= s
;
485 grpsession
[g
].sesslist
[i
].weight
= weight
;
486 grpsession
[g
].nbsession
++;
493 // Add a route to a group
495 static int grp_addroute(groupidt g
, sessionidt s
, in_addr_t ip
, int prefixlen
)
499 for (i
= 0; i
< MAXROUTEINGRP
; i
++)
501 if ((i
>= grpsession
[g
].nbroutesgrp
))
503 LOG(3, s
, session
[s
].tunnel
, " Radius reply Group %d contains route for %s/%d\n",
504 g
, fmtaddr(htonl(ip
), 0), prefixlen
);
506 grpsession
[g
].route
[i
].ip
= ip
;
507 grpsession
[g
].route
[i
].prefixlen
= prefixlen
;
508 grpsession
[g
].nbroutesgrp
++;
511 else if ((grpsession
[g
].route
[i
].ip
== ip
) && (grpsession
[g
].route
[i
].prefixlen
== prefixlen
))
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
);
520 else if (grpsession
[g
].route
[i
].ip
== 0)
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
);
525 grpsession
[g
].route
[i
].ip
= ip
;
526 grpsession
[g
].route
[i
].prefixlen
= prefixlen
;
531 if (i
>= MAXROUTEINGRP
)
533 LOG(1, s
, session
[s
].tunnel
, " Too many routes for Group %d\n", g
);
538 // Add a route to a group
540 static int grp_addroute6(groupidt g
, sessionidt s
, struct in6_addr ip6
, int prefixlen
)
543 char ipv6addr
[INET6_ADDRSTRLEN
];
545 for (i
= 0; i
< MAXROUTE6INGRP
; i
++)
547 if ((i
>= grpsession
[g
].nbroutes6grp
))
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
);
552 grpsession
[g
].route6
[i
].ipv6route
= ip6
;
553 grpsession
[g
].route6
[i
].ipv6prefixlen
= prefixlen
;
554 grpsession
[g
].nbroutes6grp
++;
557 else if (!memcmp(&grpsession
[g
].route6
[i
].ipv6route
, &ip6
, sizeof(ip6
)) && (grpsession
[g
].route6
[i
].ipv6prefixlen
== prefixlen
))
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
);
566 else if (grpsession
[g
].route6
[i
].ipv6prefixlen
== 0)
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
);
571 grpsession
[g
].route6
[i
].ipv6route
= ip6
;
572 grpsession
[g
].route6
[i
].ipv6prefixlen
= prefixlen
;
577 if (i
>= MAXROUTE6INGRP
)
579 LOG(1, s
, session
[s
].tunnel
, " Too many IPv6 routes for Group %d\n", g
);
584 // Process Sames vendor specific attribut radius
585 void grp_processvendorspecific(sessionidt s
, uint8_t *pvs
)
587 uint8_t attrib
= *pvs
;
589 uint8_t *n
= pvs
+ 2;
590 uint8_t *e
= pvs
+ pvs
[1];
592 if ((attrib
>= 22) && (attrib
<= 24))
594 while (n
< e
&& isdigit(*n
))
596 grpid
= grpid
* 10 + *n
- '0';
599 if ((grpid
== 0) || (grpid
>= MAXGROUPE
))
601 LOG(1, s
, session
[s
].tunnel
, " Group Attribute Id %d not allowed\n", grpid
);
606 LOG(1, s
, session
[s
].tunnel
, " Group Attribute Id not defined\n");
610 if (!grp_addsession(grpid
, s
, 1))
615 if (grpid
> config
->cluster_highest_groupeid
)
616 config
->cluster_highest_groupeid
= grpid
;
621 //process, Sames vendor-specific 64520
622 if (attrib
== 22) //SAMES-Group-Framed-Route
628 while (n
< e
&& (isdigit(*n
) || *n
== '.'))
636 u
= u
* 10 + *n
- '0';
643 while (n
< e
&& isdigit(*n
))
644 bits
= bits
* 10 + *n
++ - '0';
646 else if ((ip
>> 24) < 128)
648 else if ((ip
>> 24) < 192)
653 if (!grp_addroute(grpid
, s
, ip
, bits
))
656 else if (attrib
== 24)
660 uint8_t *m
= memchr(n
, '/', e
- n
);
663 inet_pton(AF_INET6
, (char *) n
, &r6
);
666 while (m
< e
&& isdigit(*m
)) {
667 prefixlen
= prefixlen
* 10 + *m
++ - '0';
672 if (!grp_addroute6(grpid
, s
, r6
, prefixlen
))
676 else if (attrib
== 23) //SAMES-Group-Session-Weight
680 while (n
< e
&& isdigit(*n
))
681 weight
= weight
* 10 + *n
++ - '0';
685 LOG(1, s
, session
[s
].tunnel
, " Group-Session-Weight 0 GroupId %d not allowed\n", grpid
);
688 if (!grp_addsession(grpid
, s
, weight
))
695 LOG(3, s
, session
[s
].tunnel
, " Unknown vendor-specific: 64520, Attrib: %d\n", attrib
);
699 // Init data structures
704 // Set default value (10s)
705 config
->grp_txrate_average_time
= 10;
707 if (!(grpsession
= shared_malloc(sizeof(groupsesst
) * MAXGROUPE
)))
709 LOG(0, 0, 0, "Error doing malloc for grouped session: %s\n", strerror(errno
));
713 memset(grpsession
, 0, sizeof(grpsession
[0]) * MAXGROUPE
);
714 for (i
= 1; i
< MAXGROUPE
; i
++)
716 grpsession
[i
].state
= GROUPEUNDEF
;
719 if (!(grp_local
= shared_malloc(sizeof(local_group
) * MAXGROUPE
)))
721 LOG(0, 0, 0, "Error doing malloc for grp_local: %s\n", strerror(errno
));
724 memset(grp_local
, 0, sizeof(grp_local
[0]) * MAXGROUPE
);
728 // Update time_changed of the group
729 void grp_time_changed()
733 for (g
= gnextgrpid
; g
!= 0; g
= grpsession
[g
].prev
)
735 grpsession
[g
].time_changed
++;
739 // Uncache all IP of a session
740 //~ static void grp_uncache_ipsession(groupidt g, sessionidt s)
745 //~ in_addr_t n_ip, j;
749 //~ for (i = 0; i < grpsession[g].nbroutesgrp; i++)
751 //~ if (grpsession[g].route[i].ip != 0)
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.
756 //~ for (j = ip; j < ip+(1<<(32-prefixlen)) ; ++j)
758 //~ n_ip = htonl(j); // To network order
759 //~ a = (uint8_t *) &n_ip;
762 //~ if (!(h = h[*a++].idx)) continue;
763 //~ if (!(h = h[*a++].idx)) continue;
764 //~ if (!(h = h[*a++].idx)) continue;
766 //~ if (s == h[*a].sess)
769 //~ //LOG(3, s, session[s].tunnel, "UnCaching ip address %s\n", fmtaddr(n_ip, 0));
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
)
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;
786 uint32_t ltime_changed
= 0, mintxrate
= 0xFFFFFFFF, maxtxrate
= 0;
792 if (grpsession
[g
].time_changed
>= config
->grp_txrate_average_time
)
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
++)
799 if ((s2
= grpsession
[g
].sesslist
[i
].sid
))
801 uint32_t coutgrp_delta
= 0;
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
;
807 txrate
= (txrate
+ (coutgrp_delta
/ltime_changed
)) >> 1;
808 grpsession
[g
].sesslist
[i
].tx_rate
= txrate
;
810 txrate
= grpsession
[g
].sesslist
[i
].tx_rate
/grpsession
[g
].sesslist
[i
].weight
;
811 if (txrate
< mintxrate
)
813 if ( session
[s2
].ppp
.phase
> Establish
&&
814 (time_now
- session
[s2
].last_packet
<= (config
->echo_timeout
+ 1)) )
816 grpsession
[g
].smin
= s2
;
821 if (txrate
> maxtxrate
)
823 if ( session
[s2
].ppp
.phase
> Establish
&&
824 (time_now
- session
[s2
].last_packet
<= (config
->echo_timeout
+ 1)) )
826 grpsession
[g
].smax
= s2
;
835 s
= sessionbyip(*p_ipv4
);
845 as
= (uint8_t *) &p_ipv6_src
[12];
846 ad
= (uint8_t *) &p_ipv6
[12];
850 as
= (uint8_t *) p_ipv4_src
;
851 ad
= (uint8_t *) p_ipv4
;
858 s
= grp_local
[g
].sid_loaddist
[ai
];
861 s
= grpsession
[g
].smin
;
862 grp_local
[g
].sid_loaddist
[ai
] = s
;
865 if (g
!= grp_groupbysession(s
))
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
);
870 grp_local
[g
].sid_loaddist
[ai
] = 0;
872 else if ( (session
[s
].ppp
.phase
> Establish
) &&
873 (time_now
- session
[s
].last_packet
<= (config
->echo_timeout
+ 1)) )
875 grp_local
[g
].sid_loaddist
[guint16_index_loadlist
++] = 0;
881 grp_local
[g
].sid_loaddist
[ai
] = 0;
887 // random between 0 and nbsession-1
888 uint indexsess
= (rand() % grpsession
[g
].nbsession
);
890 if (indexsess
>= grpsession
[g
].nbsession
)
891 indexsess
= 0; //Sanity checks.
893 s2
= grpsession
[g
].sesslist
[indexsess
].sid
;
895 (session
[s2
].ppp
.phase
> Establish
) &&
896 (time_now
- session
[s2
].last_packet
<= (config
->echo_timeout
+ 1)))
902 for (i
= 0; i
< grpsession
[g
].nbsession
; i
++)
904 if ((s2
= grpsession
[g
].sesslist
[i
].sid
))
908 if ( session
[s2
].ppp
.phase
> Establish
&&
909 (time_now
- session
[s2
].last_packet
<= (config
->echo_timeout
+ 1)) )
924 cache_ipmap(ntohl(*p_ipv4
), s
);
930 // load a groupe receive from master
931 int grp_cluster_load_groupe(groupidt g
, groupsesst
*new)
938 LOG(0, 0, 0, "ERROR: Received a group id > MAXGROUPE!\n");
942 if ((grpsession
[g
].nbroutesgrp
!= new->nbroutesgrp
) ||
943 (grpsession
[g
].nbroutes6grp
!= new->nbroutes6grp
) ||
944 (grpsession
[g
].nbsession
!= new->nbsession
))
951 // Check session list
952 for (i
= 0; i
< grpsession
[g
].nbsession
; i
++)
954 if (grpsession
[g
].sesslist
[i
].sid
!= new->sesslist
[i
].sid
)
965 for (i
= 0; i
< grpsession
[g
].nbroutesgrp
; i
++)
967 if (grpsession
[g
].route
[i
].ip
!= new->route
[i
].ip
)
977 // Check IPv6 routes list
978 for (i
= 0; i
< grpsession
[g
].nbroutes6grp
; i
++)
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
)))
989 if (grpsession
[g
].ipv6cp_opened
!= new->ipv6cp_opened
)
998 grp_setgrouproute(g
, 0);
999 grp_setgrouproute6(g
, 0);
1002 memcpy(&grpsession
[g
], new, sizeof(grpsession
[g
])); // Copy over..
1008 grp_setgrouproute(g
, 1);
1009 grp_setgrouproute6(g
, 1);