1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00
samba-mirror/ctdb/server/ipalloc_common.c

204 lines
4.8 KiB
C
Raw Normal View History

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