Merge from Master 2.2.1-2sames3.14
authorfendo <fendo@bi12info.com>
Sun, 14 Sep 2014 17:00:57 +0000 (19:00 +0200)
committerfendo <fendo@bi12info.com>
Sun, 14 Sep 2014 17:00:57 +0000 (19:00 +0200)
27 files changed:
1  2 
Makefile
arp.c
autosnoop.c
autothrottle.c
bgp.c
cli.c
cluster.c
cluster.h
control.c
debian/changelog
garden.c
grpsess.c
icmp.c
l2tplac.c
l2tpns.c
l2tpns.h
nsctl.c
ppp.c
pppoe.c
radius.c
sessionctl.c
setrxspeed.c
snoopctl.c
stripdomain.c
tbf.c
throttlectl.c
util.c

diff --cc Makefile
+++ b/Makefile
@@@ -26,7 -26,7 +26,7 @@@ INSTALL = install -c -D -o root -g roo
  l2tpns.LIBS = -lcli -ldl
  
  OBJS = arp.o cli.o cluster.o constants.o control.o icmp.o l2tpns.o \
-     ll.o md5.o ppp.o radius.o tbf.o util.o pppoe.o l2tplac.o grpsess.o
 -    ll.o md5.o ppp.o radius.o tbf.o util.o pppoe.o l2tplac.o dhcp6.o ipv6_u.o
++    ll.o md5.o ppp.o radius.o tbf.o util.o pppoe.o l2tplac.o grpsess.o dhcp6.o ipv6_u.o
  
  PROGRAMS = l2tpns nsctl
  PLUGINS = autosnoop.so autothrottle.so garden.so sessionctl.so \
@@@ -108,32 -108,35 +108,36 @@@ install: al
  .PHONY: all clean depend install
  
  ## Dependencies: (autogenerated) ##
- arp.o: arp.c l2tpns.h
- cli.o: cli.c l2tpns.h constants.h util.h cluster.h tbf.h ll.h bgp.h \
-  l2tplac.h
- cluster.o: cluster.c l2tpns.h cluster.h util.h tbf.h pppoe.h bgp.h
+ arp.o: arp.c dhcp6.h l2tpns.h
+ cli.o: cli.c dhcp6.h l2tpns.h constants.h util.h cluster.h tbf.h ll.h \
+  bgp.h l2tplac.h
+ cluster.o: cluster.c dhcp6.h l2tpns.h cluster.h util.h tbf.h pppoe.h \
+  bgp.h
  constants.o: constants.c constants.h
- control.o: control.c l2tpns.h control.h
- icmp.o: icmp.c l2tpns.h pppoe.h
- l2tpns.o: l2tpns.c md5.h l2tpns.h cluster.h plugin.h ll.h constants.h \
-  control.h util.h tbf.h bgp.h l2tplac.h pppoe.h
+ control.o: control.c dhcp6.h l2tpns.h control.h
+ icmp.o: icmp.c dhcp6.h l2tpns.h ipv6_u.h
+ l2tpns.o: l2tpns.c md5.h dhcp6.h l2tpns.h cluster.h plugin.h ll.h \
+  constants.h control.h util.h tbf.h bgp.h l2tplac.h pppoe.h
  ll.o: ll.c ll.h
  md5.o: md5.c md5.h
- ppp.o: ppp.c l2tpns.h constants.h plugin.h util.h tbf.h cluster.h \
+ ppp.o: ppp.c dhcp6.h l2tpns.h constants.h plugin.h util.h tbf.h cluster.h \
   l2tplac.h pppoe.h
- radius.o: radius.c md5.h constants.h l2tpns.h plugin.h util.h cluster.h \
-  l2tplac.h pppoe.h
- tbf.o: tbf.c l2tpns.h util.h tbf.h
- util.o: util.c l2tpns.h bgp.h
- pppoe.o: pppoe.c l2tpns.h cluster.h constants.h md5.h util.h
- l2tplac.o: l2tplac.c md5.h l2tpns.h util.h cluster.h l2tplac.h pppoe.h
+ radius.o: radius.c md5.h constants.h dhcp6.h l2tpns.h plugin.h util.h \
+  cluster.h l2tplac.h pppoe.h
+ tbf.o: tbf.c dhcp6.h l2tpns.h util.h tbf.h
+ util.o: util.c dhcp6.h l2tpns.h bgp.h
+ pppoe.o: pppoe.c dhcp6.h l2tpns.h cluster.h constants.h md5.h util.h
+ l2tplac.o: l2tplac.c md5.h dhcp6.h l2tpns.h util.h cluster.h l2tplac.h \
+  pppoe.h
 +grpsess.o: grpsess.c l2tpns.h util.h cluster.h bgp.h
