IPv6 load-balancing
authorfendo <fendo@bi12info.com>
Sun, 21 Sep 2014 11:51:32 +0000 (13:51 +0200)
committerfendo <fendo@bi12info.com>
Sun, 21 Sep 2014 11:51:32 +0000 (13:51 +0200)
Makefile
dhcp6.c
dictionary.sames
grpsess.c
l2tpns.c
l2tpns.h
ppp.c

index abab4e0..458b494 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -129,7 +129,7 @@ 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
 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
+grpsess.o: grpsess.c dhcp6.h l2tpns.h util.h cluster.h bgp.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
 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
diff --git a/dhcp6.c b/dhcp6.c
index 171c1f0..710f5c0 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -5,6 +5,7 @@
  */
 
 #include <netinet/icmp6.h>
  */
 
 #include <netinet/icmp6.h>
+#include <linux/rtnetlink.h>
 #include <netinet/ip6.h>
 #include <netinet/udp.h>
 
 #include <netinet/ip6.h>
 #include <netinet/udp.h>
 
index a8a244d..9e34def 100644 (file)
@@ -13,6 +13,7 @@ BEGIN-VENDOR  SAMES
 
 ATTRIBUTE      SAMES-Group-Framed-Route                22      string
 ATTRIBUTE      SAMES-Group-Session-Weight              23      string
 
 ATTRIBUTE      SAMES-Group-Framed-Route                22      string
 ATTRIBUTE      SAMES-Group-Session-Weight              23      string
+ATTRIBUTE      SAMES-Group-Delegated-IPv6-Prefix       24      string
 
 END-VENDOR SAMES
 
 
 END-VENDOR SAMES
 
index 5528453..92adcec 100644 (file)
--- a/grpsess.c
+++ b/grpsess.c
@@ -25,6 +25,11 @@ union grp_iphash {
        union grp_iphash *idx;
 } grp_ip_hash[256];                    // Mapping from IP address to group structures.
 
        union grp_iphash *idx;
 } grp_ip_hash[256];                    // Mapping from IP address to group structures.
 
+struct grp_ipv6radix {
+       groupidt grp;
+       struct grp_ipv6radix *branch;
+} grp_ipv6_hash[16];           // Mapping from IPv6 address to session structures.
+
 groupidt gnextgrpid = 0;
 
 typedef struct
 groupidt gnextgrpid = 0;
 
 typedef struct
@@ -91,6 +96,192 @@ groupidt grp_groupbyip(in_addr_t ip)
        return 0;
 }
 
        return 0;
 }
 
