X-Git-Url: http://git.sameswireless.fr/l2tpns.git/blobdiff_plain/4d7d7850b5d242bf9b77ac07e7c06ef523c627e6..5ff54415c95f70115272ea65263e1a4a654da57e:/cluster.c diff --git a/cluster.c b/cluster.c index 808ab84..48c2059 100644 --- a/cluster.c +++ b/cluster.c @@ -1,6 +1,6 @@ // L2TPNS Clustering Stuff -char const *cvs_id_cluster = "$Id: cluster.c,v 1.26 2004/12/16 23:40:31 bodea Exp $"; +char const *cvs_id_cluster = "$Id: cluster.c,v 1.26.2.9 2005/05/23 12:48:17 bodea Exp $"; #include #include @@ -405,18 +405,18 @@ void master_update_counts(void) if ( walk_session_number > config->cluster_highest_sessionid) walk_session_number = 1; - if (!sess_count[walk_session_number].cin && !sess_count[walk_session_number].cout) + if (!sess_local[walk_session_number].cin && !sess_local[walk_session_number].cout) continue; // Unused. Skip it. b[c].sid = walk_session_number; - b[c].in = sess_count[walk_session_number].cin; - b[c].out = sess_count[walk_session_number].cout; + b[c].in = sess_local[walk_session_number].cin; + b[c].out = sess_local[walk_session_number].cout; if (++c > MAX_B_RECS) // Send a max of 400 elements in a packet. break; // Reset counters. - sess_count[walk_session_number].cin = sess_count[walk_session_number].cout = 0; + sess_local[walk_session_number].cin = sess_local[walk_session_number].cout = 0; } if (!c) // Didn't find any that changes. Get out of here! @@ -485,14 +485,15 @@ void cluster_check_master(void) // If the master is late (missed 2 hearbeats by a second and a // hair) it may be that the switch has dropped us from the - // multicast group, try unicasting one probe to the master + // multicast group, try unicasting probes to the master // which will hopefully respond with a unicast heartbeat that // will allow us to limp along until the querier next runs. - if (TIME > (config->cluster_last_hb + 2 * config->cluster_hb_interval + 11)) + if (config->cluster_master_address + && TIME > (config->cluster_last_hb + 2 * config->cluster_hb_interval + 11)) { - if (!probed && config->cluster_master_address) + if (!probed || (TIME > (probed + 2 * config->cluster_hb_interval))) { - probed = 1; + probed = TIME; LOG(1, 0, 0, "Heartbeat from master %.1fs late, probing...\n", 0.1 * (TIME - (config->cluster_last_hb + config->cluster_hb_interval))); @@ -570,38 +571,42 @@ void cluster_check_master(void) ++count; } - if (session[i].tunnel == T_FREE) { // Unused session. Add to free list. + if (!session[i].opened) { // Unused session. Add to free list. + memset(&session[i], 0, sizeof(session[i])); + session[i].tunnel = T_FREE; session[last_free].next = i; session[i].next = 0; last_free = i; + continue; } - // Reset all the idle timeouts.. + // Reset idle timeouts.. session[i].last_packet = time_now; + // Reset die relative to our uptime rather than the old master's + if (session[i].die) session[i].die = TIME; + // Accumulate un-sent byte counters. - session[i].cin += sess_count[i].cin; - session[i].cout += sess_count[i].cout; - session[i].total_cin += sess_count[i].cin; - session[i].total_cout += sess_count[i].cout; + session[i].cin += sess_local[i].cin; + session[i].cout += sess_local[i].cout; + session[i].total_cin += sess_local[i].cin; + session[i].total_cout += sess_local[i].cout; - sess_count[i].cin = sess_count[i].cout = 0; + sess_local[i].cin = sess_local[i].cout = 0; session[i].radius = 0; // Reset authentication as the radius blocks aren't up to date. if (session[i].unique_id >= high_unique_id) // This is different to the index into the session table!!! high_unique_id = session[i].unique_id+1; - session[i].tbf_in = session[i].tbf_out = 0; // Remove stale pointers from old master. throttle_session(i, session[i].throttle_in, session[i].throttle_out); - if (session[i].tunnel != T_FREE && i > config->cluster_highest_sessionid) - config->cluster_highest_sessionid = i; + config->cluster_highest_sessionid = i; } session[last_free].next = 0; // End of chain. - last_id = high_unique_id; // Keep track of the highest used session ID. + last_id = high_unique_id; // Keep track of the highest used session ID. become_master(); @@ -617,6 +622,11 @@ void cluster_check_master(void) if (!num_peers) // lone master advertise(); +#ifdef BGP + else if (bgp_configured) + bgp_enable_routing(0); +#endif /* BGP */ + // FIXME. We need to fix up the tunnel control message // queue here! There's a number of other variables we @@ -649,12 +659,12 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig config->cluster_undefined_sessions = 0; for (i = 1 ; i < MAXSESSION; ++i) { if (i > highsession) { - session[i].tunnel = 0; // Defined. + if (session[i].tunnel == T_UNDEF) session[i].tunnel = T_FREE; // Defined. continue; } - if (session[i].tunnel != T_UNDEF) - continue; - ++config->cluster_undefined_sessions; + + if (session[i].tunnel == T_UNDEF) + ++config->cluster_undefined_sessions; } // Clear out defined tunnels, counting the number of @@ -662,12 +672,12 @@ static void cluster_check_sessions(int highsession, int freesession_ptr, int hig config->cluster_undefined_tunnels = 0; for (i = 1 ; i < MAXTUNNEL; ++i) { if (i > hightunnel) { - tunnel[i].state = TUNNELFREE; // Defined. + if (tunnel[i].state == TUNNELUNDEF) tunnel[i].state = TUNNELFREE; // Defined. continue; } - if (tunnel[i].state != TUNNELUNDEF) - continue; - ++config->cluster_undefined_tunnels; + + if (tunnel[i].state == TUNNELUNDEF) + ++config->cluster_undefined_tunnels; } @@ -892,6 +902,13 @@ static int cluster_catchup_slave(int seq, in_addr_t slave) int diff; LOG(1, 0, 0, "Slave %s sent LASTSEEN with seq %d\n", fmtaddr(slave, 0), seq); + if (!config->cluster_iam_master) { + LOG(1, 0, 0, "Got LASTSEEN but I'm not a master! Redirecting it to %s.\n", + fmtaddr(config->cluster_master_address, 0)); + + peer_send_message(slave, C_MASTER, config->cluster_master_address, NULL, 0); + return 0; + } diff = config->cluster_seq_number - seq; // How many packet do we need to send? if (diff < 0) @@ -903,9 +920,11 @@ static int cluster_catchup_slave(int seq, in_addr_t slave) return peer_send_message(slave, C_KILL, seq, NULL, 0);// Kill the slave. Nothing else to do. } + LOG(1, 0, 0, "Sending %d catchup packets to slave %s\n", diff, fmtaddr(slave, 0) ); + // Now resend every packet that it missed, in order. while (seq != config->cluster_seq_number) { - s = seq%HB_HISTORY_SIZE; + s = seq % HB_HISTORY_SIZE; if (seq != past_hearts[s].seq) { LOG(0, 0, 0, "Tried to re-send heartbeat for %s but %d doesn't match %d! (%d,%d)\n", fmtaddr(slave, 0), seq, past_hearts[s].seq, s, config->cluster_seq_number); @@ -958,8 +977,10 @@ static int cluster_add_peer(in_addr_t peer, time_t basetime, pingt *pp, int size } // Is this the master shutting down?? - if (peer == config->cluster_master_address && !basetime) { - LOG(3, 0, 0, "Master %s shutting down...\n", fmtaddr(config->cluster_master_address, 0)); + if (peer == config->cluster_master_address) { + LOG(3, 0, 0, "Master %s %s\n", fmtaddr(config->cluster_master_address, 0), + basetime ? "has restarted!" : "shutting down..."); + config->cluster_master_address = 0; config->cluster_last_hb = 0; // Force an election. cluster_check_master(); @@ -1000,6 +1021,20 @@ static int cluster_add_peer(in_addr_t peer, time_t basetime, pingt *pp, int size return 1; } +// A slave responds with C_MASTER when it gets a message which should have gone to a master. +static int cluster_set_master(in_addr_t peer, in_addr_t master) +{ + if (config->cluster_iam_master) // Sanity... + return 0; + + LOG(3, 0, 0, "Peer %s set the master to %s...\n", fmtaddr(peer, 0), + fmtaddr(master, 1)); + + config->cluster_master_address = master; + cluster_check_master(); + return 0; +} + /* Handle the slave updating the byte counters for the master. */ // // Note that we don't mark the session as dirty; We rely on @@ -1027,7 +1062,9 @@ static int cluster_handle_bytes(char *data, int size) session[b->sid].cin += b->in; session[b->sid].cout += b->out; - session[b->sid].last_packet = time_now; // Reset idle timer! + + if (b->in) + session[b->sid].last_packet = time_now; // Reset idle timer! size -= sizeof(*b); ++b; @@ -1168,18 +1205,55 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t exit(1); } + // + // Send it a unicast heartbeat to see give it a chance to die. + // NOTE: It's actually safe to do seq-number - 1 without checking + // for wrap around. + // + cluster_catchup_slave(config->cluster_seq_number - 1, addr); + return -1; // Skip it. } + // + // Try and guard against a stray master appearing. + // + // Ignore heartbeats received from another master before the + // timeout (less a smidgen) for the old master has elapsed. + // + // Note that after a clean failover, the cluster_master_address + // is cleared, so this doesn't run. + // + if (config->cluster_master_address && addr != config->cluster_master_address + && (config->cluster_last_hb + config->cluster_hb_timeout - 11) > TIME) { + LOG(0, 0, 0, "Ignoring stray heartbeat from %s, current master %s has not yet timed out (last heartbeat %.1f seconds ago).\n", + fmtaddr(addr, 0), fmtaddr(config->cluster_master_address, 1), + 0.1 * (TIME - config->cluster_last_hb)); + return -1; // ignore + } + if (config->cluster_seq_number == -1) // Don't have one. Just align to the master... config->cluster_seq_number = h->seq; config->cluster_last_hb = TIME; // Reset to ensure that we don't become master!! if (config->cluster_seq_number != h->seq) { // Out of sequence heartbeat! - LOG(1, 0, 0, "HB: Got seq# %d but was expecting %d. asking for resend.\n", h->seq, config->cluster_seq_number); + static int lastseen_seq = 0; + static time_t lastseen_time = 0; + + // limit to once per second for a particular seq# + int ask = (config->cluster_seq_number != lastseen_seq || time_now != lastseen_time); + + LOG(1, 0, 0, "HB: Got seq# %d but was expecting %d. %s.\n", + h->seq, config->cluster_seq_number, + ask ? "Asking for resend" : "Ignoring"); - peer_send_message(addr, C_LASTSEEN, config->cluster_seq_number, NULL, 0); + if (ask) + { + lastseen_seq = config->cluster_seq_number; + lastseen_time = time_now; + peer_send_message(addr, C_LASTSEEN, config->cluster_seq_number, NULL, 0); + } config->cluster_last_hb = TIME; // Reset to ensure that we don't become master!! @@ -1335,10 +1409,13 @@ int processcluster(char *data, int size, in_addr_t addr) s -= sizeof(uint32_t); switch (type) { - case C_PING: // Update the peers table. + case C_PING: // Update the peers table. return cluster_add_peer(addr, more, (pingt *) p, s); - case C_LASTSEEN: // Catch up a slave (slave missed a packet). + case C_MASTER: // Our master is wrong + return cluster_set_master(addr, more); + + case C_LASTSEEN: // Catch up a slave (slave missed a packet). return cluster_catchup_slave(more, addr); case C_FORWARD: { // Forwarded control packet. pass off to processudp. @@ -1379,6 +1456,11 @@ int processcluster(char *data, int size, in_addr_t addr) return 0; case C_BYTES: + if (!config->cluster_iam_master) { + LOG(0, 0, 0, "I'm not the master, but I got a C_BYTES from %s?\n", fmtaddr(addr, 0)); + return -1; + } + return cluster_handle_bytes(p, s); case C_KILL: // The master asked us to die!? (usually because we're too out of date).