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"
2017-09-04 09:00:48 +03:00
# include "protocol/protocol_util.h"
2016-05-26 08:31:47 +03:00
2015-11-23 08:18:16 +03:00
# 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 .
*/
2019-05-30 08:37:38 +03:00
int node_ip_coverage ( uint32_t pnn , struct public_ip_list * ips )
2015-11-23 08:18:16 +03:00
{
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 )
{
2016-12-02 06:21:59 +03:00
return bitmap_query ( ip - > available_on , pnn ) ;
2015-11-23 08:18:16 +03:00
}
bool can_node_takeover_ip ( struct ipalloc_state * ipalloc_state ,
int32_t pnn ,
struct public_ip_list * ip )
{
2016-12-10 11:39:11 +03:00
if ( ipalloc_state - > no_ip_takeover ) {
2015-11-23 08:18:16 +03:00
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 )
{
2019-05-30 08:37:38 +03:00
unsigned int pnn ;
int min = 0 , num ;
unsigned int i , numnodes ;
2015-11-23 08:18:16 +03:00
numnodes = ipalloc_state - > num ;
2019-05-30 08:40:42 +03:00
pnn = CTDB_UNKNOWN_PNN ;
2015-11-23 08:18:16 +03:00
for ( i = 0 ; i < numnodes ; i + + ) {
/* verify that this node can serve this ip */
if ( ! can_node_takeover_ip ( ipalloc_state , i , ip ) ) {
2023-03-22 11:36:23 +03:00
/* no it couldn't so skip to the next node */
2015-11-23 08:18:16 +03:00
continue ;
}
num = node_ip_coverage ( i , ipalloc_state - > all_ips ) ;
/* was this the first node we checked ? */
2019-05-30 08:40:42 +03:00
if ( pnn = = CTDB_UNKNOWN_PNN ) {
2015-11-23 08:18:16 +03:00
pnn = i ;
min = num ;
} else {
if ( num < min ) {
pnn = i ;
min = num ;
}
}
}
2019-05-30 08:40:42 +03:00
if ( pnn = = CTDB_UNKNOWN_PNN ) {
2015-11-23 08:18:16 +03:00
DEBUG ( DEBUG_WARNING , ( __location__ " Could not find node to take over public address '%s' \n " ,
2016-05-26 08:31:47 +03:00
ctdb_sock_addr_to_string ( ipalloc_state ,
2017-09-11 08:00:10 +03:00
& ip - > addr ,
false ) ) ) ;
2015-11-23 08:18:16 +03:00
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 ) {
2019-05-30 08:40:42 +03:00
if ( t - > pnn = = CTDB_UNKNOWN_PNN ) {
2015-11-23 08:18:16 +03:00
if ( find_takeover_node ( ipalloc_state , t ) ) {
DEBUG ( DEBUG_WARNING ,
( " Failed to find node to cover ip %s \n " ,
2016-05-26 08:31:47 +03:00
ctdb_sock_addr_to_string ( ipalloc_state ,
2017-09-11 08:00:10 +03:00
& t - > addr ,
false ) ) ) ;
2015-11-23 08:18:16 +03:00
}
}
}
}
void unassign_unsuitable_ips ( struct ipalloc_state * ipalloc_state )
{
struct public_ip_list * t ;
/* verify that the assigned nodes can serve that public ip
2019-05-30 08:40:42 +03:00
and set it to CTDB_UNKNOWN_PNN if not
2015-11-23 08:18:16 +03:00
*/
for ( t = ipalloc_state - > all_ips ; t ! = NULL ; t = t - > next ) {
2019-05-30 08:40:42 +03:00
if ( t - > pnn = = CTDB_UNKNOWN_PNN ) {
2015-11-23 08:18:16 +03:00
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 " ,
2017-09-11 08:00:10 +03:00
ctdb_sock_addr_to_string (
ipalloc_state ,
& t - > addr , false ) ,
2015-11-23 08:18:16 +03:00
t - > pnn ) ) ;
2019-05-30 08:40:42 +03:00
t - > pnn = CTDB_UNKNOWN_PNN ;
2015-11-23 08:18:16 +03:00
}
}
}