- bgp.o: bgp.c l2tpns.h bgp.h util.h
- autosnoop.so: autosnoop.c l2tpns.h plugin.h
- autothrottle.so: autothrottle.c l2tpns.h plugin.h
- garden.so: garden.c l2tpns.h plugin.h control.h
- sessionctl.so: sessionctl.c l2tpns.h plugin.h control.h
- setrxspeed.so: setrxspeed.c l2tpns.h plugin.h
- snoopctl.so: snoopctl.c l2tpns.h plugin.h control.h
- stripdomain.so: stripdomain.c l2tpns.h plugin.h
- throttlectl.so: throttlectl.c l2tpns.h plugin.h control.h
+ dhcp6.o: dhcp6.c dhcp6.h l2tpns.h ipv6_u.h
+ ipv6_u.o: ipv6_u.c ipv6_u.h
+ bgp.o: bgp.c dhcp6.h l2tpns.h bgp.h util.h
+ autosnoop.so: autosnoop.c dhcp6.h l2tpns.h plugin.h
+ autothrottle.so: autothrottle.c dhcp6.h l2tpns.h plugin.h
+ garden.so: garden.c dhcp6.h l2tpns.h plugin.h control.h
+ sessionctl.so: sessionctl.c dhcp6.h l2tpns.h plugin.h control.h
+ setrxspeed.so: setrxspeed.c dhcp6.h l2tpns.h plugin.h
+ snoopctl.so: snoopctl.c dhcp6.h l2tpns.h plugin.h control.h
+ stripdomain.so: stripdomain.c dhcp6.h l2tpns.h plugin.h
+ throttlectl.so: throttlectl.c dhcp6.h l2tpns.h plugin.h control.h
diff --cc arp.c
--- 1/arp.c
--- 2/arp.c
+++ b/arp.c
@@@ -5,9 -5,9 +5,10 @@@
  #include <net/ethernet.h>
  #include <net/if_arp.h>
  #include <linux/if_packet.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
  
+ #include "dhcp6.h"
  #include "l2tpns.h"
  
  /* Most of this code is based on keepalived:vrrp_arp.c */
diff --cc autosnoop.c
@@@ -1,7 -1,6 +1,8 @@@
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
+ #include "dhcp6.h"
 +
  #include "l2tpns.h"
  #include "plugin.h"
  
diff --cc autothrottle.c
@@@ -1,7 -1,6 +1,8 @@@
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
+ #include "dhcp6.h"
 +
  #include "l2tpns.h"
  #include "plugin.h"
  
diff --cc bgp.c
--- 1/bgp.c
--- 2/bgp.c
+++ b/bgp.c
@@@ -20,8 -20,8 +20,9 @@@
  #include <arpa/inet.h>
  #include <netdb.h>
  #include <fcntl.h>
 +#include <linux/rtnetlink.h>
  
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "bgp.h"
  #include "util.h"
diff --cc cli.c
--- 1/cli.c
--- 2/cli.c
+++ b/cli.c
@@@ -21,8 -21,8 +21,9 @@@
  #include <dlfcn.h>
  #include <netdb.h>
  #include <libcli.h>
 +#include <linux/rtnetlink.h>
  
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "constants.h"
  #include "util.h"
diff --cc cluster.c
+++ b/cluster.c
@@@ -16,8 -16,8 +16,9 @@@
  #include <malloc.h>
  #include <errno.h>
  #include <libcli.h>
 +#include <linux/rtnetlink.h>
  
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "cluster.h"
  #include "util.h"
diff --cc cluster.h
+++ b/cluster.h
  #define C_CBUNDLE             18      // Compressed bundle structure.
  #define C_MPPP_FORWARD        19      // MPPP Forwarded packet..
  #define C_PPPOE_FORWARD       20      // PPPOE Forwarded packet..
 +#define C_GROUPE              21      // Groupe structure.
 +#define C_CGROUPE             22      // Compressed groupe structure.
 +
  
- #define HB_VERSION            7       // Protocol version number..
+ #define HB_VERSION            8       // Protocol version number..
  #define HB_MAX_SEQ            (1<<30) // Maximum sequence number. (MUST BE A POWER OF 2!)
  #define HB_HISTORY_SIZE               64      // How many old heartbeats we remember?? (Must be a factor of HB_MAX_SEQ)
  
diff --cc control.c
+++ b/control.c
@@@ -1,9 -1,8 +1,10 @@@
  // L2TPNS: control
  
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
+ #include "dhcp6.h"
 +
  #include "l2tpns.h"
  #include "control.h"
  
@@@ -1,4 -1,23 +1,13 @@@
 -l2tpns (2.2.1-2fdn3.14) unstable; urgency=low
++l2tpns (2.2.1-2sames3.14) unstable; urgency=low
+   * Fix cluster slave; reset to 0, the end of the session when the master version < slave version.
+   * Fix cluster slave; no add the ipv6 route address (/128) if included in the delegated prefix.
 -
 - -- Fernando Alves <fendo@sameswifi.fr>  Fri, 12 Sep 2014 18:21:53 +0200
 -
 -l2tpns (2.2.1-2fdn3.13) unstable; urgency=low
 -
