Patch for adding SCTP support in CTDB

Ira Cooper ira at wakeful.net
Sat Sep 24 13:30:59 UTC 2016


Are those tools on every OS we build on?  FreeBSD?  NetBSD?  OpenBSD?
Illumos/OpenSolaris?  Solaris?

If not, can you please properly conditionalize the compilation.

Is there a reason for the 3 entry limit, or was it just handy?

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