2015-11-23 08:18:16 +03:00
/*
ctdb ip takeover code
Copyright ( C ) Ronnie Sahlberg 2007
Copyright ( C ) Andrew Tridgell 2007
Copyright ( C ) Martin Schwenke 2011
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "replace.h"
# include "system/network.h"
# include "ctdb_private.h"
# include "lib/util/time.h"
# include "lib/util/debug.h"
# include "common/logging.h"
# include "common/common.h"
# include "common/rb_tree.h"
# include "server/ipalloc_private.h"
# define TAKEOVER_TIMEOUT() timeval_current_ofs(ctdb->tunable.takeover_timeout,0)
/* Given a physical node, return the number of
public addresses that is currently assigned to this node .
*/
int node_ip_coverage ( int32_t pnn , struct public_ip_list * ips )
{
int num = 0 ;
for ( ; ips ; ips = ips - > next ) {
if ( ips - > pnn = = pnn ) {
num + + ;
}
}
return num ;
}
/* Can the given node host the given IP: is the public IP known to the
* node and is NOIPHOST unset ?
*/
static bool can_node_host_ip ( struct ipalloc_state * ipalloc_state ,
int32_t pnn ,
struct public_ip_list * ip )
{
2015-12-01 08:12:03 +03:00
struct ctdb_public_ip_list * public_ips ;
2015-11-23 08:18:16 +03:00
int i ;
if ( ipalloc_state - > noiphost [ pnn ] ) {
return false ;
}
2016-02-16 13:18:40 +03:00
if ( ipalloc_state - > available_public_ips = = NULL ) {
2015-11-23 08:18:16 +03:00
return false ;
}
2016-02-16 13:18:40 +03:00
public_ips = & ipalloc_state - > available_public_ips [ pnn ] ;
2015-11-23 08:18:16 +03:00
for ( i = 0 ; i < public_ips - > num ; i + + ) {
2015-12-01 08:12:03 +03:00
if ( ctdb_same_ip ( & ip - > addr , & public_ips - > ip [ i ] . addr ) ) {
2015-11-23 08:18:16 +03:00
/* yes, this node can serve this public ip */
return true ;
}
}
return false ;
}
bool can_node_takeover_ip ( struct ipalloc_state * ipalloc_state ,
int32_t pnn ,
struct public_ip_list * ip )
{
if ( ipalloc_state - > noiptakeover [ pnn ] ) {
return false ;
}
return can_node_host_ip ( ipalloc_state , pnn , ip ) ;
}
/* search the node lists list for a node to takeover this ip.
pick the node that currently are serving the least number of ips
so that the ips get spread out evenly .
*/
int find_takeover_node ( struct ipalloc_state * ipalloc_state ,
struct public_ip_list * ip )
{
int pnn , min = 0 , num ;
int i , numnodes ;
numnodes = ipalloc_state - > num ;
pnn = - 1 ;
for ( i = 0 ; i < numnodes ; i + + ) {
/* verify that this node can serve this ip */
if ( ! can_node_takeover_ip ( ipalloc_state , i , ip ) ) {
/* no it couldnt so skip to the next node */
continue ;
}
num = node_ip_coverage ( i , ipalloc_state - > all_ips ) ;
/* was this the first node we checked ? */
if ( pnn = = - 1 ) {
pnn = i ;
min = num ;
} else {
if ( num < min ) {
pnn = i ;
min = num ;
}
}
}
if ( pnn = = - 1 ) {
DEBUG ( DEBUG_WARNING , ( __location__ " Could not find node to take over public address '%s' \n " ,
ctdb_addr_to_str ( & ip - > addr ) ) ) ;
return - 1 ;
}
ip - > pnn = pnn ;
return 0 ;
}
uint32_t * ip_key ( ctdb_sock_addr * ip )
{
static uint32_t key [ IP_KEYLEN ] ;
bzero ( key , sizeof ( key ) ) ;
switch ( ip - > sa . sa_family ) {
case AF_INET :
key [ 3 ] = htonl ( ip - > ip . sin_addr . s_addr ) ;
break ;
case AF_INET6 : {
uint32_t * s6_a32 = ( uint32_t * ) & ( ip - > ip6 . sin6_addr . s6_addr ) ;
key [ 0 ] = htonl ( s6_a32 [ 0 ] ) ;
key [ 1 ] = htonl ( s6_a32 [ 1 ] ) ;
key [ 2 ] = htonl ( s6_a32 [ 2 ] ) ;
key [ 3 ] = htonl ( s6_a32 [ 3 ] ) ;
break ;
}
default :
DEBUG ( DEBUG_ERR , ( __location__ " ERROR, unknown family passed :%u \n " , ip - > sa . sa_family ) ) ;
return key ;
}
return key ;
}
/* Allocate any unassigned IPs just by looping through the IPs and
* finding the best node for each .
*/
void basic_allocate_unassigned ( struct ipalloc_state * ipalloc_state )
{
struct public_ip_list * t ;
/* loop over all ip's and find a physical node to cover for
each unassigned ip .
*/
for ( t = ipalloc_state - > all_ips ; t ! = NULL ; t = t - > next ) {
if ( t - > pnn = = - 1 ) {
if ( find_takeover_node ( ipalloc_state , t ) ) {
DEBUG ( DEBUG_WARNING ,
( " Failed to find node to cover ip %s \n " ,
ctdb_addr_to_str ( & t - > addr ) ) ) ;
}
}
}
}
void unassign_unsuitable_ips ( struct ipalloc_state * ipalloc_state )
{
struct public_ip_list * t ;
/* verify that the assigned nodes can serve that public ip
and set it to - 1 if not
*/
for ( t = ipalloc_state - > all_ips ; t ! = NULL ; t = t - > next ) {
if ( t - > pnn = = - 1 ) {
continue ;
}
if ( ! can_node_host_ip ( ipalloc_state , t - > pnn , t ) ! = 0 ) {
/* this node can not serve this ip. */
DEBUG ( DEBUG_DEBUG , ( " Unassign IP: %s from %d \n " ,
ctdb_addr_to_str ( & ( t - > addr ) ) ,
t - > pnn ) ) ;
t - > pnn = - 1 ;
}
}
}