Exemplo n.º 1
0
/*
  called when we get contacted by another node
  currently makes no attempt to check if the connection is really from a ctdb
  node in our cluster
*/
static void ctdb_listen_event(struct tevent_context *ev, struct tevent_fd *fde,
			      uint16_t flags, void *private_data)
{
	struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
	struct ctdb_tcp *ctcp = talloc_get_type(ctdb->private_data, struct ctdb_tcp);
	ctdb_sock_addr addr;
	socklen_t len;
	int fd, nodeid;
	struct ctdb_incoming *in;
	int one = 1;

	memset(&addr, 0, sizeof(addr));
	len = sizeof(addr);
	fd = accept(ctcp->listen_fd, (struct sockaddr *)&addr, &len);
	if (fd == -1) return;

	nodeid = ctdb_ip_to_nodeid(ctdb, &addr);

	if (nodeid == -1) {
		DEBUG(DEBUG_ERR, ("Refused connection from unknown node %s\n", ctdb_addr_to_str(&addr)));
		close(fd);
		return;
	}

	in = talloc_zero(ctcp, struct ctdb_incoming);
	in->fd = fd;
	in->ctdb = ctdb;

	set_nonblocking(in->fd);
	set_close_on_exec(in->fd);

	DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d to incoming ctdb connection\n", fd));

        if (setsockopt(in->fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&one,sizeof(one)) == -1) {
		DEBUG(DEBUG_WARNING, ("Failed to set KEEPALIVE on fd - %s\n",
				      strerror(errno)));
	}

	in->queue = ctdb_queue_setup(ctdb, in, in->fd, CTDB_TCP_ALIGNMENT,
				     ctdb_tcp_read_cb, in, "ctdbd-%s", ctdb_addr_to_str(&addr));
}
Exemplo n.º 2
0
/*
  setup the local node address
*/
int ctdb_set_address(struct ctdb_context *ctdb, const char *address)
{
    ctdb->address = talloc(ctdb, ctdb_sock_addr);
    CTDB_NO_MEMORY(ctdb, ctdb->address);

    if (ctdb_parse_address(ctdb, address, ctdb->address) != 0) {
        return -1;
    }

    ctdb->name = talloc_asprintf(ctdb, "%s:%u",
                                 ctdb_addr_to_str(ctdb->address),
                                 ctdb_addr_to_port(ctdb->address));
    return 0;
}
Exemplo n.º 3
0
/* 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)));
			}
		}
	}
}
Exemplo n.º 4
0
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;
		}
	}
}
Exemplo n.º 5
0
/* Load a nodes list file into a nodes array */
static int convert_node_map_to_list(struct ctdb_context *ctdb,
                                    TALLOC_CTX *mem_ctx,
                                    struct ctdb_node_map_old *node_map,
                                    struct ctdb_node ***nodes,
                                    uint32_t *num_nodes)
{
    int i;

    *nodes = talloc_zero_array(mem_ctx,
                               struct ctdb_node *, node_map->num);
    CTDB_NO_MEMORY(ctdb, *nodes);
    *num_nodes = node_map->num;

    for (i = 0; i < node_map->num; i++) {
        struct ctdb_node *node;

        node = talloc_zero(*nodes, struct ctdb_node);
        CTDB_NO_MEMORY(ctdb, node);
        (*nodes)[i] = node;

        node->address = node_map->nodes[i].addr;
        node->name = talloc_asprintf(node, "%s:%u",
                                     ctdb_addr_to_str(&node->address),
                                     ctdb_addr_to_port(&node->address));

        node->flags = node_map->nodes[i].flags;
        if (!(node->flags & NODE_FLAGS_DELETED)) {
            node->flags = NODE_FLAGS_UNHEALTHY;
        }
        node->flags |= NODE_FLAGS_DISCONNECTED;

        node->pnn = i;
        node->ctdb = ctdb;
        node->dead_count = 0;
    }

    return 0;
}
Exemplo n.º 6
0
/* 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;
}
Exemplo n.º 7
0
/*
  automatically find which address to listen on
*/
static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb)
{
	struct ctdb_tcp *ctcp = talloc_get_type(ctdb->private_data,
						struct ctdb_tcp);
        ctdb_sock_addr sock;
	int lock_fd, i;
	const char *lock_path = CTDB_RUNDIR "/.socket_lock";
	struct flock lock;
	int one = 1;
	int sock_size;
	struct tevent_fd *fde;

	/* If there are no nodes, then it won't be possible to find
	 * the first one.  Log a failure and short circuit the whole
	 * process.
	 */
	if (ctdb->num_nodes == 0) {
		DEBUG(DEBUG_CRIT,("No nodes available to attempt bind to - is the nodes file empty?\n"));
		return -1;
	}

	/* in order to ensure that we don't get two nodes with the
	   same adddress, we must make the bind() and listen() calls
	   atomic. The SO_REUSEADDR setsockopt only prevents double
	   binds if the first socket is in LISTEN state  */
	lock_fd = open(lock_path, O_RDWR|O_CREAT, 0666);
	if (lock_fd == -1) {
		DEBUG(DEBUG_CRIT,("Unable to open %s\n", lock_path));
		return -1;
	}

	lock.l_type = F_WRLCK;
	lock.l_whence = SEEK_SET;
	lock.l_start = 0;
	lock.l_len = 1;
	lock.l_pid = 0;

	if (fcntl(lock_fd, F_SETLKW, &lock) != 0) {
		DEBUG(DEBUG_CRIT,("Unable to lock %s\n", lock_path));
		close(lock_fd);
		return -1;
	}

	for (i=0; i < ctdb->num_nodes; i++) {
		if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
			continue;
		}
		sock = ctdb->nodes[i]->address;

		switch (sock.sa.sa_family) {
		case AF_INET:
			sock_size = sizeof(sock.ip);
			break;
		case AF_INET6:
			sock_size = sizeof(sock.ip6);
			break;
		default:
			DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
				sock.sa.sa_family));
			continue;
		}

		ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
		if (ctcp->listen_fd == -1) {
			ctdb_set_error(ctdb, "socket failed\n");
			continue;
		}

		set_close_on_exec(ctcp->listen_fd);

	        if (setsockopt(ctcp->listen_fd,SOL_SOCKET,SO_REUSEADDR,
			       (char *)&one,sizeof(one)) == -1) {
			DEBUG(DEBUG_WARNING, ("Failed to set REUSEADDR on fd - %s\n",
					      strerror(errno)));
		}

		if (bind(ctcp->listen_fd, (struct sockaddr * )&sock, sock_size) == 0) {
			break;
		}

		if (errno == EADDRNOTAVAIL) {
			DEBUG(DEBUG_DEBUG,(__location__ " Failed to bind() to socket. %s(%d)\n",
					strerror(errno), errno));
		} else {
			DEBUG(DEBUG_ERR,(__location__ " Failed to bind() to socket. %s(%d)\n",
					strerror(errno), errno));
		}

		close(ctcp->listen_fd);
		ctcp->listen_fd = -1;
	}

	if (i == ctdb->num_nodes) {
		DEBUG(DEBUG_CRIT,("Unable to bind to any of the node addresses - giving up\n"));
		goto failed;
	}
	ctdb->address = talloc_memdup(ctdb,
				      &ctdb->nodes[i]->address,
				      sizeof(ctdb_sock_addr));
	if (ctdb->address == NULL) {
		ctdb_set_error(ctdb, "Out of memory at %s:%d",
			       __FILE__, __LINE__);
		goto failed;
	}

	ctdb->name = talloc_asprintf(ctdb, "%s:%u",
				     ctdb_addr_to_str(ctdb->address),
				     ctdb_addr_to_port(ctdb->address));
	if (ctdb->name == NULL) {
		ctdb_set_error(ctdb, "Out of memory at %s:%d",
			       __FILE__, __LINE__);
		goto failed;
	}
	DEBUG(DEBUG_INFO,("ctdb chose network address %s\n", ctdb->name));

	if (listen(ctcp->listen_fd, 10) == -1) {
		goto failed;
	}

	fde = tevent_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, TEVENT_FD_READ,
			    ctdb_listen_event, ctdb);
	tevent_fd_set_auto_close(fde);

	close(lock_fd);

	return 0;

failed:
	close(lock_fd);
	if (ctcp->listen_fd != -1) {
		close(ctcp->listen_fd);
		ctcp->listen_fd = -1;
	}
	return -1;
}