l2tpns.LIBS = -lm -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
+ ll.o md5.o ppp.o radius.o tbf.o util.o pppoe.o grpsess.o
PROGRAMS = l2tpns nsctl
PLUGINS = autosnoop.so autothrottle.so garden.so sessionctl.so \
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
+grpsess.o: grpsess.c l2tpns.h util.h bgp.h
bgp.o: bgp.c l2tpns.h bgp.h util.h
l2tplac.o: l2tplac.c md5.h l2tpns.h util.h cluster.h l2tplac.h pppoe.h
autosnoop.so: autosnoop.c l2tpns.h plugin.h
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <linux/if_packet.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "bgp.h"
#include <dlfcn.h>
#include <netdb.h>
#include <libcli.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "constants.h"
#include <malloc.h>
#include <errno.h>
#include <libcli.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "cluster.h"
increment_counter(&session[i].cout, &session[i].cout_wrap, sess_local[i].cout);
session[i].cin_delta += sess_local[i].cin;
session[i].cout_delta += sess_local[i].cout;
+ session[i].coutgrp_delta += sess_local[i].cout;
session[i].pin += sess_local[i].pin;
session[i].pout += sess_local[i].pout;
session[b->sid].cin_delta += b->cin;
session[b->sid].cout_delta += b->cout;
+ session[b->sid].coutgrp_delta += b->cout;
if (b->cin)
session[b->sid].last_packet = session[b->sid].last_data = time_now;
// L2TPNS: control
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "control.h"
-l2tpns (2.2.1-2fdn3.6) unstable; urgency=low
+l2tpns (2.2.1-2sames3.7) unstable; urgency=low
+ * Merge from master
* Fix Warning: dereferencing type-punned pointer will break strict...
* Fix: Tunnel creation does not work when the length of the hostname is odd. (revert fix: Add a uint16_t control buffer type, as a union)
-- Fernando Alves <fernando.alves@sameswireless.fr> Tue, 26 Feb 2013 09:07:16 +0100
+l2tpns (2.2.1-2sames3.6) unstable; urgency=low
+
+ * Sames l2tpns version.
+
+ -- Fernando Alves <fernando.alves@sameswireless.fr> Tue, 12 Feb 2013 20:20:17 +0100
+
l2tpns (2.2.1-2fdn3.5) unstable; urgency=low
* Update debian/changelog
--- /dev/null
+# -*- text -*-
+##############################################################################
+# Vendor specific attributes SamesWireless
+# http://www.sameswireless.fr
+#
+# $Id$
+#
+##############################################################################
+
+VENDOR SAMES 64520
+
+BEGIN-VENDOR SAMES
+
+ATTRIBUTE SAMES-Group-Framed-Route 22 string
+ATTRIBUTE SAMES-Group-Session-Weight 23 string
+
+END-VENDOR SAMES
+
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include "control.h"
/* Clean up counters */
s->pin = s->pout = 0;
s->cin = s->cout = 0;
- s->cin_delta = s->cout_delta = 0;
+ s->cin_delta = s->cout_delta = s->coutgrp_delta = 0;
s->cin_wrap = s->cout_wrap = 0;
snprintf(cmd, sizeof(cmd),
--- /dev/null
+/*
+ * 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 "l2tpns.h"
+#include "util.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.
+
+static groupidt gnextgrpid = 0;
+
+// 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
+// 'sessionbyip' 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(1, 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);
+ }
+}
+
+// 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 = 0;
+ }
+ 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]));
+ }
+ else
+ {
+ // remove the session
+ memmove(&grpsession[g].sesslist[i],
+ &grpsession[g].sesslist[i+1],
+ (grpsession[g].nbsession - i) * sizeof(grpsession[g].sesslist[i]));
+ }
+ 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].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;
+ }
+
+ 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()
+{
+ // 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);
+}
+
+// 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));
+ }
+ }
+ }
+ }
+}
+
+// return the next session can be used on the group
+sessionidt grp_getnextsession(groupidt g, in_addr_t ip)
+{
+ sessionidt s = 0, s2 = 0, s3 = 0, smax = 0;
+ int i;
+ uint32_t ltime_changed = 0, mintxrate = 0xFFFFFFFF, maxtxrate = 0;
+ uint32_t txrate;
+
+ if (g >= MAXGROUPE)
+ return 0;
+
+ if (grpsession[g].time_changed < config->grp_txrate_average_time)
+ {
+ if ((s = sessionbyip(ip)))
+ {
+ if ( (session[s].ppp.phase > Establish) &&
+ (time_now - session[s].last_packet <= (config->echo_timeout + 1)) )
+ {
+ return s;
+ }
+ s = 0;
+ }
+ }
+ else
+ {
+ // recalculation txrate
+ ltime_changed = grpsession[g].time_changed;
+ grpsession[g].time_changed = 0;
+ s = 0;
+ for (i = 0; i < grpsession[g].nbsession; i++)
+ {
+ if ((s2 = grpsession[g].sesslist[i].sid))
+ {
+ s3 = s2;
+
+ grpsession[g].sesslist[i].tx_rate = session[s2].coutgrp_delta/ltime_changed;
+ session[s2].coutgrp_delta = 0;
+
+ //LOG(3, s2, session[s2].tunnel, "TX Rate: %d session weight: %d\n",
+ // grpsession[g].sesslist[i].tx_rate, grpsession[g].sesslist[i].weight);
+
+ 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)) )
+ {
+ s = s2;
+ mintxrate = txrate;
+ }
+ }
+
+ if (txrate > maxtxrate)
+ {
+ if ( session[s2].ppp.phase > Establish &&
+ (time_now - session[s2].last_packet <= (config->echo_timeout + 1)) )
+ {
+ smax = s2;
+ maxtxrate = txrate;
+ }
+ }
+ }
+ }
+
+ if (smax && (maxtxrate != mintxrate))
+ {
+ grp_uncache_ipsession(g, smax);
+ }
+ }
+
+ 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;
+ //LOG(3, s, session[s].tunnel, "New random session\n");
+ }
+ 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;
+}
#include <sys/types.h>
#include <sys/wait.h>
#include <memory.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "pppoe.h"
#include <errno.h>
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
#include "md5.h"
#include "l2tpns.h"
// Update STAT OUT
increment_counter(&session[s].cout, &session[s].cout_wrap, len); // byte count
session[s].cout_delta += len;
+ session[s].coutgrp_delta += len;
session[s].pout++;
sess_local[s].cout += len;
sess_local[s].pout++;
int epollfd = -1; // event polling
time_t basetime = 0; // base clock
char hostname[MAXHOSTNAME] = ""; // us.
-static int tunidx; // ifr_ifindex of tun device
+int tunidx; // ifr_ifindex of tun device
int nlseqnum = 0; // netlink sequence number
int min_initok_nlseqnum = 0; // minimun seq number for messages after init is ok
static int syslog_log = 0; // are we logging to syslog
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 {
- sessionidt sess;
- union iphash *idx;
-} ip_hash[256]; // Mapping from IP address to session structures.
+union iphash ip_hash[256]; // Mapping from IP address to session structures.
struct ipv6radix {
sessionidt sess;
CONFIG("pppoe_ac_name", pppoe_ac_name, STRING),
CONFIG("disable_sending_hello", disable_sending_hello, BOOL),
CONFIG("disable_no_spoof", disable_no_spoof, BOOL),
+ CONFIG("grp_txrate_average_time", grp_txrate_average_time, INT),
{ NULL, 0, 0, 0 }
};
bundlet *bundle = NULL; // Array of bundle structures.
fragmentationt *frag = NULL; // Array of fragmentation structures.
sessiont *session = NULL; // Array of session structures.
+groupsesst *grpsession = NULL; // Array of groupsesst structures.
sessionlocalt *sess_local = NULL; // Array of local per-session counters.
radiust *radius = NULL; // Array of radius structures.
ippoolt *ip_address_pool = NULL; // Array of dynamic IP addresses.
struct Tringbuffer *ringbuffer = NULL;
#endif
-static ssize_t netlink_send(struct nlmsghdr *nh);
-static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen);
-static void cache_ipmap(in_addr_t ip, sessionidt s);
static void uncache_ipmap(in_addr_t ip);
static void cache_ipv6map(struct in6_addr ip, int prefixlen, sessionidt s);
static void free_ip_address(sessionidt s);
if (f) *f = t.tv_sec + t.tv_usec / 1000000.0;
if (t.tv_sec != time_now)
{
- time_now = t.tv_sec;
- time_changed++;
+ time_now = t.tv_sec;
+ time_changed++;
+ grp_time_changed();
}
// Time in milliseconds
}
}
-static ssize_t netlink_send(struct nlmsghdr *nh)
+ssize_t netlink_send(struct nlmsghdr *nh)
{
struct sockaddr_nl nladdr;
struct iovec iov;
}
/* adapted from iproute2 */
-static void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen)
+void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen)
{
int len = RTA_LENGTH(alen);
struct rtattr *rta;
//
// (It's actually cached in network order)
//
-static void cache_ipmap(in_addr_t ip, sessionidt s)
+void cache_ipmap(in_addr_t ip, sessionidt s)
{
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;
{
increment_counter(&sp->cout, &sp->cout_wrap, len); // byte count
sp->cout_delta += len;
+ sp->coutgrp_delta += len;
sp->pout++;
sp->last_data = time_now;
void processipout(uint8_t *buf, int len)
{
sessionidt s;
+ groupidt g;
sessiont *sp;
tunnelidt t;
in_addr_t ip;
}
ip = *(uint32_t *)(buf + 16);
- if (!(s = sessionbyip(ip)))
+ if ((g = grp_groupbyip(ip)))
+ {
+ s = grp_getnextsession(g, ip);
+ if (!s)
+ {
+ // Is this a packet for a session that doesn't exist?
+ static int rate = 0; // Number of ICMP packets we've sent this second.
+ static int last = 0; // Last time we reset the ICMP packet counter 'rate'.
+
+ if (last != time_now)
+ {
+ last = time_now;
+ rate = 0;
+ }
+
+ if (rate++ < config->icmp_rate) // Only send a max of icmp_rate per second.
+ {
+ LOG(4, 0, 0, "IP: Sending ICMP host unreachable to %s\n", fmtaddr(*(in_addr_t *)(buf + 12), 0));
+ host_unreachable(*(in_addr_t *)(buf + 12), *(uint16_t *)(buf + 4),
+ config->bind_address ? config->bind_address : my_address, buf, len);
+ }
+ return;
+ }
+ }
+ else if (!(s = sessionbyip(ip)))
{
// Is this a packet for a session that doesn't exist?
static int rate = 0; // Number of ICMP packets we've sent this second.
increment_counter(&sp->cout, &sp->cout_wrap, len); // byte count
sp->cout_delta += len;
+ sp->coutgrp_delta += len;
sp->pout++;
udp_tx += len;
increment_counter(&sp->cout, &sp->cout_wrap, len); // byte count
sp->cout_delta += len;
+ sp->coutgrp_delta += len;
sp->pout++;
udp_tx += len;
session[s].die = TIME + 150; // Clean up in 15 seconds
if (session[s].ip)
- { // IP allocated, clear and unroute
+ { // IP allocated, clear and unroute
int r;
int routed = 0;
for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
// kill a session now
void sessionkill(sessionidt s, char *reason)
{
+ groupidt g;
+
CSTAT(sessionkill);
if (!session[s].opened) // not alive
#endif
LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason);
+
+ if ((g = grp_groupbysession(s)))
+ {
+ grp_removesession(g, s);
+ }
+
sessionclear(s);
cluster_send_session(s);
}
// No data in ECHO_TIMEOUT seconds, send LCP ECHO
if (session[s].ppp.phase >= Establish && (time_now - session[s].last_packet >= config->echo_timeout) &&
- (time_now - sess_local[s].last_echo >= ECHO_TIMEOUT))
+ (time_now - sess_local[s].last_echo >= config->echo_timeout))
{
uint8_t b[MAXETHER];
#ifdef LAC
lac_initremotelnsdata();
#endif
+
+ grp_initdata();
}
static int assign_ip_address(sessionidt s)
if (!session[s].bundle || (bundle[session[s].bundle].num_of_links == 1))
{
int routed = 0;
+ groupidt g;
// Add the route for this session.
for (r = 0; r < MAXROUTE && session[s].route[r].ip; r++)
}
else
cache_ipmap(session[s].ip, s);
+
+ if ((g = grp_groupbysession(s)))
+ {
+ grp_setgrouproute(g, 1);
+ }
}
sess_local[s].lcp_authtype = 0; // RADIUS authentication complete
#define MAXADDRESS 20 // Maximum length for the Endpoint Discrminiator address
#define MAXSESSION 60000 // could be up to 65535
#define MAXTBFS 6000 // Maximum token bucket filters. Might need up to 2 * session.
+#define MAXSESSINGRP 12 // Maximum number of member links in grouped session
+#define MAXGRPINSESS 12 // Maximum number of member links in session group
+#define MAXGROUPE 300 // could be up to 65535, Maximum number of grouped session
+#define MAXROUTEINGRP 15 // max static routes per group
// Tunnel Id reserved for pppoe
#define TUNNEL_ID_PPPOE 1
typedef uint16_t sessionidt;
typedef uint16_t bundleidt;
typedef uint16_t tunnelidt;
+typedef uint16_t groupidt;
typedef uint32_t clockt;
typedef uint8_t hasht[16];
#ifdef LAC
sessionidt forwardtosession; // LNS id_session to forward
uint8_t src_hwaddr[ETH_ALEN]; // MAC addr source (for pppoe sessions 6 bytes)
- char reserved[4]; // Space to expand structure without changing HB_VERSION
+ uint32_t coutgrp_delta;
#else
uint8_t src_hwaddr[ETH_ALEN]; // MAC addr source (for pppoe sessions 6 bytes)
- char reserved[6]; // Space to expand structure without changing HB_VERSION
+ uint32_t coutgrp_delta;
+ char reserved[2]; // Space to expand structure without changing HB_VERSION
#endif
}
sessiont;
+typedef struct
+{
+ uint32_t tx_rate;
+ sessionidt sid;
+ uint8_t weight;
+}
+groupsessionidt;
+
+typedef struct
+{
+ uint32_t time_changed;
+ groupidt prev;
+ groupsessionidt sesslist[MAXSESSINGRP];
+ routet route[MAXROUTEINGRP]; // static routes
+ uint8_t nbroutesgrp;
+ 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)
uint8_t pppoe_hwaddr[ETH_ALEN]; // MAC addr of interface pppoe to bind
int disable_sending_hello; // Disable l2tp sending HELLO message for Apple compatibility.
int disable_no_spoof; // Disable no spoof (permit load balancing client --> internet)
+ int grp_txrate_average_time; // caculation txrate average time (default 10s)
} configt;
enum config_typet { INT, STRING, UNSIGNED_LONG, SHORT, BOOL, IPv4, IPv6 };
int cmd_show_ipcache(struct cli_def *cli, char *command, char **argv, int argc);
int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc);
int cmd_show_hist_open(struct cli_def *cli, char *command, char **argv, int argc);
+void netlink_addattr(struct nlmsghdr *nh, int type, const void *data, int alen);
+ssize_t netlink_send(struct nlmsghdr *nh);
+void cache_ipmap(in_addr_t ip, sessionidt s);
+
#ifdef LAC
tunnelidt lac_new_tunnel();
void lac_tunnelclear(tunnelidt t);
void lac_tunnelshutdown(tunnelidt t, char *reason, int result, int error, char *msg);
#endif
+// grpsess.c
+sessionidt grp_getnextsession(groupidt g, 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);
+void grp_setgrouproute(groupidt g, int add);
+void grp_time_changed(void);
+void grp_removesession(groupidt g, sessionidt s);
+
#undef LOG
#undef LOG_HEX
#define LOG(D, s, t, f, ...) ({ if (D <= config->debug) _log(D, s, t, f, ## __VA_ARGS__); })
extern sessiont *session;
extern sessionlocalt *sess_local;
extern ippoolt *ip_address_pool;
+extern groupsesst *grpsession;
#define sessionfree (session[0].next)
extern in_addr_t my_address;
extern int clifd;
extern int epollfd;
+extern int tunidx; // ifr_ifindex of tun device
+extern union iphash ip_hash[256];
struct event_data {
enum {
#include <string.h>
#include <netdb.h>
#include <signal.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "control.h"
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "constants.h"
#include "plugin.h"
#include <netpacket/packet.h>
#include <arpa/inet.h>
#include <linux/if_pppox.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#include "cluster.h"
// Update STAT OUT
increment_counter(&session[s].cout, &session[s].cout_wrap, ll2tp); // byte count
session[s].cout_delta += ll2tp;
+ session[s].coutgrp_delta += ll2tp;
session[s].pout++;
sess_local[s].cout += ll2tp;
sess_local[s].pout++;
// Update STAT OUT
increment_counter(&session[s].cout, &session[s].cout_wrap, lpppoe); // byte count
session[s].cout_delta += lpppoe;
+ session[s].coutgrp_delta += lpppoe;
session[s].pout++;
sess_local[s].cout += lpppoe;
sess_local[s].pout++;
#include <ctype.h>
#include <netinet/in.h>
#include <errno.h>
+#include <linux/rtnetlink.h>
#include "md5.h"
#include "constants.h"
else if (vendor == 529 && attrib >= 135 && attrib <= 136) // Ascend
{
// handle old-format ascend DNS attributes below
- p += 6;
+ p += 6;
+ }
+ else if (vendor == 64520) // Sames
+ {
+ //Sames vendor-specific 64520
+ uint8_t *pvs = p + 6; // pvs set to begin to attribute
+ LOG(3, s, session[s].tunnel, " Sames vendor-specific: %d, Attrib: %d, lenght: %d\n", vendor, attrib, attrib_length);
+ grp_processvendorspecific(s, pvs);
+ continue;
}
else
{
- LOG(3, s, session[s].tunnel, " Unknown vendor-specific\n");
+ LOG(3, s, session[s].tunnel, " Unknown vendor-specific: %d, Attrib: %d\n", vendor, attrib);
continue;
}
}
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include "control.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include "control.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
// L2TPNS: token bucket filters
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "util.h"
#include "tbf.h"
#include <string.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+
#include "l2tpns.h"
#include "plugin.h"
#include "control.h"
#include <arpa/inet.h>
#include <string.h>
#include <sys/mman.h>
+#include <linux/rtnetlink.h>
#include "l2tpns.h"
#ifdef BGP