+static void grp_cache_ipv6map(struct in6_addr ip, int prefixlen, groupidt g)
+{
+       int i;
+       int niblles;
+       struct grp_ipv6radix *curnode;
+       char ipv6addr[INET6_ADDRSTRLEN];
+
+       curnode = &grp_ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
+
+       niblles = prefixlen >> 2;
+       i = 1;
+
+       while (i < niblles)
+       {
+               if (curnode->branch == NULL)
+               {
+                       if (!(curnode->branch = calloc(16, sizeof(struct grp_ipv6radix))))
+                               return;
+               }
+
+               if (i & 1)
+                       curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
+               else
+                       curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
+
+               i++;
+       }
+
+       curnode->grp = g;
+
+       if (g > 0)
+               LOG(4, 0, 0, "Caching Group:%d ip address %s/%d\n", g,
+                               inet_ntop(AF_INET6, &ip, ipv6addr,
+                               INET6_ADDRSTRLEN),
+                               prefixlen);
+       else if (g == 0)
+               LOG(4, 0, 0, "Un-caching Group:%d ip address %s/%d\n", g,
+                               inet_ntop(AF_INET6, &ip, ipv6addr,
+                               INET6_ADDRSTRLEN),
+                               prefixlen);
+}
+
+static void grp_route6set(groupidt g, struct in6_addr ip, int prefixlen, int add)
+{
+       struct {
+               struct nlmsghdr nh;
+               struct rtmsg rt;
+               char buf[64];
+       } req;
+       int metric;
+       char ipv6addr[INET6_ADDRSTRLEN];
+
+       if (!config->ipv6_prefix.s6_addr[0])
+       {
+               LOG(0, 0, 0, "Asked to set IPv6 route, but IPv6 not setup.\n");
+               return;
+       }
+
+       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_INET6;
+       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));
+       netlink_addattr(&req.nh, RTA_DST, &ip, sizeof(ip));
+       metric = 1;
+       netlink_addattr(&req.nh, RTA_METRICS, &metric, sizeof(metric));
+
+       LOG(1, g, 0, "Route Group %s %s/%d\n",
+           add ? "add" : "del",
+           inet_ntop(AF_INET6, &ip, ipv6addr, INET6_ADDRSTRLEN),
+           prefixlen);
+
+       if (netlink_send(&req.nh) < 0)
+               LOG(0, 0, 0, "grp_route6set() error in sending netlink message: %s\n", strerror(errno));
+
+#ifdef BGP
+       if (add)
+               bgp_add_route6(ip, prefixlen);
+       else
+               bgp_del_route6(ip, prefixlen);
+#endif /* BGP */
+
+       if (g)
+       {
+               if (!add)       // Are we deleting a route?
+                       g = 0;  // Caching the session as '0' is the same as uncaching.
+
+               grp_cache_ipv6map(ip, prefixlen, g);
+       }
+
+       return;
+}
+
+static groupidt grp_lookup_ipv6map(struct in6_addr ip)
+{
+       struct grp_ipv6radix *curnode;
+       int i;
+       int g;
+       char ipv6addr[INET6_ADDRSTRLEN];
+
+       curnode = &grp_ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
+       i = 1;
+       g = curnode->grp;
+
+       while (g == 0 && i < 32 && curnode->branch != NULL)
+       {
+               if (i & 1)
+                       curnode = &curnode->branch[ip.s6_addr[i>>1] & 0x0F];
+               else
+                       curnode = &curnode->branch[(ip.s6_addr[i>>1] & 0xF0)>>4];
+
+               g = curnode->grp;
+               i++;
+       }
+
+       LOG(4, 0, 0, "Looking up Group address %s and got %d\n",
+                       inet_ntop(AF_INET6, &ip, ipv6addr,
+                       INET6_ADDRSTRLEN),
+                       g);
+
+       return g;
+}
+
+groupidt grp_groupbyipv6(struct in6_addr ip)
+{
+       groupidt g = grp_lookup_ipv6map(ip);
+
+       if (g > 0 && g < MAXGROUPE)
+               return g;
+
+       return 0;
+}
+
+// Set all route of a group
+void grp_setgrouproute6(groupidt g, int add)
+{
+       int i, j;
+       int ipv6opened = 0;
+
+       if (add)
+       {
+               for (j = 0; j < grpsession[g].nbsession; j++)
+               {
+                       if (grpsession[g].sesslist[j].sid != 0)
+                       {
+                               if (session[grpsession[g].sesslist[j].sid].ppp.ipv6cp == Opened)
+                               {
+                                       // IPv6 opened
+                                       ipv6opened = 1;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if (ipv6opened || !add)
+       {
+               for (i = 0; i < grpsession[g].nbroutes6grp; i++)
+               {
+                       if (grpsession[g].route6[i].ipv6prefixlen != 0)
+                       {
+                               grpsession[g].ipv6cp_opened = add;
+                               grp_route6set(g, grpsession[g].route6[i].ipv6route, grpsession[g].route6[i].ipv6prefixlen, add);
+                       }
+               }
+       }
+}
+
 // Add a route
 //
 // This adds it to the routing table, advertises it
 // Add a route
 //
 // This adds it to the routing table, advertises it
@@ -223,6 +414,7 @@ void grp_removesession(groupidt g, sessionidt s)
 
                                // Del all routes
                                grp_setgrouproute(g, 0);
 
                                // Del all routes
                                grp_setgrouproute(g, 0);
+                               grp_setgrouproute6(g, 0);
 
                                if (gnextgrpid == g)
                                {
 
                                if (gnextgrpid == g)
                                {
@@ -343,6 +535,52 @@ static int grp_addroute(groupidt g, sessionidt s, in_addr_t ip, int prefixlen)
        return 0;
 }
 
        return 0;
 }
 
+// Add a route to a group
+// return 1 if OK
+static int grp_addroute6(groupidt g, sessionidt s, struct in6_addr ip6, int prefixlen)
+{
+       int i;
+       char ipv6addr[INET6_ADDRSTRLEN];
+
+       for (i = 0; i < MAXROUTE6INGRP; i++)
+       {
+               if ((i >= grpsession[g].nbroutes6grp))
+               {
+                       LOG(3, s, session[s].tunnel, "   Radius reply Group %d contains route for %s/%d\n",
+                               g, inet_ntop(AF_INET6, &ip6, ipv6addr, INET6_ADDRSTRLEN), prefixlen);
+
+                       grpsession[g].route6[i].ipv6route = ip6;
+                       grpsession[g].route6[i].ipv6prefixlen = prefixlen;
+                       grpsession[g].nbroutes6grp++;
+                       return 1;
+               }
+               else if (!memcmp(&grpsession[g].route6[i].ipv6route, &ip6, sizeof(ip6)) && (grpsession[g].route6[i].ipv6prefixlen == 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, inet_ntop(AF_INET6, &ip6, ipv6addr, INET6_ADDRSTRLEN), prefixlen);
+
+                       return 1;
+               }
+               else if (grpsession[g].route6[i].ipv6prefixlen == 0)
+               {
+                       LOG(3, s, session[s].tunnel, "   Radius reply Group %d contains route for %s/%d (find empty on list!!!)\n",
+                               g, inet_ntop(AF_INET6, &ip6, ipv6addr, INET6_ADDRSTRLEN), prefixlen);
+
+                       grpsession[g].route6[i].ipv6route = ip6;
+                       grpsession[g].route6[i].ipv6prefixlen = prefixlen;
+                       return 1;
+               }
+       }
+
+       if (i >= MAXROUTE6INGRP)
+       {
+               LOG(1, s, session[s].tunnel, "   Too many IPv6 routes for Group %d\n", g);
+       }
+       return 0;
+}
+
 // Process Sames vendor specific attribut radius
 void grp_processvendorspecific(sessionidt s, uint8_t *pvs)
 {
 // Process Sames vendor specific attribut radius
 void grp_processvendorspecific(sessionidt s, uint8_t *pvs)
 {
@@ -351,7 +589,7 @@ void grp_processvendorspecific(sessionidt s, uint8_t *pvs)
        uint8_t *n = pvs + 2;
        uint8_t *e = pvs + pvs[1];
 
        uint8_t *n = pvs + 2;
        uint8_t *e = pvs + pvs[1];
 
-       if ((attrib >= 22) && (attrib <= 23))
+       if ((attrib >= 22) && (attrib <= 24))
        {
                while (n < e && isdigit(*n))
                {
        {
                while (n < e && isdigit(*n))
                {
@@ -415,6 +653,26 @@ void grp_processvendorspecific(sessionidt s, uint8_t *pvs)
                if (!grp_addroute(grpid, s, ip, bits))
                        return;
        }
                if (!grp_addroute(grpid, s, ip, bits))
                        return;
        }
+       else if (attrib == 24)
+       {
+               struct in6_addr r6;
+               int prefixlen;
+               uint8_t *m = memchr(n, '/', e - n);
+
+               *m++ = 0;
+               inet_pton(AF_INET6, (char *) n, &r6);
+
+               prefixlen = 0;
+               while (m < e && isdigit(*m)) {
+                       prefixlen = prefixlen * 10 + *m++ - '0';
+               }
+
+               if (prefixlen)
+               {
+                       if (!grp_addroute6(grpid, s, r6, prefixlen))
+                               return;
+               }
+       }
        else if (attrib == 23) //SAMES-Group-Session-Weight
        {
                uint8_t weight = 0;
        else if (attrib == 23) //SAMES-Group-Session-Weight
        {
                uint8_t weight = 0;
@@ -479,46 +737,50 @@ void grp_time_changed()
 }
 
 // Uncache all IP of a session
 }
 
 // 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));
-                               }
-                       }
-               }
-       }
-}
+//~ 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
 
 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 grp_getnextsession(groupidt g, void *p_ip, void *p_ip_src, int is_ipv6)
 {
 {
+       in_addr_t *p_ipv4 = p_ip;
+       in_addr_t *p_ipv4_src = p_ip_src;
+       struct in6_addr *p_ipv6 = p_ip;
+       struct in6_addr *p_ipv6_src = p_ip_src;
        sessionidt s = 0, s2 = 0, s3 = 0;
        int i;
        uint32_t ltime_changed = 0, mintxrate = 0xFFFFFFFF, maxtxrate = 0;
        sessionidt s = 0, s2 = 0, s3 = 0;
        int i;
        uint32_t ltime_changed = 0, mintxrate = 0xFFFFFFFF, maxtxrate = 0;
@@ -569,11 +831,27 @@ sessionidt grp_getnextsession(groupidt g, in_addr_t ip, in_addr_t ip_src)
                }
        }
 
                }
        }
 
-       if ((s = sessionbyip(ip)))
+       if (!is_ipv6)
+               s = sessionbyip(*p_ipv4);
+
+       if (s || is_ipv6)
        {
        {
-               uint8_t *as = (uint8_t *) &ip_src;
-               uint8_t *ad = (uint8_t *) &ip;
-               uint16_t ai = ad[3];
+               uint8_t *as;
+               uint8_t *ad;
+               uint16_t ai;
+
+               if (is_ipv6)
+               {
+                       as = (uint8_t *) &p_ipv6_src[12];
+                       ad = (uint8_t *) &p_ipv6[12];
+               }
+               else
+               {
+                       as = (uint8_t *) p_ipv4_src;
+                       ad = (uint8_t *) p_ipv4;
+               }
+
+               ai = ad[3];
                ai <<= 8;
                ai |= as[3];
 
                ai <<= 8;
                ai |= as[3];
 
@@ -641,8 +919,10 @@ sessionidt grp_getnextsession(groupidt g, in_addr_t ip, in_addr_t ip_src)
        if (!s)
                s = s3;
 
        if (!s)
                s = s3;
 
-       if (s)
-               cache_ipmap(ntohl(ip), s);
+       if (s && !is_ipv6)
+       {
+               cache_ipmap(ntohl(*p_ipv4), s);
+       }
 
        return s;
 }
 
        return s;
 }
@@ -660,6 +940,7 @@ int grp_cluster_load_groupe(groupidt g, groupsesst *new)
        }
 
        if ((grpsession[g].nbroutesgrp != new->nbroutesgrp) ||
        }
 
        if ((grpsession[g].nbroutesgrp != new->nbroutesgrp) ||
+               (grpsession[g].nbroutes6grp != new->nbroutes6grp) ||
                (grpsession[g].nbsession != new->nbsession))
        {
                updategroup = 1;
                (grpsession[g].nbsession != new->nbsession))
        {
                updategroup = 1;
@@ -691,11 +972,31 @@ int grp_cluster_load_groupe(groupidt g, groupsesst *new)
                }
        }
 
                }
        }
 
