Patch for adding SCTP support in CTDB
Vishnu
vishnumr at gmail.com
Mon Sep 26 22:13:35 UTC 2016
On 09/24/2016 06:30 AM, Ira Cooper wrote:
> Are those tools on every OS we build on? FreeBSD? NetBSD? OpenBSD?
> Illumos/OpenSolaris? Solaris?
Yes, as far as I know. The sctp include files and general SCTP support
is available on Linux, *BSD and Solaris variants. I don't think we need
to conditionalize it. If there is a need to conditionalize it, is there
an accepted / recommended way? I'm thinking #ifdef SCTP_SUPPORT and that
is enabled with some OS detection in the automake configure scripts?
>
> If not, can you please properly conditionalize the compilation.
>
> Is there a reason for the 3 entry limit, or was it just handy?
It was just a convenient limit, no particular reason.
>
> I'm sure Martin and Amitay will have more comments.
>
> Cheers,
>
> -Ira
>
> On Fri, Sep 23, 2016 at 6:24 PM, Vishnu <vishnumr at gmail.com> wrote:
>> Hi,
>>
>> SCTP is useful in HA environments with multiple IP networks / multi-homing.
>> It provides automatic network redundancy. When setting up a HA NAS system, I
>> added sctp support to ctdb some time last year. Just updated the patch to
>> apply on the latest ctdb git tree and built it.
>>
>> Discussed this with Jose Rivera at SDC recently, he seemed to like this idea
>> of ctdb using sctp as a transport. Here's my patch:
>>
>> Cheers
>> Vishnu
>>
>> From 25d538caed0dacefd28da0e7b8b7f0d06dbd91dd Mon Sep 17 00:00:00 2001
>> From: Vishnu Rangayyan <vishnumr at gmail.com>
>> Date: Fri, 23 Sep 2016 15:09:27 -0700
>> Subject: [PATCH] Add SCTP support to allow multi-homed / multi-IP-network
>> ctdb
>> nodes to use SCTP for network path redundancy. This patch allows defining
>> upto 3 IP addresses on each ctdb node that it will try to use for sctp
>> connections. The sctp handling is very similar to tcp and hence we reuse
>> most
>> of the current tcp handling code. Requires lksctp-tools and
>> lksctp-tools-devel to build.
>>
>> ---
>> Makefile.in | 5 +-
>> common/ctdb_io.c | 33 +++++++++++-
>> config/ctdb.sysconfig | 2 +-
>> include/ctdb_private.h | 9 +++-
>> packaging/RPM/ctdb.spec.in | 4 +-
>> server/ctdb_daemon.c | 7 +++
>> server/ctdb_recover.c | 10 ++--
>> server/ctdb_server.c | 66 ++++++++++++++++++------
>> tcp/ctdb_tcp.h | 2 +
>> tcp/tcp_connect.c | 119
>> ++++++++++++++++++++++++++++++++++----------
>> tcp/tcp_init.c | 7 ++-
>> tests/src/ctdb_test_stubs.c | 10 ++--
>> 12 files changed, 216 insertions(+), 58 deletions(-)
>>
>> diff --git a/Makefile.in b/Makefile.in
>> index 55b21b7..8b7bad9 100755
>> --- a/Makefile.in
>> +++ b/Makefile.in
>> @@ -42,6 +42,8 @@ TDB_LIBS = @TDB_LIBS@
>> TDB_CFLAGS = @TDB_CFLAGS@
>> TDB_OBJ = @TDB_OBJ@
>>
>> +SCTP_LIBS = -lsctp
>> +
>> REPLACE_OBJ = @LIBREPLACEOBJ@
>>
>> SOCKET_WRAPPER_OBJ = @SOCKET_WRAPPER_OBJS@
>> @@ -75,7 +77,8 @@ LDSHFLAGS=-fPIC -shared
>> #LDSHFLAGS=-fPIC -shared -Wl,-Bsymbolic -Wl,-z,relo -Wl,-Bsymbolic-funtions
>> -Wl,--as-needed -Wl,-z,defs
>> SHLD=${CC} ${CFLAGS} ${LDSHFLAGS} -o $@
>>
>> -LIB_FLAGS=@LDFLAGS@ -Llib @LIBS@ $(POPT_LIBS) $(TALLOC_LIBS) $(TEVENT_LIBS)
>> $(TDB_LIBS) \
>> +LIB_FLAGS=@LDFLAGS@ -Llib @LIBS@ $(POPT_LIBS) $(TALLOC_LIBS) $(TEVENT_LIBS)
>> \
>> + $(TDB_LIBS) $(SCTP_LIBS) \
>> @INFINIBAND_LIBS@ @CTDB_PCAP_LDFLAGS@
>>
>> CTDB_VERSION_H = include/ctdb_version.h
>> diff --git a/common/ctdb_io.c b/common/ctdb_io.c
>> index 351006d..6d83a7d 100644
>> --- a/common/ctdb_io.c
>> +++ b/common/ctdb_io.c
>> @@ -28,6 +28,7 @@
>> #include "../include/ctdb_private.h"
>> #include "../include/ctdb_client.h"
>> #include <stdarg.h>
>> +#include <netinet/sctp.h>
>>
>> #define QUEUE_BUFFER_SIZE (16*1024)
>>
>> @@ -154,6 +155,9 @@ static void queue_io_read(struct ctdb_queue *queue)
>> ssize_t nread;
>> uint8_t *data;
>> int navail;
>> + struct ctdb_req_header hdr;
>> + int msgflags = MSG_PEEK;
>> + socklen_t fromlen = 0;
>>
>> /* check how much data is available on the socket for immediately
>> guaranteed nonblocking access.
>> @@ -161,9 +165,34 @@ static void queue_io_read(struct ctdb_queue *queue)
>> we know all reads will be successful and will neither block
>> nor fail with a "data not available right now" error
>> */
>> - if (ioctl(queue->fd, FIONREAD, &num_ready) != 0) {
>> - return;
>> + if (queue->ctdb->protocol != IPPROTO_SCTP) {
>> + if (ioctl(queue->fd, FIONREAD, &num_ready) != 0) {
>> + return;
>> + }
>> + } else {
>> + /* sctp does not support ioctls.
>> + * peek into the socket buffer and read the hdr.
>> + */
>> + num_ready = sctp_recvmsg(queue->fd, (void *)&hdr, sizeof(hdr),
>> + NULL, &fromlen, NULL, &msgflags);
>> + if (num_ready < 0) {
>> + if (errno == ECONNRESET || errno == EINTR ||
>> + errno == EAGAIN || errno == EWOULDBLOCK)
>> + return;
>> + /* something bad happened.. cleanup. */
>> + DEBUG(DEBUG_ERR, ("recv error on socket %d\n", errno));
>> + goto failed;
>> + }
>> +
>> + if (num_ready && num_ready < sizeof(hdr))
>> + /* not enough data in socket buffer */
>> + return;
>> +
>> + if (num_ready == sizeof(hdr) && hdr.ctdb_magic == CTDB_MAGIC)
>> + /* adjust length to read to entire message size */
>> + num_ready = hdr.length;
>> }
>> +
>> if (num_ready == 0) {
>> /* the descriptor has been closed */
>> goto failed;
>> diff --git a/config/ctdb.sysconfig b/config/ctdb.sysconfig
>> index 35bf5f8..63ec5a4 100644
>> --- a/config/ctdb.sysconfig
>> +++ b/config/ctdb.sysconfig
>> @@ -111,7 +111,7 @@ CTDB_RECOVERY_LOCK="/some/place/on/shared/storage"
>> # defaults to /var/run/ctdb/ctdbd.socket
>> # CTDB_SOCKET=/var/run/ctdb/ctdbd.socket
>>
>> -# what transport to use. Only tcp is currently supported
>> +# what transport to use. tcp or sctp are allowed options.
>> # defaults to tcp
>> # CTDB_TRANSPORT="tcp"
>>
>> diff --git a/include/ctdb_private.h b/include/ctdb_private.h
>> index b4966b8..b6176e0 100644
>> --- a/include/ctdb_private.h
>> +++ b/include/ctdb_private.h
>> @@ -209,12 +209,15 @@ struct ctdb_vnn {
>> bool update_in_flight;
>> };
>>
>> +#define CTDB_SCTP_MAX_NETS 3 /* max networks/IPs for sctp multi-homing
>> */
>> +
>> /*
>> state associated with one node
>> */
>> struct ctdb_node {
>> struct ctdb_context *ctdb;
>> - struct ctdb_address address;
>> + /* support multiple addresses for sctp. only address[0] used for tcp.
>> */
>> + struct ctdb_address address[CTDB_SCTP_MAX_NETS];
>> const char *name; /* for debug messages */
>> void *private_data; /* private to transport */
>> uint32_t pnn;
>> @@ -459,7 +462,9 @@ struct ctdb_context {
>> struct ctdb_freeze_handle *freeze_handles[NUM_DB_PRIORITIES+1];
>> bool freeze_transaction_started;
>> uint32_t freeze_transaction_id;
>> - struct ctdb_address address;
>> + /* support multiple addresses for sctp. only address[0] used for tcp.
>> */
>> + struct ctdb_address address[CTDB_SCTP_MAX_NETS];
>> + int protocol;
>> const char *name;
>> const char *db_directory;
>> const char *db_directory_persistent;
>> diff --git a/packaging/RPM/ctdb.spec.in b/packaging/RPM/ctdb.spec.in
>> index b7d1bef..fb27cb5 100644
>> --- a/packaging/RPM/ctdb.spec.in
>> +++ b/packaging/RPM/ctdb.spec.in
>> @@ -14,7 +14,7 @@ URL: http://ctdb.samba.org/
>> Source: ctdb-%{version}.tar.gz
>>
>> # Packages
>> -Requires: coreutils, sed, gawk, iptables, iproute, procps, ethtool, sudo
>> +Requires: coreutils, sed, gawk, iptables, iproute, procps, ethtool, sudo,
>> lksctp-tools
>> # Commands - package name might vary
>> Requires: /usr/bin/killall, /bin/kill, /bin/netstat
>>
>> @@ -60,6 +60,8 @@ BuildRequires: pcp-libs-devel
>> BuildRequires: systemd-units
>> %endif
>>
>> +BuildRequires: lksctp-tools-devel
>> +
>> %description
>> ctdb is the clustered database used by samba
>>
>> diff --git a/server/ctdb_daemon.c b/server/ctdb_daemon.c
>> index cbe6b23..db10f50 100644
>> --- a/server/ctdb_daemon.c
>> +++ b/server/ctdb_daemon.c
>> @@ -1238,6 +1238,13 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool
>> do_fork, bool use_syslog)
>> int ctdb_tcp_init(struct ctdb_context *);
>> ret = ctdb_tcp_init(ctdb);
>> }
>> +
>> + /* we reuse most of the existing tcp code for sctp */
>> + if (strcmp(ctdb->transport, "sctp") == 0) {
>> + int ctdb_tcp_init(struct ctdb_context *);
>> + ret = ctdb_tcp_init(ctdb);
>> + }
>> +
>> #ifdef USE_INFINIBAND
>> if (strcmp(ctdb->transport, "ib") == 0) {
>> int ctdb_ibw_init(struct ctdb_context *);
>> diff --git a/server/ctdb_recover.c b/server/ctdb_recover.c
>> index 1cbcc59..e22471a 100644
>> --- a/server/ctdb_recover.c
>> +++ b/server/ctdb_recover.c
>> @@ -137,12 +137,12 @@ ctdb_control_getnodemap(struct ctdb_context *ctdb,
>> uint32_t opcode, TDB_DATA ind
>> node_map = (struct ctdb_node_map *)outdata->dptr;
>> node_map->num = num_nodes;
>> for (i=0; i<num_nodes; i++) {
>> - if (parse_ip(ctdb->nodes[i]->address.address,
>> + if (parse_ip(ctdb->nodes[i]->address[0].address,
>> NULL, /* TODO: pass in the correct interface here*/
>> 0,
>> &node_map->nodes[i].addr) == 0)
>> {
>> - DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a
>> sockaddr\n", ctdb->nodes[i]->address.address));
>> + DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a
>> sockaddr\n", ctdb->nodes[i]->address[0].address));
>> }
>>
>> node_map->nodes[i].pnn = ctdb->nodes[i]->pnn;
>> @@ -175,8 +175,8 @@ ctdb_control_getnodemapv4(struct ctdb_context *ctdb,
>> uint32_t opcode, TDB_DATA i
>> node_map = (struct ctdb_node_mapv4 *)outdata->dptr;
>> node_map->num = num_nodes;
>> for (i=0; i<num_nodes; i++) {
>> - if (parse_ipv4(ctdb->nodes[i]->address.address, 0,
>> &node_map->nodes[i].sin) == 0) {
>> - DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a
>> sockaddr\n", ctdb->nodes[i]->address.address));
>> + if (parse_ipv4(ctdb->nodes[i]->address[0].address, 0,
>> &node_map->nodes[i].sin) == 0) {
>> + DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a
>> sockaddr\n", ctdb->nodes[i]->address[0].address));
>> return -1;
>> }
>>
>> @@ -210,7 +210,7 @@ ctdb_reload_nodes_event(struct event_context *ev, struct
>> timed_event *te,
>>
>> for (i=0; i<ctdb->num_nodes; i++) {
>> /* keep any identical pre-existing nodes and connections */
>> - if ((i < num_nodes) && ctdb_same_address(&ctdb->nodes[i]->address,
>> &nodes[i]->address)) {
>> + if ((i < num_nodes) &&
>> ctdb_same_address(&ctdb->nodes[i]->address[0], &nodes[i]->address[0])) {
>> talloc_free(ctdb->nodes[i]);
>> ctdb->nodes[i] = talloc_steal(ctdb->nodes, nodes[i]);
>> continue;
>> diff --git a/server/ctdb_server.c b/server/ctdb_server.c
>> index c45f4cb..22e83c6 100644
>> --- a/server/ctdb_server.c
>> +++ b/server/ctdb_server.c
>> @@ -41,14 +41,19 @@ int ctdb_set_transport(struct ctdb_context *ctdb, const
>> char *transport)
>> */
>> int ctdb_ip_to_nodeid(struct ctdb_context *ctdb, const char *nodeip)
>> {
>> - int nodeid;
>> + int nodeid, i;
>>
>> for (nodeid=0;nodeid<ctdb->num_nodes;nodeid++) {
>> if (ctdb->nodes[nodeid]->flags & NODE_FLAGS_DELETED) {
>> continue;
>> }
>> - if (!strcmp(ctdb->nodes[nodeid]->address.address, nodeip)) {
>> - return nodeid;
>> + for (i = 0; i < CTDB_SCTP_MAX_NETS; i++) {
>> + if (!ctdb->nodes[nodeid]->address[i].address)
>> + break;
>> + if (!strcmp(ctdb->nodes[nodeid]->address[i].address,
>> + nodeip)) {
>> + return nodeid;
>> + }
>> }
>> }
>>
>> @@ -83,6 +88,8 @@ int ctdb_set_recovery_lock_file(struct ctdb_context *ctdb,
>> const char *file)
>> static int ctdb_add_node(struct ctdb_context *ctdb, char *nstr)
>> {
>> struct ctdb_node *node, **nodep;
>> + int i, ret;
>> + char *addr_list, *token, *saveptr;
>>
>> nodep = talloc_realloc(ctdb, ctdb->nodes, struct ctdb_node *,
>> ctdb->num_nodes+1);
>> CTDB_NO_MEMORY(ctdb, nodep);
>> @@ -93,21 +100,33 @@ static int ctdb_add_node(struct ctdb_context *ctdb,
>> char *nstr)
>> CTDB_NO_MEMORY(ctdb, *nodep);
>> node = *nodep;
>>
>> - if (ctdb_parse_address(ctdb, node, nstr, &node->address) != 0) {
>> - return -1;
>> + /* allow a comma or space separated list of ip addresses per node */
>> + addr_list = talloc_strdup(ctdb->nodes, nstr);
>> + CTDB_NO_MEMORY(ctdb, addr_list);
>> +
>> + token = strtok_r(addr_list, " ,", &saveptr);
>> + for (i = 0; i < CTDB_SCTP_MAX_NETS && token; i++) {
>> + ret = ctdb_parse_address(ctdb, node, token, &(node->address[i]));
>> + if (ret)
>> + break;
>> + token = strtok_r(NULL, " ,", &saveptr);
>> }
>> + talloc_free(addr_list);
>> + if (ret)
>> + return -1;
>> +
>> node->ctdb = ctdb;
>> node->name = talloc_asprintf(node, "%s:%u",
>> - node->address.address,
>> - node->address.port);
>> + node->address[0].address,
>> + node->address[0].port);
>> /* this assumes that the nodes are kept in sorted order, and no gaps */
>> node->pnn = ctdb->num_nodes;
>>
>> /* nodes start out disconnected and unhealthy */
>> node->flags = (NODE_FLAGS_DISCONNECTED | NODE_FLAGS_UNHEALTHY);
>>
>> - if (ctdb->address.address &&
>> - ctdb_same_address(&ctdb->address, &node->address)) {
>> + if (ctdb->address[0].address &&
>> + ctdb_same_address(&ctdb->address[0], &node->address[0])) {
>> /* for automatic binding to interfaces, see tcp_connect.c */
>> ctdb->pnn = node->pnn;
>> }
>> @@ -138,7 +157,7 @@ static int ctdb_add_deleted_node(struct ctdb_context
>> *ctdb)
>> CTDB_NO_MEMORY(ctdb, *nodep);
>> node = *nodep;
>>
>> - if (ctdb_parse_address(ctdb, node, "0.0.0.0", &node->address) != 0) {
>> + if (ctdb_parse_address(ctdb, node, "0.0.0.0", &node->address[0]) != 0)
>> {
>> DEBUG(DEBUG_ERR,("Failed to setup deleted node %d\n",
>> ctdb->num_nodes));
>> return -1;
>> }
>> @@ -245,13 +264,28 @@ void ctdb_load_nodes_file(struct ctdb_context *ctdb)
>> */
>> int ctdb_set_address(struct ctdb_context *ctdb, const char *address)
>> {
>> - if (ctdb_parse_address(ctdb, ctdb, address, &ctdb->address) != 0) {
>> - return -1;
>> + int i, ret = 0;
>> + char *addr_list, *token, *saveptr;
>> +
>> + /* allow a comma or space separated list of ip addresses for us */
>> + addr_list = talloc_strdup(ctdb, address);
>> + CTDB_NO_MEMORY(ctdb, addr_list);
>> +
>> + token = strtok_r(addr_list, " ,", &saveptr);
>> + for (i = 0; i < CTDB_SCTP_MAX_NETS && token; i++) {
>> + ret = ctdb_parse_address(ctdb, ctdb, token, &(ctdb->address[i]));
>> + if (ret)
>> + break;
>> + token = strtok_r(NULL, " ,", &saveptr);
>> }
>> -
>> - ctdb->name = talloc_asprintf(ctdb, "%s:%u",
>> - ctdb->address.address,
>> - ctdb->address.port);
>> + talloc_free(addr_list);
>> + if (ret)
>> + return -1;
>> +
>> + ctdb->name = talloc_asprintf(ctdb, "%s:%u",
>> + ctdb->address[0].address,
>> + ctdb->address[0].port);
>> +
>> return 0;
>> }
>>
>> diff --git a/tcp/ctdb_tcp.h b/tcp/ctdb_tcp.h
>> index 5b6b651..37b0457 100644
>> --- a/tcp/ctdb_tcp.h
>> +++ b/tcp/ctdb_tcp.h
>> @@ -20,6 +20,8 @@
>> #ifndef _CTDB_TCP_H
>> #define _CTDB_TCP_H
>>
>> +#include <netinet/sctp.h>
>> +
>> /* ctdb_tcp main state */
>> struct ctdb_tcp {
>> struct ctdb_context *ctdb;
>> diff --git a/tcp/tcp_connect.c b/tcp/tcp_connect.c
>> index 9df3300..3c74b44 100644
>> --- a/tcp/tcp_connect.c
>> +++ b/tcp/tcp_connect.c
>> @@ -95,7 +95,10 @@ static void ctdb_node_connect_write(struct event_context
>> *ev, struct fd_event *f
>> talloc_free(tnode->connect_fde);
>> tnode->connect_fde = NULL;
>>
>> - setsockopt(tnode->fd,IPPROTO_TCP,TCP_NODELAY,(char
>> *)&one,sizeof(one));
>> + if (ctdb->protocol == IPPROTO_TCP) {
>> + setsockopt(tnode->fd,IPPROTO_TCP,TCP_NODELAY,(char *)&one,
>> + sizeof(one));
>> + }
>> setsockopt(tnode->fd,SOL_SOCKET,SO_KEEPALIVE,(char
>> *)&one,sizeof(one));
>>
>> ctdb_queue_set_fd(tnode->out_queue, tnode->fd);
>> @@ -137,15 +140,15 @@ void ctdb_tcp_node_connect(struct event_context *ev,
>> struct timed_event *te,
>> #ifdef HAVE_SOCK_SIN_LEN
>> sock_out.ip.sin_len = sizeof(sock_out);
>> #endif
>> - if (ctdb_tcp_get_address(ctdb, node->address.address, &sock_out) != 0)
>> {
>> + if (ctdb_tcp_get_address(ctdb, node->address[0].address, &sock_out) !=
>> 0) {
>> return;
>> }
>> switch (sock_out.sa.sa_family) {
>> case AF_INET:
>> - sock_out.ip.sin_port = htons(node->address.port);
>> + sock_out.ip.sin_port = htons(node->address[0].port);
>> break;
>> case AF_INET6:
>> - sock_out.ip6.sin6_port = htons(node->address.port);
>> + sock_out.ip6.sin6_port = htons(node->address[0].port);
>> break;
>> default:
>> DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
>> @@ -153,7 +156,7 @@ void ctdb_tcp_node_connect(struct event_context *ev,
>> struct timed_event *te,
>> return;
>> }
>>
>> - tnode->fd = socket(sock_out.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
>> + tnode->fd = socket(sock_out.sa.sa_family, SOCK_STREAM, ctdb->protocol);
>> if (tnode->fd == -1) {
>> DEBUG(DEBUG_ERR, (__location__ "Failed to create socket\n"));
>> return;
>> @@ -170,7 +173,7 @@ void ctdb_tcp_node_connect(struct event_context *ev,
>> struct timed_event *te,
>> * a dedicated non-routeable network.
>> */
>> ZERO_STRUCT(sock_in);
>> - if (ctdb_tcp_get_address(ctdb, ctdb->address.address, &sock_in) != 0) {
>> + if (ctdb_tcp_get_address(ctdb, ctdb->address[0].address, &sock_in) !=
>> 0) {
>> DEBUG(DEBUG_ERR, (__location__ " Failed to find our address.
>> Failing bind.\n"));
>> close(tnode->fd);
>> return;
>> @@ -282,8 +285,8 @@ 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;
>> + ctdb_sock_addr sock, sock_sctp;
>> + int lock_fd, i, j;
>> const char *lock_path = VARDIR "/run/ctdb/.socket_lock";
>> struct flock lock;
>> int one = 1;
>> @@ -327,18 +330,18 @@ static int ctdb_tcp_listen_automatic(struct
>> ctdb_context *ctdb)
>> }
>> ZERO_STRUCT(sock);
>> if (ctdb_tcp_get_address(ctdb,
>> - ctdb->nodes[i]->address.address,
>> + ctdb->nodes[i]->address[0].address,
>> &sock) != 0) {
>> continue;
>> }
>>
>> switch (sock.sa.sa_family) {
>> case AF_INET:
>> - sock.ip.sin_port = htons(ctdb->nodes[i]->address.port);
>> + sock.ip.sin_port = htons(ctdb->nodes[i]->address[0].port);
>> sock_size = sizeof(sock.ip);
>> break;
>> case AF_INET6:
>> - sock.ip6.sin6_port = htons(ctdb->nodes[i]->address.port);
>> + sock.ip6.sin6_port = htons(ctdb->nodes[i]->address[0].port);
>> sock_size = sizeof(sock.ip6);
>> break;
>> default:
>> @@ -350,7 +353,7 @@ static int ctdb_tcp_listen_automatic(struct ctdb_context
>> *ctdb)
>> sock.ip.sin_len = sock_size;
>> #endif
>>
>> - ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM,
>> IPPROTO_TCP);
>> + ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM,
>> ctdb->protocol);
>> if (ctcp->listen_fd == -1) {
>> ctdb_set_error(ctdb, "socket failed\n");
>> continue;
>> @@ -377,17 +380,51 @@ static int ctdb_tcp_listen_automatic(struct
>> ctdb_context *ctdb)
>> DEBUG(DEBUG_CRIT,("Unable to bind to any of the node addresses -
>> giving up\n"));
>> goto failed;
>> }
>> - ctdb->address.address = talloc_strdup(ctdb,
>> ctdb->nodes[i]->address.address);
>> - ctdb->address.port = ctdb->nodes[i]->address.port;
>> + ctdb->address[0].address = talloc_strdup(ctdb,
>> ctdb->nodes[i]->address[0].address);
>> + ctdb->address[0].port = ctdb->nodes[i]->address[0].port;
>> ctdb->name = talloc_asprintf(ctdb, "%s:%u",
>> - ctdb->address.address,
>> - ctdb->address.port);
>> + ctdb->address[0].address,
>> + ctdb->address[0].port);
>> ctdb->pnn = ctdb->nodes[i]->pnn;
>> DEBUG(DEBUG_INFO,("ctdb chose network address %s:%u pnn %u\n",
>> - ctdb->address.address,
>> - ctdb->address.port,
>> + ctdb->address[0].address,
>> + ctdb->address[0].port,
>> ctdb->pnn));
>>
>> + if (ctdb->protocol == IPPROTO_SCTP) {
>> + /* try to add any additional addresses specified */
>> + for (j = 1; j < CTDB_SCTP_MAX_NETS; j++) {
>> + if (!ctdb->nodes[i]->address[j].address)
>> + break;
>> + ZERO_STRUCT(sock_sctp);
>> + if (ctdb_tcp_get_address(ctdb,
>> + ctdb->nodes[i]->address[j].address,
>> + &sock_sctp) != 0) {
>> + continue;
>> + }
>> + if (sock_sctp.sa.sa_family != sock.sa.sa_family) {
>> + DEBUG(DEBUG_ERR, (__location__ "Cannot mix IPv4 and IPv6
>> addresses, skipping %s\n",
>> + ctdb->nodes[i]->address[j].address));
>> + continue;
>> + }
>> + switch (sock_sctp.sa.sa_family) {
>> + case AF_INET:
>> + sock_sctp.ip.sin_port =
>> htons(ctdb->nodes[i]->address[j].port);
>> + break;
>> + case AF_INET6:
>> + sock_sctp.ip6.sin6_port =
>> htons(ctdb->nodes[i]->address[j].port);
>> + break;
>> + }
>> + if (sctp_bindx(ctcp->listen_fd,
>> + (struct sockaddr *)&sock_sctp, 1,
>> + SCTP_BINDX_ADD_ADDR) != 0) {
>> + DEBUG(DEBUG_ERR, (__location__ "sctp_bindx failed for
>> %s\n",
>> + ctdb->nodes[i]->address[j].address));
>> + continue;
>> + }
>> + }
>> + }
>> +
>> if (listen(ctcp->listen_fd, 10) == -1) {
>> goto failed;
>> }
>> @@ -415,30 +452,30 @@ int ctdb_tcp_listen(struct ctdb_context *ctdb)
>> {
>> struct ctdb_tcp *ctcp = talloc_get_type(ctdb->private_data,
>> struct ctdb_tcp);
>> - ctdb_sock_addr sock;
>> - int sock_size;
>> + ctdb_sock_addr sock, sock_sctp;
>> + int sock_size, i;
>> int one = 1;
>> struct tevent_fd *fde;
>>
>> /* we can either auto-bind to the first available address, or we can
>> use a specified address */
>> - if (!ctdb->address.address) {
>> + if (!ctdb->address[0].address) {
>> return ctdb_tcp_listen_automatic(ctdb);
>> }
>>
>> ZERO_STRUCT(sock);
>> - if (ctdb_tcp_get_address(ctdb, ctdb->address.address,
>> + if (ctdb_tcp_get_address(ctdb, ctdb->address[0].address,
>> &sock) != 0) {
>> goto failed;
>> }
>>
>> switch (sock.sa.sa_family) {
>> case AF_INET:
>> - sock.ip.sin_port = htons(ctdb->address.port);
>> + sock.ip.sin_port = htons(ctdb->address[0].port);
>> sock_size = sizeof(sock.ip);
>> break;
>> case AF_INET6:
>> - sock.ip6.sin6_port = htons(ctdb->address.port);
>> + sock.ip6.sin6_port = htons(ctdb->address[0].port);
>> sock_size = sizeof(sock.ip6);
>> break;
>> default:
>> @@ -450,7 +487,7 @@ int ctdb_tcp_listen(struct ctdb_context *ctdb)
>> sock.ip.sin_len = sock_size;
>> #endif
>>
>> - ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
>> + ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM,
>> ctdb->protocol);
>> if (ctcp->listen_fd == -1) {
>> ctdb_set_error(ctdb, "socket failed\n");
>> return -1;
>> @@ -465,6 +502,38 @@ int ctdb_tcp_listen(struct ctdb_context *ctdb)
>> goto failed;
>> }
>>
>> + if (ctdb->protocol == IPPROTO_SCTP) {
>> + /* try to add any additional addresses specified */
>> + for (i = 1; i < CTDB_SCTP_MAX_NETS; i++) {
>> + if (!ctdb->address[i].address)
>> + break;
>> + ZERO_STRUCT(sock_sctp);
>> + if (ctdb_tcp_get_address(ctdb, ctdb->address[i].address,
>> + &sock_sctp) != 0) {
>> + continue;
>> + }
>> + if (sock_sctp.sa.sa_family != sock.sa.sa_family) {
>> + DEBUG(DEBUG_ERR, (__location__ "Cannot mix IPv4 and IPv6
>> addresses, skipping %s\n",
>> + ctdb->address[i].address));
>> + continue;
>> + }
>> + switch (sock_sctp.sa.sa_family) {
>> + case AF_INET:
>> + sock_sctp.ip.sin_port = htons(ctdb->address[i].port);
>> + break;
>> + case AF_INET6:
>> + sock_sctp.ip6.sin6_port = htons(ctdb->address[i].port);
>> + break;
>> + }
>> + if (sctp_bindx(ctcp->listen_fd,(struct sockaddr *)&sock_sctp,
>> + 1, SCTP_BINDX_ADD_ADDR) != 0) {
>> + DEBUG(DEBUG_ERR, (__location__ "sctp_bindx failed for
>> %s\n",
>> + ctdb->address[i].address));
>> + continue;
>> + }
>> + }
>> + }
>> +
>> if (listen(ctcp->listen_fd, 10) == -1) {
>> goto failed;
>> }
>> diff --git a/tcp/tcp_init.c b/tcp/tcp_init.c
>> index a65e732..8ab94c4 100644
>> --- a/tcp/tcp_init.c
>> +++ b/tcp/tcp_init.c
>> @@ -92,7 +92,7 @@ static int ctdb_tcp_connect_node(struct ctdb_node *node)
>>
>> /* startup connection to the other server - will happen on
>> next event loop */
>> - if (!ctdb_same_address(&ctdb->address, &node->address)) {
>> + if (!ctdb_same_address(&ctdb->address[0], &node->address[0])) {
>> tnode->connect_te = event_add_timed(ctdb->ev, tnode,
>> timeval_zero(),
>> ctdb_tcp_node_connect, node);
>> @@ -190,6 +190,11 @@ int ctdb_tcp_init(struct ctdb_context *ctdb)
>> ctcp = talloc_zero(ctdb, struct ctdb_tcp);
>> CTDB_NO_MEMORY(ctdb, ctcp);
>>
>> + if (strcmp(ctdb->transport, "sctp") == 0) {
>> + ctdb->protocol = IPPROTO_SCTP;
>> + } else {
>> + ctdb->protocol = IPPROTO_TCP; /* default */
>> + }
>> ctcp->listen_fd = -1;
>> ctcp->ctdb = ctdb;
>> ctdb->private_data = ctcp;
>> diff --git a/tests/src/ctdb_test_stubs.c b/tests/src/ctdb_test_stubs.c
>> index 456b1fd..c545577 100644
>> --- a/tests/src/ctdb_test_stubs.c
>> +++ b/tests/src/ctdb_test_stubs.c
>> @@ -17,6 +17,8 @@
>> along with this program; if not, see <http://www.gnu.org/licenses/>.
>> */
>>
>> +#include <netinet/sctp.h>
>> +
>> /* Read a nodemap from stdin. Each line looks like:
>> * <PNN> <FLAGS> [RECMASTER] [CURRENT]
>> * EOF or a blank line terminates input.
>> @@ -95,8 +97,8 @@ void ctdb_test_stubs_read_nodemap(struct ctdb_context
>> *ctdb)
>> ctdb->nodes[ctdb->num_nodes]->ctdb = ctdb;
>> ctdb->nodes[ctdb->num_nodes]->name = "fakectdb";
>> ctdb->nodes[ctdb->num_nodes]->pnn = pnn;
>> - ctdb->nodes[ctdb->num_nodes]->address.address = ip;
>> - ctdb->nodes[ctdb->num_nodes]->address.port = 0;
>> + ctdb->nodes[ctdb->num_nodes]->address[0].address = ip;
>> + ctdb->nodes[ctdb->num_nodes]->address[0].port = 0;
>> ctdb->nodes[ctdb->num_nodes]->flags = flags;
>> ctdb->num_nodes++;
>> }
>> @@ -352,12 +354,12 @@ ctdb_control_getnodemap(struct ctdb_context *ctdb,
>> uint32_t opcode, TDB_DATA ind
>> node_map = (struct ctdb_node_map *)outdata->dptr;
>> node_map->num = num_nodes;
>> for (i=0; i<num_nodes; i++) {
>> - if (parse_ip(ctdb->nodes[i]->address.address,
>> + if (parse_ip(ctdb->nodes[i]->address[0].address,
>> NULL, /* TODO: pass in the correct interface here*/
>> 0,
>> &node_map->nodes[i].addr) == 0)
>> {
>> - DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a
>> sockaddr\n", ctdb->nodes[i]->address.address));
>> + DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a
>> sockaddr\n", ctdb->nodes[i]->address[0].address));
>> }
>>
>> node_map->nodes[i].pnn = ctdb->nodes[i]->pnn;
>> --
>> 1.8.3.1
>>
>>
>>
More information about the samba-technical
mailing list