X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/348452cffc1ac8cbe007108905de0022f684aa9d..aa77d4f89aa291e851c9be8a64ecfdb1434e83c9:/l2tpns.c diff --git a/l2tpns.c b/l2tpns.c index 603d66b..e9f768a 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -4,7 +4,7 @@ // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced // vim: sw=8 ts=8 -char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.73.2.3 2005/01/13 07:58:54 bodea Exp $"; +char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.73.2.17 2005/07/03 02:40:22 bodea Exp $"; #include #include @@ -83,7 +83,7 @@ uint32_t eth_tx = 0; static uint32_t ip_pool_size = 1; // Size of the pool of addresses used for dynamic address allocation. time_t time_now = 0; // Current time in seconds since epoch. static char time_now_string[64] = {0}; // Current time as a string. -static char main_quit = 0; // True if we're in the process of exiting. +char main_quit = 0; // True if we're in the process of exiting. linked_list *loaded_plugins; linked_list *plugins[MAX_PLUGIN_TYPES]; @@ -122,6 +122,7 @@ config_descriptt config_values[] = { CONFIG("cluster_interface", cluster_interface, STRING), CONFIG("cluster_hb_interval", cluster_hb_interval, INT), CONFIG("cluster_hb_timeout", cluster_hb_timeout, INT), + CONFIG("cluster_master_min_adv", cluster_master_min_adv, INT), { NULL, 0, 0, 0 }, }; @@ -180,6 +181,9 @@ static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int static tunnelidt new_tunnel(void); static int unhide_avp(uint8_t *avp, tunnelidt t, sessionidt s, uint16_t length); +// on slaves, alow BGP to withdraw cleanly before exiting +#define QUIT_DELAY 5 + // return internal time (10ths since process startup) static clockt now(void) { @@ -479,7 +483,7 @@ sessionidt sessionbyip(in_addr_t ip) int s = lookup_ipmap(ip); CSTAT(call_sessionbyip); - if (s > 0 && s < MAXSESSION && session[s].tunnel) + if (s > 0 && s < MAXSESSION && session[s].opened) return (sessionidt) s; return 0; @@ -579,8 +583,11 @@ sessionidt sessionbyuser(char *username) int s; CSTAT(call_sessionbyuser); - for (s = 1; s < MAXSESSION ; ++s) + for (s = 1; s <= config->cluster_highest_sessionid ; ++s) { + if (!session[s].opened) + continue; + if (session[s].walled_garden) continue; // Skip walled garden users. @@ -622,17 +629,16 @@ void send_garp(in_addr_t ip) sendarp(ifr.ifr_ifindex, mac, ip); } -// Find session by username, 0 for not found static sessiont *sessiontbysessionidt(sessionidt s) { - if (!s || s > MAXSESSION) return NULL; + if (!s || s >= MAXSESSION) return NULL; return &session[s]; } static sessionidt sessionidtbysessiont(sessiont *s) { sessionidt val = s-session; - if (s < session || val > MAXSESSION) return 0; + if (s < session || val >= MAXSESSION) return 0; return val; } @@ -794,7 +800,7 @@ static void processipout(uint8_t * buf, int len) { INC_STAT(tun_rx_dropped, sess_local[s].packets_dropped); LOG(3, s, t, "Dropped %u/%u packets to %s for %suser %s\n", - sess_local[s].packets_out, sess_local[s].packets_dropped, + sess_local[s].packets_dropped, sess_local[s].packets_out, fmtaddr(ip, 0), sp->throttle_out ? "throttled " : "", sp->user); } @@ -1012,7 +1018,7 @@ static void controladd(controlt * c, tunnelidt t, sessionidt s) // void throttle_session(sessionidt s, int rate_in, int rate_out) { - if (!session[s].tunnel) + if (!session[s].opened) return; // No-one home. if (!*session[s].user) @@ -1050,7 +1056,7 @@ void throttle_session(sessionidt s, int rate_in, int rate_out) // add/remove filters from session (-1 = no change) void filter_session(sessionidt s, int filter_in, int filter_out) { - if (!session[s].tunnel) + if (!session[s].opened) return; // No-one home. if (!*session[s].user) @@ -1093,9 +1099,9 @@ void sessionshutdown(sessionidt s, char *reason) CSTAT(call_sessionshutdown); - if (!session[s].tunnel) + if (!session[s].opened) { - LOG(3, s, session[s].tunnel, "Called sessionshutdown on a session with no tunnel.\n"); + LOG(3, s, session[s].tunnel, "Called sessionshutdown on an unopened session.\n"); return; // not a live session } @@ -1106,7 +1112,7 @@ void sessionshutdown(sessionidt s, char *reason) run_plugins(PLUGIN_KILL_SESSION, &data); } - if (session[s].opened && !walled_garden && !session[s].die) + if (session[s].ip && !walled_garden && !session[s].die) { // RADIUS Stop message uint16_t r = session[s].radius; @@ -1115,7 +1121,6 @@ void sessionshutdown(sessionidt s, char *reason) if (!(r = radiusnew(s))) { LOG(1, s, session[s].tunnel, "No free RADIUS sessions for Stop message\n"); - STAT(radius_overflow); } else { @@ -1167,7 +1172,7 @@ void sessionshutdown(sessionidt s, char *reason) } if (!session[s].die) - session[s].die = now() + 150; // Clean up in 15 seconds + session[s].die = TIME + 150; // Clean up in 15 seconds // update filter refcounts if (session[s].filter_in) ip_filters[session[s].filter_in - 1].used--; @@ -1187,6 +1192,12 @@ void sendipcp(tunnelidt t, sessionidt s) if (!r) r = radiusnew(s); + if (!r) + { + sessionshutdown(s, "No free RADIUS sessions for IPCP"); + return; + } + if (radius[r].state != RADIUSIPCP) { radius[r].state = RADIUSIPCP; @@ -1205,7 +1216,7 @@ void sendipcp(tunnelidt t, sessionidt s) if (!q) return; *q = ConfigReq; - q[1] = r << RADIUS_SHIFT; // ID, dont care, we only send one type of request + q[1] = r >> RADIUS_SHIFT; // ID, dont care, we only send one type of request *(uint16_t *) (q + 2) = htons(10); q[4] = 3; q[5] = 6; @@ -1217,24 +1228,39 @@ void sendipcp(tunnelidt t, sessionidt s) session[s].flags &= ~SF_IPCP_ACKED; // Clear flag. } +static void sessionclear(sessionidt s) +{ + memset(&session[s], 0, sizeof(session[s])); + memset(&sess_local[s], 0, sizeof(sess_local[s])); + memset(&cli_session_actions[s], 0, sizeof(cli_session_actions[s])); + + session[s].tunnel = T_FREE; // Mark it as free. + session[s].next = sessionfree; + sessionfree = s; +} + // kill a session now -static void sessionkill(sessionidt s, char *reason) +void sessionkill(sessionidt s, char *reason) { CSTAT(call_sessionkill); - session[s].die = now(); + if (!session[s].opened) // not alive + return; + + if (session[s].next) + { + LOG(0, s, session[s].tunnel, "Tried to kill a session with next pointer set (%d)\n", session[s].next); + return; + } + + session[s].die = TIME; sessionshutdown(s, reason); // close radius/routes, etc. if (session[s].radius) radiusclear(session[s].radius, s); // cant send clean accounting data, session is killed LOG(2, s, session[s].tunnel, "Kill session %d (%s): %s\n", s, session[s].user, reason); - - memset(&session[s], 0, sizeof(session[s])); - session[s].tunnel = T_FREE; // Mark it as free. - session[s].next = sessionfree; - sessionfree = s; - cli_session_actions[s].action = 0; + sessionclear(s); cluster_send_session(s); } @@ -1265,7 +1291,7 @@ static void tunnelkill(tunnelidt t, char *reason) controlfree = c; } // kill sessions - for (s = 1; s < MAXSESSION; s++) + for (s = 1; s <= config->cluster_highest_sessionid ; ++s) if (session[s].tunnel == t) sessionkill(s, reason); @@ -1292,12 +1318,12 @@ static void tunnelshutdown(tunnelidt t, char *reason) LOG(1, 0, t, "Shutting down tunnel %d (%s)\n", t, reason); // close session - for (s = 1; s < MAXSESSION; s++) + for (s = 1; s <= config->cluster_highest_sessionid ; ++s) if (session[s].tunnel == t) sessionshutdown(s, reason); tunnel[t].state = TUNNELDIE; - tunnel[t].die = now() + 700; // Clean up in 70 seconds + tunnel[t].die = TIME + 700; // Clean up in 70 seconds cluster_send_tunnel(t); // TBA - should we wait for sessions to stop? { // Send StopCCN @@ -1836,7 +1862,8 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) if (!sessionfree) { STAT(session_overflow); - tunnelshutdown(t, "No free sessions"); + LOG(1, 0, t, "No free sessions\n"); + return; } else { @@ -1854,13 +1881,13 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) if (!(r = radiusnew(s))) { LOG(1, s, t, "No free RADIUS sessions for ICRQ\n"); - sessionkill(s, "no free RADIUS sesions"); + sessionclear(s); return; } c = controlnew(11); // sending ICRP session[s].id = sessionid++; - session[s].opened = time(NULL); + session[s].opened = time_now; session[s].tunnel = t; session[s].far = asession; session[s].last_packet = time_now; @@ -1943,7 +1970,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) l -= 2; } - if (s && !session[s].tunnel) // Is something wrong?? + if (s && !session[s].opened) // Is something wrong?? { if (!config->cluster_iam_master) { @@ -1952,10 +1979,7 @@ void processudp(uint8_t * buf, int len, struct sockaddr_in *addr) return; } - - LOG(1, s, t, "UDP packet contains session %d but no session[%d].tunnel " - "exists (LAC said tunnel = %d). Dropping packet.\n", s, s, t); - + LOG(1, s, t, "UDP packet contains session which is not opened. Dropping packet.\n"); STAT(tunnel_rx_errors); return; } @@ -2123,7 +2147,7 @@ static int regular_cleanups(void) if (s > config->cluster_highest_sessionid) s = 1; - if (!session[s].tunnel) // Session isn't in use + if (!session[s].opened) // Session isn't in use continue; if (!session[s].die && session[s].ip && !(session[s].flags & SF_IPCP_ACKED)) @@ -2272,8 +2296,39 @@ static int regular_cleanups(void) static int still_busy(void) { int i; + static time_t stopped_bgp = 0; static clockt last_talked = 0; static clockt start_busy_wait = 0; + + if (!config->cluster_iam_master) + { +#ifdef BGP + if (bgp_configured) + { + if (!stopped_bgp) + { + LOG(1, 0, 0, "Shutting down in %d seconds, stopping BGP...\n", QUIT_DELAY); + + for (i = 0; i < BGP_NUM_PEERS; i++) + if (bgp_peers[i].state == Established) + bgp_stop(&bgp_peers[i]); + + stopped_bgp = time_now; + + // we don't want to become master + cluster_send_ping(0); + + return 1; + } + + if (time_now < (stopped_bgp + QUIT_DELAY)) + return 1; + } +#endif /* BGP */ + + return 0; + } + if (start_busy_wait == 0) start_busy_wait = TIME; @@ -2577,6 +2632,7 @@ static void mainloop(void) // // Important!!! We MUST not process any packets past this point! + LOG(1, 0, 0, "Clean shutdown complete\n"); } static void stripdomain(char *host) @@ -2665,6 +2721,7 @@ static void initdata(int optdebug, char *optconfig) config->debug = optdebug; config->num_tbfs = MAXTBFS; config->rl_rate = 28; // 28kbps + config->cluster_master_min_adv = 1; if (!(tunnel = shared_malloc(sizeof(tunnelt) * MAXTUNNEL))) { @@ -2731,7 +2788,7 @@ memset(ip_filters, 0, sizeof(ip_filtert) * MAXFILTER); memset(ip_address_pool, 0, sizeof(ippoolt) * MAXIPPOOL); // Put all the sessions on the free list marked as undefined. - for (i = 1; i < MAXSESSION - 1; i++) + for (i = 1; i < MAXSESSION; i++) { session[i].next = i + 1; session[i].tunnel = T_UNDEF; // mark it as not filled in. @@ -2740,7 +2797,7 @@ memset(ip_filters, 0, sizeof(ip_filtert) * MAXFILTER); sessionfree = 1; // Mark all the tunnels as undefined (waiting to be filled in by a download). - for (i = 1; i < MAXTUNNEL- 1; i++) + for (i = 1; i < MAXTUNNEL; i++) tunnel[i].state = TUNNELUNDEF; // mark it as not filled in. if (!*hostname) @@ -2866,7 +2923,7 @@ void rebuild_address_pool(void) for (i = 0; i < MAXSESSION; ++i) { int ipid; - if (!session[i].ip || !session[i].tunnel) + if (!(session[i].opened && session[i].ip)) continue; ipid = - lookup_ipmap(htonl(session[i].ip)); @@ -3256,14 +3313,6 @@ int main(int argc, char *argv[]) mainloop(); -#ifdef BGP - /* try to shut BGP down cleanly; with luck the sockets will be - writable since we're out of the select */ - for (i = 0; i < BGP_NUM_PEERS; i++) - if (bgp_peers[i].state == Established) - bgp_stop(&bgp_peers[i]); -#endif /* BGP */ - /* remove plugins (so cleanup code gets run) */ plugins_done(); @@ -3638,7 +3687,7 @@ static void update_config() if (!config->numradiusservers) LOG(0, 0, 0, "No RADIUS servers defined!\n"); - config->num_radfds = 2 << RADIUS_SHIFT; + config->num_radfds = 1 << RADIUS_SHIFT; // Update plugins for (i = 0; i < MAXPLUGINS; i++) @@ -3739,7 +3788,7 @@ int sessionsetup(tunnelidt t, sessionidt s) LOG(3, s, t, "Doing session setup for session\n"); - if (!session[s].ip || session[s].ip == 0xFFFFFFFE) + if (!session[s].ip) { assign_ip_address(s); if (!session[s].ip) @@ -4337,7 +4386,7 @@ void become_master(void) { for (s = 1; s <= config->cluster_highest_sessionid ; ++s) { - if (!session[s].tunnel) // Not an in-use session. + if (!session[s].opened) // Not an in-use session. continue; run_plugins(PLUGIN_NEW_SESSION_MASTER, &session[s]); @@ -4369,7 +4418,7 @@ int cmd_show_hist_idle(struct cli_def *cli, char *command, char **argv, int argc for (s = 1; s <= config->cluster_highest_sessionid ; ++s) { int idle; - if (!session[s].tunnel) + if (!session[s].opened) continue; idle = time_now - session[s].last_packet; @@ -4407,7 +4456,7 @@ int cmd_show_hist_open(struct cli_def *cli, char *command, char **argv, int argc for (s = 1; s <= config->cluster_highest_sessionid ; ++s) { int open = 0, d; - if (!session[s].tunnel) + if (!session[s].opened) continue; d = time_now - session[s].opened;