From 5af99cbe433a12603f405b54c575b46fad7f2b5e Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 17 Sep 2025 09:48:15 -0700 Subject: [PATCH] Add IPv6 support to the kernel module. This adds IPv6 support to the kernel module side. Signed-off-by: Auke Kok --- kmod/src/client.c | 2 +- kmod/src/fence.c | 20 ++++-- kmod/src/fence.h | 2 +- kmod/src/net.c | 38 ++++++---- kmod/src/net.h | 59 ++++++++++------ kmod/src/quorum.c | 146 ++++++++++++++++++++++++++++----------- kmod/src/quorum.h | 4 +- kmod/src/scoutfs_trace.h | 40 ++++++----- kmod/src/server.c | 8 +-- kmod/src/server.h | 21 ------ 10 files changed, 212 insertions(+), 128 deletions(-) diff --git a/kmod/src/client.c b/kmod/src/client.c index cffd2bfa..25ea716f 100644 --- a/kmod/src/client.c +++ b/kmod/src/client.c @@ -479,7 +479,7 @@ static void scoutfs_client_connect_worker(struct work_struct *work) struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); struct scoutfs_mount_options opts; struct scoutfs_net_greeting greet; - struct sockaddr_in sin; + struct sockaddr_storage sin; bool am_quorum; int ret; diff --git a/kmod/src/fence.c b/kmod/src/fence.c index a3579228..b5c68dd0 100644 --- a/kmod/src/fence.c +++ b/kmod/src/fence.c @@ -26,6 +26,7 @@ #include "sysfs.h" #include "server.h" #include "fence.h" +#include "net.h" /* * Fencing ensures that a given mount can no longer write to the @@ -81,7 +82,7 @@ struct pending_fence { struct timer_list timer; ktime_t start_kt; - __be32 ipv4_addr; + union scoutfs_inet_addr addr; bool fenced; bool error; int reason; @@ -173,14 +174,19 @@ static ssize_t error_store(struct kobject *kobj, struct kobj_attribute *attr, co } SCOUTFS_ATTR_RW(error); -static ssize_t ipv4_addr_show(struct kobject *kobj, +static ssize_t inet_addr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { DECLARE_FENCE_FROM_KOBJ(fence, kobj); + struct sockaddr_storage sin; - return snprintf(buf, PAGE_SIZE, "%pI4", &fence->ipv4_addr); + memset(&sin, 0, sizeof(struct sockaddr_storage)); + + scoutfs_addr_to_sin(&sin, &fence->addr); + + return snprintf(buf, PAGE_SIZE, "%pISc", SIN_ARG(&sin)); } -SCOUTFS_ATTR_RO(ipv4_addr); +SCOUTFS_ATTR_RO(inet_addr); static ssize_t reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -214,7 +220,7 @@ static struct attribute *fence_attrs[] = { SCOUTFS_ATTR_PTR(elapsed_secs), SCOUTFS_ATTR_PTR(fenced), SCOUTFS_ATTR_PTR(error), - SCOUTFS_ATTR_PTR(ipv4_addr), + SCOUTFS_ATTR_PTR(inet_addr), SCOUTFS_ATTR_PTR(reason), SCOUTFS_ATTR_PTR(rid), NULL, @@ -234,7 +240,7 @@ static void fence_timeout(struct timer_list *timer) wake_up(&fi->waitq); } -int scoutfs_fence_start(struct super_block *sb, u64 rid, __be32 ipv4_addr, int reason) +int scoutfs_fence_start(struct super_block *sb, u64 rid, union scoutfs_inet_addr *addr, int reason) { DECLARE_FENCE_INFO(sb, fi); struct pending_fence *existing; @@ -253,7 +259,7 @@ int scoutfs_fence_start(struct super_block *sb, u64 rid, __be32 ipv4_addr, int r timer_setup(&fence->timer, fence_timeout, 0); fence->start_kt = ktime_get(); - fence->ipv4_addr = ipv4_addr; + memcpy(&fence->addr, addr, sizeof(union scoutfs_inet_addr)); fence->fenced = false; fence->error = false; fence->reason = reason; diff --git a/kmod/src/fence.h b/kmod/src/fence.h index f9139001..40d51943 100644 --- a/kmod/src/fence.h +++ b/kmod/src/fence.h @@ -7,7 +7,7 @@ enum { SCOUTFS_FENCE_QUORUM_BLOCK_LEADER, }; -int scoutfs_fence_start(struct super_block *sb, u64 rid, __be32 ipv4_addr, int reason); +int scoutfs_fence_start(struct super_block *sb, u64 rid, union scoutfs_inet_addr *addr, int reason); int scoutfs_fence_next(struct super_block *sb, u64 *rid, int *reason, bool *error); int scoutfs_fence_reason_pending(struct super_block *sb, int reason); int scoutfs_fence_free(struct super_block *sb, u64 rid); diff --git a/kmod/src/net.c b/kmod/src/net.c index 8ff4a22d..9e6d0fab 100644 --- a/kmod/src/net.c +++ b/kmod/src/net.c @@ -1218,7 +1218,8 @@ static void scoutfs_net_connect_worker(struct work_struct *work) trace_scoutfs_net_connect_work_enter(sb, 0, 0); - ret = sock_create_kern(&init_net, AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + ret = sock_create_kern(&init_net, conn->connect_sin.ss_family, + SOCK_STREAM, IPPROTO_TCP, &sock); if (ret) goto out; @@ -1239,7 +1240,9 @@ static void scoutfs_net_connect_worker(struct work_struct *work) trace_scoutfs_conn_connect_start(conn); ret = kernel_connect(sock, (struct sockaddr *)&conn->connect_sin, - sizeof(struct sockaddr_in), 0); + conn->connect_sin.ss_family == AF_INET ? + sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), + 0); if (ret) goto out; @@ -1281,6 +1284,13 @@ static bool empty_accepted_list(struct scoutfs_net_connection *conn) return empty; } +/* + * sockaddr_storage wraps both _in and _in6, which have _port always + * __be16 at the same offset, and we only need to test whether it's + * zero. + */ +#define sockaddr_port_is_nonzero(sin) ((sin).__data[0] || (sin).__data[1]) + /* * Safely shut down an active connection. This can be triggered by * errors in workers or by an external call to free the connection. The @@ -1304,7 +1314,7 @@ static void scoutfs_net_shutdown_worker(struct work_struct *work) trace_scoutfs_conn_shutdown_start(conn); /* connected and accepted conns print a message */ - if (conn->peername.sin_port != 0) + if (sockaddr_port_is_nonzero(conn->peername)) scoutfs_info(sb, "%s "SIN_FMT" -> "SIN_FMT, conn->listening_conn ? "server closing" : "client disconnected", @@ -1434,6 +1444,7 @@ static void scoutfs_net_reconn_free_worker(struct work_struct *work) DEFINE_CONN_FROM_WORK(conn, work, reconn_free_dwork.work); struct super_block *sb = conn->sb; struct scoutfs_net_connection *acc; + union scoutfs_inet_addr addr; unsigned long now = jiffies; unsigned long deadline = 0; bool requeue = false; @@ -1454,8 +1465,9 @@ restart: if (!test_conn_fl(conn, shutting_down)) { scoutfs_info(sb, "client "SIN_FMT" reconnect timed out, fencing", SIN_ARG(&acc->last_peername)); + scoutfs_sin_to_addr(&addr, &acc->last_peername); ret = scoutfs_fence_start(sb, acc->rid, - acc->last_peername.sin_addr.s_addr, + &addr, SCOUTFS_FENCE_CLIENT_RECONNECT); if (ret) { scoutfs_err(sb, "client fence returned err %d, shutting down server", @@ -1537,9 +1549,9 @@ scoutfs_net_alloc_conn(struct super_block *sb, conn->req_funcs = req_funcs; spin_lock_init(&conn->lock); init_waitqueue_head(&conn->waitq); - conn->sockname.sin_family = AF_INET; - conn->peername.sin_family = AF_INET; - conn->last_peername.sin_family = AF_INET; + conn->sockname.ss_family = AF_UNSPEC; + conn->peername.ss_family = AF_UNSPEC; + conn->last_peername.ss_family = AF_UNSPEC; INIT_LIST_HEAD(&conn->accepted_head); INIT_LIST_HEAD(&conn->accepted_list); conn->next_send_seq = 1; @@ -1618,7 +1630,7 @@ void scoutfs_net_free_conn(struct super_block *sb, */ int scoutfs_net_bind(struct super_block *sb, struct scoutfs_net_connection *conn, - struct sockaddr_in *sin) + struct sockaddr_storage *sin) { struct socket *sock = NULL; int addrlen; @@ -1629,7 +1641,7 @@ int scoutfs_net_bind(struct super_block *sb, if (WARN_ON_ONCE(conn->sock)) return -EINVAL; - ret = sock_create_kern(&init_net, AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + ret = sock_create_kern(&init_net, sin->ss_family, SOCK_STREAM, IPPROTO_TCP, &sock); if (ret) goto out; @@ -1641,7 +1653,7 @@ int scoutfs_net_bind(struct super_block *sb, if (ret) goto out; - addrlen = sizeof(struct sockaddr_in); + addrlen = sin->ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); ret = kernel_bind(sock, (struct sockaddr *)sin, addrlen); if (ret) goto out; @@ -1657,7 +1669,7 @@ int scoutfs_net_bind(struct super_block *sb, ret = 0; conn->sock = sock; - *sin = conn->sockname; + sin = (struct sockaddr_storage *)&conn->sockname; out: if (ret < 0 && sock) @@ -1692,7 +1704,7 @@ static bool connect_result(struct scoutfs_net_connection *conn, int *error) done = true; *error = 0; } else if (test_conn_fl(conn, shutting_down) || - conn->connect_sin.sin_family == 0) { + conn->connect_sin.ss_family == AF_UNSPEC) { done = true; *error = -ESHUTDOWN; } @@ -1713,7 +1725,7 @@ static bool connect_result(struct scoutfs_net_connection *conn, int *error) */ int scoutfs_net_connect(struct super_block *sb, struct scoutfs_net_connection *conn, - struct sockaddr_in *sin, unsigned long timeout_ms) + struct sockaddr_storage *sin, unsigned long timeout_ms) { int ret = 0; diff --git a/kmod/src/net.h b/kmod/src/net.h index a2bdd690..2e151ac7 100644 --- a/kmod/src/net.h +++ b/kmod/src/net.h @@ -49,15 +49,15 @@ struct scoutfs_net_connection { unsigned long flags; /* CONN_FL_* bitmask */ unsigned long reconn_deadline; - struct sockaddr_in connect_sin; + struct sockaddr_storage connect_sin; unsigned long connect_timeout_ms; struct socket *sock; u64 rid; u64 greeting_id; - struct sockaddr_in sockname; - struct sockaddr_in peername; - struct sockaddr_in last_peername; + struct sockaddr_storage sockname; + struct sockaddr_storage peername; + struct sockaddr_storage last_peername; struct list_head accepted_head; struct scoutfs_net_connection *listening_conn; @@ -99,27 +99,44 @@ enum conn_flags { CONN_FL_reconn_freeing = (1UL << 6), /* waiting done, setter frees */ }; -#define SIN_FMT "%pIS:%u" -#define SIN_ARG(sin) sin, be16_to_cpu((sin)->sin_port) +#define SIN_FMT "%pISpc" +#define SIN_ARG(sin) sin -static inline void scoutfs_addr_to_sin(struct sockaddr_in *sin, +static inline void scoutfs_addr_to_sin(struct sockaddr_storage *sin, union scoutfs_inet_addr *addr) { - BUG_ON(addr->v4.family != cpu_to_le16(SCOUTFS_AF_IPV4)); - - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = cpu_to_be32(le32_to_cpu(addr->v4.addr)); - sin->sin_port = cpu_to_be16(le16_to_cpu(addr->v4.port)); + if (addr->v4.family == cpu_to_le16(SCOUTFS_AF_IPV4)) { + struct sockaddr_in *sin4 = (struct sockaddr_in *)sin; + memset(sin, 0, sizeof(struct sockaddr_storage)); + sin4->sin_family = AF_INET; + sin4->sin_addr.s_addr = cpu_to_be32(le32_to_cpu(addr->v4.addr)); + sin4->sin_port = cpu_to_be16(le16_to_cpu(addr->v4.port)); + } else if (addr->v6.family == cpu_to_le16(SCOUTFS_AF_IPV6)) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sin; + memset(sin, 0, sizeof(struct sockaddr_storage)); + sin6->sin6_family = AF_INET6; + memcpy(&sin6->sin6_addr.in6_u.u6_addr8, &addr->v6.addr, 16); + sin6->sin6_port = cpu_to_be16(le16_to_cpu(addr->v6.port)); + } else + BUG(); } -static inline void scoutfs_sin_to_addr(union scoutfs_inet_addr *addr, struct sockaddr_in *sin) +static inline void scoutfs_sin_to_addr(union scoutfs_inet_addr *addr, struct sockaddr_storage *sin) { - BUG_ON(sin->sin_family != AF_INET); - - memset(addr, 0, sizeof(union scoutfs_inet_addr)); - addr->v4.family = cpu_to_le16(SCOUTFS_AF_IPV4); - addr->v4.addr = be32_to_le32(sin->sin_addr.s_addr); - addr->v4.port = be16_to_le16(sin->sin_port); + if (sin->ss_family == AF_INET) { + struct sockaddr_in *sin4 = (struct sockaddr_in *)sin; + memset(addr, 0, sizeof(union scoutfs_inet_addr)); + addr->v4.family = cpu_to_le16(SCOUTFS_AF_IPV4); + addr->v4.addr = be32_to_le32(sin4->sin_addr.s_addr); + addr->v4.port = be16_to_le16(sin4->sin_port); + } else if (sin->ss_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sin; + memset(addr, 0, sizeof(union scoutfs_inet_addr)); + addr->v6.family = cpu_to_le16(SCOUTFS_AF_IPV6); + memcpy(&addr->v6.addr, &sin6->sin6_addr.in6_u.u6_addr8, 16); + addr->v6.port = be16_to_le16(sin6->sin6_port); + } else + BUG(); } struct scoutfs_net_connection * @@ -130,10 +147,10 @@ scoutfs_net_alloc_conn(struct super_block *sb, u64 scoutfs_net_client_rid(struct scoutfs_net_connection *conn); int scoutfs_net_connect(struct super_block *sb, struct scoutfs_net_connection *conn, - struct sockaddr_in *sin, unsigned long timeout_ms); + struct sockaddr_storage *sin, unsigned long timeout_ms); int scoutfs_net_bind(struct super_block *sb, struct scoutfs_net_connection *conn, - struct sockaddr_in *sin); + struct sockaddr_storage *sin); void scoutfs_net_listen(struct super_block *sb, struct scoutfs_net_connection *conn); int scoutfs_net_submit_request(struct super_block *sb, diff --git a/kmod/src/quorum.c b/kmod/src/quorum.c index 18246222..ce936627 100644 --- a/kmod/src/quorum.c +++ b/kmod/src/quorum.c @@ -145,14 +145,26 @@ struct quorum_info { #define DECLARE_QUORUM_INFO_KOBJ(kobj, name) \ DECLARE_QUORUM_INFO(SCOUTFS_SYSFS_ATTRS_SB(kobj), name) -static bool quorum_slot_present(struct scoutfs_quorum_config *qconf, int i) +static bool quorum_slot_ipv4(struct scoutfs_quorum_config *qconf, int i) { BUG_ON(i < 0 || i > SCOUTFS_QUORUM_MAX_SLOTS); return qconf->slots[i].addr.v4.family == cpu_to_le16(SCOUTFS_AF_IPV4); } -static void quorum_slot_sin(struct scoutfs_quorum_config *qconf, int i, struct sockaddr_in *sin) +static bool quorum_slot_ipv6(struct scoutfs_quorum_config *qconf, int i) +{ + BUG_ON(i < 0 || i > SCOUTFS_QUORUM_MAX_SLOTS); + + return qconf->slots[i].addr.v6.family == cpu_to_le16(SCOUTFS_AF_IPV6); +} + +static bool quorum_slot_present(struct scoutfs_quorum_config *qconf, int i) +{ + return quorum_slot_ipv4(qconf, i) || quorum_slot_ipv6(qconf, i); +} + +static void quorum_slot_sin(struct scoutfs_quorum_config *qconf, int i, struct sockaddr_storage *sin) { BUG_ON(i < 0 || i >= SCOUTFS_QUORUM_MAX_SLOTS); @@ -179,11 +191,18 @@ static int create_socket(struct super_block *sb) { DECLARE_QUORUM_INFO(sb, qinf); struct socket *sock = NULL; - struct sockaddr_in sin; + struct sockaddr_storage sin; + struct scoutfs_quorum_slot slot = qinf->qconf.slots[qinf->our_quorum_slot_nr]; int addrlen; int ret; - ret = sock_create_kern(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + if (le16_to_cpu(slot.addr.v4.family) == SCOUTFS_AF_IPV4) + ret = sock_create_kern(&init_net, PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock); + else if (le16_to_cpu(slot.addr.v6.family) == SCOUTFS_AF_IPV6) + ret = sock_create_kern(&init_net, PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock); + else + BUG(); + if (ret) { scoutfs_err(sb, "quorum couldn't create udp socket: %d", ret); goto out; @@ -192,9 +211,9 @@ static int create_socket(struct super_block *sb) /* rather fail and retry than block waiting for free */ sock->sk->sk_allocation = GFP_ATOMIC; + addrlen = (le16_to_cpu(slot.addr.v4.family) == SCOUTFS_AF_IPV4) ? + sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); quorum_slot_sin(&qinf->qconf, qinf->our_quorum_slot_nr, &sin); - - addrlen = sizeof(sin); ret = kernel_bind(sock, (struct sockaddr *)&sin, addrlen); if (ret) { scoutfs_err(sb, "quorum failed to bind udp socket to "SIN_FMT": %d", @@ -241,7 +260,7 @@ static int send_msg_members(struct super_block *sb, int type, u64 term, int only .iov_base = &qmes, .iov_len = sizeof(qmes), }; - struct sockaddr_in sin; + struct sockaddr_storage sin; struct msghdr mh = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL, .msg_name = &sin, @@ -545,7 +564,8 @@ int scoutfs_quorum_fence_leaders(struct super_block *sb, struct scoutfs_quorum_c struct scoutfs_quorum_block_event (*old)[NR_OLD]; struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); struct scoutfs_quorum_block blk; - struct sockaddr_in sin; + struct sockaddr_storage sin; + union scoutfs_inet_addr addr; const __le64 lefsid = cpu_to_le64(sbi->fsid); const u64 rid = sbi->rid; bool fence_started = false; @@ -605,7 +625,8 @@ int scoutfs_quorum_fence_leaders(struct super_block *sb, struct scoutfs_quorum_c scoutfs_info(sb, "fencing previous leader "SCSBF" at term %llu in slot %u with address "SIN_FMT, SCSB_LEFR_ARGS(lefsid, fence_rid), le64_to_cpu(old[i][j].term), i, SIN_ARG(&sin)); - ret = scoutfs_fence_start(sb, le64_to_cpu(fence_rid), sin.sin_addr.s_addr, + scoutfs_sin_to_addr(&addr, &sin); + ret = scoutfs_fence_start(sb, le64_to_cpu(fence_rid), &addr, SCOUTFS_FENCE_QUORUM_BLOCK_LEADER); if (ret < 0) goto out_free; @@ -717,7 +738,7 @@ static void scoutfs_quorum_worker(struct work_struct *work) struct quorum_info *qinf = container_of(work, struct quorum_info, work); struct scoutfs_mount_options opts; struct super_block *sb = qinf->sb; - struct sockaddr_in unused; + struct sockaddr_storage unused; struct quorum_host_msg msg; struct quorum_status qst = {0,}; struct hb_recording hbr; @@ -999,7 +1020,7 @@ out: * leader with the greatest elected term. If we get it wrong the * connection will timeout and the client will try again. */ -int scoutfs_quorum_server_sin(struct super_block *sb, struct sockaddr_in *sin) +int scoutfs_quorum_server_sin(struct super_block *sb, struct sockaddr_storage *sin) { struct scoutfs_super_block *super = NULL; struct scoutfs_quorum_block blk; @@ -1058,7 +1079,7 @@ u8 scoutfs_quorum_votes_needed(struct super_block *sb) return qinf->votes_needed; } -void scoutfs_quorum_slot_sin(struct scoutfs_quorum_config *qconf, int i, struct sockaddr_in *sin) +void scoutfs_quorum_slot_sin(struct scoutfs_quorum_config *qconf, int i, struct sockaddr_storage *sin) { return quorum_slot_sin(qconf, i, sin); } @@ -1217,8 +1238,12 @@ static int verify_quorum_slots(struct super_block *sb, struct quorum_info *qinf, struct scoutfs_quorum_config *qconf) { char slots[(SCOUTFS_QUORUM_MAX_SLOTS * 3) + 1]; - struct sockaddr_in other; - struct sockaddr_in sin; + struct sockaddr_storage other; + struct sockaddr_storage sin; + struct sockaddr_in *sin4; + struct sockaddr_in *other4; + struct sockaddr_in6 *sin6; + struct sockaddr_in6 *other6; int found = 0; int ret; int i; @@ -1229,35 +1254,78 @@ static int verify_quorum_slots(struct super_block *sb, struct quorum_info *qinf, if (!quorum_slot_present(qconf, i)) continue; - scoutfs_quorum_slot_sin(qconf, i, &sin); + if (quorum_slot_ipv4(qconf, i)) { + scoutfs_quorum_slot_sin(qconf, i, &sin); + sin4 = (struct sockaddr_in *)&sin; - if (!valid_ipv4_unicast(sin.sin_addr.s_addr)) { - scoutfs_err(sb, "quorum slot #%d has invalid ipv4 unicast address: "SIN_FMT, - i, SIN_ARG(&sin)); - return -EINVAL; - } - - if (!valid_ipv4_port(sin.sin_port)) { - scoutfs_err(sb, "quorum slot #%d has invalid ipv4 port number:"SIN_FMT, - i, SIN_ARG(&sin)); - return -EINVAL; - } - - for (j = i + 1; j < SCOUTFS_QUORUM_MAX_SLOTS; j++) { - if (!quorum_slot_present(qconf, j)) - continue; - - scoutfs_quorum_slot_sin(qconf, j, &other); - - if (sin.sin_addr.s_addr == other.sin_addr.s_addr && - sin.sin_port == other.sin_port) { - scoutfs_err(sb, "quorum slots #%u and #%u have the same address: "SIN_FMT, - i, j, SIN_ARG(&sin)); + if (!valid_ipv4_unicast(sin4->sin_addr.s_addr)) { + scoutfs_err(sb, "quorum slot #%d has invalid ipv4 unicast address: "SIN_FMT, + i, SIN_ARG(&sin)); return -EINVAL; } - } - found++; + if (!valid_ipv4_port(sin4->sin_port)) { + scoutfs_err(sb, "quorum slot #%d has invalid ipv4 port number:"SIN_FMT, + i, SIN_ARG(&sin)); + return -EINVAL; + } + + for (j = i + 1; j < SCOUTFS_QUORUM_MAX_SLOTS; j++) { + if (!quorum_slot_ipv4(qconf, j)) + continue; + + scoutfs_quorum_slot_sin(qconf, j, &other); + other4 = (struct sockaddr_in *)&other; + + if (sin4->sin_addr.s_addr == other4->sin_addr.s_addr && + sin4->sin_port == other4->sin_port) { + scoutfs_err(sb, "quorum slots #%u and #%u have the same address: "SIN_FMT, + i, j, SIN_ARG(&sin)); + return -EINVAL; + } + } + + found++; + } else if (quorum_slot_ipv6(qconf, i)) { + quorum_slot_sin(qconf, i, &sin); + sin6 = (struct sockaddr_in6 *)&sin; + + if ((sin6->sin6_addr.in6_u.u6_addr32[0] == 0) && (sin6->sin6_addr.in6_u.u6_addr32[1] == 0) && + (sin6->sin6_addr.in6_u.u6_addr32[2] == 0) && (sin6->sin6_addr.in6_u.u6_addr32[3] == 0)) { + scoutfs_err(sb, "quorum slot #%d has unspecified ipv6 address:"SIN_FMT, + i, SIN_ARG(&sin)); + return -EINVAL; + } + + if (sin6->sin6_addr.in6_u.u6_addr8[0] == 0xff) { + scoutfs_err(sb, "quorum slot #%d has multicast ipv6 address:"SIN_FMT, + i, SIN_ARG(&sin)); + return -EINVAL; + } + + if (!valid_ipv4_port(sin6->sin6_port)) { + scoutfs_err(sb, "quorum slot #%d has invalid ipv6 port number:"SIN_FMT, + i, SIN_ARG(&sin)); + return -EINVAL; + } + + for (j = i + 1; j < SCOUTFS_QUORUM_MAX_SLOTS; j++) { + if (!quorum_slot_ipv6(qconf, j)) + continue; + + quorum_slot_sin(qconf, j, &other); + other6 = (struct sockaddr_in6 *)&other; + + if ((ipv6_addr_equal(&sin6->sin6_addr, &other6->sin6_addr)) && + (sin6->sin6_port == other6->sin6_port)) { + scoutfs_err(sb, "quorum slots #%u and #%u have the same address: "SIN_FMT, + i, j, SIN_ARG(&sin)); + return -EINVAL; + } + } + + found++; + } } if (found == 0) { diff --git a/kmod/src/quorum.h b/kmod/src/quorum.h index 500a5d16..4e29bcee 100644 --- a/kmod/src/quorum.h +++ b/kmod/src/quorum.h @@ -1,11 +1,11 @@ #ifndef _SCOUTFS_QUORUM_H_ #define _SCOUTFS_QUORUM_H_ -int scoutfs_quorum_server_sin(struct super_block *sb, struct sockaddr_in *sin); +int scoutfs_quorum_server_sin(struct super_block *sb, struct sockaddr_storage *sin); u8 scoutfs_quorum_votes_needed(struct super_block *sb); void scoutfs_quorum_slot_sin(struct scoutfs_quorum_config *qconf, int i, - struct sockaddr_in *sin); + struct sockaddr_storage *sin); int scoutfs_quorum_fence_leaders(struct super_block *sb, struct scoutfs_quorum_config *qconf, u64 term); diff --git a/kmod/src/scoutfs_trace.h b/kmod/src/scoutfs_trace.h index 90fbc0aa..0da75d57 100644 --- a/kmod/src/scoutfs_trace.h +++ b/kmod/src/scoutfs_trace.h @@ -1355,35 +1355,37 @@ DEFINE_EVENT(scoutfs_lock_class, scoutfs_lock_shrink, ); DECLARE_EVENT_CLASS(scoutfs_net_class, - TP_PROTO(struct super_block *sb, struct sockaddr_in *name, - struct sockaddr_in *peer, struct scoutfs_net_header *nh), + TP_PROTO(struct super_block *sb, struct sockaddr_storage *name, + struct sockaddr_storage *peer, struct scoutfs_net_header *nh), TP_ARGS(sb, name, peer, nh), TP_STRUCT__entry( SCSB_TRACE_FIELDS - si4_trace_define(name) - si4_trace_define(peer) + __field_struct(struct sockaddr_storage, name) + __field_struct(struct sockaddr_storage, peer) snh_trace_define(nh) ), TP_fast_assign( SCSB_TRACE_ASSIGN(sb); - si4_trace_assign(name, name); - si4_trace_assign(peer, peer); + memcpy(&__entry->name, name, sizeof(struct sockaddr_storage)); + memcpy(&__entry->peer, peer, sizeof(struct sockaddr_storage)); snh_trace_assign(nh, nh); ), - TP_printk(SCSBF" name "SI4_FMT" peer "SI4_FMT" nh "SNH_FMT, - SCSB_TRACE_ARGS, si4_trace_args(name), si4_trace_args(peer), + TP_printk(SCSBF" name "SIN_FMT" peer "SIN_FMT" nh "SNH_FMT, + SCSB_TRACE_ARGS, + &__entry->name, + &__entry->peer, snh_trace_args(nh)) ); DEFINE_EVENT(scoutfs_net_class, scoutfs_net_send_message, - TP_PROTO(struct super_block *sb, struct sockaddr_in *name, - struct sockaddr_in *peer, struct scoutfs_net_header *nh), + TP_PROTO(struct super_block *sb, struct sockaddr_storage *name, + struct sockaddr_storage *peer, struct scoutfs_net_header *nh), TP_ARGS(sb, name, peer, nh) ); DEFINE_EVENT(scoutfs_net_class, scoutfs_net_recv_message, - TP_PROTO(struct super_block *sb, struct sockaddr_in *name, - struct sockaddr_in *peer, struct scoutfs_net_header *nh), + TP_PROTO(struct super_block *sb, struct sockaddr_storage *name, + struct sockaddr_storage *peer, struct scoutfs_net_header *nh), TP_ARGS(sb, name, peer, nh) ); @@ -1416,8 +1418,8 @@ DECLARE_EVENT_CLASS(scoutfs_net_conn_class, __field(void *, sock) __field(__u64, c_rid) __field(__u64, greeting_id) - si4_trace_define(sockname) - si4_trace_define(peername) + __field_struct(struct sockaddr_storage, sockname) + __field_struct(struct sockaddr_storage, peername) __field(unsigned char, e_accepted_head) __field(void *, listening_conn) __field(unsigned char, e_accepted_list) @@ -1435,8 +1437,8 @@ DECLARE_EVENT_CLASS(scoutfs_net_conn_class, __entry->sock = conn->sock; __entry->c_rid = conn->rid; __entry->greeting_id = conn->greeting_id; - si4_trace_assign(sockname, &conn->sockname); - si4_trace_assign(peername, &conn->peername); + memcpy(&__entry->sockname, &conn->sockname, sizeof(struct sockaddr_storage)); + memcpy(&__entry->peername, &conn->peername, sizeof(struct sockaddr_storage)); __entry->e_accepted_head = !!list_empty(&conn->accepted_head); __entry->listening_conn = conn->listening_conn; __entry->e_accepted_list = !!list_empty(&conn->accepted_list); @@ -1446,7 +1448,7 @@ DECLARE_EVENT_CLASS(scoutfs_net_conn_class, __entry->e_resend_queue = !!list_empty(&conn->resend_queue); __entry->recv_seq = atomic64_read(&conn->recv_seq); ), - TP_printk(SCSBF" flags %s rc_dl %lu cto %lu sk %p rid %llu grid %llu sn "SI4_FMT" pn "SI4_FMT" eah %u lc %p eal %u nss %llu nsi %llu esq %u erq %u rs %llu", + TP_printk(SCSBF" flags %s rc_dl %lu cto %lu sk %p rid %llu grid %llu sn "SIN_FMT" pn "SIN_FMT" eah %u lc %p eal %u nss %llu nsi %llu esq %u erq %u rs %llu", SCSB_TRACE_ARGS, print_conn_flags(__entry->flags), __entry->reconn_deadline, @@ -1454,8 +1456,8 @@ DECLARE_EVENT_CLASS(scoutfs_net_conn_class, __entry->sock, __entry->c_rid, __entry->greeting_id, - si4_trace_args(sockname), - si4_trace_args(peername), + &__entry->sockname, + &__entry->peername, __entry->e_accepted_head, __entry->listening_conn, __entry->e_accepted_list, diff --git a/kmod/src/server.c b/kmod/src/server.c index 73a8bfa7..002e28b9 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -3649,7 +3649,7 @@ static bool invalid_mounted_client_item(struct scoutfs_btree_item_ref *iref) * it's acceptable to see -EEXIST. */ static int insert_mounted_client(struct super_block *sb, u64 rid, u64 gr_flags, - struct sockaddr_in *sin) + struct sockaddr_storage *sin) { DECLARE_SERVER_INFO(sb, server); struct scoutfs_super_block *super = DIRTY_SUPER_SB(sb); @@ -4402,7 +4402,7 @@ static void fence_pending_recov_worker(struct work_struct *work) break; } - ret = scoutfs_fence_start(sb, rid, le32_to_be32(addr.v4.addr), + ret = scoutfs_fence_start(sb, rid, &addr, SCOUTFS_FENCE_CLIENT_RECOVERY); if (ret < 0) { scoutfs_err(sb, "fence returned err %d, shutting down server", ret); @@ -4553,7 +4553,7 @@ static void scoutfs_server_worker(struct work_struct *work) struct scoutfs_net_connection *conn = NULL; struct scoutfs_mount_options opts; DECLARE_WAIT_QUEUE_HEAD(waitq); - struct sockaddr_in sin; + struct sockaddr_storage sin; bool alloc_init = false; u64 max_seq; int ret; @@ -4562,7 +4562,7 @@ static void scoutfs_server_worker(struct work_struct *work) scoutfs_options_read(sb, &opts); scoutfs_quorum_slot_sin(&server->qconf, opts.quorum_slot_nr, &sin); - scoutfs_info(sb, "server starting at "SIN_FMT, SIN_ARG(&sin)); + scoutfs_info(sb, "server starting at "SIN_FMT, &sin); scoutfs_block_writer_init(sb, &server->wri); server->finalize_sent_seq = 0; diff --git a/kmod/src/server.h b/kmod/src/server.h index f795ea0f..d1f01e88 100644 --- a/kmod/src/server.h +++ b/kmod/src/server.h @@ -1,27 +1,6 @@ #ifndef _SCOUTFS_SERVER_H_ #define _SCOUTFS_SERVER_H_ -#define SI4_FMT "%u.%u.%u.%u:%u" - -#define si4_trace_define(name) \ - __field(__u32, name##_addr) \ - __field(__u16, name##_port) - -#define si4_trace_assign(name, sin) \ -do { \ - __typeof__(sin) _sin = (sin); \ - \ - __entry->name##_addr = be32_to_cpu(_sin->sin_addr.s_addr); \ - __entry->name##_port = be16_to_cpu(_sin->sin_port); \ -} while(0) - -#define si4_trace_args(name) \ - (__entry->name##_addr >> 24), \ - (__entry->name##_addr >> 16) & 255, \ - (__entry->name##_addr >> 8) & 255, \ - __entry->name##_addr & 255, \ - __entry->name##_port - #define SNH_FMT \ "seq %llu recv_seq %llu id %llu data_len %u cmd %u flags 0x%x error %u" #define SNH_ARG(nh) \