Skip to content

Commit ca94b99

Browse files
committed
BUG#29249542 - CANNOT SETUP REPLICATION WITHOUT IPV6 SINCE 8.0.14
Problem ========================= Since Mysql server 8.0.14, we cannot setup a replication group using mysql-shell (and probably by using mysql client). The server fails with these messages (note the "cannot use port xxx" and the "adding ipv6 localhost to whitelist" even though no ipv6 is available) Analysis and Fix ========================= When adding ipv6.disable=1 to a into a boot configuration, we are left without kernel support for IPv6. As such, we can't have calls that use directly AF_INET6 or "::1". Remove all hardcoded AF_INET6 assumptions. ReviewBoard: 21337
1 parent b01b5e6 commit ca94b99

File tree

3 files changed

+141
-31
lines changed

3 files changed

+141
-31
lines changed

plugin/group_replication/libmysqlgcs/src/bindings/xcom/xcom/task.c

Lines changed: 126 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -1390,6 +1390,33 @@ static result create_server_socket() {
13901390
return fd;
13911391
}
13921392

1393+
static result create_server_socket_v4() {
1394+
result fd = {0, 0};
1395+
/* Create socket */
1396+
if ((fd = xcom_checked_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)).val < 0) {
1397+
G_MESSAGE(
1398+
"Unable to create socket v4"
1399+
"(socket=%d, errno=%d)!",
1400+
fd.val, to_errno(GET_OS_ERR));
1401+
return fd;
1402+
}
1403+
{
1404+
int reuse = 1;
1405+
SET_OS_ERR(0);
1406+
if (setsockopt(fd.val, SOL_SOCKET, SOCK_OPT_REUSEADDR, (void *)&reuse,
1407+
sizeof(reuse)) < 0) {
1408+
fd.funerr = to_errno(GET_OS_ERR);
1409+
G_MESSAGE(
1410+
"Unable to set socket options "
1411+
"(socket=%d, errno=%d)!",
1412+
fd.val, to_errno(GET_OS_ERR));
1413+
close_socket(&fd.val);
1414+
return fd;
1415+
}
1416+
}
1417+
return fd;
1418+
}
1419+
13931420
/**
13941421
* @brief Initializes a sockaddr prepared to be used in bind()
13951422
*
@@ -1400,7 +1427,7 @@ static result create_server_socket() {
14001427
* @param port the port to bind.
14011428
*/
14021429
static void init_server_addr(struct sockaddr **sock_addr, socklen_t *sock_len,
1403-
xcom_port port) {
1430+
xcom_port port, int family) {
14041431
struct addrinfo *address_info = NULL, hints, *address_info_loop;
14051432
memset(&hints, 0, sizeof(hints));
14061433

@@ -1412,7 +1439,7 @@ static void init_server_addr(struct sockaddr **sock_addr, socklen_t *sock_len,
14121439

14131440
address_info_loop = address_info;
14141441
while (address_info_loop) {
1415-
if (address_info_loop->ai_family == AF_INET6) {
1442+
if (address_info_loop->ai_family == family) {
14161443
if (*sock_addr == NULL) {
14171444
*sock_addr = (struct sockaddr *)malloc(address_info_loop->ai_addrlen);
14181445
}
@@ -1433,18 +1460,40 @@ result announce_tcp(xcom_port port) {
14331460
result fd;
14341461
struct sockaddr *sock_addr = NULL;
14351462
socklen_t sock_addr_len;
1463+
int server_socket_v6_ok = 0;
14361464

1465+
// Try and create a V6 server socket. It should succeed if the OS
1466+
// supports IPv6, and fail otherwise.
14371467
fd = create_server_socket();
14381468
if (fd.val < 0) {
1439-
return fd;
1469+
// If the OS does not support IPv6, we fall back to IPv4.
1470+
fd = create_server_socket_v4();
1471+
if (fd.val < 0) {
1472+
return fd;
1473+
}
1474+
} else {
1475+
server_socket_v6_ok = 1;
14401476
}
1441-
init_server_addr(&sock_addr, &sock_addr_len, port);
1477+
init_server_addr(&sock_addr, &sock_addr_len, port,
1478+
server_socket_v6_ok ? AF_INET6 : AF_INET);
14421479
if (sock_addr == NULL || (bind(fd.val, sock_addr, sock_addr_len) < 0)) {
1443-
int err = to_errno(GET_OS_ERR);
1444-
G_MESSAGE("Unable to bind to %s:%d (socket=%d, errno=%d)!", "INADDR_ANY",
1445-
port, fd.val, err);
1446-
goto err;
1480+
// If we fail to bind to the desired address, we fall back to an
1481+
// IPv4 socket.
1482+
fd = create_server_socket_v4();
1483+
if (fd.val < 0) {
1484+
return fd;
1485+
}
1486+
1487+
free(sock_addr);
1488+
init_server_addr(&sock_addr, &sock_addr_len, port, AF_INET);
1489+
if (bind(fd.val, sock_addr, sock_addr_len) < 0) {
1490+
int err = to_errno(GET_OS_ERR);
1491+
G_MESSAGE("Unable to bind to %s:%d (socket=%d, errno=%d)!", "INADDR_ANY",
1492+
port, fd.val, err);
1493+
goto err;
1494+
}
14471495
}
1496+
14481497
G_DEBUG("Successfully bound to %s:%d (socket=%d).", "INADDR_ANY", port,
14491498
fd.val);
14501499
if (listen(fd.val, 32) < 0) {
@@ -1490,38 +1539,83 @@ result announce_tcp(xcom_port port) {
14901539
* These are used by the local_server and the XCom queue. They will use a local
14911540
* TCP connection to signal that the queue has work to be consumed.
14921541
*/
1493-
static void init_local_server_addr(struct sockaddr_in6 *sock_addr) {
1542+
static void init_local_server_addr_v6(struct sockaddr_in6 *sock_addr) {
14941543
memset(sock_addr, 0, sizeof(*sock_addr));
14951544
sock_addr->sin6_family = AF_INET6;
14961545
sock_addr->sin6_addr = in6addr_loopback;
14971546
sock_addr->sin6_port = 0;
14981547
}
14991548

1549+
static void init_local_server_addr_v4(struct sockaddr_in *sock_addr) {
1550+
memset(sock_addr, 0, sizeof(*sock_addr));
1551+
sock_addr->sin_family = AF_INET;
1552+
sock_addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1553+
sock_addr->sin_port = 0;
1554+
}
1555+
15001556
result announce_tcp_local_server() {
15011557
result fd;
15021558
struct sockaddr_in6 sock_addr;
15031559
struct sockaddr_in6 bound_addr;
1504-
socklen_t bound_addr_len = sizeof(bound_addr);
1560+
struct sockaddr_in sock_addr_v4;
1561+
struct sockaddr_in bound_addr_v4;
1562+
int bind_v6 = 0;
1563+
15051564
int error_code = 0;
1565+
xcom_port port = 0;
1566+
socklen_t bound_addr_len = 0;
15061567

1568+
// Try to create an IPv6 server socket. It should succeed if the
1569+
// OS supports IPv6, and fail otherwise.
15071570
fd = create_server_socket();
15081571
if (fd.val < 0) {
1509-
/* purecov: begin inspected */
1510-
return fd;
1511-
/* purecov: end */
1572+
// If the OS does *not* support IPv6, we fall back to IPv4.
1573+
fd = create_server_socket_v4();
1574+
if (fd.val < 0) {
1575+
return fd;
1576+
}
1577+
} else {
1578+
bind_v6 = 1;
15121579
}
1513-
init_local_server_addr(&sock_addr);
1514-
xcom_port port = 0;
1515-
if (bind(fd.val, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) {
1516-
/* purecov: begin inspected */
1517-
int err = to_errno(GET_OS_ERR);
1518-
G_MESSAGE("Unable to bind to %s:%d (socket=%d, errno=%d)!", "0.0.0.0", port,
1519-
fd.val, err);
1520-
goto err;
1521-
/* purecov: end */
1580+
1581+
int bind_result = 0;
1582+
if (bind_v6) {
1583+
init_local_server_addr_v6(&sock_addr);
1584+
bind_result =
1585+
bind(fd.val, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
1586+
}
1587+
1588+
if (bind_result < 0 || !bind_v6) {
1589+
if (bind_result < 0) {
1590+
fd = create_server_socket_v4();
1591+
}
1592+
// If we fail to bind to the desired address,
1593+
// we fall back to an IPv4 socket.
1594+
init_local_server_addr_v4(&sock_addr_v4);
1595+
bind_result =
1596+
bind(fd.val, (struct sockaddr *)&sock_addr_v4, sizeof(sock_addr_v4));
1597+
1598+
if (bind_result < 0) {
1599+
/* purecov: begin inspected */
1600+
int err = to_errno(GET_OS_ERR);
1601+
G_MESSAGE("Unable to bind to %s:%d (socket=%d, errno=%d)!", "0.0.0.0",
1602+
port, fd.val, err);
1603+
goto err;
1604+
/* purecov: end */
1605+
} else {
1606+
bind_v6 = 0;
1607+
}
1608+
}
1609+
1610+
if (bind_v6) {
1611+
bound_addr_len = sizeof(bound_addr);
1612+
error_code =
1613+
getsockname(fd.val, (struct sockaddr *)&bound_addr, &bound_addr_len);
1614+
} else {
1615+
bound_addr_len = sizeof(bound_addr_v4);
1616+
error_code =
1617+
getsockname(fd.val, (struct sockaddr *)&bound_addr_v4, &bound_addr_len);
15221618
}
1523-
error_code =
1524-
getsockname(fd.val, (struct sockaddr *)&bound_addr, &bound_addr_len);
15251619
if (error_code != 0) {
15261620
/* purecov: begin inspected */
15271621
G_MESSAGE(
@@ -1531,7 +1625,13 @@ result announce_tcp_local_server() {
15311625
goto err;
15321626
/* purecov: end */
15331627
}
1534-
port = ntohs(bound_addr.sin6_port);
1628+
1629+
if (bind_v6) {
1630+
port = ntohs(bound_addr.sin6_port);
1631+
} else {
1632+
port = ntohs(bound_addr_v4.sin_port);
1633+
}
1634+
15351635
G_DEBUG("Successfully bound to %s:%d (socket=%d).", "0.0.0.0", port, fd.val);
15361636
if (listen(fd.val, 32) < 0) {
15371637
/* purecov: begin inspected */
@@ -1563,7 +1663,6 @@ result announce_tcp_local_server() {
15631663
close_socket(&fd.val);
15641664
return fd;
15651665
}
1566-
15671666
int accept_tcp(int fd, int *ret) {
15681667
struct sockaddr_storage sock_addr;
15691668
DECL_ENV

plugin/group_replication/libmysqlgcs/src/bindings/xcom/xcom/task.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -587,6 +587,7 @@ extern int block_fd(int fd);
587587
extern int connect_tcp(char *server, xcom_port port, int *ret);
588588
extern result announce_tcp(xcom_port port);
589589
extern result announce_tcp_local_server();
590+
extern result announce_tcp_local_server_v6();
590591
extern int accept_tcp(int fd, int *ret);
591592

592593
extern int task_read(connection_descriptor const *con, void *buf, int n,

plugin/group_replication/libmysqlgcs/src/bindings/xcom/xcom/xcom_base.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -1095,6 +1095,12 @@ bool xcom_input_new_signal_connection() {
10951095
assert(input_signal_connection == NULL);
10961096
input_signal_connection =
10971097
connect_xcom((char *)"::1", local_server_port, false);
1098+
1099+
if (input_signal_connection == NULL) {
1100+
input_signal_connection =
1101+
connect_xcom((char *)"127.0.0.1", local_server_port, false);
1102+
}
1103+
10981104
return (input_signal_connection != NULL);
10991105
}
11001106
#else
@@ -1103,6 +1109,10 @@ void xcom_input_new_signal_connection(void) {
11031109
assert(local_server_port != 0);
11041110
assert(input_signal_connection == NULL);
11051111
input_signal_connection = connect_xcom((char *)"::1", local_server_port);
1112+
if (input_signal_connection == NULL) {
1113+
input_signal_connection =
1114+
connect_xcom((char *)"127.0.0.1", local_server_port, false);
1115+
}
11061116
assert(input_signal_connection != NULL);
11071117
}
11081118
#endif
@@ -5399,7 +5409,6 @@ static result checked_create_socket(int domain, int type, int protocol) {
53995409
G_MESSAGE("Socket creation failed with error %d - %s.", retval.funerr,
54005410
strerror(retval.funerr));
54015411
#endif
5402-
abort();
54035412
}
54045413
return retval;
54055414
}
@@ -5681,7 +5690,8 @@ static connection_descriptor *connect_xcom(char *server, xcom_port port) {
56815690
*/
56825691
if ((fd = checked_create_socket(addr->ai_family, SOCK_STREAM, IPPROTO_TCP))
56835692
.val < 0) {
5684-
G_ERROR("Error creating socket in local GR->GCS connection.");
5693+
G_ERROR("Error creating socket in local GR->GCS connection to address %s.",
5694+
server);
56855695
goto end;
56865696
}
56875697

0 commit comments

Comments
 (0)