+       if (!updategroup)
+       {
+               // Check IPv6 routes list
+               for (i = 0; i < grpsession[g].nbroutes6grp; i++)
+               {
+                       if ((grpsession[g].route6[i].ipv6prefixlen != new->route6[i].ipv6prefixlen) || 
+                           memcmp(&grpsession[g].route6[i].ipv6route, &new->route6[i].ipv6route, sizeof(new->route6[i].ipv6route)))
+                       {
+                               updategroup = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (grpsession[g].ipv6cp_opened != new->ipv6cp_opened)
+       {
+               updategroup = 1;
+       }
+
        // needs update
        if (updategroup)
        {
                // Del all routes
                grp_setgrouproute(g, 0);
        // needs update
        if (updategroup)
        {
                // Del all routes
                grp_setgrouproute(g, 0);
+               grp_setgrouproute6(g, 0);
        }
 
        memcpy(&grpsession[g], new, sizeof(grpsession[g]));     // Copy over..
        }
 
        memcpy(&grpsession[g], new, sizeof(grpsession[g]));     // Copy over..
@@ -705,6 +1006,7 @@ int grp_cluster_load_groupe(groupidt g, groupsesst *new)
        {
                // Add all routes
                grp_setgrouproute(g, 1);
        {
                // Add all routes
                grp_setgrouproute(g, 1);
+               grp_setgrouproute6(g, 1);
        }
 
        return 1;
        }
 
        return 1;
index 5c887ec..5445013 100644 (file)
--- a/l2tpns.c
+++ b/l2tpns.c
@@ -94,7 +94,11 @@ uint16_t MSS = 0;            // TCP MSS
 struct cli_session_actions *cli_session_actions = NULL;        // Pending session changes requested by CLI
 struct cli_tunnel_actions *cli_tunnel_actions = NULL;  // Pending tunnel changes required by CLI
 
 struct cli_session_actions *cli_session_actions = NULL;        // Pending session changes requested by CLI
 struct cli_tunnel_actions *cli_tunnel_actions = NULL;  // Pending tunnel changes required by CLI
 
-union iphash ip_hash[256];     // Mapping from IP address to session structures.
+union iphash
+{
+       sessionidt sess;
+       union iphash *idx;
+}ip_hash[256]; // Mapping from IP address to session structures.
 
 struct ipv6radix {
        sessionidt sess;
 
 struct ipv6radix {
        sessionidt sess;
@@ -979,7 +983,6 @@ static sessionidt lookup_ipv6map(struct in6_addr ip)
        int s;
        char ipv6addr[INET6_ADDRSTRLEN];
 
        int s;
        char ipv6addr[INET6_ADDRSTRLEN];
 
-       curnode = &ipv6_hash[ip.s6_addr[0]];
        curnode = &ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
        i = 1;
        s = curnode->sess;
        curnode = &ipv6_hash[((ip.s6_addr[0]) & 0xF0)>>4];
        i = 1;
        s = curnode->sess;
@@ -1076,7 +1079,6 @@ void cache_ipmap(in_addr_t ip, sessionidt s)
 
        if (s > 0)
                LOG(4, s, session[s].tunnel, "Caching ip address %s\n", fmtaddr(nip, 0));
 
        if (s > 0)
                LOG(4, s, session[s].tunnel, "Caching ip address %s\n", fmtaddr(nip, 0));
-
        else if (s == 0)
                LOG(4, 0, 0, "Un-caching ip address %s\n", fmtaddr(nip, 0));
        // else a map to an ip pool index.
        else if (s == 0)
                LOG(4, 0, 0, "Un-caching ip address %s\n", fmtaddr(nip, 0));
        // else a map to an ip pool index.
@@ -1484,7 +1486,7 @@ void processipout(uint8_t *buf, int len)
        ip = *(uint32_t *)(buf + 16);
        if ((g = grp_groupbyip(ip)))
        {
        ip = *(uint32_t *)(buf + 16);
        if ((g = grp_groupbyip(ip)))
        {
-               s = grp_getnextsession(g, ip, ip_src);
+               s = grp_getnextsession(g, &ip, &ip_src, 0);
                if (!s)
                {
                        // Is this a packet for a session that doesn't exist?
                if (!s)
                {
                        // Is this a packet for a session that doesn't exist?
@@ -1735,9 +1737,11 @@ void processipout(uint8_t *buf, int len)
 static void processipv6out(uint8_t * buf, int len)
 {
        sessionidt s;
 static void processipv6out(uint8_t * buf, int len)
 {
        sessionidt s;
+       groupidt g;
        sessiont *sp;
        tunnelidt t;
        sessiont *sp;
        tunnelidt t;
-       struct in6_addr ip6;
+       struct in6_addr *p_ip6;
+       struct in6_addr *p_ip6_src;
 
        uint8_t *data = buf;    // Keep a copy of the originals.
        int size = len;
 
        uint8_t *data = buf;    // Keep a copy of the originals.
        int size = len;
@@ -1770,12 +1774,16 @@ static void processipv6out(uint8_t * buf, int len)
                return;
        }
 
                return;
        }
 
-       ip6 = *(struct in6_addr *)(buf+24);
-       s = sessionbyipv6(ip6);
+       p_ip6_src = (struct in6_addr *)(buf+8);
+       p_ip6 = (struct in6_addr *)(buf+24);
 
 
-       if (s == 0)
+       if ((g = grp_groupbyipv6(*p_ip6)))
        {
        {
-               s = sessionbyipv6new(ip6);
+               s = grp_getnextsession(g, p_ip6, p_ip6_src, 1);
+       }
+       else if (!(s = sessionbyipv6(*p_ip6)))
+       {
+               s = sessionbyipv6new(*p_ip6);
        }
 
        if (s == 0)
        }
 
        if (s == 0)
@@ -5958,9 +5966,12 @@ int load_session(sessionidt s, sessiont *new)
        }
 
        // check v6 routing
        }
 
        // check v6 routing
-       for (i = 0; i < MAXROUTE6 && new->route6[i].ipv6prefixlen; i++)
+       if (new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
        {
        {
-               route6set(s, new->route6[i].ipv6route, new->route6[i].ipv6prefixlen, 1);
+               for (i = 0; i < MAXROUTE6 && new->route6[i].ipv6prefixlen; i++)
+               {
+                       route6set(s, new->route6[i].ipv6route, new->route6[i].ipv6prefixlen, 1);
+               }
        }
 
        if (new->ipv6address.s6_addr[0] && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
        }
 
        if (new->ipv6address.s6_addr[0] && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened)
index a5a89f4..45428e6 100644 (file)
--- a/l2tpns.h
+++ b/l2tpns.h
@@ -27,6 +27,7 @@
 #define MAXSESSINGRP   12              // Maximum number of member links in grouped session
 #define MAXGROUPE              300     // could be up to 65535, Maximum number of grouped session
 #define MAXROUTEINGRP  15              // max static routes per group
 #define MAXSESSINGRP   12              // Maximum number of member links in grouped session
 #define MAXGROUPE              300     // could be up to 65535, Maximum number of grouped session
 #define MAXROUTEINGRP  15              // max static routes per group
+#define MAXROUTE6INGRP 15              // max static Ipv6 routes per group
 
 // Tunnel Id reserved for pppoe
 #define TUNNEL_ID_PPPOE        1
 
 // Tunnel Id reserved for pppoe
 #define TUNNEL_ID_PPPOE        1
@@ -371,17 +372,14 @@ typedef struct
        sessionidt smin;
        groupsesslistt sesslist[MAXSESSINGRP];
        routet route[MAXROUTEINGRP];            // static routes
        sessionidt smin;
        groupsesslistt sesslist[MAXSESSINGRP];
        routet route[MAXROUTEINGRP];            // static routes
+       routet6 route6[MAXROUTE6INGRP];         // static IPv6 routes
+       uint8_t ipv6cp_opened;
        uint8_t nbroutesgrp;
        uint8_t nbroutesgrp;
+       uint8_t nbroutes6grp;
        uint8_t nbsession;
 }
 groupsesst;
 
        uint8_t nbsession;
 }
 groupsesst;
 
-union iphash
-{
-       sessionidt sess;
-       union iphash *idx;
-};                     // Mapping from IP address to session structures.
-
 typedef struct
 {
         int state;                              // current state (bundlestate enum)
 typedef struct
 {
         int state;                              // current state (bundlestate enum)
@@ -1026,12 +1024,14 @@ void lac_send_ICRQ(tunnelidt t, sessionidt s);
 void lac_tunnelshutdown(tunnelidt t, char *reason, int result, int error, char *msg);
 
 // grpsess.c
 void lac_tunnelshutdown(tunnelidt t, char *reason, int result, int error, char *msg);
 
 // grpsess.c
-sessionidt grp_getnextsession(groupidt g, in_addr_t ip, in_addr_t ip_src);
+sessionidt grp_getnextsession(groupidt g, void *p_ip, void *p_ip_src, int is_ipv6);
 void grp_initdata(void);
 void grp_processvendorspecific(sessionidt s, uint8_t *pvs);
 groupidt grp_groupbysession(sessionidt s);
 groupidt grp_groupbyip(in_addr_t ip);
 void grp_initdata(void);
 void grp_processvendorspecific(sessionidt s, uint8_t *pvs);
 groupidt grp_groupbysession(sessionidt s);
 groupidt grp_groupbyip(in_addr_t ip);
+groupidt grp_groupbyipv6(struct in6_addr ip);
 void grp_setgrouproute(groupidt g, int add);
 void grp_setgrouproute(groupidt g, int add);
+void grp_setgrouproute6(groupidt g, int add);
 void grp_time_changed(void);
 void grp_removesession(groupidt g, sessionidt s);
 int grp_cluster_load_groupe(groupidt g, groupsesst *new);
 void grp_time_changed(void);
 void grp_removesession(groupidt g, sessionidt s);
 int grp_cluster_load_groupe(groupidt g, groupsesst *new);
@@ -1085,7 +1085,6 @@ extern in_addr_t my_address;
 extern int clifd;
 extern int epollfd;
 extern int tunidx;             // ifr_ifindex of tun device
 extern int clifd;
 extern int epollfd;
 extern int tunidx;             // ifr_ifindex of tun device
-extern union iphash ip_hash[256];
 
 struct event_data {
        enum {
 
 struct event_data {
        enum {
diff --git a/ppp.c b/ppp.c
index c4f9ab4..29bf1bc 100644 (file)
--- a/ppp.c
+++ b/ppp.c
@@ -1482,6 +1482,7 @@ void processipcp(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
 static void ipv6cp_open(sessionidt s, tunnelidt t)
 {
        int i;
 static void ipv6cp_open(sessionidt s, tunnelidt t)
 {
        int i;
+       groupidt g;
        LOG(3, s, t, "IPV6CP: Opened\n");
 
        change_state(s, ipv6cp, Opened);
        LOG(3, s, t, "IPV6CP: Opened\n");
 
        change_state(s, ipv6cp, Opened);
@@ -1497,6 +1498,12 @@ static void ipv6cp_open(sessionidt s, tunnelidt t)
                        route6set(s, session[s].ipv6address, 128, 1);
        }
 
                        route6set(s, session[s].ipv6address, 128, 1);
        }
 
+       if ((g = grp_groupbysession(s)))
+       {
+               grp_setgrouproute6(g, 1);
+               cluster_send_groupe(g);
+       }
+
        // Send an initial RA (TODO: Should we send these regularly?)
        send_ipv6_ra(s, t, NULL);
 }
        // Send an initial RA (TODO: Should we send these regularly?)
        send_ipv6_ra(s, t, NULL);
 }
@@ -2267,7 +2274,8 @@ void processipv6in(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l)
        if (session[s].ipv6address.s6_addr[0])
        {
                if ((sessionbyipv6new(ip) != s) &&
        if (session[s].ipv6address.s6_addr[0])
        {
                if ((sessionbyipv6new(ip) != s) &&
-                       (ip.s6_addr[0] != 0xFE || ip.s6_addr[1] != 0x80 || ip.s6_addr16[1] != 0 || ip.s6_addr16[2] != 0 || ip.s6_addr16[3] != 0))
+                       (ip.s6_addr[0] != 0xFE || ip.s6_addr[1] != 0x80 || ip.s6_addr16[1] != 0 || ip.s6_addr16[2] != 0 || ip.s6_addr16[3] != 0) &&
+                       (!grp_groupbyipv6(ip)))
                {
                        char str[INET6_ADDRSTRLEN];
                        LOG(5, s, t, "Dropping packet with spoofed IP %s\n",
                {
                        char str[INET6_ADDRSTRLEN];
                        LOG(5, s, t, "Dropping packet with spoofed IP %s\n",