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("disable_sending_hello", disable_sending_hello, BOOL),
CONFIG("disable_no_spoof", disable_no_spoof, BOOL),
CONFIG("bind_multi_address", bind_multi_address, STRING),
+ CONFIG("grp_txrate_average_time", grp_txrate_average_time, INT),
CONFIG("pppoe_only_equal_svc_name", pppoe_only_equal_svc_name, BOOL),
+ CONFIG("multi_hostname", multi_hostname, STRING),
{ 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;
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.
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
}
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);
}
controlt *c = controlnew(2); // sending SCCRP
control16(c, 2, version, 1); // protocol version
control32(c, 3, 3, 1); // framing
- controls(c, 7, hostname, 1); // host name
+ controls(c, 7, config->multi_n_hostname[tunnel[t].indexudp][0]?config->multi_n_hostname[tunnel[t].indexudp]:hostname, 1); // host name
if (sendchalresponse) controlb(c, 13, sendchalresponse, 16, 1); // Send Challenge response
control16(c, 9, t, 1); // assigned tunnel
controladd(c, 0, t); // send the resply
{
LOG(3, s, t, "sending SCCCN to REMOTE LNS\n");
controlt *c = controlnew(3); // sending SCCCN
- controls(c, 7, hostname, 1); // host name
+ controls(c, 7, config->multi_n_hostname[tunnel[t].indexudp][0]?config->multi_n_hostname[tunnel[t].indexudp]:hostname, 1); // host name
controls(c, 8, Vendor_name, 1); // Vendor name
control16(c, 2, version, 1); // protocol version
control32(c, 3, 3, 1); // framing Capabilities
// 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];
#endif /* BGP */
lac_initremotelnsdata();
+
+ grp_initdata();
}
static int assign_ip_address(sessionidt s)
LOG(0, 0, 0, "Can't lock pages: %s\n", strerror(errno));
}
+ //LOG(3, 0, 0, "Debug sizeof struct: sessiont %lu, tunnelt %lu, bundlet %lu, groupsesst %lu\n",
+ // sizeof(sessiont), sizeof(tunnelt), sizeof(bundlet), sizeof(groupsesst));
+
mainloop();
/* remove plugins (so cleanup code gets run) */
config->iftun_n_address[config->nbmultiaddress] = htonl(ip);
config->nbmultiaddress++;
LOG(1, 0, 0, "Bind address %s\n", fmtaddr(htonl(ip), 0));
+
+ if (config->nbmultiaddress >= MAX_BINDADDR) break;
}
sip = n;
config->iftun_n_address[0] = config->iftun_address;
}
+ if (*config->multi_hostname)
+ {
+ char *shost = config->multi_hostname;
+ char *n = shost;
+ char *e = config->multi_hostname + strlen(config->multi_hostname);
+ config->nbmultihostname = 0;
+
+ while (*shost && (shost < e))
+ {
+ while ((n < e) && (*n == ' ' || *n == '\t')) n++;
+
+ i = 0;
+ while (n < e && (*n != ',') && (*n != '\t'))
+ {
+ config->multi_n_hostname[config->nbmultihostname][i] = *n;
+ n++;i++;
+ }
+ if (i > 0)
+ {
+ config->multi_n_hostname[config->nbmultihostname][i] = 0;
+ LOG(1, 0, 0, "Bind Hostname %s\n", config->multi_n_hostname[config->nbmultihostname]);
+ config->nbmultihostname++;
+ if (config->nbmultihostname >= MAX_NBHOSTNAME) break;
+ }
+ }
+
+ if (config->nbmultihostname >= 1)
+ {
+ strcpy(hostname, config->multi_n_hostname[0]);
+ strcpy(config->hostname, hostname);
+ }
+ }
+
if (!*config->pppoe_ac_name)
strncpy(config->pppoe_ac_name, DEFAULT_PPPOE_AC_NAME, sizeof(config->pppoe_ac_name) - 1);
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);
+ cluster_send_groupe(g);
+ }
}
sess_local[s].lcp_authtype = 0; // RADIUS authentication complete
// Sent SCCRQ - Start Control Connection Request
controlt *c = controlnew(1); // sending SCCRQ
- controls(c, 7, hostname, 1); // host name
+ controls(c, 7, config->multi_n_hostname[tunnel[t].indexudp][0]?config->multi_n_hostname[tunnel[t].indexudp]:hostname, 1); // host name
controls(c, 8, Vendor_name, 1); // Vendor name
control16(c, 2, version, 1); // protocol version
control32(c, 3, 3, 1); // framing Capabilities
#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 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
// Multi bind address constants
#define MAX_UDPFD 4
#define MAX_BINDADDR MAX_UDPFD
+ // + 1 for the LAC Hostname
+ #define MAX_NBHOSTNAME (MAX_UDPFD + 1)
// 4 + 1 for the udplac
#define INIT_TABUDPFD {-1, -1, -1, -1, -1}
#define INIT_TABUDPVAR {0, 0, 0, 0, 0}
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];
struct in6_addr ipv6route; // Static IPv6 route
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
+ char reserved[4]; // Space to expand structure without changing HB_VERSION
}
sessiont;
+typedef struct
+{
+ uint32_t tx_rate;
+ uint32_t prev_coutgrp;
+ sessionidt sid;
+ uint8_t weight;
+}
+groupsesslistt;
+
+typedef struct
+{
+ int state; // current state (groupestate enum)
+ uint32_t time_changed;
+ groupidt prev;
+ sessionidt smax;
+ sessionidt smin;
+ groupsesslistt 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)
BUNDLEUNDEF, // Undefined
};
+enum
+{
+ GROUPEFREE, // Not in use
+ GROUPEOPEN, // Active bundle
+ GROUPEUNDEF // Undefined
+};
+
enum
{
NULLCLASS = 0, //End Point Discriminator classes
int cluster_undefined_sessions; // How many sessions we're yet to receive from the master.
int cluster_undefined_bundles; // How many bundles we're yet to receive from the master.
int cluster_undefined_tunnels; // How many tunnels we're yet to receive from the master.
+ int cluster_undefined_groupes; // How many groupes we're yet to receive from the master.
int cluster_highest_sessionid;
int cluster_highest_bundleid;
+ int cluster_highest_groupeid;
int cluster_highest_tunnelid;
clockt cluster_last_hb; // Last time we saw a heartbeat from the master.
int cluster_last_hb_ver; // Heartbeat version last seen from master
int nbudpfd; // number UDP file handle
int nbmultiaddress; // number multi address to bind
int indexlacudpfd; // Index UDP LAC file handle (in udpfd[])
+ int nbmultihostname; // number hostname, normally the same number as the nbudpfd
++ int grp_txrate_average_time; // caculation txrate average time (default 10s)
in_addr_t bind_n_address[MAX_BINDADDR];
in_addr_t iftun_n_address[MAX_BINDADDR];
char bind_multi_address[256];
- int grp_txrate_average_time; // caculation txrate average time (default 10s)
+ char multi_hostname[512];
+ char multi_n_hostname[MAX_NBHOSTNAME][MAXHOSTNAME]; // list hostname
} 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);
+
tunnelidt lac_new_tunnel();
void lac_tunnelclear(tunnelidt t);
void lac_send_SCCRQ(tunnelidt t, uint8_t * auth, unsigned int auth_len);
void lac_send_ICRQ(tunnelidt t, sessionidt s);
void lac_tunnelshutdown(tunnelidt t, char *reason, int result, int error, char *msg);
+// 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);
+int grp_cluster_load_groupe(groupidt g, groupsesst *new);
+
#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;
+extern groupidt gnextgrpid;
#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 {