[3/5] ocfs2/cluster: support IPv6 socket connection between nodes
diff mbox series

Message ID 5BD19C56.5040201@huawei.com
State New
Headers show
Series
  • ocfs2: support IPv6 communication in o2cb cluster
Related show

Commit Message

piaojun Oct. 25, 2018, 10:35 a.m. UTC
Both IPv4 and IPv6 will be supported when connecting or accepting other
nodes in cluster according to configuration by uppper user.

Signed-off-by: Jun Piao <piaojun@huawei.com>
---
 fs/ocfs2/cluster/nodemanager.c |   4 +-
 fs/ocfs2/cluster/nodemanager.h |   2 +-
 fs/ocfs2/cluster/tcp.c         | 190 ++++++++++++++++++++++++++++++-----------
 3 files changed, 141 insertions(+), 55 deletions(-)

Patch
diff mbox series

diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index 292f5dd..6813517 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -115,7 +115,7 @@  static struct o2nm_node *o2nm_node_ip_tree_lookup(struct o2nm_cluster *cluster,
 	return ret;
 }

-struct o2nm_node *o2nm_get_node_by_ip(__be32 addr)
+struct o2nm_node *o2nm_get_node_by_ip(u8 addr[])
 {
 	struct o2nm_node *node = NULL;
 	struct o2nm_cluster *cluster = o2nm_single_cluster;
@@ -124,7 +124,7 @@  struct o2nm_node *o2nm_get_node_by_ip(__be32 addr)
 		goto out;

 	read_lock(&cluster->cl_nodes_lock);
-	node = o2nm_node_ip_tree_lookup(cluster, (u8 *)&addr, NULL, NULL);
+	node = o2nm_node_ip_tree_lookup(cluster, addr, NULL, NULL);
 	if (node)
 		config_item_get(&node->nd_item);
 	read_unlock(&cluster->cl_nodes_lock);
diff --git a/fs/ocfs2/cluster/nodemanager.h b/fs/ocfs2/cluster/nodemanager.h
index 1f3cfc5..e5f8701 100644
--- a/fs/ocfs2/cluster/nodemanager.h
+++ b/fs/ocfs2/cluster/nodemanager.h
@@ -85,7 +85,7 @@  struct o2nm_cluster {

 int o2nm_configured_node_map(unsigned long *map, unsigned bytes);
 struct o2nm_node *o2nm_get_node_by_num(u8 node_num);
-struct o2nm_node *o2nm_get_node_by_ip(__be32 addr);
+struct o2nm_node *o2nm_get_node_by_ip(u8 addr[]);
 void o2nm_node_get(struct o2nm_node *node);
 void o2nm_node_put(struct o2nm_node *node);

diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 1296f78..82fa8da 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1583,10 +1583,13 @@  static void o2net_start_connect(struct work_struct *work)
 	struct o2net_sock_container *sc = NULL;
 	struct o2nm_node *node = NULL, *mynode = NULL;
 	struct socket *sock = NULL;
+	struct sockaddr *mysa = NULL, *remotesa = NULL;
 	struct sockaddr_in myaddr = {0, }, remoteaddr = {0, };
-	int ret = 0, stop;
+	struct sockaddr_in6 myaddr6 = {0, }, remoteaddr6 = {0, };
+	int ret = 0, stop, addr_len;
 	unsigned int timeout;
 	unsigned int noio_flag;
+	unsigned short sa_family;

 	/*
 	 * sock_create allocates the sock with GFP_KERNEL. We must set
@@ -1633,7 +1636,33 @@  static void o2net_start_connect(struct work_struct *work)
 		goto out;
 	}

-	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+	if (mynode->nd_ipnet_type == IPV4_TYPE) {
+		myaddr.sin_family = sa_family = AF_INET;
+		myaddr.sin_addr.s_addr = mynode->nd_ipv4_address;
+		myaddr.sin_port = htons(0); /* any port */
+		mysa = (struct sockaddr *)&myaddr;
+
+		remoteaddr.sin_family = AF_INET;
+		remoteaddr.sin_addr.s_addr = node->nd_ipv4_address;
+		remoteaddr.sin_port = node->nd_ipv4_port;
+		remotesa = (struct sockaddr *)&remoteaddr;
+		addr_len = sizeof(myaddr);
+	} else {
+		myaddr6.sin6_family = sa_family = AF_INET6;
+		memcpy(&myaddr6.sin6_addr, mynode->nd_ipv6_address,
+				sizeof(mynode->nd_ipv6_address));
+		myaddr6.sin6_port = htons(0); /* any port */
+		mysa = (struct sockaddr *)&myaddr6;
+
+		remoteaddr6.sin6_family = AF_INET6;
+		memcpy(&remoteaddr6.sin6_addr, node->nd_ipv6_address,
+				sizeof(node->nd_ipv6_address));
+		remoteaddr6.sin6_port = node->nd_ipv6_port;
+		remotesa = (struct sockaddr *)&remoteaddr6;
+		addr_len = sizeof(myaddr6);
+	}
+
+	ret = sock_create(sa_family, SOCK_STREAM, IPPROTO_TCP, &sock);
 	if (ret < 0) {
 		mlog(0, "can't create socket: %d\n", ret);
 		goto out;
@@ -1642,15 +1671,14 @@  static void o2net_start_connect(struct work_struct *work)

 	sock->sk->sk_allocation = GFP_ATOMIC;

-	myaddr.sin_family = AF_INET;
-	myaddr.sin_addr.s_addr = mynode->nd_ipv4_address;
-	myaddr.sin_port = htons(0); /* any port */
-
-	ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
-			      sizeof(myaddr));
+	ret = sock->ops->bind(sock, mysa, addr_len);
 	if (ret) {
-		mlog(ML_ERROR, "bind failed with %d at address %pI4\n",
-		     ret, &mynode->nd_ipv4_address);
+		if (mynode->nd_ipnet_type == IPV4_TYPE)
+			mlog(ML_ERROR, "bind failed with %d at address %pI4\n",
+			     ret, &mynode->nd_ipv4_address);
+		else
+			mlog(ML_ERROR, "bind failed with %d at address %pI6\n",
+			     ret, mynode->nd_ipv6_address);
 		goto out;
 	}

@@ -1673,13 +1701,9 @@  static void o2net_start_connect(struct work_struct *work)
 	o2net_set_nn_state(nn, sc, 0, 0);
 	spin_unlock(&nn->nn_lock);

-	remoteaddr.sin_family = AF_INET;
-	remoteaddr.sin_addr.s_addr = node->nd_ipv4_address;
-	remoteaddr.sin_port = node->nd_ipv4_port;
-
 	ret = sc->sc_sock->ops->connect(sc->sc_sock,
-					(struct sockaddr *)&remoteaddr,
-					sizeof(remoteaddr),
+					remotesa,
+					addr_len,
 					O_NONBLOCK);
 	if (ret == -EINPROGRESS)
 		ret = 0;
@@ -1819,11 +1843,13 @@  int o2net_register_hb_callbacks(void)

 static int o2net_accept_one(struct socket *sock, int *more)
 {
-	int ret;
+	int ret, slen;
+	struct sockaddr *sa = NULL;
 	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
 	struct socket *new_sock = NULL;
 	struct o2nm_node *node = NULL;
-	struct o2nm_node *local_node = NULL;
+	struct o2nm_node *local_node = o2nm_get_node_by_num(o2nm_this_node());
 	struct o2net_sock_container *sc = NULL;
 	struct o2net_node *nn;
 	unsigned int noio_flag;
@@ -1864,22 +1890,39 @@  static int o2net_accept_one(struct socket *sock, int *more)
 		goto out;
 	}

-	ret = new_sock->ops->getname(new_sock, (struct sockaddr *) &sin, 1);
+	if (local_node->nd_ipnet_type == IPV4_TYPE) {
+		sa = (struct sockaddr *)&sin;
+		slen = sizeof(sin);
+	} else {
+		sa = (struct sockaddr *)&sin6;
+		slen = sizeof(sin6);
+	}
+	ret = new_sock->ops->getname(new_sock, sa, 1);
 	if (ret < 0)
 		goto out;

-	node = o2nm_get_node_by_ip(sin.sin_addr.s_addr);
-	if (node == NULL) {
-		printk(KERN_NOTICE "o2net: Attempt to connect from unknown "
-		       "node at %pI4:%d\n", &sin.sin_addr.s_addr,
-		       ntohs(sin.sin_port));
-		ret = -EINVAL;
-		goto out;
+	if (local_node->nd_ipnet_type == IPV4_TYPE) {
+		node = o2nm_get_node_by_ip((u8 *)&sin.sin_addr.s_addr);
+		if (node == NULL) {
+			printk(KERN_NOTICE "o2net: Attempt to connect from unknown "
+			       "node at %pI4:%d\n", &sin.sin_addr.s_addr,
+			       ntohs(sin.sin_port));
+			ret = -EINVAL;
+			goto out;
+		}
+	} else {
+		node = o2nm_get_node_by_ip(sin6.sin6_addr.s6_addr);
+		if (node == NULL) {
+			printk(KERN_NOTICE "o2net: Attempt to connect from unknown "
+			       "node at %pI6:%d\n", sin6.sin6_addr.s6_addr,
+			       ntohs(sin6.sin6_port));
+			ret = -EINVAL;
+			goto out;
+		}
 	}

 	if (o2nm_this_node() >= node->nd_num) {
-		local_node = o2nm_get_node_by_num(o2nm_this_node());
-		if (local_node)
+		if (local_node->nd_ipnet_type == IPV4_TYPE)
 			printk(KERN_NOTICE "o2net: Unexpected connect attempt "
 					"seen at node '%s' (%u, %pI4:%d) from "
 					"node '%s' (%u, %pI4:%d)\n",
@@ -1889,6 +1932,16 @@  static int o2net_accept_one(struct socket *sock, int *more)
 					node->nd_name,
 					node->nd_num, &sin.sin_addr.s_addr,
 					ntohs(sin.sin_port));
+		else
+			printk(KERN_NOTICE "o2net: Unexpected connect attempt "
+					"seen at node '%s' (%u, %pI6:%d) from "
+					"node '%s' (%u, %pI6:%d)\n",
+					local_node->nd_name, local_node->nd_num,
+					local_node->nd_ipv6_address,
+					ntohs(local_node->nd_ipv6_port),
+					node->nd_name,
+					node->nd_num, sin6.sin6_addr.s6_addr,
+					ntohs(sin6.sin6_port));
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1896,10 +1949,16 @@  static int o2net_accept_one(struct socket *sock, int *more)
 	/* this happens all the time when the other node sees our heartbeat
 	 * and tries to connect before we see their heartbeat */
 	if (!o2hb_check_node_heartbeating_from_callback(node->nd_num)) {
-		mlog(ML_CONN, "attempt to connect from node '%s' at "
-		     "%pI4:%d but it isn't heartbeating\n",
-		     node->nd_name, &sin.sin_addr.s_addr,
-		     ntohs(sin.sin_port));
+		if (local_node->nd_ipnet_type == IPV4_TYPE)
+			mlog(ML_CONN, "attempt to connect from node '%s' at "
+			     "%pI4:%d but it isn't heartbeating\n",
+			     node->nd_name, &sin.sin_addr.s_addr,
+			     ntohs(sin.sin_port));
+		else
+			mlog(ML_CONN, "attempt to connect from node '%s' at "
+			     "%pI6:%d but it isn't heartbeating\n",
+			     node->nd_name, sin6.sin6_addr.s6_addr,
+			     ntohs(sin6.sin6_port));
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1913,10 +1972,16 @@  static int o2net_accept_one(struct socket *sock, int *more)
 		ret = 0;
 	spin_unlock(&nn->nn_lock);
 	if (ret) {
-		printk(KERN_NOTICE "o2net: Attempt to connect from node '%s' "
-		       "at %pI4:%d but it already has an open connection\n",
-		       node->nd_name, &sin.sin_addr.s_addr,
-		       ntohs(sin.sin_port));
+		if (local_node->nd_ipnet_type == IPV4_TYPE)
+			printk(KERN_NOTICE "o2net: Attempt to connect from node '%s' "
+			       "at %pI4:%d but it already has an open connection\n",
+			       node->nd_name, &sin.sin_addr.s_addr,
+			       ntohs(sin.sin_port));
+		else
+			printk(KERN_NOTICE "o2net: Attempt to connect from node '%s' "
+			       "at %pI6:%d but it already has an open connection\n",
+			       node->nd_name, sin6.sin6_addr.s6_addr,
+			       ntohs(sin6.sin6_port));
 		goto out;
 	}

@@ -2022,17 +2087,30 @@  static void o2net_listen_data_ready(struct sock *sk)
 		ready(sk);
 }

-static int o2net_open_listening_sock(__be32 addr, __be16 port)
+static int o2net_open_listening_sock(struct o2nm_node *node)
 {
 	struct socket *sock = NULL;
-	int ret;
-	struct sockaddr_in sin = {
-		.sin_family = PF_INET,
-		.sin_addr = { .s_addr = addr },
-		.sin_port = port,
-	};
+	int ret, addr_len;
+	struct sockaddr *sa = NULL;
+	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
+	unsigned short sa_family;
+
+	if (node->nd_ipnet_type == IPV4_TYPE) {
+		sin.sin_family = sa_family = PF_INET;
+		sin.sin_addr.s_addr = node->nd_ipv4_address;
+		sin.sin_port = node->nd_ipv4_port;
+		sa = (struct sockaddr *)&sin;
+		addr_len = sizeof(sin);
+	} else {
+		sin6.sin6_family = sa_family = PF_INET6;
+		memcpy(&sin6.sin6_addr, node->nd_ipv6_address, sizeof(sin6.sin6_addr));
+		sin6.sin6_port = node->nd_ipv6_port;
+		sa = (struct sockaddr *)&sin6;
+		addr_len = sizeof(sin6);
+	}

-	ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+	ret = sock_create(sa_family, SOCK_STREAM, IPPROTO_TCP, &sock);
 	if (ret < 0) {
 		printk(KERN_ERR "o2net: Error %d while creating socket\n", ret);
 		goto out;
@@ -2049,17 +2127,26 @@  static int o2net_open_listening_sock(__be32 addr, __be16 port)
 	INIT_WORK(&o2net_listen_work, o2net_accept_many);

 	sock->sk->sk_reuse = SK_CAN_REUSE;
-	ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin));
+	ret = sock->ops->bind(sock, sa, addr_len);
 	if (ret < 0) {
-		printk(KERN_ERR "o2net: Error %d while binding socket at "
-		       "%pI4:%u\n", ret, &addr, ntohs(port));
+		if (node->nd_ipnet_type == IPV4_TYPE)
+			printk(KERN_ERR "o2net: Error %d while binding socket at "
+			       "%pI4:%u\n", ret, &sin.sin_addr.s_addr, ntohs(sin.sin_port));
+		else
+			printk(KERN_ERR "o2net: Error %d while binding socket at "
+			       "%pI6:%u\n", ret, sin6.sin6_addr.s6_addr, ntohs(sin6.sin6_port));
 		goto out;
 	}

 	ret = sock->ops->listen(sock, 64);
-	if (ret < 0)
-		printk(KERN_ERR "o2net: Error %d while listening on %pI4:%u\n",
-		       ret, &addr, ntohs(port));
+	if (ret < 0) {
+		if (node->nd_ipnet_type == IPV4_TYPE)
+			printk(KERN_ERR "o2net: Error %d while listening on %pI4:%u\n",
+			       ret, &sin.sin_addr.s_addr, ntohs(sin.sin_port));
+		else
+			printk(KERN_ERR "o2net: Error %d while listening on %pI6:%u\n",
+			       ret, sin6.sin6_addr.s6_addr, ntohs(sin6.sin6_port));
+	}

 out:
 	if (ret) {
@@ -2091,8 +2178,7 @@  int o2net_start_listening(struct o2nm_node *node)
 		return -ENOMEM; /* ? */
 	}

-	ret = o2net_open_listening_sock(node->nd_ipv4_address,
-					node->nd_ipv4_port);
+	ret = o2net_open_listening_sock(node);
 	if (ret) {
 		destroy_workqueue(o2net_wq);
 		o2net_wq = NULL;