2007-05-25 11:16:50 +04:00
/*
2007-09-04 08:36:52 +04:00
ctdb ip takeover code
2007-05-25 11:16:50 +04:00
Copyright ( C ) Ronnie Sahlberg 2007
Copyright ( C ) Andrew Tridgell 2007
2011-07-28 09:16:46 +04:00
Copyright ( C ) Martin Schwenke 2011
2007-05-25 11:16:50 +04:00
2007-05-31 07:50:53 +04:00
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
2007-07-10 09:29:31 +04:00
the Free Software Foundation ; either version 3 of the License , or
2007-05-31 07:50:53 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
2007-05-25 11:16:50 +04:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2007-05-31 07:50:53 +04:00
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
2007-07-10 09:29:31 +04:00
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2007-05-25 11:16:50 +04:00
*/
2015-10-26 08:50:46 +03:00
# include "replace.h"
2007-05-25 11:16:50 +04:00
# include "system/network.h"
# include "system/filesys.h"
2015-10-26 08:50:46 +03:00
# include "system/time.h"
2007-05-25 11:16:50 +04:00
# include "system/wait.h"
2015-10-26 08:50:46 +03:00
# include <talloc.h>
# include <tevent.h>
# include "lib/util/dlinklist.h"
# include "lib/util/debug.h"
# include "lib/util/samba_util.h"
2024-04-10 14:02:39 +03:00
# include "lib/util/util_file.h"
2016-11-29 04:55:06 +03:00
# include "lib/util/sys_rw.h"
2015-09-24 02:10:59 +03:00
# include "lib/util/util_process.h"
2015-10-26 08:50:46 +03:00
2018-06-08 00:27:07 +03:00
# include "protocol/protocol_util.h"
2015-10-26 08:50:46 +03:00
# include "ctdb_private.h"
# include "ctdb_client.h"
2015-03-17 06:30:18 +03:00
# include "common/reqid.h"
2015-10-23 06:11:53 +03:00
# include "common/system.h"
2018-06-28 13:15:37 +03:00
# include "common/system_socket.h"
2015-10-23 06:17:34 +03:00
# include "common/common.h"
2015-11-11 07:41:10 +03:00
# include "common/logging.h"
2024-08-06 06:49:01 +03:00
# include "common/path.h"
2007-05-25 11:16:50 +04:00
2019-08-19 05:06:40 +03:00
# include "conf/ctdb_config.h"
2018-08-21 06:41:22 +03:00
2015-11-23 08:18:16 +03:00
# include "server/ipalloc.h"
2007-05-25 11:16:50 +04:00
2007-06-05 11:43:19 +04:00
# define TAKEOVER_TIMEOUT() timeval_current_ofs(ctdb->tunable.takeover_timeout,0)
2007-05-25 11:16:50 +04:00
2007-05-27 09:26:29 +04:00
# define CTDB_ARP_INTERVAL 1
# define CTDB_ARP_REPEAT 3
2007-05-25 15:27:26 +04:00
2015-10-28 09:34:24 +03:00
struct ctdb_interface {
struct ctdb_interface * prev , * next ;
2009-12-16 12:39:40 +03:00
const char * name ;
bool link_up ;
uint32_t references ;
} ;
2016-08-24 11:21:51 +03:00
struct vnn_interface {
struct vnn_interface * prev , * next ;
struct ctdb_interface * iface ;
} ;
2016-06-13 23:44:29 +03:00
/* state associated with a public ip address */
struct ctdb_vnn {
struct ctdb_vnn * prev , * next ;
struct ctdb_interface * iface ;
2016-08-24 11:21:51 +03:00
struct vnn_interface * ifaces ;
2016-06-13 23:44:29 +03:00
ctdb_sock_addr public_address ;
uint8_t public_netmask_bits ;
2024-07-25 07:40:18 +03:00
const char * name ;
2016-06-13 23:44:29 +03:00
2019-06-07 23:38:56 +03:00
/*
* The node number that is serving this public address - set
2024-07-25 06:41:35 +03:00
* to CTDB_UNKNOWN_PNN if no node is serving it
2019-06-07 23:38:56 +03:00
*/
uint32_t pnn ;
2016-06-13 23:44:29 +03:00
/* List of clients to tickle for this public address */
struct ctdb_tcp_array * tcp_array ;
/* whether we need to update the other nodes with changes to our list
of connected clients */
bool tcp_update_needed ;
/* a context to hang sending gratious arp events off */
TALLOC_CTX * takeover_ctx ;
/* Set to true any time an update to this VNN is in flight.
This helps to avoid races . */
bool update_in_flight ;
/* If CTDB_CONTROL_DEL_PUBLIC_IP is received for this IP
* address then this flag is set . It will be deleted in the
* release IP callback . */
bool delete_pending ;
} ;
2016-07-29 12:48:37 +03:00
static const char * iface_string ( const struct ctdb_interface * iface )
2009-12-16 10:54:02 +03:00
{
2016-07-29 12:48:37 +03:00
return ( iface ! = NULL ? iface - > name : " __none__ " ) ;
}
2009-12-16 12:39:40 +03:00
2016-07-29 12:48:37 +03:00
static const char * ctdb_vnn_iface_string ( const struct ctdb_vnn * vnn )
{
return iface_string ( vnn - > iface ) ;
2009-12-16 12:39:40 +03:00
}
2024-07-25 07:47:06 +03:00
static const char * ctdb_vnn_address_string ( const struct ctdb_vnn * vnn )
{
return vnn - > name ;
}
2016-08-25 04:41:11 +03:00
static struct ctdb_interface * ctdb_find_iface ( struct ctdb_context * ctdb ,
const char * iface ) ;
2016-08-24 09:59:46 +03:00
static struct ctdb_interface *
ctdb_add_local_iface ( struct ctdb_context * ctdb , const char * iface )
2009-12-16 12:39:40 +03:00
{
2015-10-28 09:34:24 +03:00
struct ctdb_interface * i ;
2009-12-16 12:39:40 +03:00
2016-03-18 12:41:45 +03:00
if ( strlen ( iface ) > CTDB_IFACE_SIZE ) {
DEBUG ( DEBUG_ERR , ( " Interface name too long \" %s \" \n " , iface ) ) ;
2016-08-24 09:59:46 +03:00
return NULL ;
2016-03-18 12:41:45 +03:00
}
2015-07-27 00:02:57 +03:00
/* Verify that we don't have an entry for this ip yet */
2016-08-25 04:41:11 +03:00
i = ctdb_find_iface ( ctdb , iface ) ;
if ( i ! = NULL ) {
return i ;
2009-12-16 12:39:40 +03:00
}
/* create a new structure for this interface */
2015-10-28 09:34:24 +03:00
i = talloc_zero ( ctdb , struct ctdb_interface ) ;
2016-08-24 09:49:30 +03:00
if ( i = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " out of memory \n " ) ) ;
2016-08-24 09:59:46 +03:00
return NULL ;
2016-08-24 09:49:30 +03:00
}
2009-12-16 12:39:40 +03:00
i - > name = talloc_strdup ( i , iface ) ;
2016-08-24 09:49:30 +03:00
if ( i - > name = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " out of memory \n " ) ) ;
talloc_free ( i ) ;
2016-08-24 09:59:46 +03:00
return NULL ;
2016-08-24 09:49:30 +03:00
}
2015-05-08 10:11:24 +03:00
i - > link_up = true ;
2009-12-16 12:39:40 +03:00
DLIST_ADD ( ctdb - > ifaces , i ) ;
2016-08-24 09:59:46 +03:00
return i ;
2009-12-16 12:39:40 +03:00
}
2016-08-24 13:41:49 +03:00
static bool vnn_has_interface ( struct ctdb_vnn * vnn ,
const struct ctdb_interface * iface )
2012-11-23 13:09:07 +04:00
{
2016-08-24 11:21:51 +03:00
struct vnn_interface * i ;
2012-11-23 13:09:07 +04:00
2016-08-24 11:21:51 +03:00
for ( i = vnn - > ifaces ; i ! = NULL ; i = i - > next ) {
2016-08-24 13:41:49 +03:00
if ( iface = = i - > iface ) {
2012-11-23 13:09:07 +04:00
return true ;
}
}
return false ;
}
/* If any interfaces now have no possible IPs then delete them. This
* implementation is naive ( i . e . simple ) rather than clever
* ( i . e . complex ) . Given that this is run on delip and that operation
* is rare , this doesn ' t need to be efficient - it needs to be
* foolproof . One alternative is reference counting , where the logic
* is distributed and can , therefore , be broken in multiple places .
* Another alternative is to build a red - black tree of interfaces that
2016-04-11 01:02:36 +03:00
* can have addresses ( by walking ctdb - > vnn once ) and then walking
* ctdb - > ifaces once and deleting those not in the tree . Let ' s go to
* one of those if the naive implementation causes problems . . . : - )
2012-11-23 13:09:07 +04:00
*/
static void ctdb_remove_orphaned_ifaces ( struct ctdb_context * ctdb ,
2014-01-22 10:01:19 +04:00
struct ctdb_vnn * vnn )
2012-11-23 13:09:07 +04:00
{
2015-10-28 09:34:24 +03:00
struct ctdb_interface * i , * next ;
2012-11-23 13:09:07 +04:00
/* For each interface, check if there's an IP using it. */
2014-03-31 10:04:21 +04:00
for ( i = ctdb - > ifaces ; i ! = NULL ; i = next ) {
2012-11-23 13:09:07 +04:00
struct ctdb_vnn * tv ;
bool found ;
2014-03-31 10:04:21 +04:00
next = i - > next ;
2012-11-23 13:09:07 +04:00
/* Only consider interfaces named in the given VNN. */
2016-08-24 13:41:49 +03:00
if ( ! vnn_has_interface ( vnn , i ) ) {
2014-03-31 10:04:21 +04:00
continue ;
2012-11-23 13:09:07 +04:00
}
/* Search for a vnn with this interface. */
found = false ;
for ( tv = ctdb - > vnn ; tv ; tv = tv - > next ) {
2016-08-24 13:41:49 +03:00
if ( vnn_has_interface ( tv , i ) ) {
2012-11-23 13:09:07 +04:00
found = true ;
break ;
}
}
if ( ! found ) {
/* None of the VNNs are using this interface. */
DLIST_REMOVE ( ctdb - > ifaces , i ) ;
2014-01-22 10:01:19 +04:00
talloc_free ( i ) ;
2012-11-23 13:09:07 +04:00
}
}
}
2015-10-28 09:34:24 +03:00
static struct ctdb_interface * ctdb_find_iface ( struct ctdb_context * ctdb ,
const char * iface )
2009-12-16 12:39:40 +03:00
{
2015-10-28 09:34:24 +03:00
struct ctdb_interface * i ;
2009-12-16 12:39:40 +03:00
for ( i = ctdb - > ifaces ; i ; i = i - > next ) {
if ( strcmp ( i - > name , iface ) = = 0 ) {
return i ;
}
}
return NULL ;
}
2015-10-28 09:34:24 +03:00
static struct ctdb_interface * ctdb_vnn_best_iface ( struct ctdb_context * ctdb ,
struct ctdb_vnn * vnn )
2009-12-16 12:39:40 +03:00
{
2016-08-24 11:21:51 +03:00
struct vnn_interface * i ;
2015-10-28 09:34:24 +03:00
struct ctdb_interface * cur = NULL ;
struct ctdb_interface * best = NULL ;
2009-12-16 12:39:40 +03:00
2016-08-24 11:21:51 +03:00
for ( i = vnn - > ifaces ; i ! = NULL ; i = i - > next ) {
2009-12-16 12:39:40 +03:00
2016-08-24 13:38:03 +03:00
cur = i - > iface ;
2009-12-16 12:39:40 +03:00
if ( ! cur - > link_up ) {
continue ;
}
if ( best = = NULL ) {
best = cur ;
continue ;
}
if ( cur - > references < best - > references ) {
best = cur ;
continue ;
}
}
return best ;
}
static int32_t ctdb_vnn_assign_iface ( struct ctdb_context * ctdb ,
struct ctdb_vnn * vnn )
{
2015-10-28 09:34:24 +03:00
struct ctdb_interface * best = NULL ;
2009-12-16 12:39:40 +03:00
if ( vnn - > iface ) {
2024-07-25 07:50:32 +03:00
DBG_INFO ( " public address '%s' still assigned to iface '%s' \n " ,
ctdb_vnn_address_string ( vnn ) ,
ctdb_vnn_iface_string ( vnn ) ) ;
2009-12-16 12:39:40 +03:00
return 0 ;
}
best = ctdb_vnn_best_iface ( ctdb , vnn ) ;
if ( best = = NULL ) {
2024-07-25 07:50:32 +03:00
DBG_ERR ( " public address '%s' cannot assign to iface any iface \n " ,
ctdb_vnn_address_string ( vnn ) ) ;
2009-12-16 12:39:40 +03:00
return - 1 ;
}
vnn - > iface = best ;
best - > references + + ;
vnn - > pnn = ctdb - > pnn ;
2024-07-25 07:50:32 +03:00
DBG_INFO ( " public address '%s' now assigned to iface '%s' refs[%d] \n " ,
ctdb_vnn_address_string ( vnn ) ,
ctdb_vnn_iface_string ( vnn ) ,
best - > references ) ;
2009-12-16 12:39:40 +03:00
return 0 ;
}
static void ctdb_vnn_unassign_iface ( struct ctdb_context * ctdb ,
struct ctdb_vnn * vnn )
{
2024-07-25 07:50:32 +03:00
DBG_INFO ( " public address '%s' "
" now unassigned (old iface '%s' refs[%d]) \n " ,
ctdb_vnn_address_string ( vnn ) ,
ctdb_vnn_iface_string ( vnn ) ,
vnn - > iface ! = NULL ? vnn - > iface - > references : 0 ) ;
2009-12-16 12:39:40 +03:00
if ( vnn - > iface ) {
vnn - > iface - > references - - ;
}
vnn - > iface = NULL ;
if ( vnn - > pnn = = ctdb - > pnn ) {
2019-06-07 23:40:40 +03:00
vnn - > pnn = CTDB_UNKNOWN_PNN ;
2009-12-16 12:39:40 +03:00
}
2009-12-16 10:54:02 +03:00
}
2009-12-16 18:08:45 +03:00
static bool ctdb_vnn_available ( struct ctdb_context * ctdb ,
struct ctdb_vnn * vnn )
{
2018-06-18 09:22:14 +03:00
uint32_t flags ;
2016-08-24 11:21:51 +03:00
struct vnn_interface * i ;
2009-12-16 18:08:45 +03:00
2015-10-28 12:41:08 +03:00
/* Nodes that are not RUNNING can not host IPs */
if ( ctdb - > runstate ! = CTDB_RUNSTATE_RUNNING ) {
return false ;
}
2018-06-18 09:22:14 +03:00
flags = ctdb - > nodes [ ctdb - > pnn ] - > flags ;
if ( ( flags & ( NODE_FLAGS_INACTIVE | NODE_FLAGS_DISABLED ) ) ! = 0 ) {
return false ;
}
2014-01-22 06:30:47 +04:00
if ( vnn - > delete_pending ) {
return false ;
}
2009-12-16 18:08:45 +03:00
if ( vnn - > iface & & vnn - > iface - > link_up ) {
return true ;
}
2016-08-24 11:21:51 +03:00
for ( i = vnn - > ifaces ; i ! = NULL ; i = i - > next ) {
2016-08-24 13:38:03 +03:00
if ( i - > iface - > link_up ) {
2009-12-16 18:08:45 +03:00
return true ;
}
}
return false ;
}
2007-05-25 15:27:26 +04:00
struct ctdb_takeover_arp {
struct ctdb_context * ctdb ;
uint32_t count ;
2008-06-04 09:13:00 +04:00
ctdb_sock_addr addr ;
2007-07-24 01:46:51 +04:00
struct ctdb_tcp_array * tcparray ;
2007-09-04 03:50:07 +04:00
struct ctdb_vnn * vnn ;
2007-05-25 15:27:26 +04:00
} ;
2007-07-20 04:06:41 +04:00
2007-05-27 09:26:29 +04:00
/*
lists of tcp endpoints
*/
struct ctdb_tcp_list {
struct ctdb_tcp_list * prev , * next ;
2023-11-16 13:56:59 +03:00
struct ctdb_client * client ;
2015-10-28 10:14:21 +03:00
struct ctdb_connection connection ;
2007-05-27 09:26:29 +04:00
} ;
2007-05-25 15:27:26 +04:00
/*
send a gratuitous arp
*/
2015-10-26 08:50:09 +03:00
static void ctdb_control_send_arp ( struct tevent_context * ev ,
struct tevent_timer * te ,
2007-05-25 15:27:26 +04:00
struct timeval t , void * private_data )
{
struct ctdb_takeover_arp * arp = talloc_get_type ( private_data ,
struct ctdb_takeover_arp ) ;
2019-06-07 23:38:56 +03:00
int ret ;
2007-07-24 01:46:51 +04:00
struct ctdb_tcp_array * tcparray ;
2022-06-23 07:30:34 +03:00
const char * iface ;
/* IP address might have been released between sends */
if ( arp - > vnn - > iface = = NULL ) {
DBG_INFO ( " Cancelling ARP send for released IP %s \n " ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( arp - > vnn ) ) ;
2022-06-23 07:30:34 +03:00
talloc_free ( arp ) ;
return ;
}
2007-07-24 01:46:51 +04:00
2022-06-23 07:30:34 +03:00
iface = ctdb_vnn_iface_string ( arp - > vnn ) ;
2009-12-16 10:54:02 +03:00
ret = ctdb_sys_send_arp ( & arp - > addr , iface ) ;
2007-05-25 15:27:26 +04:00
if ( ret ! = 0 ) {
2018-08-10 10:23:56 +03:00
DBG_ERR ( " Failed to send ARP on interface %s: %s \n " ,
iface , strerror ( ret ) ) ;
2007-05-25 15:27:26 +04:00
}
2007-07-24 01:46:51 +04:00
tcparray = arp - > tcparray ;
if ( tcparray ) {
2019-06-07 23:38:56 +03:00
unsigned int i ;
2007-07-24 01:46:51 +04:00
for ( i = 0 ; i < tcparray - > num ; i + + ) {
2015-10-28 10:14:21 +03:00
struct ctdb_connection * tcon ;
2022-07-05 12:33:15 +03:00
char buf [ 128 ] ;
2008-08-19 08:58:29 +04:00
tcon = & tcparray - > connections [ i ] ;
2022-07-05 12:33:15 +03:00
ret = ctdb_connection_to_buf ( buf ,
sizeof ( buf ) ,
tcon ,
2022-07-05 12:33:15 +03:00
false ,
2022-07-05 12:33:15 +03:00
" -> " ) ;
if ( ret ! = 0 ) {
strlcpy ( buf , " UNKNOWN " , sizeof ( buf ) ) ;
}
D_INFO ( " Send TCP tickle ACK: %s \n " , buf ) ;
2008-05-14 09:47:47 +04:00
ret = ctdb_sys_send_tcp (
2015-10-28 10:14:21 +03:00
& tcon - > src ,
& tcon - > dst ,
2008-05-14 09:47:47 +04:00
0 , 0 , 0 ) ;
2007-07-24 01:46:51 +04:00
if ( ret ! = 0 ) {
2022-07-05 12:33:15 +03:00
DBG_ERR ( " Failed to send TCP tickle ACK: %s \n " ,
buf ) ;
2007-07-24 01:46:51 +04:00
}
2007-05-27 09:26:29 +04:00
}
}
2007-05-25 15:27:26 +04:00
arp - > count + + ;
if ( arp - > count = = CTDB_ARP_REPEAT ) {
talloc_free ( arp ) ;
return ;
}
2007-07-12 03:22:06 +04:00
2015-10-26 08:50:09 +03:00
tevent_add_timer ( arp - > ctdb - > ev , arp - > vnn - > takeover_ctx ,
timeval_current_ofs ( CTDB_ARP_INTERVAL , 100000 ) ,
ctdb_control_send_arp , arp ) ;
2007-05-25 15:27:26 +04:00
}
2010-01-16 15:20:45 +03:00
static int32_t ctdb_announce_vnn_iface ( struct ctdb_context * ctdb ,
struct ctdb_vnn * vnn )
{
struct ctdb_takeover_arp * arp ;
struct ctdb_tcp_array * tcparray ;
if ( ! vnn - > takeover_ctx ) {
vnn - > takeover_ctx = talloc_new ( vnn ) ;
if ( ! vnn - > takeover_ctx ) {
return - 1 ;
}
}
arp = talloc_zero ( vnn - > takeover_ctx , struct ctdb_takeover_arp ) ;
if ( ! arp ) {
return - 1 ;
}
arp - > ctdb = ctdb ;
arp - > addr = vnn - > public_address ;
arp - > vnn = vnn ;
tcparray = vnn - > tcp_array ;
if ( tcparray ) {
/* add all of the known tcp connections for this IP to the
list of tcp connections to send tickle acks for */
arp - > tcparray = talloc_steal ( arp , tcparray ) ;
vnn - > tcp_array = NULL ;
vnn - > tcp_update_needed = true ;
}
2015-10-26 08:50:09 +03:00
tevent_add_timer ( arp - > ctdb - > ev , vnn - > takeover_ctx ,
timeval_zero ( ) , ctdb_control_send_arp , arp ) ;
2010-01-16 15:20:45 +03:00
return 0 ;
}
2010-01-16 15:30:58 +03:00
struct ctdb_do_takeip_state {
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ;
2010-01-16 15:30:58 +03:00
struct ctdb_vnn * vnn ;
} ;
2007-05-25 11:16:50 +04:00
/*
2007-06-01 13:05:41 +04:00
called when takeip event finishes
2007-05-25 11:16:50 +04:00
*/
2010-01-16 15:30:58 +03:00
static void ctdb_do_takeip_callback ( struct ctdb_context * ctdb , int status ,
void * private_data )
2007-05-25 11:16:50 +04:00
{
2010-01-16 15:30:58 +03:00
struct ctdb_do_takeip_state * state =
talloc_get_type ( private_data , struct ctdb_do_takeip_state ) ;
2010-01-16 15:20:45 +03:00
int32_t ret ;
2010-09-13 09:42:00 +04:00
TDB_DATA data ;
2007-05-25 11:16:50 +04:00
2007-06-01 13:05:41 +04:00
if ( status ! = 0 ) {
2018-07-10 11:18:33 +03:00
if ( status = = - ETIMEDOUT ) {
2009-12-07 16:18:57 +03:00
ctdb_ban_self ( ctdb ) ;
}
2024-07-25 07:50:32 +03:00
DBG_ERR ( " Failed to takeover IP %s on interface %s \n " ,
ctdb_vnn_address_string ( state - > vnn ) ,
ctdb_vnn_iface_string ( state - > vnn ) ) ;
2007-06-01 13:05:41 +04:00
ctdb_request_control_reply ( ctdb , state - > c , NULL , status , NULL ) ;
2011-04-10 23:56:14 +04:00
2007-06-01 13:05:41 +04:00
talloc_free ( state ) ;
return ;
2007-05-26 08:01:08 +04:00
}
2007-05-25 11:16:50 +04:00
2012-04-04 08:42:56 +04:00
if ( ctdb - > do_checkpublicip ) {
2010-01-16 15:20:45 +03:00
ret = ctdb_announce_vnn_iface ( ctdb , state - > vnn ) ;
if ( ret ! = 0 ) {
ctdb_request_control_reply ( ctdb , state - > c , NULL , - 1 , NULL ) ;
talloc_free ( state ) ;
return ;
2007-05-27 09:26:29 +04:00
}
2012-04-04 08:42:56 +04:00
}
2024-07-25 07:47:06 +03:00
data . dptr = ( uint8_t * ) discard_const (
ctdb_vnn_address_string ( state - > vnn ) ) ;
2010-09-13 09:42:00 +04:00
data . dsize = strlen ( ( char * ) data . dptr ) + 1 ;
DEBUG ( DEBUG_INFO , ( __location__ " sending TAKE_IP for '%s' \n " , data . dptr ) ) ;
ctdb_daemon_send_message ( ctdb , ctdb - > pnn , CTDB_SRVID_TAKE_IP , data ) ;
2007-06-01 13:05:41 +04:00
/* the control succeeded */
ctdb_request_control_reply ( ctdb , state - > c , NULL , 0 , NULL ) ;
talloc_free ( state ) ;
return ;
2007-05-25 11:16:50 +04:00
}
2012-07-11 08:46:07 +04:00
static int ctdb_takeip_destructor ( struct ctdb_do_takeip_state * state )
{
state - > vnn - > update_in_flight = false ;
return 0 ;
}
2010-01-16 15:30:58 +03:00
/*
take over an ip address
*/
static int32_t ctdb_do_takeip ( struct ctdb_context * ctdb ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ,
2010-01-16 15:30:58 +03:00
struct ctdb_vnn * vnn )
{
int ret ;
struct ctdb_do_takeip_state * state ;
2012-07-11 08:46:07 +04:00
if ( vnn - > update_in_flight ) {
2024-07-25 07:50:32 +03:00
D_NOTICE ( " Takeover of IP %s/%u rejected "
" update for this IP already in flight \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ) ;
2012-07-11 08:46:07 +04:00
return - 1 ;
}
2010-01-16 15:30:58 +03:00
ret = ctdb_vnn_assign_iface ( ctdb , vnn ) ;
if ( ret ! = 0 ) {
2024-07-25 07:50:32 +03:00
D_ERR ( " Takeover of IP %s/%u failed to "
" assign a usable interface \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ) ;
2010-01-16 15:30:58 +03:00
return - 1 ;
}
state = talloc ( vnn , struct ctdb_do_takeip_state ) ;
CTDB_NO_MEMORY ( ctdb , state ) ;
2016-08-31 01:29:13 +03:00
state - > c = NULL ;
2010-01-16 15:30:58 +03:00
state - > vnn = vnn ;
2012-07-11 08:46:07 +04:00
vnn - > update_in_flight = true ;
talloc_set_destructor ( state , ctdb_takeip_destructor ) ;
2024-07-25 07:50:32 +03:00
D_NOTICE ( " Takeover of IP %s/%u on interface %s \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ,
ctdb_vnn_iface_string ( vnn ) ) ;
2010-01-16 15:30:58 +03:00
ret = ctdb_event_script_callback ( ctdb ,
state ,
ctdb_do_takeip_callback ,
state ,
CTDB_EVENT_TAKE_IP ,
" %s %s %u " ,
ctdb_vnn_iface_string ( vnn ) ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ,
2010-01-16 15:30:58 +03:00
vnn - > public_netmask_bits ) ;
if ( ret ! = 0 ) {
2024-07-25 07:50:32 +03:00
DBG_ERR ( " Failed to takeover IP %s on interface %s \n " ,
ctdb_vnn_address_string ( vnn ) ,
ctdb_vnn_iface_string ( vnn ) ) ;
2010-01-16 15:30:58 +03:00
talloc_free ( state ) ;
return - 1 ;
}
2016-08-31 01:29:13 +03:00
state - > c = talloc_steal ( ctdb , c ) ;
2010-01-16 15:30:58 +03:00
return 0 ;
}
2010-01-16 17:01:17 +03:00
struct ctdb_do_updateip_state {
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ;
2015-10-28 09:34:24 +03:00
struct ctdb_interface * old ;
2010-01-16 17:01:17 +03:00
struct ctdb_vnn * vnn ;
} ;
/*
called when updateip event finishes
*/
static void ctdb_do_updateip_callback ( struct ctdb_context * ctdb , int status ,
void * private_data )
{
struct ctdb_do_updateip_state * state =
talloc_get_type ( private_data , struct ctdb_do_updateip_state ) ;
if ( status ! = 0 ) {
2018-07-10 11:18:33 +03:00
if ( status = = - ETIMEDOUT ) {
2010-01-16 17:01:17 +03:00
ctdb_ban_self ( ctdb ) ;
}
2024-07-25 07:50:32 +03:00
D_ERR ( " Failed update of IP %s from interface %s to %s \n " ,
ctdb_vnn_address_string ( state - > vnn ) ,
iface_string ( state - > old ) ,
ctdb_vnn_iface_string ( state - > vnn ) ) ;
2010-01-16 17:01:17 +03:00
/*
* All we can do is reset the old interface
* and let the next run fix it
*/
ctdb_vnn_unassign_iface ( ctdb , state - > vnn ) ;
state - > vnn - > iface = state - > old ;
state - > vnn - > iface - > references + + ;
ctdb_request_control_reply ( ctdb , state - > c , NULL , status , NULL ) ;
talloc_free ( state ) ;
return ;
}
/* the control succeeded */
ctdb_request_control_reply ( ctdb , state - > c , NULL , 0 , NULL ) ;
talloc_free ( state ) ;
return ;
}
2012-07-11 08:46:07 +04:00
static int ctdb_updateip_destructor ( struct ctdb_do_updateip_state * state )
{
state - > vnn - > update_in_flight = false ;
return 0 ;
}
2010-01-16 17:01:17 +03:00
/*
update ( move ) an ip address
*/
static int32_t ctdb_do_updateip ( struct ctdb_context * ctdb ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ,
2010-01-16 17:01:17 +03:00
struct ctdb_vnn * vnn )
{
int ret ;
struct ctdb_do_updateip_state * state ;
2015-10-28 09:34:24 +03:00
struct ctdb_interface * old = vnn - > iface ;
2016-07-29 12:48:37 +03:00
const char * old_name = iface_string ( old ) ;
2011-08-22 18:40:58 +04:00
const char * new_name ;
2010-01-16 17:01:17 +03:00
2012-07-11 08:46:07 +04:00
if ( vnn - > update_in_flight ) {
2024-07-25 07:50:32 +03:00
D_NOTICE ( " Update of IP %s/%u rejected "
" update for this IP already in flight \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ) ;
2012-07-11 08:46:07 +04:00
return - 1 ;
}
2010-01-16 17:01:17 +03:00
ctdb_vnn_unassign_iface ( ctdb , vnn ) ;
ret = ctdb_vnn_assign_iface ( ctdb , vnn ) ;
if ( ret ! = 0 ) {
2024-07-25 07:50:32 +03:00
D_ERR ( " Update of IP %s/%u failed to "
" assign a usable interface (old iface '%s') \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ,
old_name ) ;
2010-01-16 17:01:17 +03:00
return - 1 ;
}
2016-08-25 04:48:36 +03:00
if ( old = = vnn - > iface ) {
2011-05-04 05:34:17 +04:00
/* A benign update from one interface onto itself.
* no need to run the eventscripts in this case , just return
* success .
*/
ctdb_request_control_reply ( ctdb , c , NULL , 0 , NULL ) ;
return 0 ;
}
2010-01-16 17:01:17 +03:00
state = talloc ( vnn , struct ctdb_do_updateip_state ) ;
CTDB_NO_MEMORY ( ctdb , state ) ;
2016-08-31 01:29:13 +03:00
state - > c = NULL ;
2010-01-16 17:01:17 +03:00
state - > old = old ;
state - > vnn = vnn ;
2012-07-11 08:46:07 +04:00
vnn - > update_in_flight = true ;
talloc_set_destructor ( state , ctdb_updateip_destructor ) ;
2016-08-25 04:48:36 +03:00
new_name = ctdb_vnn_iface_string ( vnn ) ;
2024-07-25 07:50:32 +03:00
D_NOTICE ( " Update of IP %s/%u from "
" interface %s to %s \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ,
old_name ,
new_name ) ;
2010-01-16 17:01:17 +03:00
ret = ctdb_event_script_callback ( ctdb ,
state ,
ctdb_do_updateip_callback ,
state ,
CTDB_EVENT_UPDATE_IP ,
" %s %s %s %u " ,
2016-07-29 12:48:37 +03:00
old_name ,
2011-05-04 05:34:17 +04:00
new_name ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ,
2010-01-16 17:01:17 +03:00
vnn - > public_netmask_bits ) ;
if ( ret ! = 0 ) {
2024-07-25 07:50:32 +03:00
D_ERR ( " Failed update IP %s from interface %s to %s \n " ,
ctdb_vnn_address_string ( vnn ) ,
old_name ,
new_name ) ;
2010-01-16 17:01:17 +03:00
talloc_free ( state ) ;
return - 1 ;
}
2016-08-31 01:29:13 +03:00
state - > c = talloc_steal ( ctdb , c ) ;
2010-01-16 17:01:17 +03:00
return 0 ;
}
2007-07-20 04:06:41 +04:00
/*
2024-08-29 11:27:54 +03:00
* Find vnn that has public IP addr , return NULL if not found
2007-07-20 04:06:41 +04:00
*/
2024-08-29 11:27:54 +03:00
static struct ctdb_vnn * find_public_ip_vnn ( struct ctdb_context * ctdb ,
ctdb_sock_addr * addr )
2007-07-20 04:06:41 +04:00
{
2024-08-29 11:27:54 +03:00
struct ctdb_vnn * vnn = NULL ;
2007-07-20 04:06:41 +04:00
2024-08-29 11:27:54 +03:00
for ( vnn = ctdb - > vnn ; vnn ! = NULL ; vnn = vnn - > next ) {
2008-08-19 08:58:29 +04:00
if ( ctdb_same_ip ( & vnn - > public_address , addr ) ) {
2007-09-04 12:20:29 +04:00
return vnn ;
2007-07-20 04:06:41 +04:00
}
}
2007-09-04 03:50:07 +04:00
return NULL ;
2007-07-20 04:06:41 +04:00
}
2007-05-25 11:16:50 +04:00
/*
2007-06-01 13:05:41 +04:00
take over an ip address
2007-05-25 11:16:50 +04:00
*/
2010-01-16 15:30:58 +03:00
int32_t ctdb_control_takeover_ip ( struct ctdb_context * ctdb ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ,
2010-01-16 15:30:58 +03:00
TDB_DATA indata ,
2007-06-01 13:05:41 +04:00
bool * async_reply )
2007-05-25 11:16:50 +04:00
{
2007-06-01 13:05:41 +04:00
int ret ;
2007-06-04 14:07:37 +04:00
struct ctdb_public_ip * pip = ( struct ctdb_public_ip * ) indata . dptr ;
2007-09-04 03:50:07 +04:00
struct ctdb_vnn * vnn ;
2010-01-16 15:30:58 +03:00
bool have_ip = false ;
2010-01-16 17:01:17 +03:00
bool do_updateip = false ;
2010-01-16 15:30:58 +03:00
bool do_takeip = false ;
2015-10-28 09:34:24 +03:00
struct ctdb_interface * best_iface = NULL ;
2007-06-04 14:07:37 +04:00
2010-01-18 17:38:01 +03:00
if ( pip - > pnn ! = ctdb - > pnn ) {
DEBUG ( DEBUG_ERR , ( __location__ " takeoverip called for an ip '%s' "
" with pnn %d, but we're node %d \n " ,
ctdb_addr_to_str ( & pip - > addr ) ,
pip - > pnn , ctdb - > pnn ) ) ;
return - 1 ;
}
2007-09-04 03:50:07 +04:00
/* update out vnn list */
2008-08-19 08:58:29 +04:00
vnn = find_public_ip_vnn ( ctdb , & pip - > addr ) ;
2007-09-04 03:50:07 +04:00
if ( vnn = = NULL ) {
2010-01-16 15:30:58 +03:00
DEBUG ( DEBUG_INFO , ( " takeoverip called for an ip '%s' that is not a public address \n " ,
2008-08-19 08:58:29 +04:00
ctdb_addr_to_str ( & pip - > addr ) ) ) ;
2007-09-04 03:50:07 +04:00
return 0 ;
}
2007-05-26 08:01:08 +04:00
2018-08-21 06:41:22 +03:00
if ( ctdb_config . failover_disabled = = 0 & & ctdb - > do_checkpublicip ) {
2012-04-04 08:42:56 +04:00
have_ip = ctdb_sys_have_ip ( & pip - > addr ) ;
}
2010-01-18 17:08:15 +03:00
best_iface = ctdb_vnn_best_iface ( ctdb , vnn ) ;
if ( best_iface = = NULL ) {
2024-07-25 07:50:32 +03:00
D_ERR ( " takeoverip of IP %s/%u failed to find "
" a usable interface (old %s, have_ip %d) \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ,
ctdb_vnn_iface_string ( vnn ) ,
have_ip ) ;
2010-01-18 17:08:15 +03:00
return - 1 ;
}
2010-01-16 17:01:17 +03:00
2019-06-07 23:40:40 +03:00
if ( vnn - > pnn ! = ctdb - > pnn & & have_ip & & vnn - > pnn ! = CTDB_UNKNOWN_PNN ) {
2024-07-25 07:50:32 +03:00
DBG_ERR ( " takeoverip of IP %s is known to the kernel, "
" and we have it on iface[%s], "
" but it was assigned to node %d "
" and we are node %d, banning ourself \n " ,
ctdb_vnn_address_string ( vnn ) ,
ctdb_vnn_iface_string ( vnn ) ,
vnn - > pnn ,
ctdb - > pnn ) ;
2010-01-18 17:04:32 +03:00
ctdb_ban_self ( ctdb ) ;
return - 1 ;
}
2019-06-07 23:40:40 +03:00
if ( vnn - > pnn = = CTDB_UNKNOWN_PNN & & have_ip ) {
2016-08-03 04:05:06 +03:00
/* This will cause connections to be reset and
* reestablished . However , this is a very unusual
* situation and doing this will completely repair the
* inconsistency in the VNN .
*/
2024-07-25 07:50:32 +03:00
DBG_WARNING (
" Doing updateip for IP %s already on an interface \n " ,
ctdb_vnn_address_string ( vnn ) ) ;
2016-08-03 04:05:06 +03:00
do_updateip = true ;
2010-12-03 05:28:35 +03:00
}
2010-01-16 17:01:17 +03:00
if ( vnn - > iface ) {
2012-08-15 09:28:14 +04:00
if ( vnn - > iface ! = best_iface ) {
if ( ! vnn - > iface - > link_up ) {
2010-01-16 17:01:17 +03:00
do_updateip = true ;
2012-08-15 09:28:14 +04:00
} else if ( vnn - > iface - > references > ( best_iface - > references + 1 ) ) {
/* only move when the rebalance gains something */
do_updateip = true ;
2010-01-16 17:01:17 +03:00
}
}
}
2010-01-16 15:30:58 +03:00
if ( ! have_ip ) {
2010-01-16 17:01:17 +03:00
if ( do_updateip ) {
ctdb_vnn_unassign_iface ( ctdb , vnn ) ;
do_updateip = false ;
}
2010-01-16 15:30:58 +03:00
do_takeip = true ;
2009-12-16 12:39:40 +03:00
}
2010-01-16 15:30:58 +03:00
if ( do_takeip ) {
ret = ctdb_do_takeip ( ctdb , c , vnn ) ;
if ( ret ! = 0 ) {
return - 1 ;
}
2010-01-16 17:01:17 +03:00
} else if ( do_updateip ) {
ret = ctdb_do_updateip ( ctdb , c , vnn ) ;
if ( ret ! = 0 ) {
return - 1 ;
}
2010-01-16 15:30:58 +03:00
} else {
/*
* The interface is up and the kernel known the ip
* = > do nothing
*/
2010-01-18 17:22:16 +03:00
DEBUG ( DEBUG_INFO , ( " Redundant takeover of IP %s/%u on interface %s (ip already held) \n " ,
ctdb_addr_to_str ( & pip - > addr ) ,
vnn - > public_netmask_bits ,
ctdb_vnn_iface_string ( vnn ) ) ) ;
2010-01-16 15:30:58 +03:00
return 0 ;
2007-05-26 08:01:08 +04:00
}
2007-05-25 11:16:50 +04:00
2007-06-01 13:05:41 +04:00
/* tell ctdb_control.c that we will be replying asynchronously */
* async_reply = true ;
return 0 ;
}
2014-01-22 06:30:47 +04:00
static void do_delete_ip ( struct ctdb_context * ctdb , struct ctdb_vnn * vnn )
{
DLIST_REMOVE ( ctdb - > vnn , vnn ) ;
ctdb_vnn_unassign_iface ( ctdb , vnn ) ;
2014-01-22 10:01:19 +04:00
ctdb_remove_orphaned_ifaces ( ctdb , vnn ) ;
2014-01-22 06:30:47 +04:00
talloc_free ( vnn ) ;
}
2016-08-11 06:57:43 +03:00
static struct ctdb_vnn * release_ip_post ( struct ctdb_context * ctdb ,
struct ctdb_vnn * vnn ,
ctdb_sock_addr * addr )
{
TDB_DATA data ;
/* Send a message to all clients of this node telling them
* that the cluster has been reconfigured and they should
* close any connections on this IP address
*/
data . dptr = ( uint8_t * ) ctdb_addr_to_str ( addr ) ;
data . dsize = strlen ( ( char * ) data . dptr ) + 1 ;
DEBUG ( DEBUG_INFO , ( " Sending RELEASE_IP message for %s \n " , data . dptr ) ) ;
ctdb_daemon_send_message ( ctdb , ctdb - > pnn , CTDB_SRVID_RELEASE_IP , data ) ;
ctdb_vnn_unassign_iface ( ctdb , vnn ) ;
/* Process the IP if it has been marked for deletion */
if ( vnn - > delete_pending ) {
do_delete_ip ( ctdb , vnn ) ;
return NULL ;
}
return vnn ;
}
2016-08-19 09:30:46 +03:00
struct release_ip_callback_state {
struct ctdb_req_control_old * c ;
ctdb_sock_addr * addr ;
struct ctdb_vnn * vnn ;
2016-08-19 09:38:50 +03:00
uint32_t target_pnn ;
2016-08-19 09:30:46 +03:00
} ;
2007-06-01 13:05:41 +04:00
/*
called when releaseip event finishes
*/
2016-08-19 09:30:46 +03:00
static void release_ip_callback ( struct ctdb_context * ctdb , int status ,
2007-06-01 13:05:41 +04:00
void * private_data )
{
2016-08-19 09:30:46 +03:00
struct release_ip_callback_state * state =
talloc_get_type ( private_data , struct release_ip_callback_state ) ;
2007-06-01 13:05:41 +04:00
2018-07-10 11:18:33 +03:00
if ( status = = - ETIMEDOUT ) {
2009-12-07 16:18:57 +03:00
ctdb_ban_self ( ctdb ) ;
}
2018-08-21 06:41:22 +03:00
if ( ctdb_config . failover_disabled = = 0 & & ctdb - > do_checkpublicip ) {
2015-05-08 05:34:43 +03:00
if ( ctdb_sys_have_ip ( state - > addr ) ) {
DEBUG ( DEBUG_ERR ,
( " IP %s still hosted during release IP callback, failing \n " ,
ctdb_addr_to_str ( state - > addr ) ) ) ;
ctdb_request_control_reply ( ctdb , state - > c ,
NULL , - 1 , NULL ) ;
talloc_free ( state ) ;
return ;
}
2013-06-24 10:05:03 +04:00
}
2016-08-19 09:38:50 +03:00
state - > vnn - > pnn = state - > target_pnn ;
2016-08-11 06:57:43 +03:00
state - > vnn = release_ip_post ( ctdb , state - > vnn , state - > addr ) ;
2014-01-22 06:30:47 +04:00
2007-06-01 13:05:41 +04:00
/* the control succeeded */
ctdb_request_control_reply ( ctdb , state - > c , NULL , 0 , NULL ) ;
talloc_free ( state ) ;
}
2016-08-19 09:30:46 +03:00
static int ctdb_releaseip_destructor ( struct release_ip_callback_state * state )
2012-07-11 08:46:07 +04:00
{
2014-01-22 06:30:47 +04:00
if ( state - > vnn ! = NULL ) {
state - > vnn - > update_in_flight = false ;
}
2012-07-11 08:46:07 +04:00
return 0 ;
}
2007-06-01 13:05:41 +04:00
/*
release an ip address
*/
int32_t ctdb_control_release_ip ( struct ctdb_context * ctdb ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ,
2007-06-01 13:05:41 +04:00
TDB_DATA indata ,
bool * async_reply )
{
int ret ;
2016-08-19 09:30:46 +03:00
struct release_ip_callback_state * state ;
2007-06-04 14:07:37 +04:00
struct ctdb_public_ip * pip = ( struct ctdb_public_ip * ) indata . dptr ;
2007-09-04 03:50:07 +04:00
struct ctdb_vnn * vnn ;
2016-08-20 13:02:44 +03:00
const char * iface ;
2007-06-04 14:07:37 +04:00
2007-09-04 03:50:07 +04:00
/* update our vnn list */
2008-08-19 08:58:29 +04:00
vnn = find_public_ip_vnn ( ctdb , & pip - > addr ) ;
2007-09-04 03:50:07 +04:00
if ( vnn = = NULL ) {
2009-09-03 22:09:30 +04:00
DEBUG ( DEBUG_INFO , ( " releaseip called for an ip '%s' that is not a public address \n " ,
2008-08-19 08:58:29 +04:00
ctdb_addr_to_str ( & pip - > addr ) ) ) ;
2007-09-04 03:50:07 +04:00
return 0 ;
}
2007-06-01 13:05:41 +04:00
2007-09-12 07:22:31 +04:00
/* stop any previous arps */
talloc_free ( vnn - > takeover_ctx ) ;
vnn - > takeover_ctx = NULL ;
2016-08-19 09:38:50 +03:00
/* RELEASE_IP controls are sent to all nodes that should not
* be hosting a particular IP . This serves 2 purposes . The
* first is to help resolve any inconsistencies . If a node
2023-03-22 11:36:23 +03:00
* does unexpectedly host an IP then it will be released . The
2016-08-19 09:38:50 +03:00
* 2 nd is to use a " redundant release " to tell non - takeover
* nodes where an IP is moving to . This is how " ctdb ip " can
* report the ( likely ) location of an IP by only asking the
* local node . Redundant releases need to update the PNN but
* are otherwise ignored .
2012-07-11 08:46:07 +04:00
*/
2018-08-21 06:41:22 +03:00
if ( ctdb_config . failover_disabled = = 0 & & ctdb - > do_checkpublicip ) {
2012-04-04 08:42:56 +04:00
if ( ! ctdb_sys_have_ip ( & pip - > addr ) ) {
DEBUG ( DEBUG_DEBUG , ( " Redundant release of IP %s/%u on interface %s (ip not held) \n " ,
ctdb_addr_to_str ( & pip - > addr ) ,
vnn - > public_netmask_bits ,
ctdb_vnn_iface_string ( vnn ) ) ) ;
2016-08-19 09:38:50 +03:00
vnn - > pnn = pip - > pnn ;
2012-04-04 08:42:56 +04:00
ctdb_vnn_unassign_iface ( ctdb , vnn ) ;
return 0 ;
}
2012-07-02 08:09:32 +04:00
} else {
if ( vnn - > iface = = NULL ) {
DEBUG ( DEBUG_DEBUG , ( " Redundant release of IP %s/%u (ip not held) \n " ,
ctdb_addr_to_str ( & pip - > addr ) ,
vnn - > public_netmask_bits ) ) ;
2016-08-19 09:38:50 +03:00
vnn - > pnn = pip - > pnn ;
2012-07-02 08:09:32 +04:00
return 0 ;
}
2012-07-11 08:46:07 +04:00
}
/* There is a potential race between take_ip and us because we
* update the VNN via a callback that run when the
* eventscripts have been run . Avoid the race by allowing one
* update to be in flight at a time .
*/
if ( vnn - > update_in_flight ) {
2024-07-25 07:50:32 +03:00
D_NOTICE ( " Release of IP %s/%u rejected "
" update for this IP already in flight \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ) ;
2012-07-11 08:46:07 +04:00
return - 1 ;
}
2016-08-20 13:02:44 +03:00
iface = ctdb_vnn_iface_string ( vnn ) ;
2010-01-18 17:04:32 +03:00
2010-01-18 17:12:46 +03:00
DEBUG ( DEBUG_NOTICE , ( " Release of IP %s/%u on interface %s node:%d \n " ,
2008-08-19 08:58:29 +04:00
ctdb_addr_to_str ( & pip - > addr ) ,
2012-06-20 04:08:11 +04:00
vnn - > public_netmask_bits ,
iface ,
2009-10-06 04:40:38 +04:00
pip - > pnn ) ) ;
2007-06-01 13:05:41 +04:00
2016-08-19 09:30:46 +03:00
state = talloc ( ctdb , struct release_ip_callback_state ) ;
2015-04-16 09:25:53 +03:00
if ( state = = NULL ) {
ctdb_set_error ( ctdb , " Out of memory at %s:%d " ,
__FILE__ , __LINE__ ) ;
return - 1 ;
}
2007-06-01 13:05:41 +04:00
2016-08-31 01:29:13 +03:00
state - > c = NULL ;
state - > addr = talloc ( state , ctdb_sock_addr ) ;
2015-04-16 09:25:53 +03:00
if ( state - > addr = = NULL ) {
ctdb_set_error ( ctdb , " Out of memory at %s:%d " ,
__FILE__ , __LINE__ ) ;
talloc_free ( state ) ;
return - 1 ;
}
2008-08-19 08:58:29 +04:00
* state - > addr = pip - > addr ;
2016-08-19 09:38:50 +03:00
state - > target_pnn = pip - > pnn ;
2008-08-19 08:58:29 +04:00
state - > vnn = vnn ;
2007-07-20 04:06:41 +04:00
2012-07-11 08:46:07 +04:00
vnn - > update_in_flight = true ;
talloc_set_destructor ( state , ctdb_releaseip_destructor ) ;
2007-06-06 07:45:12 +04:00
ret = ctdb_event_script_callback ( ctdb ,
state , release_ip_callback , state ,
2009-11-24 03:46:49 +03:00
CTDB_EVENT_RELEASE_IP ,
" %s %s %u " ,
2012-06-20 04:08:11 +04:00
iface ,
2009-12-16 11:48:21 +03:00
ctdb_addr_to_str ( & pip - > addr ) ,
2007-09-04 03:50:07 +04:00
vnn - > public_netmask_bits ) ;
2007-06-01 13:05:41 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to release IP %s on interface %s \n " ,
2008-08-19 08:58:29 +04:00
ctdb_addr_to_str ( & pip - > addr ) ,
2009-12-16 10:54:02 +03:00
ctdb_vnn_iface_string ( vnn ) ) ) ;
2007-06-01 13:05:41 +04:00
talloc_free ( state ) ;
return - 1 ;
}
/* tell the control that we will be reply asynchronously */
* async_reply = true ;
2016-08-31 01:29:13 +03:00
state - > c = talloc_steal ( state , c ) ;
2007-05-25 11:16:50 +04:00
return 0 ;
}
2009-12-14 20:52:06 +03:00
static int ctdb_add_public_address ( struct ctdb_context * ctdb ,
ctdb_sock_addr * addr ,
2024-06-18 08:54:26 +03:00
unsigned mask , const char * ifaces )
2007-09-04 03:50:07 +04:00
{
struct ctdb_vnn * vnn ;
2009-12-14 20:52:06 +03:00
char * tmp ;
const char * iface ;
2007-09-04 03:50:07 +04:00
2016-08-20 13:21:34 +03:00
/* Verify that we don't have an entry for this IP yet */
for ( vnn = ctdb - > vnn ; vnn ! = NULL ; vnn = vnn - > next ) {
if ( ctdb_same_sockaddr ( addr , & vnn - > public_address ) ) {
2022-07-05 05:17:05 +03:00
D_ERR ( " Duplicate public IP address '%s' \n " ,
ctdb_addr_to_str ( addr ) ) ;
2016-08-20 13:21:34 +03:00
return - 1 ;
}
}
2016-08-20 13:34:33 +03:00
/* Create a new VNN structure for this IP address */
2007-09-04 12:20:29 +04:00
vnn = talloc_zero ( ctdb , struct ctdb_vnn ) ;
2016-08-20 13:29:04 +03:00
if ( vnn = = NULL ) {
2022-07-05 05:17:05 +03:00
DBG_ERR ( " Memory allocation error \n " ) ;
2016-08-20 13:29:04 +03:00
return - 1 ;
}
2024-07-25 07:40:18 +03:00
vnn - > name = ctdb_sock_addr_to_string ( vnn , addr , false ) ;
if ( vnn - > name = = NULL ) {
DBG_ERR ( " Memory allocation error \n " ) ;
talloc_free ( vnn ) ;
return - 1 ;
}
2009-12-14 20:52:06 +03:00
tmp = talloc_strdup ( vnn , ifaces ) ;
2016-08-20 13:29:04 +03:00
if ( tmp = = NULL ) {
2022-07-05 05:17:05 +03:00
DBG_ERR ( " Memory allocation error \n " ) ;
2016-08-20 13:29:04 +03:00
talloc_free ( vnn ) ;
return - 1 ;
}
2009-12-14 20:52:06 +03:00
for ( iface = strtok ( tmp , " , " ) ; iface ; iface = strtok ( NULL , " , " ) ) {
2016-08-24 11:21:51 +03:00
struct vnn_interface * vnn_iface ;
2016-08-24 09:59:46 +03:00
struct ctdb_interface * i ;
2022-07-05 05:17:05 +03:00
2016-08-20 13:34:33 +03:00
if ( ! ctdb_sys_check_iface_exists ( iface ) ) {
2022-07-05 05:17:05 +03:00
D_ERR ( " Unknown interface %s for public address %s \n " ,
iface ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ) ;
2016-08-20 13:34:33 +03:00
talloc_free ( vnn ) ;
return - 1 ;
}
2016-08-24 09:55:15 +03:00
2016-08-24 09:59:46 +03:00
i = ctdb_add_local_iface ( ctdb , iface ) ;
if ( i = = NULL ) {
2022-07-05 05:17:05 +03:00
D_ERR ( " Failed to add interface '%s' "
" for public address %s \n " ,
iface ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ) ;
2016-08-24 09:55:15 +03:00
talloc_free ( vnn ) ;
return - 1 ;
}
2016-08-24 11:21:51 +03:00
vnn_iface = talloc_zero ( vnn , struct vnn_interface ) ;
if ( vnn_iface = = NULL ) {
2022-07-05 05:17:05 +03:00
DBG_ERR ( " Memory allocation error \n " ) ;
2016-08-20 13:29:04 +03:00
talloc_free ( vnn ) ;
return - 1 ;
}
2016-08-24 11:21:51 +03:00
vnn_iface - > iface = i ;
DLIST_ADD_END ( vnn - > ifaces , vnn_iface ) ;
2009-12-14 20:52:06 +03:00
}
talloc_free ( tmp ) ;
2008-08-19 08:58:29 +04:00
vnn - > public_address = * addr ;
2007-09-10 08:27:29 +04:00
vnn - > public_netmask_bits = mask ;
vnn - > pnn = - 1 ;
2009-12-16 12:39:40 +03:00
2007-09-04 12:20:29 +04:00
DLIST_ADD ( ctdb - > vnn , vnn ) ;
2007-09-04 03:50:07 +04:00
2007-05-25 11:16:50 +04:00
return 0 ;
}
/*
2007-09-04 03:50:07 +04:00
setup the public address lists from a file
2007-05-25 11:16:50 +04:00
*/
2024-06-18 08:54:26 +03:00
int ctdb_set_public_addresses ( struct ctdb_context * ctdb )
2007-05-25 11:16:50 +04:00
{
2018-03-06 03:30:07 +03:00
bool ok ;
2007-05-25 11:16:50 +04:00
char * * lines ;
int nlines ;
int i ;
2018-03-06 03:30:07 +03:00
/* If no public addresses file given then try the default */
if ( ctdb - > public_addresses_file = = NULL ) {
2024-08-06 06:49:01 +03:00
ctdb - > public_addresses_file = path_etcdir_append (
ctdb , " public_addresses " ) ;
2018-03-06 03:30:07 +03:00
if ( ctdb - > public_addresses_file = = NULL ) {
DBG_ERR ( " Out of memory \n " ) ;
return - 1 ;
}
}
/* If the file doesn't exist then warn and do nothing */
ok = file_exist ( ctdb - > public_addresses_file ) ;
if ( ! ok ) {
D_WARNING ( " Not loading public addresses, no file %s \n " ,
ctdb - > public_addresses_file ) ;
return 0 ;
}
2014-08-15 10:11:45 +04:00
lines = file_lines_load ( ctdb - > public_addresses_file , & nlines , 0 , ctdb ) ;
2007-05-25 11:16:50 +04:00
if ( lines = = NULL ) {
2012-04-30 09:50:44 +04:00
ctdb_set_error ( ctdb , " Failed to load public address list '%s' \n " , ctdb - > public_addresses_file ) ;
2007-05-25 11:16:50 +04:00
return - 1 ;
}
2007-05-29 10:23:47 +04:00
while ( nlines > 0 & & strcmp ( lines [ nlines - 1 ] , " " ) = = 0 ) {
nlines - - ;
}
2007-05-25 11:16:50 +04:00
for ( i = 0 ; i < nlines ; i + + ) {
2007-09-10 08:27:29 +04:00
unsigned mask ;
2008-08-19 08:58:29 +04:00
ctdb_sock_addr addr ;
2009-01-19 17:33:24 +03:00
const char * addrstr ;
2009-12-14 20:52:06 +03:00
const char * ifaces ;
2008-10-07 12:25:10 +04:00
char * tok , * line ;
2018-06-08 00:27:07 +03:00
int ret ;
2007-09-10 08:27:29 +04:00
2008-10-07 12:25:10 +04:00
line = lines [ i ] ;
while ( ( * line = = ' ' ) | | ( * line = = ' \t ' ) ) {
line + + ;
}
if ( * line = = ' # ' ) {
continue ;
}
2008-10-07 12:34:34 +04:00
if ( strcmp ( line , " " ) = = 0 ) {
2008-10-07 12:25:10 +04:00
continue ;
}
tok = strtok ( line , " \t " ) ;
2009-01-19 17:33:24 +03:00
addrstr = tok ;
2018-02-20 11:06:51 +03:00
2007-09-10 08:27:29 +04:00
tok = strtok ( NULL , " \t " ) ;
if ( tok = = NULL ) {
2018-02-20 11:06:51 +03:00
D_ERR ( " No interface specified at line %u "
" of public addresses file \n " , i + 1 ) ;
talloc_free ( lines ) ;
return - 1 ;
2007-09-10 08:27:29 +04:00
}
2018-02-20 11:06:51 +03:00
ifaces = tok ;
2007-05-29 06:16:59 +04:00
2018-06-08 00:27:07 +03:00
if ( addrstr = = NULL ) {
D_ERR ( " Badly formed line %u in public address list \n " ,
i + 1 ) ;
2009-01-19 17:33:24 +03:00
talloc_free ( lines ) ;
return - 1 ;
}
2018-06-08 00:27:07 +03:00
ret = ctdb_sock_addr_mask_from_string ( addrstr , & addr , & mask ) ;
if ( ret ! = 0 ) {
D_ERR ( " Badly formed line %u in public address list \n " ,
i + 1 ) ;
talloc_free ( lines ) ;
return - 1 ;
}
2024-06-18 08:54:26 +03:00
if ( ctdb_add_public_address ( ctdb , & addr , mask , ifaces ) ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_CRIT , ( " Failed to add line %u to the public address list \n " , i + 1 ) ) ;
2007-09-04 03:50:07 +04:00
talloc_free ( lines ) ;
2007-05-29 06:16:59 +04:00
return - 1 ;
}
2007-05-25 11:16:50 +04:00
}
2011-09-06 11:02:19 +04:00
2018-03-06 03:30:07 +03:00
D_NOTICE ( " Loaded public addresses from %s \n " ,
ctdb - > public_addresses_file ) ;
2007-05-25 11:16:50 +04:00
talloc_free ( lines ) ;
return 0 ;
}
2007-06-18 21:54:06 +04:00
/*
2023-11-16 13:56:59 +03:00
destroy a ctdb_tcp_list structure
2007-06-18 21:54:06 +04:00
*/
2023-11-16 13:56:59 +03:00
static int ctdb_tcp_list_destructor ( struct ctdb_tcp_list * tcp )
2007-06-18 21:54:06 +04:00
{
2023-11-16 13:56:59 +03:00
struct ctdb_client * client = tcp - > client ;
struct ctdb_connection * conn = & tcp - > connection ;
char conn_str [ 132 ] = { 0 , } ;
int ret ;
ret = ctdb_connection_to_buf ( conn_str ,
sizeof ( conn_str ) ,
conn ,
false ,
" -> " ) ;
if ( ret ! = 0 ) {
strlcpy ( conn_str , " UNKNOWN " , sizeof ( conn_str ) ) ;
}
D_DEBUG ( " removing client TCP connection %s "
" (client_id %u pid %d) \n " ,
conn_str , client - > client_id , client - > pid ) ;
DLIST_REMOVE ( client - > tcp_list , tcp ) ;
/*
* We don ' t call ctdb_remove_connection ( vnn , conn ) here
* as we want the caller to decide if it ' s called
* directly ( local only ) or indirectly via a
* CTDB_CONTROL_TCP_REMOVE broadcast
*/
2008-08-19 08:58:29 +04:00
2007-06-18 21:54:06 +04:00
return 0 ;
}
2007-05-27 09:26:29 +04:00
/*
called by a client to inform us of a TCP connection that it is managing
that should tickled with an ACK when IP takeover is done
*/
2007-07-20 04:06:41 +04:00
int32_t ctdb_control_tcp_client ( struct ctdb_context * ctdb , uint32_t client_id ,
2007-05-27 09:26:29 +04:00
TDB_DATA indata )
{
2015-03-17 06:30:18 +03:00
struct ctdb_client * client = reqid_find ( ctdb - > idr , client_id , struct ctdb_client ) ;
2015-10-29 06:25:34 +03:00
struct ctdb_connection * tcp_sock = NULL ;
2007-05-27 09:26:29 +04:00
struct ctdb_tcp_list * tcp ;
2015-10-28 10:14:21 +03:00
struct ctdb_connection t ;
2007-05-27 09:26:29 +04:00
int ret ;
2007-05-27 18:34:40 +04:00
TDB_DATA data ;
2007-09-04 03:50:07 +04:00
struct ctdb_vnn * vnn ;
2023-12-13 02:22:04 +03:00
char conn_str [ 132 ] = { 0 , } ;
2007-06-18 21:54:06 +04:00
2014-02-11 11:07:08 +04:00
/* If we don't have public IPs, tickles are useless */
if ( ctdb - > vnn = = NULL ) {
return 0 ;
}
2015-10-29 06:25:34 +03:00
tcp_sock = ( struct ctdb_connection * ) indata . dptr ;
2009-01-13 08:17:20 +03:00
2023-12-12 15:27:17 +03:00
ctdb_canonicalize_ip_inplace ( & tcp_sock - > src ) ;
ctdb_canonicalize_ip_inplace ( & tcp_sock - > dst ) ;
2009-01-13 08:17:20 +03:00
2023-12-13 02:22:04 +03:00
ret = ctdb_connection_to_buf ( conn_str ,
sizeof ( conn_str ) ,
tcp_sock ,
false ,
" -> " ) ;
if ( ret ! = 0 ) {
strlcpy ( conn_str , " UNKNOWN " , sizeof ( conn_str ) ) ;
}
2023-12-13 02:29:05 +03:00
vnn = find_public_ip_vnn ( ctdb , & tcp_sock - > dst ) ;
2007-09-04 03:50:07 +04:00
if ( vnn = = NULL ) {
2023-12-13 02:22:04 +03:00
D_ERR ( " Could not register TCP connection %s - "
" not a public address (client_id %u pid %u) \n " ,
conn_str , client_id , client - > pid ) ;
2007-08-27 05:49:42 +04:00
return 0 ;
}
2007-09-12 07:22:31 +04:00
if ( vnn - > pnn ! = ctdb - > pnn ) {
2023-12-13 02:29:05 +03:00
D_ERR ( " Attempt to register tcp client for IP %s we don't hold - "
" failing (client_id %u pid %u) \n " ,
ctdb_addr_to_str ( & tcp_sock - > dst ) ,
client_id , client - > pid ) ;
2007-09-12 07:22:31 +04:00
/* failing this call will tell smbd to die */
return - 1 ;
}
2007-05-27 09:26:29 +04:00
tcp = talloc ( client , struct ctdb_tcp_list ) ;
CTDB_NO_MEMORY ( ctdb , tcp ) ;
2023-11-16 13:56:59 +03:00
tcp - > client = client ;
2007-05-27 09:26:29 +04:00
2015-10-28 10:14:21 +03:00
tcp - > connection . src = tcp_sock - > src ;
tcp - > connection . dst = tcp_sock - > dst ;
2007-05-27 09:26:29 +04:00
DLIST_ADD ( client - > tcp_list , tcp ) ;
2023-11-16 13:56:59 +03:00
talloc_set_destructor ( tcp , ctdb_tcp_list_destructor ) ;
2007-05-27 09:26:29 +04:00
2015-10-28 10:14:21 +03:00
t . src = tcp_sock - > src ;
t . dst = tcp_sock - > dst ;
2007-05-27 18:34:40 +04:00
data . dptr = ( uint8_t * ) & t ;
data . dsize = sizeof ( t ) ;
2023-12-13 02:22:04 +03:00
D_INFO ( " Registered TCP connection %s (client_id %u pid %u) \n " ,
conn_str , client_id , client - > pid ) ;
2007-07-19 09:04:54 +04:00
2007-05-27 09:26:29 +04:00
/* tell all nodes about this tcp connection */
2007-06-10 02:46:33 +04:00
ret = ctdb_daemon_send_control ( ctdb , CTDB_BROADCAST_CONNECTED , 0 ,
2007-05-27 09:26:29 +04:00
CTDB_CONTROL_TCP_ADD ,
2007-05-27 18:34:40 +04:00
0 , CTDB_CTRL_FLAG_NOREPLY , data , NULL , NULL ) ;
2007-05-27 09:26:29 +04:00
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Failed to send CTDB_CONTROL_TCP_ADD \n " ) ) ;
2007-05-27 09:26:29 +04:00
return - 1 ;
}
return 0 ;
}
2023-11-15 18:31:53 +03:00
static bool ctdb_client_remove_tcp ( struct ctdb_client * client ,
const struct ctdb_connection * conn )
{
struct ctdb_tcp_list * tcp = NULL ;
struct ctdb_tcp_list * tcp_next = NULL ;
bool found = false ;
for ( tcp = client - > tcp_list ; tcp ! = NULL ; tcp = tcp_next ) {
bool same ;
tcp_next = tcp - > next ;
same = ctdb_connection_same ( conn , & tcp - > connection ) ;
if ( ! same ) {
continue ;
}
TALLOC_FREE ( tcp ) ;
found = true ;
}
return found ;
}
/*
called by a client to inform us of a TCP connection that was disconnected
*/
int32_t ctdb_control_tcp_client_disconnected ( struct ctdb_context * ctdb ,
uint32_t client_id ,
TDB_DATA indata )
{
struct ctdb_client * client = reqid_find ( ctdb - > idr , client_id , struct ctdb_client ) ;
struct ctdb_connection * tcp_sock = NULL ;
int ret ;
TDB_DATA data ;
char conn_str [ 132 ] = { 0 , } ;
bool found = false ;
tcp_sock = ( struct ctdb_connection * ) indata . dptr ;
ctdb_canonicalize_ip_inplace ( & tcp_sock - > src ) ;
ctdb_canonicalize_ip_inplace ( & tcp_sock - > dst ) ;
ret = ctdb_connection_to_buf ( conn_str ,
sizeof ( conn_str ) ,
tcp_sock ,
false ,
" -> " ) ;
if ( ret ! = 0 ) {
strlcpy ( conn_str , " UNKNOWN " , sizeof ( conn_str ) ) ;
}
found = ctdb_client_remove_tcp ( client , tcp_sock ) ;
if ( ! found ) {
DBG_DEBUG ( " TCP connection %s not found "
" (client_id %u pid %u). \n " ,
conn_str , client_id , client - > pid ) ;
return 0 ;
}
D_INFO ( " deregistered TCP connection %s "
" (client_id %u pid %u) \n " ,
conn_str , client_id , client - > pid ) ;
data . dptr = ( uint8_t * ) tcp_sock ;
data . dsize = sizeof ( * tcp_sock ) ;
/* tell all nodes about this tcp connection is gone */
ret = ctdb_daemon_send_control ( ctdb ,
CTDB_BROADCAST_CONNECTED ,
0 ,
CTDB_CONTROL_TCP_REMOVE ,
0 ,
CTDB_CTRL_FLAG_NOREPLY ,
data ,
NULL ,
NULL ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " Failed to send CTDB_CONTROL_TCP_REMOVE: %s \n " ,
conn_str ) ;
return - 1 ;
}
return 0 ;
}
2023-11-17 17:59:57 +03:00
/*
called by a client to inform us of a TCP connection was passed to a different
" client " ( typically with multichannel to another smbd process ) .
*/
int32_t ctdb_control_tcp_client_passed ( struct ctdb_context * ctdb ,
uint32_t client_id ,
TDB_DATA indata )
{
struct ctdb_client * client = reqid_find ( ctdb - > idr , client_id , struct ctdb_client ) ;
struct ctdb_connection * tcp_sock = NULL ;
int ret ;
char conn_str [ 132 ] = { 0 , } ;
bool found = false ;
tcp_sock = ( struct ctdb_connection * ) indata . dptr ;
ctdb_canonicalize_ip_inplace ( & tcp_sock - > src ) ;
ctdb_canonicalize_ip_inplace ( & tcp_sock - > dst ) ;
ret = ctdb_connection_to_buf ( conn_str ,
sizeof ( conn_str ) ,
tcp_sock ,
false ,
" -> " ) ;
if ( ret ! = 0 ) {
strlcpy ( conn_str , " UNKNOWN " , sizeof ( conn_str ) ) ;
}
found = ctdb_client_remove_tcp ( client , tcp_sock ) ;
if ( ! found ) {
DBG_DEBUG ( " TCP connection from %s not found "
" (client_id %u pid %u). \n " ,
conn_str , client_id , client - > pid ) ;
return 0 ;
}
D_INFO ( " TCP connection from %s "
" (client_id %u pid %u) passed to another client \n " ,
conn_str , client_id , client - > pid ) ;
/*
* We don ' t call CTDB_CONTROL_TCP_REMOVE
* nor ctdb_remove_connection ( ) as the connection
* is still alive , but handled by another client
*/
return 0 ;
}
2007-05-27 09:26:29 +04:00
/*
find a tcp address on a list
*/
2015-10-28 10:14:21 +03:00
static struct ctdb_connection * ctdb_tcp_find ( struct ctdb_tcp_array * array ,
struct ctdb_connection * tcp )
2007-05-27 09:26:29 +04:00
{
2019-06-07 23:38:56 +03:00
unsigned int i ;
2007-07-20 04:06:41 +04:00
if ( array = = NULL ) {
return NULL ;
}
for ( i = 0 ; i < array - > num ; i + + ) {
2015-10-28 10:14:21 +03:00
if ( ctdb_same_sockaddr ( & array - > connections [ i ] . src , & tcp - > src ) & &
ctdb_same_sockaddr ( & array - > connections [ i ] . dst , & tcp - > dst ) ) {
2007-07-20 04:06:41 +04:00
return & array - > connections [ i ] ;
2007-05-27 09:26:29 +04:00
}
}
return NULL ;
}
2010-08-18 06:36:03 +04:00
2007-05-27 09:26:29 +04:00
/*
called by a daemon to inform us of a TCP connection that one of its
clients managing that should tickled with an ACK when IP takeover is
done
*/
2024-09-30 05:22:46 +03:00
int32_t ctdb_control_tcp_add ( struct ctdb_context * ctdb ,
TDB_DATA indata ,
bool tcp_update_needed )
2007-05-27 09:26:29 +04:00
{
2015-10-28 10:14:21 +03:00
struct ctdb_connection * p = ( struct ctdb_connection * ) indata . dptr ;
2007-07-20 04:06:41 +04:00
struct ctdb_tcp_array * tcparray ;
2007-09-04 03:50:07 +04:00
struct ctdb_vnn * vnn ;
2024-09-30 05:22:46 +03:00
char conn_str [ 132 ] = { 0 , } ;
int ret ;
2007-05-27 09:26:29 +04:00
2014-02-11 11:07:08 +04:00
/* If we don't have public IPs, tickles are useless */
if ( ctdb - > vnn = = NULL ) {
return 0 ;
}
2024-09-30 05:22:46 +03:00
ret = ctdb_connection_to_buf ( conn_str ,
sizeof ( conn_str ) ,
p ,
false ,
" -> " ) ;
if ( ret ! = 0 ) {
strlcpy ( conn_str , " UNKNOWN " , sizeof ( conn_str ) ) ;
}
2015-10-28 10:14:21 +03:00
vnn = find_public_ip_vnn ( ctdb , & p - > dst ) ;
2007-09-04 03:50:07 +04:00
if ( vnn = = NULL ) {
2024-09-30 05:22:46 +03:00
DBG_INFO ( " Attempt to add connection %s "
" but destination is not a public address \n " ,
conn_str ) ;
2008-08-19 08:58:29 +04:00
2007-10-09 05:56:09 +04:00
return - 1 ;
2007-09-04 03:50:07 +04:00
}
tcparray = vnn - > tcp_array ;
2007-07-20 04:06:41 +04:00
2024-09-30 05:37:57 +03:00
/* Do we already have this tickle ?*/
if ( ctdb_tcp_find ( tcparray , p ) ! = NULL ) {
DBG_DEBUG ( " Already had connection %s \n " , conn_str ) ;
return 0 ;
}
2007-07-20 04:06:41 +04:00
/* If this is the first tickle */
if ( tcparray = = NULL ) {
2014-01-22 08:00:33 +04:00
tcparray = talloc ( vnn , struct ctdb_tcp_array ) ;
2007-07-20 04:06:41 +04:00
CTDB_NO_MEMORY ( ctdb , tcparray ) ;
2007-09-04 03:50:07 +04:00
vnn - > tcp_array = tcparray ;
2007-07-20 04:06:41 +04:00
tcparray - > num = 0 ;
2024-09-30 05:40:57 +03:00
tcparray - > connections = NULL ;
2007-07-20 04:06:41 +04:00
}
/* A new tickle, we must add it to the array */
2024-09-30 05:22:46 +03:00
tcparray - > connections = talloc_realloc ( tcparray ,
tcparray - > connections ,
struct ctdb_connection ,
tcparray - > num + 1 ) ;
2007-07-20 09:05:55 +04:00
CTDB_NO_MEMORY ( ctdb , tcparray - > connections ) ;
2007-07-20 04:06:41 +04:00
2015-10-28 10:14:21 +03:00
tcparray - > connections [ tcparray - > num ] . src = p - > src ;
tcparray - > connections [ tcparray - > num ] . dst = p - > dst ;
2007-07-20 04:06:41 +04:00
tcparray - > num + + ;
2014-01-22 08:00:48 +04:00
2024-09-30 05:22:46 +03:00
D_INFO ( " Added connection %s \n " , conn_str ) ;
2007-07-20 04:06:41 +04:00
2010-08-18 06:36:03 +04:00
if ( tcp_update_needed ) {
vnn - > tcp_update_needed = true ;
}
2007-05-27 09:26:29 +04:00
return 0 ;
}
2007-07-11 12:24:25 +04:00
2024-09-30 05:22:46 +03:00
static void ctdb_remove_connection ( struct ctdb_vnn * vnn ,
struct ctdb_connection * conn )
2007-05-27 09:26:29 +04:00
{
2015-10-28 10:14:21 +03:00
struct ctdb_connection * tcpp ;
2024-09-30 05:22:46 +03:00
char conn_str [ 132 ] = { 0 , } ;
int ret ;
2007-07-20 04:06:41 +04:00
2007-09-04 03:50:07 +04:00
if ( vnn = = NULL ) {
2007-07-20 09:05:55 +04:00
return ;
}
2024-09-30 05:22:46 +03:00
ret = ctdb_connection_to_buf ( conn_str ,
sizeof ( conn_str ) ,
conn ,
false ,
" -> " ) ;
if ( ret ! = 0 ) {
strlcpy ( conn_str , " UNKNOWN " , sizeof ( conn_str ) ) ;
}
/* If the array is empty there is nothing to remove */
2007-09-04 03:50:07 +04:00
if ( vnn - > tcp_array = = NULL ) {
2024-09-30 05:22:46 +03:00
D_INFO ( " Attempt to remove untracked connection %s (empty) \n " ,
conn_str ) ;
2007-07-20 09:05:55 +04:00
return ;
2007-05-27 09:26:29 +04:00
}
2007-07-20 04:06:41 +04:00
2007-09-04 03:50:07 +04:00
tcpp = ctdb_tcp_find ( vnn - > tcp_array , conn ) ;
2007-07-20 04:06:41 +04:00
if ( tcpp = = NULL ) {
2024-09-30 05:30:13 +03:00
D_DEBUG ( " Attempt to remove untracked connection %s \n " , conn_str ) ;
2007-07-20 09:05:55 +04:00
return ;
2007-07-20 04:06:41 +04:00
}
2024-09-30 05:22:46 +03:00
/*
* We need to remove this entry from the array . Instead of
* allocating a new array and copying data to it , cheat and
* just copy the last entry in the existing array to the entry
* that is to be removed and just shrink the size .
2007-07-20 04:06:41 +04:00
*/
2007-09-04 03:50:07 +04:00
* tcpp = vnn - > tcp_array - > connections [ vnn - > tcp_array - > num - 1 ] ;
vnn - > tcp_array - > num - - ;
2007-07-20 04:06:41 +04:00
2024-09-30 05:22:46 +03:00
/* Last entry deleted, so remove the entire array */
2007-09-04 03:50:07 +04:00
if ( vnn - > tcp_array - > num = = 0 ) {
talloc_free ( vnn - > tcp_array ) ;
vnn - > tcp_array = NULL ;
2024-09-30 05:22:46 +03:00
}
2007-07-20 04:06:41 +04:00
2007-09-04 03:50:07 +04:00
vnn - > tcp_update_needed = true ;
2007-07-20 04:06:41 +04:00
2024-09-30 05:22:46 +03:00
D_INFO ( " Removed connection %s \n " , conn_str ) ;
2007-05-27 09:26:29 +04:00
}
2010-08-18 06:36:03 +04:00
/*
called by a daemon to inform us of a TCP connection that one of its
clients used are no longer needed in the tickle database
*/
int32_t ctdb_control_tcp_remove ( struct ctdb_context * ctdb , TDB_DATA indata )
{
2015-05-21 15:42:13 +03:00
struct ctdb_vnn * vnn ;
2015-10-28 10:14:21 +03:00
struct ctdb_connection * conn = ( struct ctdb_connection * ) indata . dptr ;
2010-08-18 06:36:03 +04:00
2014-02-11 11:07:08 +04:00
/* If we don't have public IPs, tickles are useless */
if ( ctdb - > vnn = = NULL ) {
return 0 ;
}
2015-05-21 15:42:13 +03:00
vnn = find_public_ip_vnn ( ctdb , & conn - > dst ) ;
if ( vnn = = NULL ) {
2024-09-30 05:22:46 +03:00
char conn_str [ 132 ] = { 0 , } ;
int ret ;
ret = ctdb_connection_to_buf ( conn_str ,
sizeof ( conn_str ) ,
conn ,
false ,
" -> " ) ;
if ( ret ! = 0 ) {
strlcpy ( conn_str , " UNKNOWN " , sizeof ( conn_str ) ) ;
}
DBG_ERR ( " Attempt to remove connection %s "
" but destination is not a public address \n " ,
conn_str ) ;
2015-05-21 15:42:13 +03:00
return 0 ;
}
ctdb_remove_connection ( vnn , conn ) ;
2010-08-18 06:36:03 +04:00
return 0 ;
}
2017-11-20 07:37:39 +03:00
static void ctdb_send_set_tcp_tickles_for_all ( struct ctdb_context * ctdb ,
bool force ) ;
2007-05-27 18:34:40 +04:00
/*
2014-03-05 09:21:45 +04:00
Called when another daemon starts - causes all tickles for all
2014-02-27 06:47:28 +04:00
public addresses we are serving to be sent to the new node on the
2017-11-20 07:37:39 +03:00
next check . This actually causes the tickles to be sent to the
other node immediately . In case there is an error , the periodic
timer will send the updates on timer event . This is simple and
2014-02-27 06:47:28 +04:00
doesn ' t require careful error handling .
2007-05-27 18:34:40 +04:00
*/
2014-02-27 06:47:28 +04:00
int32_t ctdb_control_startup ( struct ctdb_context * ctdb , uint32_t pnn )
2007-05-27 18:34:40 +04:00
{
2014-03-05 09:21:45 +04:00
DEBUG ( DEBUG_INFO , ( " Received startup control from node %lu \n " ,
( unsigned long ) pnn ) ) ;
2017-11-20 07:37:39 +03:00
ctdb_send_set_tcp_tickles_for_all ( ctdb , true ) ;
2007-05-27 18:34:40 +04:00
return 0 ;
}
2007-05-27 09:26:29 +04:00
/*
called when a client structure goes away - hook to remove
elements from the tcp_list in all daemons
*/
void ctdb_takeover_client_destructor_hook ( struct ctdb_client * client )
{
while ( client - > tcp_list ) {
2015-05-21 15:42:13 +03:00
struct ctdb_vnn * vnn ;
2007-05-27 09:26:29 +04:00
struct ctdb_tcp_list * tcp = client - > tcp_list ;
2015-05-21 15:42:13 +03:00
struct ctdb_connection * conn = & tcp - > connection ;
vnn = find_public_ip_vnn ( client - > ctdb ,
& conn - > dst ) ;
2015-05-21 17:13:48 +03:00
/* If the IP address is hosted on this node then
* remove the connection . */
2023-11-16 13:56:59 +03:00
if ( vnn ! = NULL & & vnn - > pnn = = client - > ctdb - > pnn ) {
2015-05-21 17:13:48 +03:00
ctdb_remove_connection ( vnn , conn ) ;
}
/* Otherwise this function has been called because the
* server IP address has been released to another node
* and the client has exited . This means that we
* should not delete the connection information . The
* takeover node processes connections too . */
2023-11-16 13:56:59 +03:00
/*
* The destructor removes from the list
*/
TALLOC_FREE ( tcp ) ;
2007-05-27 09:26:29 +04:00
}
}
2007-05-29 07:33:59 +04:00
void ctdb_release_all_ips ( struct ctdb_context * ctdb )
{
2016-08-11 07:07:44 +03:00
struct ctdb_vnn * vnn , * next ;
2013-07-02 08:43:17 +04:00
int count = 0 ;
2007-09-04 03:50:07 +04:00
2018-08-21 06:41:22 +03:00
if ( ctdb_config . failover_disabled = = 1 ) {
2015-05-08 08:20:04 +03:00
return ;
}
2016-08-11 07:07:44 +03:00
for ( vnn = ctdb - > vnn ; vnn ! = NULL ; vnn = next ) {
2024-06-18 08:38:18 +03:00
bool have_ip ;
int ret ;
2016-08-11 07:07:44 +03:00
/* vnn can be freed below in release_ip_post() */
next = vnn - > next ;
2008-08-19 08:58:29 +04:00
if ( ! ctdb_sys_have_ip ( & vnn - > public_address ) ) {
2009-12-16 12:39:40 +03:00
ctdb_vnn_unassign_iface ( ctdb , vnn ) ;
2007-09-13 04:45:06 +04:00
continue ;
2007-05-29 07:33:59 +04:00
}
2013-07-02 08:43:17 +04:00
2015-07-24 08:32:42 +03:00
/* Don't allow multiple releases at once. Some code,
* particularly ctdb_tickle_sentenced_connections ( ) is
* not re - entrant */
if ( vnn - > update_in_flight ) {
2024-07-25 07:50:32 +03:00
DBG_WARNING (
" Not releasing IP %s/%u on interface %s, "
" an update is already in progress \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ,
ctdb_vnn_iface_string ( vnn ) ) ;
2015-07-24 08:32:42 +03:00
continue ;
}
vnn - > update_in_flight = true ;
2024-07-25 07:50:32 +03:00
D_INFO ( " Release of IP %s/%u on interface %s node:-1 \n " ,
ctdb_vnn_address_string ( vnn ) ,
vnn - > public_netmask_bits ,
ctdb_vnn_iface_string ( vnn ) ) ;
2013-07-02 08:43:17 +04:00
2024-06-18 08:38:18 +03:00
/*
* releaseip timeouts are converted to success , or IP
* might be released but releaseip event failed ( due
* to failure of script after 10. interface ) , so try
* hard to correctly report failures . . .
2016-07-30 04:12:19 +03:00
*/
2024-06-18 08:38:18 +03:00
ret = ctdb_event_script_args (
ctdb ,
CTDB_EVENT_RELEASE_IP ,
" %s %s %u " ,
ctdb_vnn_iface_string ( vnn ) ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ,
2024-06-18 08:38:18 +03:00
vnn - > public_netmask_bits ) ;
have_ip = ctdb_sys_have_ip ( & vnn - > public_address ) ;
if ( have_ip ) {
if ( ret ! = 0 ) {
DBG_ERR ( " Error releasing IP %s \n " ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ) ;
2024-06-18 08:38:18 +03:00
} else {
DBG_ERR ( " IP %s not released (timed out?) \n " ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ) ;
2024-06-18 08:38:18 +03:00
}
vnn - > update_in_flight = false ;
continue ;
}
if ( ret ! = 0 ) {
DBG_ERR ( " Error releasing IP %s (but IP is gone!) \n " ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ) ;
2016-07-30 04:12:19 +03:00
vnn - > update_in_flight = false ;
continue ;
}
2016-03-05 06:05:21 +03:00
2016-08-11 07:07:44 +03:00
vnn = release_ip_post ( ctdb , vnn , & vnn - > public_address ) ;
if ( vnn ! = NULL ) {
vnn - > update_in_flight = false ;
}
2013-07-02 08:43:17 +04:00
count + + ;
2007-05-29 07:33:59 +04:00
}
2013-07-02 08:43:17 +04:00
DEBUG ( DEBUG_NOTICE , ( __location__ " Released %d public IPs \n " , count ) ) ;
2007-05-29 07:33:59 +04:00
}
2007-06-04 15:11:51 +04:00
/*
2007-06-04 16:28:52 +04:00
get list of public IPs
2007-06-04 15:11:51 +04:00
*/
2007-07-13 05:31:18 +04:00
int32_t ctdb_control_get_public_ips ( struct ctdb_context * ctdb ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c , TDB_DATA * outdata )
2007-06-04 15:11:51 +04:00
{
2007-09-04 03:50:07 +04:00
int i , num , len ;
2015-10-28 09:16:24 +03:00
struct ctdb_public_ip_list_old * ips ;
2007-09-04 03:50:07 +04:00
struct ctdb_vnn * vnn ;
2009-12-16 18:08:45 +03:00
bool only_available = false ;
if ( c - > flags & CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE ) {
only_available = true ;
}
2007-06-04 15:11:51 +04:00
2007-09-04 03:50:07 +04:00
/* count how many public ip structures we have */
num = 0 ;
2007-09-04 12:20:29 +04:00
for ( vnn = ctdb - > vnn ; vnn ; vnn = vnn - > next ) {
num + + ;
2007-09-04 03:50:07 +04:00
}
2007-06-04 15:11:51 +04:00
2015-10-28 09:16:24 +03:00
len = offsetof ( struct ctdb_public_ip_list_old , ips ) +
2007-09-04 03:50:07 +04:00
num * sizeof ( struct ctdb_public_ip ) ;
2007-06-04 16:28:52 +04:00
ips = talloc_zero_size ( outdata , len ) ;
2007-06-04 15:11:51 +04:00
CTDB_NO_MEMORY ( ctdb , ips ) ;
2007-09-04 03:50:07 +04:00
i = 0 ;
2007-09-04 12:20:29 +04:00
for ( vnn = ctdb - > vnn ; vnn ; vnn = vnn - > next ) {
2009-12-16 18:08:45 +03:00
if ( only_available & & ! ctdb_vnn_available ( ctdb , vnn ) ) {
continue ;
}
2008-08-19 08:58:29 +04:00
ips - > ips [ i ] . pnn = vnn - > pnn ;
ips - > ips [ i ] . addr = vnn - > public_address ;
2007-09-04 12:20:29 +04:00
i + + ;
2007-06-04 15:11:51 +04:00
}
2009-12-16 18:08:45 +03:00
ips - > num = i ;
2015-10-28 09:16:24 +03:00
len = offsetof ( struct ctdb_public_ip_list_old , ips ) +
2009-12-16 18:08:45 +03:00
i * sizeof ( struct ctdb_public_ip ) ;
outdata - > dsize = len ;
outdata - > dptr = ( uint8_t * ) ips ;
2007-06-04 15:11:51 +04:00
return 0 ;
}
2007-07-11 06:33:14 +04:00
2009-12-16 16:40:21 +03:00
int32_t ctdb_control_get_public_ip_info ( struct ctdb_context * ctdb ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ,
2009-12-16 16:40:21 +03:00
TDB_DATA indata ,
TDB_DATA * outdata )
{
2009-12-16 13:20:28 +03:00
int i , num , len ;
ctdb_sock_addr * addr ;
2015-10-28 11:39:51 +03:00
struct ctdb_public_ip_info_old * info ;
2009-12-16 13:20:28 +03:00
struct ctdb_vnn * vnn ;
2016-08-24 11:21:51 +03:00
struct vnn_interface * iface ;
2009-12-16 13:20:28 +03:00
addr = ( ctdb_sock_addr * ) indata . dptr ;
vnn = find_public_ip_vnn ( ctdb , addr ) ;
if ( vnn = = NULL ) {
DEBUG ( DEBUG_ERR , ( __location__ " Could not get public ip info, "
" '%s'not a public address \n " ,
ctdb_addr_to_str ( addr ) ) ) ;
return - 1 ;
}
/* count how many public ip structures we have */
num = 0 ;
2016-08-24 11:21:51 +03:00
for ( iface = vnn - > ifaces ; iface ! = NULL ; iface = iface - > next ) {
2009-12-16 13:20:28 +03:00
num + + ;
}
2015-10-28 11:39:51 +03:00
len = offsetof ( struct ctdb_public_ip_info_old , ifaces ) +
2015-10-28 11:37:17 +03:00
num * sizeof ( struct ctdb_iface ) ;
2009-12-16 13:20:28 +03:00
info = talloc_zero_size ( outdata , len ) ;
CTDB_NO_MEMORY ( ctdb , info ) ;
info - > ip . addr = vnn - > public_address ;
info - > ip . pnn = vnn - > pnn ;
info - > active_idx = 0xFFFFFFFF ;
2016-08-24 11:21:51 +03:00
i = 0 ;
for ( iface = vnn - > ifaces ; iface ! = NULL ; iface = iface - > next ) {
2015-10-28 09:34:24 +03:00
struct ctdb_interface * cur ;
2009-12-16 13:20:28 +03:00
2016-08-24 13:38:03 +03:00
cur = iface - > iface ;
2009-12-16 13:20:28 +03:00
if ( vnn - > iface = = cur ) {
info - > active_idx = i ;
}
2016-03-18 03:49:49 +03:00
strncpy ( info - > ifaces [ i ] . name , cur - > name ,
sizeof ( info - > ifaces [ i ] . name ) ) ;
info - > ifaces [ i ] . name [ sizeof ( info - > ifaces [ i ] . name ) - 1 ] = ' \0 ' ;
2009-12-16 13:20:28 +03:00
info - > ifaces [ i ] . link_state = cur - > link_up ;
info - > ifaces [ i ] . references = cur - > references ;
2016-08-24 11:21:51 +03:00
i + + ;
2009-12-16 13:20:28 +03:00
}
info - > num = i ;
2015-10-28 11:39:51 +03:00
len = offsetof ( struct ctdb_public_ip_info_old , ifaces ) +
2015-10-28 11:37:17 +03:00
i * sizeof ( struct ctdb_iface ) ;
2009-12-16 13:20:28 +03:00
outdata - > dsize = len ;
outdata - > dptr = ( uint8_t * ) info ;
return 0 ;
2009-12-16 16:40:21 +03:00
}
int32_t ctdb_control_get_ifaces ( struct ctdb_context * ctdb ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ,
2009-12-16 16:40:21 +03:00
TDB_DATA * outdata )
{
2009-12-16 13:14:44 +03:00
int i , num , len ;
2015-10-28 11:43:48 +03:00
struct ctdb_iface_list_old * ifaces ;
2015-10-28 09:34:24 +03:00
struct ctdb_interface * cur ;
2009-12-16 13:14:44 +03:00
/* count how many public ip structures we have */
num = 0 ;
for ( cur = ctdb - > ifaces ; cur ; cur = cur - > next ) {
num + + ;
}
2015-10-28 11:43:48 +03:00
len = offsetof ( struct ctdb_iface_list_old , ifaces ) +
2015-10-28 11:37:17 +03:00
num * sizeof ( struct ctdb_iface ) ;
2009-12-16 13:14:44 +03:00
ifaces = talloc_zero_size ( outdata , len ) ;
CTDB_NO_MEMORY ( ctdb , ifaces ) ;
i = 0 ;
for ( cur = ctdb - > ifaces ; cur ; cur = cur - > next ) {
2016-03-18 03:49:49 +03:00
strncpy ( ifaces - > ifaces [ i ] . name , cur - > name ,
sizeof ( ifaces - > ifaces [ i ] . name ) ) ;
ifaces - > ifaces [ i ] . name [ sizeof ( ifaces - > ifaces [ i ] . name ) - 1 ] = ' \0 ' ;
2009-12-16 13:14:44 +03:00
ifaces - > ifaces [ i ] . link_state = cur - > link_up ;
ifaces - > ifaces [ i ] . references = cur - > references ;
i + + ;
}
ifaces - > num = i ;
2015-10-28 11:43:48 +03:00
len = offsetof ( struct ctdb_iface_list_old , ifaces ) +
2015-10-28 11:37:17 +03:00
i * sizeof ( struct ctdb_iface ) ;
2009-12-16 13:14:44 +03:00
outdata - > dsize = len ;
outdata - > dptr = ( uint8_t * ) ifaces ;
return 0 ;
2009-12-16 16:40:21 +03:00
}
int32_t ctdb_control_set_iface_link ( struct ctdb_context * ctdb ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ,
2009-12-16 16:40:21 +03:00
TDB_DATA indata )
{
2015-10-28 11:37:17 +03:00
struct ctdb_iface * info ;
2015-10-28 09:34:24 +03:00
struct ctdb_interface * iface ;
2009-12-17 12:30:36 +03:00
bool link_up = false ;
2015-10-28 11:37:17 +03:00
info = ( struct ctdb_iface * ) indata . dptr ;
2009-12-17 12:30:36 +03:00
if ( info - > name [ CTDB_IFACE_SIZE ] ! = ' \0 ' ) {
int len = strnlen ( info - > name , CTDB_IFACE_SIZE ) ;
DEBUG ( DEBUG_ERR , ( __location__ " name[%*.*s] not terminated \n " ,
len , len , info - > name ) ) ;
return - 1 ;
}
switch ( info - > link_state ) {
case 0 :
link_up = false ;
break ;
case 1 :
link_up = true ;
break ;
default :
DEBUG ( DEBUG_ERR , ( __location__ " link_state[%u] invalid \n " ,
( unsigned int ) info - > link_state ) ) ;
return - 1 ;
}
if ( info - > references ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " references[%u] should be 0 \n " ,
( unsigned int ) info - > references ) ) ;
return - 1 ;
}
iface = ctdb_find_iface ( ctdb , info - > name ) ;
if ( iface = = NULL ) {
return - 1 ;
}
if ( link_up = = iface - > link_up ) {
return 0 ;
}
2016-08-10 09:53:54 +03:00
DEBUG ( DEBUG_ERR ,
2009-12-17 12:30:36 +03:00
( " iface[%s] has changed it's link status %s => %s \n " ,
iface - > name ,
iface - > link_up ? " up " : " down " ,
link_up ? " up " : " down " ) ) ;
iface - > link_up = link_up ;
return 0 ;
2009-12-16 16:40:21 +03:00
}
2007-07-11 06:33:14 +04:00
2007-07-20 04:06:41 +04:00
/*
called by a daemon to inform us of the entire list of TCP tickles for
a particular public address .
this control should only be sent by the node that is currently serving
that public address .
*/
2007-07-20 09:05:55 +04:00
int32_t ctdb_control_set_tcp_tickle_list ( struct ctdb_context * ctdb , TDB_DATA indata )
2007-07-20 04:06:41 +04:00
{
2015-10-28 10:44:19 +03:00
struct ctdb_tickle_list_old * list = ( struct ctdb_tickle_list_old * ) indata . dptr ;
2007-07-20 04:06:41 +04:00
struct ctdb_tcp_array * tcparray ;
2007-09-04 03:50:07 +04:00
struct ctdb_vnn * vnn ;
2007-07-20 04:06:41 +04:00
2023-03-22 11:36:23 +03:00
/* We must at least have tickles.num or else we can't verify the size
2007-07-20 04:06:41 +04:00
of the received data blob
*/
2015-10-28 10:44:19 +03:00
if ( indata . dsize < offsetof ( struct ctdb_tickle_list_old , connections ) ) {
DEBUG ( DEBUG_ERR , ( " Bad indata in ctdb_tickle_list. Not enough data for the tickle.num field \n " ) ) ;
2007-07-20 04:06:41 +04:00
return - 1 ;
}
/* verify that the size of data matches what we expect */
2015-10-28 10:44:19 +03:00
if ( indata . dsize < offsetof ( struct ctdb_tickle_list_old , connections )
+ sizeof ( struct ctdb_connection ) * list - > num ) {
DEBUG ( DEBUG_ERR , ( " Bad indata in ctdb_tickle_list \n " ) ) ;
2007-07-20 04:06:41 +04:00
return - 1 ;
2014-01-22 08:00:48 +04:00
}
2007-07-20 04:06:41 +04:00
2014-03-05 09:21:45 +04:00
DEBUG ( DEBUG_INFO , ( " Received tickle update for public address %s \n " ,
ctdb_addr_to_str ( & list - > addr ) ) ) ;
2008-08-19 08:58:29 +04:00
vnn = find_public_ip_vnn ( ctdb , & list - > addr ) ;
2007-09-04 03:50:07 +04:00
if ( vnn = = NULL ) {
2014-01-22 08:00:48 +04:00
DEBUG ( DEBUG_INFO , ( __location__ " Could not set tcp tickle list, '%s' is not a public address \n " ,
2008-08-19 08:58:29 +04:00
ctdb_addr_to_str ( & list - > addr ) ) ) ;
2007-09-04 03:50:07 +04:00
return 1 ;
}
2007-07-20 04:06:41 +04:00
2015-03-27 07:30:16 +03:00
if ( vnn - > pnn = = ctdb - > pnn ) {
DEBUG ( DEBUG_INFO ,
( " Ignoring redundant set tcp tickle list, this node hosts '%s' \n " ,
ctdb_addr_to_str ( & list - > addr ) ) ) ;
return 0 ;
}
2007-07-20 04:06:41 +04:00
/* remove any old ticklelist we might have */
2007-09-04 03:50:07 +04:00
talloc_free ( vnn - > tcp_array ) ;
vnn - > tcp_array = NULL ;
2007-07-20 04:06:41 +04:00
2014-01-22 08:00:33 +04:00
tcparray = talloc ( vnn , struct ctdb_tcp_array ) ;
2007-07-20 04:06:41 +04:00
CTDB_NO_MEMORY ( ctdb , tcparray ) ;
2015-10-28 10:44:19 +03:00
tcparray - > num = list - > num ;
2007-07-20 09:05:55 +04:00
2015-10-28 10:14:21 +03:00
tcparray - > connections = talloc_array ( tcparray , struct ctdb_connection , tcparray - > num ) ;
2007-07-20 09:05:55 +04:00
CTDB_NO_MEMORY ( ctdb , tcparray - > connections ) ;
2015-10-28 10:44:19 +03:00
memcpy ( tcparray - > connections , & list - > connections [ 0 ] ,
2015-10-28 10:14:21 +03:00
sizeof ( struct ctdb_connection ) * tcparray - > num ) ;
2007-07-20 04:06:41 +04:00
/* We now have a new fresh tickle list array for this vnn */
2014-01-22 08:00:33 +04:00
vnn - > tcp_array = tcparray ;
2007-07-20 04:06:41 +04:00
return 0 ;
}
2007-07-20 09:05:55 +04:00
/*
called to return the full list of tickles for the puclic address associated
with the provided vnn
*/
int32_t ctdb_control_get_tcp_tickle_list ( struct ctdb_context * ctdb , TDB_DATA indata , TDB_DATA * outdata )
{
2008-08-19 08:58:29 +04:00
ctdb_sock_addr * addr = ( ctdb_sock_addr * ) indata . dptr ;
2015-10-28 10:44:19 +03:00
struct ctdb_tickle_list_old * list ;
2007-07-20 09:05:55 +04:00
struct ctdb_tcp_array * tcparray ;
2019-06-07 23:38:56 +03:00
unsigned int num , i ;
2007-09-04 03:50:07 +04:00
struct ctdb_vnn * vnn ;
2015-03-23 12:18:25 +03:00
unsigned port ;
2007-07-20 09:05:55 +04:00
2008-08-19 08:58:29 +04:00
vnn = find_public_ip_vnn ( ctdb , addr ) ;
2007-09-04 03:50:07 +04:00
if ( vnn = = NULL ) {
2015-03-23 12:18:25 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Could not get tcp tickle list, '%s' is not a public address \n " ,
2008-08-19 08:58:29 +04:00
ctdb_addr_to_str ( addr ) ) ) ;
2007-09-04 03:50:07 +04:00
return 1 ;
2007-07-20 09:05:55 +04:00
}
2015-03-23 12:18:25 +03:00
port = ctdb_addr_to_port ( addr ) ;
2007-09-04 03:50:07 +04:00
tcparray = vnn - > tcp_array ;
2015-03-23 12:18:25 +03:00
num = 0 ;
if ( tcparray ! = NULL ) {
if ( port = = 0 ) {
/* All connections */
num = tcparray - > num ;
} else {
/* Count connections for port */
for ( i = 0 ; i < tcparray - > num ; i + + ) {
if ( port = = ctdb_addr_to_port ( & tcparray - > connections [ i ] . dst ) ) {
num + + ;
}
}
}
2007-07-20 09:05:55 +04:00
}
2015-10-28 10:44:19 +03:00
outdata - > dsize = offsetof ( struct ctdb_tickle_list_old , connections )
2015-10-28 10:14:21 +03:00
+ sizeof ( struct ctdb_connection ) * num ;
2007-07-20 09:05:55 +04:00
outdata - > dptr = talloc_size ( outdata , outdata - > dsize ) ;
CTDB_NO_MEMORY ( ctdb , outdata - > dptr ) ;
2015-10-28 10:44:19 +03:00
list = ( struct ctdb_tickle_list_old * ) outdata - > dptr ;
2007-07-20 09:05:55 +04:00
2008-08-19 08:58:29 +04:00
list - > addr = * addr ;
2015-10-28 10:44:19 +03:00
list - > num = num ;
2015-03-23 12:18:25 +03:00
if ( num = = 0 ) {
return 0 ;
}
num = 0 ;
for ( i = 0 ; i < tcparray - > num ; i + + ) {
if ( port = = 0 | | \
port = = ctdb_addr_to_port ( & tcparray - > connections [ i ] . dst ) ) {
list - > connections [ num ] = tcparray - > connections [ i ] ;
num + + ;
}
2007-07-20 09:05:55 +04:00
}
return 0 ;
}
/*
set the list of all tcp tickles for a public address
*/
2014-03-13 09:53:15 +04:00
static int ctdb_send_set_tcp_tickles_for_ip ( struct ctdb_context * ctdb ,
ctdb_sock_addr * addr ,
struct ctdb_tcp_array * tcparray )
2007-07-20 09:05:55 +04:00
{
int ret , num ;
TDB_DATA data ;
2015-10-28 10:44:19 +03:00
struct ctdb_tickle_list_old * list ;
2007-07-20 09:05:55 +04:00
if ( tcparray ) {
num = tcparray - > num ;
} else {
num = 0 ;
}
2015-10-28 10:44:19 +03:00
data . dsize = offsetof ( struct ctdb_tickle_list_old , connections ) +
2015-10-28 10:14:21 +03:00
sizeof ( struct ctdb_connection ) * num ;
2007-07-20 09:05:55 +04:00
data . dptr = talloc_size ( ctdb , data . dsize ) ;
CTDB_NO_MEMORY ( ctdb , data . dptr ) ;
2015-10-28 10:44:19 +03:00
list = ( struct ctdb_tickle_list_old * ) data . dptr ;
2008-08-19 08:58:29 +04:00
list - > addr = * addr ;
2015-10-28 10:44:19 +03:00
list - > num = num ;
2007-07-20 09:05:55 +04:00
if ( tcparray ) {
2015-10-28 10:44:19 +03:00
memcpy ( & list - > connections [ 0 ] , tcparray - > connections , sizeof ( struct ctdb_connection ) * num ) ;
2007-07-20 09:05:55 +04:00
}
2014-03-13 09:53:15 +04:00
ret = ctdb_daemon_send_control ( ctdb , CTDB_BROADCAST_ALL , 0 ,
2007-07-20 09:05:55 +04:00
CTDB_CONTROL_SET_TCP_TICKLE_LIST ,
0 , CTDB_CTRL_FLAG_NOREPLY , data , NULL , NULL ) ;
if ( ret ! = 0 ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " ctdb_control for set tcp tickles failed \n " ) ) ;
2007-07-20 09:05:55 +04:00
return - 1 ;
}
talloc_free ( data . dptr ) ;
return ret ;
}
2017-11-20 07:17:15 +03:00
static void ctdb_send_set_tcp_tickles_for_all ( struct ctdb_context * ctdb ,
bool force )
2007-07-20 09:05:55 +04:00
{
2007-09-04 03:50:07 +04:00
struct ctdb_vnn * vnn ;
2017-11-20 07:17:15 +03:00
int ret ;
2007-07-20 09:05:55 +04:00
2017-11-20 07:17:15 +03:00
for ( vnn = ctdb - > vnn ; vnn ! = NULL ; vnn = vnn - > next ) {
/* we only send out updates for public addresses that
2007-09-04 12:20:29 +04:00
we have taken over
2007-07-20 09:05:55 +04:00
*/
2007-09-04 12:20:29 +04:00
if ( ctdb - > pnn ! = vnn - > pnn ) {
2007-07-20 09:05:55 +04:00
continue ;
}
2017-11-20 07:17:15 +03:00
2007-07-20 09:05:55 +04:00
/* We only send out the updates if we need to */
2017-11-20 07:17:15 +03:00
if ( ! force & & ! vnn - > tcp_update_needed ) {
2007-07-20 09:05:55 +04:00
continue ;
}
2017-11-20 07:17:15 +03:00
2014-03-13 09:53:15 +04:00
ret = ctdb_send_set_tcp_tickles_for_ip ( ctdb ,
& vnn - > public_address ,
vnn - > tcp_array ) ;
2007-07-20 09:05:55 +04:00
if ( ret ! = 0 ) {
2017-11-20 07:17:15 +03:00
D_ERR ( " Failed to send the tickle update for ip %s \n " ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ) ;
2017-11-20 07:17:15 +03:00
vnn - > tcp_update_needed = true ;
2014-01-29 08:54:35 +04:00
} else {
2017-11-20 07:17:15 +03:00
D_INFO ( " Sent tickle update for ip %s \n " ,
2024-07-25 07:47:06 +03:00
ctdb_vnn_address_string ( vnn ) ) ;
2014-01-29 08:54:35 +04:00
vnn - > tcp_update_needed = false ;
2007-07-20 09:05:55 +04:00
}
}
2017-11-20 07:17:15 +03:00
}
/*
perform tickle updates if required
*/
static void ctdb_update_tcp_tickles ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * private_data )
{
struct ctdb_context * ctdb = talloc_get_type (
private_data , struct ctdb_context ) ;
ctdb_send_set_tcp_tickles_for_all ( ctdb , false ) ;
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , ctdb - > tickle_update_context ,
timeval_current_ofs ( ctdb - > tunable . tickle_update_interval , 0 ) ,
ctdb_update_tcp_tickles , ctdb ) ;
}
2007-07-20 09:05:55 +04:00
/*
start periodic update of tcp tickles
*/
void ctdb_start_tcp_tickle_update ( struct ctdb_context * ctdb )
{
ctdb - > tickle_update_context = talloc_new ( ctdb ) ;
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , ctdb - > tickle_update_context ,
timeval_current_ofs ( ctdb - > tunable . tickle_update_interval , 0 ) ,
ctdb_update_tcp_tickles , ctdb ) ;
2007-07-20 09:05:55 +04:00
}
2007-10-09 05:56:09 +04:00
struct control_gratious_arp {
struct ctdb_context * ctdb ;
2008-06-04 09:13:00 +04:00
ctdb_sock_addr addr ;
2007-10-09 05:56:09 +04:00
const char * iface ;
int count ;
} ;
/*
send a control_gratuitous arp
*/
2015-10-26 08:50:09 +03:00
static void send_gratious_arp ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * private_data )
2007-10-09 05:56:09 +04:00
{
int ret ;
struct control_gratious_arp * arp = talloc_get_type ( private_data ,
struct control_gratious_arp ) ;
2008-06-04 09:13:00 +04:00
ret = ctdb_sys_send_arp ( & arp - > addr , arp - > iface ) ;
2007-10-09 05:56:09 +04:00
if ( ret ! = 0 ) {
2018-08-10 10:23:56 +03:00
DBG_ERR ( " Failed to send gratuitous ARP on iface %s: %s \n " ,
arp - > iface , strerror ( ret ) ) ;
2007-10-09 05:56:09 +04:00
}
arp - > count + + ;
if ( arp - > count = = CTDB_ARP_REPEAT ) {
talloc_free ( arp ) ;
return ;
}
2015-10-26 08:50:09 +03:00
tevent_add_timer ( arp - > ctdb - > ev , arp ,
timeval_current_ofs ( CTDB_ARP_INTERVAL , 0 ) ,
send_gratious_arp , arp ) ;
2007-10-09 05:56:09 +04:00
}
/*
send a gratious arp
*/
int32_t ctdb_control_send_gratious_arp ( struct ctdb_context * ctdb , TDB_DATA indata )
{
2015-10-29 06:47:54 +03:00
struct ctdb_addr_info_old * gratious_arp = ( struct ctdb_addr_info_old * ) indata . dptr ;
2007-10-09 05:56:09 +04:00
struct control_gratious_arp * arp ;
/* verify the size of indata */
2015-10-29 06:47:54 +03:00
if ( indata . dsize < offsetof ( struct ctdb_addr_info_old , iface ) ) {
2008-07-04 11:04:37 +04:00
DEBUG ( DEBUG_ERR , ( __location__ " Too small indata to hold a ctdb_control_gratious_arp structure. Got %u require %u bytes \n " ,
( unsigned ) indata . dsize ,
2015-10-29 06:47:54 +03:00
( unsigned ) offsetof ( struct ctdb_addr_info_old , iface ) ) ) ;
2007-10-09 05:56:09 +04:00
return - 1 ;
}
if ( indata . dsize ! =
2015-10-29 06:47:54 +03:00
( offsetof ( struct ctdb_addr_info_old , iface )
2007-10-09 05:56:09 +04:00
+ gratious_arp - > len ) ) {
2008-02-04 12:07:15 +03:00
DEBUG ( DEBUG_ERR , ( __location__ " Wrong size of indata. Was %u bytes "
2008-01-05 01:30:49 +03:00
" but should be %u bytes \n " ,
( unsigned ) indata . dsize ,
2015-10-29 06:47:54 +03:00
( unsigned ) ( offsetof ( struct ctdb_addr_info_old , iface ) + gratious_arp - > len ) ) ) ;
2007-10-09 05:56:09 +04:00
return - 1 ;
}
arp = talloc ( ctdb , struct control_gratious_arp ) ;
CTDB_NO_MEMORY ( ctdb , arp ) ;
arp - > ctdb = ctdb ;
2008-06-04 09:13:00 +04:00
arp - > addr = gratious_arp - > addr ;
2007-10-09 05:56:09 +04:00
arp - > iface = talloc_strdup ( arp , gratious_arp - > iface ) ;
CTDB_NO_MEMORY ( ctdb , arp - > iface ) ;
arp - > count = 0 ;
2015-10-26 08:50:09 +03:00
tevent_add_timer ( arp - > ctdb - > ev , arp ,
timeval_zero ( ) , send_gratious_arp , arp ) ;
2007-10-09 05:56:09 +04:00
return 0 ;
}
2008-03-27 01:23:27 +03:00
int32_t ctdb_control_add_public_address ( struct ctdb_context * ctdb , TDB_DATA indata )
{
2015-10-29 06:46:21 +03:00
struct ctdb_addr_info_old * pub = ( struct ctdb_addr_info_old * ) indata . dptr ;
2009-06-05 11:00:47 +04:00
int ret ;
2008-03-27 01:23:27 +03:00
/* verify the size of indata */
2015-10-29 06:46:21 +03:00
if ( indata . dsize < offsetof ( struct ctdb_addr_info_old , iface ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Too small indata to hold a ctdb_addr_info structure \n " ) ) ;
2008-03-27 01:23:27 +03:00
return - 1 ;
}
if ( indata . dsize ! =
2015-10-29 06:46:21 +03:00
( offsetof ( struct ctdb_addr_info_old , iface )
2008-03-27 01:23:27 +03:00
+ pub - > len ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Wrong size of indata. Was %u bytes "
" but should be %u bytes \n " ,
( unsigned ) indata . dsize ,
2015-10-29 06:46:21 +03:00
( unsigned ) ( offsetof ( struct ctdb_addr_info_old , iface ) + pub - > len ) ) ) ;
2008-03-27 01:23:27 +03:00
return - 1 ;
}
2013-05-14 09:38:08 +04:00
DEBUG ( DEBUG_NOTICE , ( " Add IP %s \n " , ctdb_addr_to_str ( & pub - > addr ) ) ) ;
2024-06-18 08:54:26 +03:00
ret = ctdb_add_public_address ( ctdb , & pub - > addr , pub - > mask , & pub - > iface [ 0 ] ) ;
2009-06-05 11:00:47 +04:00
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Failed to add public address \n " ) ) ;
return - 1 ;
}
return 0 ;
2008-03-27 01:23:27 +03:00
}
2014-01-22 10:12:09 +04:00
int32_t ctdb_control_del_public_address ( struct ctdb_context * ctdb , TDB_DATA indata )
2008-03-27 01:23:27 +03:00
{
2015-10-29 06:46:21 +03:00
struct ctdb_addr_info_old * pub = ( struct ctdb_addr_info_old * ) indata . dptr ;
2008-03-27 01:23:27 +03:00
struct ctdb_vnn * vnn ;
/* verify the size of indata */
2015-10-29 06:46:21 +03:00
if ( indata . dsize < offsetof ( struct ctdb_addr_info_old , iface ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Too small indata to hold a ctdb_addr_info structure \n " ) ) ;
2008-03-27 01:23:27 +03:00
return - 1 ;
}
if ( indata . dsize ! =
2015-10-29 06:46:21 +03:00
( offsetof ( struct ctdb_addr_info_old , iface )
2008-03-27 01:23:27 +03:00
+ pub - > len ) ) {
DEBUG ( DEBUG_ERR , ( __location__ " Wrong size of indata. Was %u bytes "
" but should be %u bytes \n " ,
( unsigned ) indata . dsize ,
2015-10-29 06:46:21 +03:00
( unsigned ) ( offsetof ( struct ctdb_addr_info_old , iface ) + pub - > len ) ) ) ;
2008-03-27 01:23:27 +03:00
return - 1 ;
}
2013-05-14 09:38:08 +04:00
DEBUG ( DEBUG_NOTICE , ( " Delete IP %s \n " , ctdb_addr_to_str ( & pub - > addr ) ) ) ;
2024-08-29 11:38:58 +03:00
vnn = find_public_ip_vnn ( ctdb , & pub - > addr ) ;
if ( vnn = = NULL ) {
D_ERR ( " Delete IP of unknown public IP address %s \n " ,
ctdb_addr_to_str ( & pub - > addr ) ) ;
return - 1 ;
}
2014-01-22 06:30:47 +04:00
2024-08-29 11:38:58 +03:00
if ( vnn - > pnn = = ctdb - > pnn ) {
/*
* This IP is currently being hosted . Defer the
* deletion until the next takeover run . " ctdb
* reloadips " will always cause a takeover run. " ctdb
* delip " will now need an explicit " ctdb
* ipreallocated " afterwards.
*/
vnn - > delete_pending = true ;
} else {
/*
* This IP is not hosted on the current node so just
* delete it now .
*/
do_delete_ip ( ctdb , vnn ) ;
2008-03-27 01:23:27 +03:00
}
2024-08-29 11:38:58 +03:00
return 0 ;
2008-03-27 01:23:27 +03:00
}
2013-04-19 07:05:02 +04:00
struct ipreallocated_callback_state {
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ;
2013-04-19 07:05:02 +04:00
} ;
static void ctdb_ipreallocated_callback ( struct ctdb_context * ctdb ,
int status , void * p )
{
struct ipreallocated_callback_state * state =
talloc_get_type ( p , struct ipreallocated_callback_state ) ;
2023-11-23 17:04:09 +03:00
TDB_DATA data = { . dsize = 0 , } ;
2013-04-19 07:05:02 +04:00
if ( status ! = 0 ) {
DEBUG ( DEBUG_ERR ,
( " \" ipreallocated \" event script failed (status %d) \n " ,
status ) ) ;
2018-07-10 11:18:33 +03:00
if ( status = = - ETIMEDOUT ) {
2013-04-19 07:05:02 +04:00
ctdb_ban_self ( ctdb ) ;
}
}
2023-11-23 17:04:09 +03:00
D_INFO ( " Sending IPREALLOCATED message \n " ) ;
ctdb_daemon_send_message ( ctdb , ctdb - > pnn , CTDB_SRVID_IPREALLOCATED , data ) ;
2013-04-19 07:05:02 +04:00
ctdb_request_control_reply ( ctdb , state - > c , NULL , status , NULL ) ;
talloc_free ( state ) ;
}
/* A control to run the ipreallocated event */
int32_t ctdb_control_ipreallocated ( struct ctdb_context * ctdb ,
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ,
2013-04-19 07:05:02 +04:00
bool * async_reply )
{
int ret ;
struct ipreallocated_callback_state * state ;
state = talloc ( ctdb , struct ipreallocated_callback_state ) ;
CTDB_NO_MEMORY ( ctdb , state ) ;
DEBUG ( DEBUG_INFO , ( __location__ " Running \" ipreallocated \" event \n " ) ) ;
ret = ctdb_event_script_callback ( ctdb , state ,
ctdb_ipreallocated_callback , state ,
2013-12-16 08:57:42 +04:00
CTDB_EVENT_IPREALLOCATED ,
2013-04-19 07:05:02 +04:00
" %s " , " " ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to run \" ipreallocated \" event \n " ) ) ;
talloc_free ( state ) ;
return - 1 ;
}
/* tell the control that we will be reply asynchronously */
state - > c = talloc_steal ( state , c ) ;
* async_reply = true ;
return 0 ;
}
2023-10-26 09:55:17 +03:00
struct start_ipreallocate_callback_state {
struct ctdb_req_control_old * c ;
} ;
static void ctdb_start_ipreallocate_callback ( struct ctdb_context * ctdb ,
int status , void * p )
{
struct start_ipreallocate_callback_state * state = talloc_get_type_abort (
p , struct start_ipreallocate_callback_state ) ;
2024-02-27 11:13:57 +03:00
TDB_DATA data = { . dsize = 0 , } ;
2023-10-26 09:55:17 +03:00
if ( status ! = 0 ) {
D_ERR ( " \" startipreallocate \" event failed (status %d) \n " ,
status ) ;
if ( status = = - ETIMEDOUT ) {
ctdb_ban_self ( ctdb ) ;
}
}
2024-02-27 11:13:57 +03:00
D_INFO ( " Sending START_IPREALLOCATE message \n " ) ;
ctdb_daemon_send_message ( ctdb ,
ctdb - > pnn ,
CTDB_SRVID_START_IPREALLOCATE ,
data ) ;
2023-10-26 09:55:17 +03:00
ctdb_request_control_reply ( ctdb , state - > c , NULL , status , NULL ) ;
talloc_free ( state ) ;
}
/* A control to run the startipreallocate event */
int32_t ctdb_control_start_ipreallocate ( struct ctdb_context * ctdb ,
struct ctdb_req_control_old * c ,
bool * async_reply )
{
int ret ;
struct start_ipreallocate_callback_state * state ;
/* Nodes that are not RUNNING can not host IPs */
if ( ctdb - > runstate ! = CTDB_RUNSTATE_RUNNING ) {
DBG_INFO ( " Skipping \" startipreallocate \" event, not RUNNING \n " ) ;
return 0 ;
}
state = talloc ( ctdb , struct start_ipreallocate_callback_state ) ;
if ( state = = NULL ) {
DBG_ERR ( " Memory allocation error \n " ) ;
return - 1 ;
}
DBG_INFO ( " Running \" startipreallocate \" event \n " ) ;
ret = ctdb_event_script_callback ( ctdb ,
state ,
ctdb_start_ipreallocate_callback ,
state ,
CTDB_EVENT_START_IPREALLOCATE ,
" %s " ,
" " ) ;
if ( ret ! = 0 ) {
D_ERR ( " Failed to run \" startipreallocate \" event \n " ) ;
talloc_free ( state ) ;
return - 1 ;
}
/* tell the control that we will be reply asynchronously */
state - > c = talloc_steal ( state , c ) ;
* async_reply = true ;
return 0 ;
}
2012-04-30 09:50:44 +04:00
struct ctdb_reloadips_handle {
struct ctdb_context * ctdb ;
2015-10-29 08:42:05 +03:00
struct ctdb_req_control_old * c ;
2012-04-30 09:50:44 +04:00
int status ;
int fd [ 2 ] ;
pid_t child ;
2015-10-26 08:50:09 +03:00
struct tevent_fd * fde ;
2012-04-30 09:50:44 +04:00
} ;
static int ctdb_reloadips_destructor ( struct ctdb_reloadips_handle * h )
{
2012-05-01 09:27:12 +04:00
if ( h = = h - > ctdb - > reload_ips ) {
h - > ctdb - > reload_ips = NULL ;
2012-04-30 09:50:44 +04:00
}
2012-05-01 09:27:12 +04:00
if ( h - > c ! = NULL ) {
ctdb_request_control_reply ( h - > ctdb , h - > c , NULL , h - > status , NULL ) ;
h - > c = NULL ;
2012-04-30 09:50:44 +04:00
}
2012-05-03 05:42:41 +04:00
ctdb_kill ( h - > ctdb , h - > child , SIGKILL ) ;
2012-04-30 09:50:44 +04:00
return 0 ;
}
2015-10-26 08:50:09 +03:00
static void ctdb_reloadips_timeout_event ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval t , void * private_data )
2012-04-30 09:50:44 +04:00
{
struct ctdb_reloadips_handle * h = talloc_get_type ( private_data , struct ctdb_reloadips_handle ) ;
talloc_free ( h ) ;
2015-10-26 08:50:09 +03:00
}
2012-04-30 09:50:44 +04:00
2015-10-26 08:50:09 +03:00
static void ctdb_reloadips_child_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
uint16_t flags , void * private_data )
2012-04-30 09:50:44 +04:00
{
struct ctdb_reloadips_handle * h = talloc_get_type ( private_data , struct ctdb_reloadips_handle ) ;
2012-05-01 09:27:12 +04:00
2012-04-30 09:50:44 +04:00
char res ;
int ret ;
2014-07-30 15:03:53 +04:00
ret = sys_read ( h - > fd [ 0 ] , & res , 1 ) ;
2012-04-30 09:50:44 +04:00
if ( ret < 1 | | res ! = 0 ) {
2012-05-01 09:27:12 +04:00
DEBUG ( DEBUG_ERR , ( __location__ " Reloadips child process returned error \n " ) ) ;
2012-04-30 09:50:44 +04:00
res = 1 ;
}
h - > status = res ;
2012-05-01 09:27:12 +04:00
2012-04-30 09:50:44 +04:00
talloc_free ( h ) ;
}
static int ctdb_reloadips_child ( struct ctdb_context * ctdb )
{
TALLOC_CTX * mem_ctx = talloc_new ( NULL ) ;
2015-10-28 09:16:24 +03:00
struct ctdb_public_ip_list_old * ips ;
2012-04-30 09:50:44 +04:00
struct ctdb_vnn * vnn ;
2013-09-05 09:56:51 +04:00
struct client_async_data * async_data ;
struct timeval timeout ;
TDB_DATA data ;
struct ctdb_client_control_state * state ;
2013-09-06 05:21:10 +04:00
bool first_add ;
2019-06-07 23:38:56 +03:00
unsigned int i ;
int ret ;
2012-04-30 09:50:44 +04:00
2013-07-05 08:04:20 +04:00
CTDB_NO_MEMORY ( ctdb , mem_ctx ) ;
2013-09-05 09:56:51 +04:00
/* Read IPs from local node */
ret = ctdb_ctrl_get_public_ips ( ctdb , TAKEOVER_TIMEOUT ( ) ,
CTDB_CURRENT_NODE , mem_ctx , & ips ) ;
2012-04-30 09:50:44 +04:00
if ( ret ! = 0 ) {
2013-09-05 09:56:51 +04:00
DEBUG ( DEBUG_ERR ,
( " Unable to fetch public IPs from local node \n " ) ) ;
2012-04-30 09:50:44 +04:00
talloc_free ( mem_ctx ) ;
return - 1 ;
}
2013-09-05 09:56:51 +04:00
/* Read IPs file - this is safe since this is a child process */
2012-04-30 09:50:44 +04:00
ctdb - > vnn = NULL ;
2024-06-18 08:54:26 +03:00
if ( ctdb_set_public_addresses ( ctdb ) ! = 0 ) {
2012-04-30 09:50:44 +04:00
DEBUG ( DEBUG_ERR , ( " Failed to re-read public addresses file \n " ) ) ;
talloc_free ( mem_ctx ) ;
return - 1 ;
2013-07-05 08:04:20 +04:00
}
2012-04-30 09:50:44 +04:00
2013-09-05 09:56:51 +04:00
async_data = talloc_zero ( mem_ctx , struct client_async_data ) ;
CTDB_NO_MEMORY ( ctdb , async_data ) ;
2012-04-30 09:50:44 +04:00
2013-09-05 09:56:51 +04:00
/* Compare IPs between node and file for IPs to be deleted */
2012-04-30 09:50:44 +04:00
for ( i = 0 ; i < ips - > num ; i + + ) {
2024-08-29 11:38:58 +03:00
struct ctdb_addr_info_old * pub = NULL ;
2012-04-30 09:50:44 +04:00
2024-08-29 11:38:58 +03:00
vnn = find_public_ip_vnn ( ctdb , & ips - > ips [ i ] . addr ) ;
if ( vnn ! = NULL ) {
/* IP is still in file */
continue ;
}
2012-04-30 09:50:44 +04:00
2024-08-29 11:38:58 +03:00
/*
* Delete IP ips - > ips [ i ]
*/
2012-04-30 09:50:44 +04:00
2024-08-29 11:38:58 +03:00
D_NOTICE ( " IP %s no longer configured, deleting it \n " ,
ctdb_addr_to_str ( & ips - > ips [ i ] . addr ) ) ;
2013-09-05 09:56:51 +04:00
2024-08-29 11:38:58 +03:00
pub = talloc_zero ( mem_ctx , struct ctdb_addr_info_old ) ;
CTDB_NO_MEMORY ( ctdb , pub ) ;
2013-09-05 09:56:51 +04:00
2024-08-29 11:38:58 +03:00
pub - > addr = ips - > ips [ i ] . addr ;
pub - > mask = 0 ;
pub - > len = 0 ;
2013-09-05 09:56:51 +04:00
2024-08-29 11:38:58 +03:00
timeout = TAKEOVER_TIMEOUT ( ) ;
2013-09-05 09:56:51 +04:00
2024-08-29 11:38:58 +03:00
data . dsize = offsetof ( struct ctdb_addr_info_old ,
iface ) + pub - > len ;
data . dptr = ( uint8_t * ) pub ;
2013-09-05 09:56:51 +04:00
2024-08-29 11:38:58 +03:00
state = ctdb_control_send ( ctdb , CTDB_CURRENT_NODE , 0 ,
CTDB_CONTROL_DEL_PUBLIC_IP ,
0 , data , async_data ,
& timeout , NULL ) ;
if ( state = = NULL ) {
DBG_ERR ( " Failed sending CTDB_CONTROL_DEL_PUBLIC_IP \n " ) ;
goto failed ;
2012-04-30 09:50:44 +04:00
}
2024-08-29 11:38:58 +03:00
ctdb_client_async_add ( async_data , state ) ;
2012-04-30 09:50:44 +04:00
}
2013-09-05 09:56:51 +04:00
/* Compare IPs between node and file for IPs to be added */
2013-09-06 05:21:10 +04:00
first_add = true ;
2012-04-30 09:50:44 +04:00
for ( vnn = ctdb - > vnn ; vnn ; vnn = vnn - > next ) {
for ( i = 0 ; i < ips - > num ; i + + ) {
2013-09-05 09:56:51 +04:00
if ( ctdb_same_ip ( & vnn - > public_address ,
& ips - > ips [ i ] . addr ) ) {
/* IP already on node */
2012-04-30 09:50:44 +04:00
break ;
}
}
if ( i = = ips - > num ) {
2013-09-05 09:56:51 +04:00
/* Add IP ips->ips[i] */
2015-10-29 06:46:21 +03:00
struct ctdb_addr_info_old * pub ;
2012-06-15 09:07:04 +04:00
const char * ifaces = NULL ;
2013-09-05 09:56:51 +04:00
uint32_t len ;
2016-08-24 11:21:51 +03:00
struct vnn_interface * iface = NULL ;
2012-04-30 09:50:44 +04:00
2024-07-25 07:50:32 +03:00
D_NOTICE ( " New IP %s configured, adding it \n " ,
ctdb_vnn_address_string ( vnn ) ) ;
2013-09-06 05:21:10 +04:00
if ( first_add ) {
uint32_t pnn = ctdb_get_pnn ( ctdb ) ;
data . dsize = sizeof ( pnn ) ;
data . dptr = ( uint8_t * ) & pnn ;
ret = ctdb_client_send_message (
ctdb ,
CTDB_BROADCAST_CONNECTED ,
CTDB_SRVID_REBALANCE_NODE ,
data ) ;
if ( ret ! = 0 ) {
DEBUG ( DEBUG_WARNING ,
( " Failed to send message to force node reallocation - IPs may be unbalanced \n " ) ) ;
}
first_add = false ;
}
2012-04-30 09:50:44 +04:00
2016-08-24 11:21:51 +03:00
ifaces = vnn - > ifaces - > iface - > name ;
iface = vnn - > ifaces - > next ;
while ( iface ! = NULL ) {
2013-09-05 09:56:51 +04:00
ifaces = talloc_asprintf ( vnn , " %s,%s " , ifaces ,
2016-08-24 11:21:51 +03:00
iface - > iface - > name ) ;
iface = iface - > next ;
2012-04-30 09:50:44 +04:00
}
2013-09-05 09:56:51 +04:00
len = strlen ( ifaces ) + 1 ;
pub = talloc_zero_size ( mem_ctx ,
2015-10-29 06:46:21 +03:00
offsetof ( struct ctdb_addr_info_old , iface ) + len ) ;
2013-09-05 09:56:51 +04:00
CTDB_NO_MEMORY ( ctdb , pub ) ;
pub - > addr = vnn - > public_address ;
pub - > mask = vnn - > public_netmask_bits ;
pub - > len = len ;
2013-07-05 08:04:20 +04:00
memcpy ( & pub - > iface [ 0 ] , ifaces , pub - > len ) ;
2012-04-30 09:50:44 +04:00
2013-09-05 09:56:51 +04:00
timeout = TAKEOVER_TIMEOUT ( ) ;
2015-10-29 06:46:21 +03:00
data . dsize = offsetof ( struct ctdb_addr_info_old ,
2013-09-05 09:56:51 +04:00
iface ) + pub - > len ;
data . dptr = ( uint8_t * ) pub ;
state = ctdb_control_send ( ctdb , CTDB_CURRENT_NODE , 0 ,
CTDB_CONTROL_ADD_PUBLIC_IP ,
0 , data , async_data ,
& timeout , NULL ) ;
if ( state = = NULL ) {
DEBUG ( DEBUG_ERR ,
( __location__
" failed sending CTDB_CONTROL_ADD_PUBLIC_IP \n " ) ) ;
goto failed ;
2012-04-30 09:50:44 +04:00
}
2014-01-22 09:02:46 +04:00
ctdb_client_async_add ( async_data , state ) ;
2012-04-30 09:50:44 +04:00
}
}
2013-09-05 09:56:51 +04:00
if ( ctdb_client_async_wait ( ctdb , async_data ) ! = 0 ) {
DEBUG ( DEBUG_ERR , ( __location__ " Add/delete IPs failed \n " ) ) ;
goto failed ;
}
2013-07-05 08:04:20 +04:00
talloc_free ( mem_ctx ) ;
2012-04-30 09:50:44 +04:00
return 0 ;
2013-09-05 09:56:51 +04:00
failed :
talloc_free ( mem_ctx ) ;
return - 1 ;
2012-04-30 09:50:44 +04:00
}
/* This control is sent to force the node to re-read the public addresses file
and drop any addresses we should nnot longer host , and add new addresses
that we are now able to host
*/
2015-10-29 08:42:05 +03:00
int32_t ctdb_control_reload_public_ips ( struct ctdb_context * ctdb , struct ctdb_req_control_old * c , bool * async_reply )
2012-04-30 09:50:44 +04:00
{
struct ctdb_reloadips_handle * h ;
pid_t parent = getpid ( ) ;
if ( ctdb - > reload_ips ! = NULL ) {
talloc_free ( ctdb - > reload_ips ) ;
2012-05-01 09:27:12 +04:00
ctdb - > reload_ips = NULL ;
2012-04-30 09:50:44 +04:00
}
h = talloc ( ctdb , struct ctdb_reloadips_handle ) ;
CTDB_NO_MEMORY ( ctdb , h ) ;
h - > ctdb = ctdb ;
2012-05-01 09:27:12 +04:00
h - > c = NULL ;
2012-04-30 09:50:44 +04:00
h - > status = - 1 ;
2012-05-01 09:27:12 +04:00
2012-04-30 09:50:44 +04:00
if ( pipe ( h - > fd ) = = - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to create pipe for ctdb_freeze_lock \n " ) ) ;
talloc_free ( h ) ;
return - 1 ;
}
h - > child = ctdb_fork ( ctdb ) ;
if ( h - > child = = ( pid_t ) - 1 ) {
DEBUG ( DEBUG_ERR , ( " Failed to fork a child for reloadips \n " ) ) ;
close ( h - > fd [ 0 ] ) ;
close ( h - > fd [ 1 ] ) ;
talloc_free ( h ) ;
return - 1 ;
}
/* child process */
if ( h - > child = = 0 ) {
signed char res = 0 ;
2012-05-01 09:27:12 +04:00
2012-04-30 09:50:44 +04:00
close ( h - > fd [ 0 ] ) ;
2015-09-24 02:10:59 +03:00
prctl_set_comment ( " ctdb_reloadips " ) ;
2016-11-25 06:44:10 +03:00
if ( switch_from_server_to_client ( ctdb ) ! = 0 ) {
2012-04-30 09:50:44 +04:00
DEBUG ( DEBUG_CRIT , ( " ERROR: Failed to switch reloadips child into client mode \n " ) ) ;
res = - 1 ;
} else {
res = ctdb_reloadips_child ( ctdb ) ;
if ( res ! = 0 ) {
DEBUG ( DEBUG_ERR , ( " Failed to reload ips on local node \n " ) ) ;
}
}
2014-07-30 15:03:53 +04:00
sys_write ( h - > fd [ 1 ] , & res , 1 ) ;
2015-12-08 06:20:59 +03:00
ctdb_wait_for_process_to_exit ( parent ) ;
2012-04-30 09:50:44 +04:00
_exit ( 0 ) ;
}
2012-05-01 09:27:12 +04:00
h - > c = talloc_steal ( h , c ) ;
2012-04-30 09:50:44 +04:00
close ( h - > fd [ 1 ] ) ;
set_close_on_exec ( h - > fd [ 0 ] ) ;
2012-05-01 09:27:12 +04:00
talloc_set_destructor ( h , ctdb_reloadips_destructor ) ;
2015-10-26 08:50:09 +03:00
h - > fde = tevent_add_fd ( ctdb - > ev , h , h - > fd [ 0 ] , TEVENT_FD_READ ,
ctdb_reloadips_child_handler , ( void * ) h ) ;
2012-05-01 09:27:12 +04:00
tevent_fd_set_auto_close ( h - > fde ) ;
2012-04-30 09:50:44 +04:00
2015-10-26 08:50:09 +03:00
tevent_add_timer ( ctdb - > ev , h , timeval_current_ofs ( 120 , 0 ) ,
ctdb_reloadips_timeout_event , h ) ;
2012-04-30 09:50:44 +04:00
/* we reply later */
2012-05-17 10:08:37 +04:00
* async_reply = true ;
2012-04-30 09:50:44 +04:00
return 0 ;
}