+   * Add DHCPv6 functionality
 -
 - -- Fernando Alves <fendo@sameswifi.fr>  Thu, 11 Sep 2014 16:10:38 +0200
 -
 -l2tpns (2.2.1-2fdn3.12) unstable; urgency=low
 -
+   * Fix: remove old IPV6 routes on master
 - -- Fernando Alves <fendo@sameswifi.fr>  Tue, 10 Dec 2013 23:13:20 +0100
++ -- Fernando Alves <fendo@sameswifi.fr>  Sun, 14 Sep 2014 18:27:09 +0200
 -l2tpns (2.2.1-2fdn3.11) unstable; urgency=low
 +l2tpns (2.2.1-2sames3.12) UNRELEASED; urgency=low
  
    * Fix: throttle ipv6 out.
    * Fix: remove old IPV6 routes on slave
diff --cc garden.c
+++ b/garden.c
@@@ -3,9 -3,8 +3,10 @@@
  #include <stdlib.h>
  #include <sys/wait.h>
  #include <sys/types.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
 +
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "plugin.h"
  #include "control.h"
diff --cc grpsess.c
index d3fae30,0000000..5528453
mode 100644,000000..100644
--- /dev/null
+++ b/grpsess.c
@@@ -1,709 -1,0 +1,711 @@@
 +/*
 + * Fernando ALVES 2013
 + * Grouped session for load balancing and fail-over
 + * GPL licenced
 + */
 +
 +#include <errno.h>
 +#include <ctype.h>
 +#include <string.h>
 +#include <sys/socket.h>
 +#include <linux/rtnetlink.h>
++#include <netinet/ip6.h>
 +
