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