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