++#include "dhcp6.h"
 +#include "l2tpns.h"
 +#include "util.h"
 +#include "cluster.h"
 +
 +#ifdef BGP
 +#include "bgp.h"
 +#endif
 +
 +union grp_iphash {
 +      groupidt grp;
 +      union grp_iphash *idx;
 +} grp_ip_hash[256];                   // Mapping from IP address to group structures.
 +
 +groupidt gnextgrpid = 0;
 +
 +typedef struct
 +{
 +      sessionidt sid_loaddist[0x10000];
 +}
 +local_group;
 +
 +local_group *grp_local = NULL;                // Array of local_group structures.
 +
 +// Find gruop by IP, < 1 for not found
 +//
 +// Confusingly enough, this 'ip' must be
 +// in _network_ order. This being the common
 +// case when looking it up from IP packet headers.
 +static groupidt grp_lookup_ipmap(in_addr_t ip)
 +{
 +      uint8_t *a = (uint8_t *) &ip;
 +      union grp_iphash *h = grp_ip_hash;
 +
 +      if (!(h = h[*a++].idx)) return 0;
 +      if (!(h = h[*a++].idx)) return 0;
 +      if (!(h = h[*a++].idx)) return 0;
 +
 +      return h[*a].grp;
 +}
 +
 +//
 +// Take an IP address in HOST byte order and
 +// add it to the grouid by IP cache.
 +//
 +// (It's actually cached in network order)
 +//
 +static void grp_cache_ipmap(in_addr_t ip, groupidt g)
 +{
 +      in_addr_t nip = htonl(ip);      // MUST be in network order. I.e. MSB must in be ((char *) (&ip))[0]
 +      uint8_t *a = (uint8_t *) &nip;
 +      union grp_iphash *h = grp_ip_hash;
 +      int i;
 +
 +      for (i = 0; i < 3; i++)
 +      {
 +              if (!(h[a[i]].idx || (h[a[i]].idx = calloc(256, sizeof(union grp_iphash)))))
 +                      return;
 +
 +              h = h[a[i]].idx;
 +      }
 +
 +      h[a[3]].grp = g;
 +
 +      if (g > 0)
 +              LOG(4, 0, 0, "Caching Group:%d ip address %s\n", g, fmtaddr(nip, 0));
 +      else if (g == 0)
 +              LOG(4, 0, 0, "Un-caching Group ip address %s\n", fmtaddr(nip, 0));
 +}
 +
 +groupidt grp_groupbyip(in_addr_t ip)
 +{
 +      groupidt g = grp_lookup_ipmap(ip);
 +
 +      if (g > 0 && g < MAXGROUPE)
 +              return g;
 +
 +      return 0;
 +}
 +
 +// Add a route
 +//
 +// This adds it to the routing table, advertises it
 +// via BGP if enabled, and stuffs it into the
 +// 'groupbyip' cache.
 +//
 +// 'ip' must be in _host_ order.
 +//
 +static void grp_routeset(groupidt g, in_addr_t ip, int prefixlen, int add)
 +{
 +      struct {
 +              struct nlmsghdr nh;
 +              struct rtmsg rt;
 +              char buf[32];
 +      } req;
 +      int i;
 +      in_addr_t n_ip;
 +
 +      if (!prefixlen) prefixlen = 32;
 +
 +      ip &= 0xffffffff << (32 - prefixlen);;  // Force the ip to be the first one in the route.
 +
 +      memset(&req, 0, sizeof(req));
 +
 +      if (add)
 +      {
 +              req.nh.nlmsg_type = RTM_NEWROUTE;
 +              req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE;
 +      }
 +      else
 +      {
 +              req.nh.nlmsg_type = RTM_DELROUTE;
 +              req.nh.nlmsg_flags = NLM_F_REQUEST;
 +      }
 +
 +      req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rt));
 +
 +      req.rt.rtm_family = AF_INET;
 +      req.rt.rtm_dst_len = prefixlen;
 +      req.rt.rtm_table = RT_TABLE_MAIN;
 +      req.rt.rtm_protocol = 42;
 +      req.rt.rtm_scope = RT_SCOPE_LINK;
 +      req.rt.rtm_type = RTN_UNICAST;
 +
 +      netlink_addattr(&req.nh, RTA_OIF, &tunidx, sizeof(int));
 +      n_ip = htonl(ip);
 +      netlink_addattr(&req.nh, RTA_DST, &n_ip, sizeof(n_ip));
 +
 +      LOG(3, 0, 0, "Route (Group) %s %s/%d\n", add ? "add" : "del", fmtaddr(htonl(ip), 0), prefixlen);
 +
 +      if (netlink_send(&req.nh) < 0)
 +              LOG(0, 0, 0, "grp_routeset() error in sending netlink message: %s\n", strerror(errno));
 +
 +#ifdef BGP
 +      if (add)
 +              bgp_add_route(htonl(ip), prefixlen);
 +      else
 +              bgp_del_route(htonl(ip), prefixlen);
 +#endif /* BGP */
 +
 +      // Add/Remove the IPs to the 'groupbyip' cache.
 +      // Note that we add the zero address in the case of
 +      // a network route. Roll on CIDR.
 +
 +      // Note that 'g == 0' implies this is the address pool.
 +      // We still cache it here, because it will pre-fill
 +      // the malloc'ed tree.
 +      if (g)
 +      {
 +              if (!add)       // Are we deleting a route?
 +                      g = 0;  // Caching the session as '0' is the same as uncaching.
 +
 +              for (i = ip; i < ip+(1<<(32-prefixlen)) ; ++i)
 +              {
 +                      grp_cache_ipmap(i, g);
 +                      if (!g) cache_ipmap(i, 0);
 +              }
 +      }
 +}
 +
 +// Set all route of a group
 +void grp_setgrouproute(groupidt g, int add)
 +{
 +      int i;
 +      for (i = 0; i < grpsession[g].nbroutesgrp; i++)
 +      {
 +              if (grpsession[g].route[i].ip != 0)
 +              {
 +                      grp_routeset(g, grpsession[g].route[i].ip, grpsession[g].route[i].prefixlen, add);
 +              }
 +      }
 +}
 +
 +// return group id by session
 +groupidt grp_groupbysession(sessionidt s)
 +{
 +      groupidt g = 0;
 +      int i;
 +      for (g = gnextgrpid; g != 0; g = grpsession[g].prev)
 +      {
 +              for (i = 0; i < grpsession[g].nbsession; i++)
 +              {
 +                      if (grpsession[g].sesslist[i].sid == s)
 +                      {       // session found in group
 +                              return g;
 +                      }
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +// Remove a session to a group
 +// return 1 if OK
 +void grp_removesession(groupidt g, sessionidt s)
 +{
 +      int i;
 +
 +      if (grpsession[g].nbsession <= 0)
 +              return;
 +
 +      for (i = 0; i < grpsession[g].nbsession; i++)
 +      {
 +              if (grpsession[g].sesslist[i].sid == s)
 +              {       // session found on group
 +                      --grpsession[g].nbsession;
 +                      if (grpsession[g].nbsession == 0)
 +                      {
 +                              // Group is empty, remove it
 +
 +                              // Del all routes
 +                              grp_setgrouproute(g, 0);
 +
 +                              if (gnextgrpid == g)
 +                              {
 +                                      gnextgrpid = grpsession[g].prev;
 +                              }
 +                              else
 +                              {
 +                                      groupidt g2;
 +                                      for (g2 = gnextgrpid; g2 != 0; g2 = grpsession[g2].prev)
 +                                      {
 +                                              if (grpsession[g2].prev == g)
 +                                              {
 +                                                      grpsession[g2].prev = grpsession[g].prev;
 +                                                      break;
 +                                              }
 +                                      }
 +                              }
 +
 +                              memset(&grpsession[g], 0, sizeof(grpsession[0]));
 +                              grpsession[g].state = GROUPEFREE;
 +                      }
 +                      else
 +                      {
 +                              // remove the session
 +                              memmove(&grpsession[g].sesslist[i],
 +                                              &grpsession[g].sesslist[i+1],
 +                                              (grpsession[g].nbsession - i) * sizeof(grpsession[g].sesslist[i]));
 +                      }
 +
 +                      cluster_send_groupe(g);
 +                      return;
 +              }
 +      }
 +}
 +
 +// Add a session to a group
 +// return 1 if OK
 +static int grp_addsession(groupidt g, sessionidt s, uint8_t weight)
 +{
 +      int i;
 +
 +      for (i = 0; i < grpsession[g].nbsession; i++)
 +      {
 +              if (grpsession[g].sesslist[i].sid == s)
 +              {       // already in group
 +                      if ((!grpsession[g].sesslist[i].weight) || (weight > 1))
 +                              grpsession[g].sesslist[i].weight = weight; // update Weight session (for load-balancing)
 +
 +                      return 1;
 +              }
 +      }
 +
 +      if (i >= MAXSESSINGRP)
 +      {
 +              LOG(1, s, session[s].tunnel, "   Too many session for Group %d\n", g);
 +              return 0;
 +      }
 +      else
 +      {       // add session id to group
 +              if (i == 0)
 +              {
 +                      // it's the first session of the group, set to next group
 +                      grpsession[g].prev = gnextgrpid;
 +                      gnextgrpid = g;
 +                      grpsession[g].state = GROUPEOPEN;
 +              }
 +              grpsession[g].sesslist[i].sid = s;
 +              grpsession[g].sesslist[i].weight = weight;
 +              grpsession[g].nbsession++;
 +
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +// Add a route to a group
 +// return 1 if OK
 +static int grp_addroute(groupidt g, sessionidt s, in_addr_t ip, int prefixlen)
 +{
 +      int i;
 +
 +      for (i = 0; i < MAXROUTEINGRP; i++)
 +      {
 +              if ((i >= grpsession[g].nbroutesgrp))
 +              {
 +                      LOG(3, s, session[s].tunnel, "   Radius reply Group %d contains route for %s/%d\n",
 +                              g, fmtaddr(htonl(ip), 0), prefixlen);
 +
 +                      grpsession[g].route[i].ip = ip;
 +                      grpsession[g].route[i].prefixlen = prefixlen;
 +                      grpsession[g].nbroutesgrp++;
 +                      return 1;
 +              }
 +              else if ((grpsession[g].route[i].ip == ip) && (grpsession[g].route[i].prefixlen == prefixlen))
 +              {
 +                      // route already defined in group
 +                      LOG(3, s, session[s].tunnel,
 +                              "   Radius reply Group %d contains route for %s/%d (this already defined)\n",
 +                              g, fmtaddr(htonl(ip), 0), prefixlen);
 +
 +                      return 1;
 +              }
 +              else if (grpsession[g].route[i].ip == 0)
 +              {
 +                      LOG(3, s, session[s].tunnel, "   Radius reply Group %d contains route for %s/%d (find empty on list!!!)\n",
 +                              g, fmtaddr(htonl(ip), 0), prefixlen);
 +
 +                      grpsession[g].route[i].ip = ip;
 +                      grpsession[g].route[i].prefixlen = prefixlen;
 +                      return 1;
 +              }
 +      }
 +
 +      if (i >= MAXROUTEINGRP)
 +      {
 +              LOG(1, s, session[s].tunnel, "   Too many routes for Group %d\n", g);
 +      }
 +      return 0;
 +}
 +
 +// Process Sames vendor specific attribut radius
 +void grp_processvendorspecific(sessionidt s, uint8_t *pvs)
 +{
 +      uint8_t attrib = *pvs;
 +      groupidt grpid = 0;
 +      uint8_t *n = pvs + 2;
 +      uint8_t *e = pvs + pvs[1];
 +
 +      if ((attrib >= 22) && (attrib <= 23))
 +      {
 +              while (n < e && isdigit(*n))
 +              {
 +                      grpid = grpid * 10 + *n - '0';
 +                      n++;
 +              }
 +              if ((grpid == 0) || (grpid >= MAXGROUPE))
 +              {
 +                      LOG(1, s, session[s].tunnel, "   Group Attribute Id %d not allowed\n", grpid);
 +                      return;
 +              }
 +              else if (*n != ',')
 +              {
 +                      LOG(1, s, session[s].tunnel, "   Group Attribute Id not defined\n");
 +                      return;
 +              }
 +
 +              if (!grp_addsession(grpid, s, 1))
 +              {
 +                      return;
 +              }
 +
 +              if (grpid > config->cluster_highest_groupeid)
 +                      config->cluster_highest_groupeid = grpid;
 +
 +              n++;
 +      }
 +
 +      //process, Sames vendor-specific 64520
 +      if (attrib == 22) //SAMES-Group-Framed-Route
 +      {
 +              in_addr_t ip = 0;
 +              uint8_t u = 0;
 +              uint8_t bits = 0;
 +
 +              while (n < e && (isdigit(*n) || *n == '.'))
 +              {
 +                      if (*n == '.')
 +                      {
 +                              ip = (ip << 8) + u;
 +                              u = 0;
 +                      }
 +                      else
 +                              u = u * 10 + *n - '0';
 +                      n++;
 +              }
 +              ip = (ip << 8) + u;
 +              if (*n == '/')
 +              {
 +                      n++;
 +                      while (n < e && isdigit(*n))
 +                              bits = bits * 10 + *n++ - '0';
 +              }
 +              else if ((ip >> 24) < 128)
 +                      bits = 8;
 +              else if ((ip >> 24) < 192)
 +                      bits = 16;
 +              else
 +                      bits = 24;
 +
 +              if (!grp_addroute(grpid, s, ip, bits))
 +                      return;
 +      }
 +      else if (attrib == 23) //SAMES-Group-Session-Weight
 +      {
 +              uint8_t weight = 0;
 +
 +              while (n < e && isdigit(*n))
 +                      weight = weight * 10 + *n++ - '0';
 +
 +              if (!weight)
 +              {
 +                      LOG(1, s, session[s].tunnel, "   Group-Session-Weight 0 GroupId %d not allowed\n", grpid);
 +                      return;
 +              }
 +              if (!grp_addsession(grpid, s, weight))
 +              {
 +                      return;
 +              }
 +      }
 +      else
 +      {
 +              LOG(3, s, session[s].tunnel, "   Unknown vendor-specific: 64520, Attrib: %d\n", attrib);
 +      }
 +}
 +
 +// Init data structures
 +void grp_initdata()
 +{
 +      int i;
 +
 +      // Set default value (10s)
 +      config->grp_txrate_average_time = 10;
 +
 +      if (!(grpsession = shared_malloc(sizeof(groupsesst) * MAXGROUPE)))
 +      {
 +              LOG(0, 0, 0, "Error doing malloc for grouped session: %s\n", strerror(errno));
 +              exit(1);
 +      }
 +
 +      memset(grpsession, 0, sizeof(grpsession[0]) * MAXGROUPE);
 +      for (i = 1; i < MAXGROUPE; i++)
 +      {
 +              grpsession[i].state = GROUPEUNDEF;
 +      }
 +
 +      if (!(grp_local = shared_malloc(sizeof(local_group) * MAXGROUPE)))
 +      {
 +              LOG(0, 0, 0, "Error doing malloc for grp_local: %s\n", strerror(errno));
 +              exit(1);
 +      }
 +      memset(grp_local, 0, sizeof(grp_local[0]) * MAXGROUPE);
 +
 +}
 +
 +// Update time_changed of the group
 +void grp_time_changed()
 +{
 +      groupidt g;
 +
 +      for (g = gnextgrpid; g != 0; g = grpsession[g].prev)
 +      {
 +              grpsession[g].time_changed++;
 +      }
 +}
 +
 +// Uncache all IP of a session
 +static void grp_uncache_ipsession(groupidt g, sessionidt s)
 +{
 +      int i;
 +      uint8_t *a;
 +      in_addr_t ip;
 +      in_addr_t n_ip, j;
 +      int prefixlen;
 +      union iphash *h;
 +
 +      for (i = 0; i < grpsession[g].nbroutesgrp; i++)
 +      {
 +              if (grpsession[g].route[i].ip != 0)
 +              {
 +                      prefixlen = grpsession[g].route[i].prefixlen;
 +                      ip = grpsession[g].route[i].ip & (0xffffffff << (32 - prefixlen));      // Force the ip to be the first one in the route.
 +
 +                      for (j = ip; j < ip+(1<<(32-prefixlen)) ; ++j)
 +                      {
 +                              n_ip = htonl(j); // To network order
 +                              a = (uint8_t *) &n_ip;
 +                              h = ip_hash;
 +
 +                              if (!(h = h[*a++].idx)) continue;
 +                              if (!(h = h[*a++].idx)) continue;
 +                              if (!(h = h[*a++].idx)) continue;
 +
 +                              if (s == h[*a].sess)
 +                              {
 +                                      h[*a].sess = 0;
 +                                      //LOG(3, s, session[s].tunnel, "UnCaching ip address %s\n", fmtaddr(n_ip, 0));
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +uint16_t guint16_index_loadlist;
 +// return the next session can be used on the group
 +sessionidt grp_getnextsession(groupidt g, in_addr_t ip, in_addr_t ip_src)
 +{
 +      sessionidt s = 0, s2 = 0, s3 = 0;
 +      int i;
 +      uint32_t ltime_changed = 0, mintxrate = 0xFFFFFFFF, maxtxrate = 0;
 +      uint32_t txrate = 0;
 +
 +      if (g >= MAXGROUPE)
 +              return 0;
 +
 +      if (grpsession[g].time_changed >= config->grp_txrate_average_time)
 +      {
 +              // recalculation txrate
 +              ltime_changed = grpsession[g].time_changed;
 +              grpsession[g].time_changed = 0;
 +              for (i = 0; i < grpsession[g].nbsession; i++)
 +              {
 +                      if ((s2 = grpsession[g].sesslist[i].sid))
 +                      {
 +                              uint32_t coutgrp_delta = 0;
 +
 +                              if (session[s2].cout >= grpsession[g].sesslist[i].prev_coutgrp)
 +                                      coutgrp_delta = session[s2].cout - grpsession[g].sesslist[i].prev_coutgrp;
 +                              grpsession[g].sesslist[i].prev_coutgrp = session[s2].cout;
 +
 +                              txrate = (txrate + (coutgrp_delta/ltime_changed)) >> 1;
 +                              grpsession[g].sesslist[i].tx_rate = txrate;
 +
 +                              txrate = grpsession[g].sesslist[i].tx_rate/grpsession[g].sesslist[i].weight;
 +                              if (txrate < mintxrate)
 +                              {
 +                                      if ( session[s2].ppp.phase > Establish &&
 +                                              (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
 +                                      {
 +                                              grpsession[g].smin = s2;
 +                                              mintxrate = txrate;
 +                                      }
 +                              }
 +
 +                              if (txrate > maxtxrate)
 +                              {
 +                                      if ( session[s2].ppp.phase > Establish &&
 +                                      (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
 +                                      {
 +                                              grpsession[g].smax = s2;
 +                                              maxtxrate = txrate;
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if ((s = sessionbyip(ip)))
 +      {
 +              uint8_t *as = (uint8_t *) &ip_src;
 +              uint8_t *ad = (uint8_t *) &ip;
 +              uint16_t ai = ad[3];
 +              ai <<= 8;
 +              ai |= as[3];
 +
 +              s = grp_local[g].sid_loaddist[ai];
 +              if (!s)
 +              {
 +                      s = grpsession[g].smin;
 +                      grp_local[g].sid_loaddist[ai] = s;
 +              }
 +
 +              if (g != grp_groupbysession(s))
 +              {
 +                      // This session does not belong to this group
 +                      LOG(3, s, session[s].tunnel, "Warning, the session does not belong to group %d\n", g);
 +                      s = 0;
 +                      grp_local[g].sid_loaddist[ai] = 0;
 +              }
 +              else if ( (session[s].ppp.phase > Establish) &&
 +                       (time_now - session[s].last_packet <= (config->echo_timeout + 1)) )
 +              {
 +                      grp_local[g].sid_loaddist[guint16_index_loadlist++] = 0;
 +                      return s;
 +              }
 +              else
 +              {
 +                      s = 0;
 +                      grp_local[g].sid_loaddist[ai] = 0;
 +              }
 +      }
 +
 +      if (!s)
 +      {
 +              // random between 0 and nbsession-1
 +              uint indexsess = (rand() % grpsession[g].nbsession);
 +
 +              if (indexsess >= grpsession[g].nbsession)
 +                      indexsess = 0; //Sanity checks.
 +
 +              s2 = grpsession[g].sesslist[indexsess].sid;
 +              if (s2 &&
 +                      (session[s2].ppp.phase > Establish) &&
 +                      (time_now - session[s2].last_packet <= (config->echo_timeout + 1)))
 +              {
 +                      s = s2;
 +              }
 +              else
 +              {
 +                      for (i = 0; i < grpsession[g].nbsession; i++)
 +                      {
 +                              if ((s2 = grpsession[g].sesslist[i].sid))
 +                              {
 +                                      s3 = s2;
 +
 +                                      if ( session[s2].ppp.phase > Establish &&
 +                                              (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
 +                                      {
 +                                              s = s2;
 +                                              break;
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      if (!s)
 +              s = s3;
 +
 +      if (s)
 +              cache_ipmap(ntohl(ip), s);
 +
 +      return s;
 +}
 +
 +// load a groupe receive from master
 +int grp_cluster_load_groupe(groupidt g, groupsesst *new)
 +{
 +      int i;
 +      int updategroup = 0;
 +
 +      if (g >= MAXGROUPE)
 +      {
 +              LOG(0, 0, 0, "ERROR: Received a group id > MAXGROUPE!\n");
 +              return 0;
 +      }
 +
 +      if ((grpsession[g].nbroutesgrp != new->nbroutesgrp) ||
 +              (grpsession[g].nbsession != new->nbsession))
 +      {
 +              updategroup = 1;
 +      }
 +
 +      if (!updategroup)
 +      {
 +              // Check session list
 +              for (i = 0; i < grpsession[g].nbsession; i++)
 +              {
 +                      if (grpsession[g].sesslist[i].sid != new->sesslist[i].sid)
 +                      {
 +                              updategroup = 1;
 +                              break;
 +                      }
 +              }
 +      }
 +
 +      if (!updategroup)
 +      {
 +              // Check routes list
 +              for (i = 0; i < grpsession[g].nbroutesgrp; i++)
 +              {
 +                      if (grpsession[g].route[i].ip != new->route[i].ip)
 +                      {
 +                              updategroup = 1;
 +                              break;
 +                      }
 +              }
 +      }
 +
 +      // needs update
 +      if (updategroup)
 +      {
 +              // Del all routes
 +              grp_setgrouproute(g, 0);
 +      }
 +
 +      memcpy(&grpsession[g], new, sizeof(grpsession[g]));     // Copy over..
 +
 +      // needs update
 +      if (updategroup)
 +      {
 +              // Add all routes
 +              grp_setgrouproute(g, 1);
 +      }
 +
 +      return 1;
 +}
diff --cc icmp.c
--- 1/icmp.c
--- 2/icmp.c
+++ b/icmp.c
@@@ -4,19 -4,12 +4,13 @@@
  #include <linux/ip.h>
  #include <linux/icmp.h>
  #include <netinet/icmp6.h>
- #include <stdio.h>
- #include <sys/socket.h>
  #include <unistd.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <memory.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
  
+ #include "dhcp6.h"
  #include "l2tpns.h"
- #include "pppoe.h"
+ #include "ipv6_u.h"
  
  static uint16_t _checksum(uint8_t *addr, int count);
  
diff --cc l2tplac.c
+++ b/l2tplac.c
@@@ -7,10 -7,10 +7,11 @@@
  
  #include <errno.h>
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
  
  #include "md5.h"
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "util.h"
  #include "cluster.h"
diff --cc l2tpns.c
Simple merge
diff --cc l2tpns.h
+++ b/l2tpns.h
@@@ -15,7 -15,7 +15,7 @@@
  #include <sys/types.h>
  #include <libcli.h>
  
- #define VERSION       "2.2.1"
 -#define VERSION       "2.2.1-2fdn3.13"
++#define VERSION       "2.2.1-2sames3.14"
  
  // Limits
  #define MAXTUNNEL     500             // could be up to 65535
diff --cc nsctl.c
+++ b/nsctl.c
@@@ -7,9 -7,8 +7,10 @@@
  #include <string.h>
  #include <netdb.h>
  #include <signal.h>
 +#include <sys/socket.h>
 +#include <linux/rtnetlink.h>
  
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "control.h"
  
diff --cc ppp.c
--- 1/ppp.c
--- 2/ppp.c
+++ b/ppp.c
@@@ -5,9 -5,8 +5,10 @@@
  #include <unistd.h>
  #include <errno.h>
  #include <stdlib.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
 +
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "constants.h"
  #include "plugin.h"
diff --cc pppoe.c
+++ b/pppoe.c
@@@ -21,8 -21,8 +21,9 @@@
  #include <netpacket/packet.h>
  #include <arpa/inet.h>
  #include <linux/if_pppox.h>
 +#include <linux/rtnetlink.h>
  
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "cluster.h"
  #include "constants.h"
diff --cc radius.c
Simple merge
diff --cc sessionctl.c
@@@ -1,7 -1,6 +1,8 @@@
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
 +
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "plugin.h"
  #include "control.h"
diff --cc setrxspeed.c
@@@ -1,7 -1,6 +1,8 @@@
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
 +
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "plugin.h"
  
diff --cc snoopctl.c
@@@ -1,7 -1,6 +1,8 @@@
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
 +
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "plugin.h"
  #include "control.h"
diff --cc stripdomain.c
@@@ -1,7 -1,6 +1,8 @@@
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
 +
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "plugin.h"
  
diff --cc tbf.c
--- 1/tbf.c
--- 2/tbf.c
+++ b/tbf.c
@@@ -1,9 -1,8 +1,10 @@@
  // L2TPNS: token bucket filters
  
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
 +
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "util.h"
  #include "tbf.h"
diff --cc throttlectl.c
@@@ -1,7 -1,6 +1,8 @@@
  #include <string.h>
- #include <sys/socket.h>
 +#include <linux/rtnetlink.h>
+ #include <netinet/ip6.h>
 +
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #include "plugin.h"
  #include "control.h"
diff --cc util.c
--- 1/util.c
--- 2/util.c
+++ b/util.c
@@@ -8,8 -8,8 +8,9 @@@
  #include <arpa/inet.h>
  #include <string.h>
  #include <sys/mman.h>
 +#include <linux/rtnetlink.h>
  
+ #include "dhcp6.h"
  #include "l2tpns.h"
  #ifdef BGP
  #include "bgp.h"