diff --git a/criu/cr-check.c b/criu/cr-check.c index 8fab51ca45..f616feb50c 100644 --- a/criu/cr-check.c +++ b/criu/cr-check.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1362,6 +1363,27 @@ static int check_ns_pid(void) return 0; } +static int check_udp_repair(void) +{ + int sk, val; + + sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sk < 0) { + pr_perror("Can't create UDP socket"); + return -1; + } + + val = 1; + if (setsockopt(sk, SOL_UDP, UDP_REPAIR, &val, sizeof(val))) { + pr_perror("Can't turn UDP_REPAIR on"); + close(sk); + return -1; + } + + close(sk); + return 0; +} + static int (*chk_feature)(void); /* @@ -1487,6 +1509,7 @@ int cr_check(void) if (opts.check_experimental_features) { ret |= check_autofs(); ret |= check_compat_cr(); + ret |= check_udp_repair(); } pr_msg("%s\n", ret ? CHECK_MAYBE : CHECK_GOOD); @@ -1590,6 +1613,7 @@ static struct feature_list feature_list[] = { { "pidfd_store", check_pidfd_store }, { "ns_pid", check_ns_pid }, { "apparmor_stacking", check_apparmor_stacking }, + { "udp_repair", check_udp_repair }, { NULL, NULL }, }; diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index df0a3b7e27..49c8a75b4c 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -32,8 +32,9 @@ TST_NOFILE := \ socket_listen4v6 \ socket_udp \ socket_udp-broadcast \ - socket_udp-corked \ + socket_udp_repair \ socket6_udp \ + socket6_udp_repair \ socket_udp_shutdown \ sk-freebind \ sk-freebind-false \ diff --git a/test/zdtm/static/socket6_udp_repair.c b/test/zdtm/static/socket6_udp_repair.c new file mode 100644 index 0000000000..838a89fd51 --- /dev/null +++ b/test/zdtm/static/socket6_udp_repair.c @@ -0,0 +1,175 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Test for C/R UDP socket's queue\n"; +const char *test_author = "Bui Quang Minh \n"; + +/* Description: + * Checkpoint/restore a corked UDP socket with 2 packets in send queue + * and 2 packets in recv queue + */ + +#define PORT 3000 + +#define MSG1_1 "msg1_1" +#define MSG1_2 "msg1_2" +#define MSG2 "msg2" +#define MSG3 "msg_3" + +int main(int argc, char **argv) +{ + int ret, sk1, sk2, sk3, aux; + struct sockaddr_in6 addr1, addr2, addr3, addr; + unsigned int addr_len; + char recv_buffer[256], buffer[256]; + + test_init(argc, argv); + + sk1 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sk1 < 0) { + pr_perror("Can't create socket"); + return 1; + } + + sk2 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sk2 < 0) { + pr_perror("Can't create socket"); + return 1; + } + + sk3 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sk3 < 0) { + pr_perror("Can't create socket"); + return 1; + } + + memset(&addr1, 0, sizeof(addr1)); + addr1.sin6_family = AF_INET6; + addr1.sin6_port = htons(PORT); + inet_pton(AF_INET6, "::1", &addr1.sin6_addr); + ret = bind(sk1, (struct sockaddr *)&addr1, sizeof(addr1)); + if (ret < 0) { + pr_perror("Can't bind socket"); + return 1; + } + + memset(&addr2, 0, sizeof(addr2)); + addr2.sin6_family = AF_INET6; + addr2.sin6_port = htons(PORT + 1); + inet_pton(AF_INET6, "::1", &addr2.sin6_addr); + ret = bind(sk2, (struct sockaddr *)&addr2, sizeof(addr2)); + if (ret < 0) { + pr_perror("Can't bind socket"); + return 1; + } + + memset(&addr3, 0, sizeof(addr3)); + addr3.sin6_family = AF_INET6; + addr3.sin6_port = htons(PORT + 2); + inet_pton(AF_INET6, "::1", &addr3.sin6_addr); + ret = bind(sk3, (struct sockaddr *)&addr3, sizeof(addr3)); + if (ret < 0) { + pr_perror("Can't bind socket"); + return 1; + } + + ret = sendto(sk2, MSG2, sizeof(MSG2), 0, (struct sockaddr *)&addr1, sizeof(addr1)); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + ret = sendto(sk3, MSG3, sizeof(MSG3), 0, (struct sockaddr *)&addr1, sizeof(addr1)); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + aux = 1; + if (setsockopt(sk1, SOL_UDP, UDP_CORK, &aux, sizeof(aux))) { + pr_perror("Can't set UDP_CORK"); + return 1; + } + + ret = sendto(sk1, MSG1_1, sizeof(MSG1_1), 0, (struct sockaddr *)&addr3, sizeof(addr3)); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + ret = sendto(sk1, MSG1_2, sizeof(MSG1_2), 0, (struct sockaddr *)&addr3, sizeof(addr3)); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + close(sk2); + + test_daemon(); + test_waitsig(); + + aux = 0; + if (setsockopt(sk1, SOL_UDP, UDP_CORK, &aux, sizeof(aux))) { + fail("Can't unset UDP_CORK"); + return 1; + } + + addr_len = sizeof(addr); + ret = recvfrom(sk3, recv_buffer, sizeof(recv_buffer), 0, (struct sockaddr *)&addr, &addr_len); + if (ret < 0) { + fail("Can't receive corked packet"); + return 1; + } + + memcpy(buffer, MSG1_1, sizeof(MSG1_1)); + memcpy(buffer + sizeof(MSG1_1), MSG1_2, sizeof(MSG1_2)); + if (ret != sizeof(MSG1_1) + sizeof(MSG1_2) || memcmp(recv_buffer, buffer, ret)) { + fail("Message 1 mismatch"); + return 1; + } + + if (addr_len != sizeof(struct sockaddr_in6) || memcmp(&addr1, &addr, addr_len)) { + fail("Wrong peer"); + return 1; + } + + ret = recvfrom(sk1, recv_buffer, sizeof(recv_buffer), 0, (struct sockaddr *)&addr, &addr_len); + if (ret < 0) { + fail("Can't receive MSG2"); + return 1; + } + + if (ret != sizeof(MSG2) || memcmp(recv_buffer, MSG2, sizeof(MSG2))) { + fail("Message 2 mismatch"); + return 1; + } + + if (addr_len != sizeof(struct sockaddr_in6) || memcmp(&addr2, &addr, addr_len)) { + fail("Wrong peer"); + return 1; + } + + ret = recvfrom(sk1, recv_buffer, sizeof(recv_buffer), 0, (struct sockaddr *)&addr, &addr_len); + if (ret < 0) { + fail("Can't receive MSG3"); + return 1; + } + + if (ret != sizeof(MSG3) || memcmp(recv_buffer, MSG3, sizeof(MSG3))) { + fail("Message 3 mismatch"); + return 1; + } + + if (addr_len != sizeof(struct sockaddr_in6) || memcmp(&addr3, &addr, addr_len)) { + fail("Wrong peer"); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/socket6_udp_repair.desc b/test/zdtm/static/socket6_udp_repair.desc new file mode 100644 index 0000000000..e00480e2e4 --- /dev/null +++ b/test/zdtm/static/socket6_udp_repair.desc @@ -0,0 +1 @@ +{'flags': 'suid', 'feature': 'udp_repair'} diff --git a/test/zdtm/static/socket_udp-corked.c b/test/zdtm/static/socket_udp-corked.c deleted file mode 100644 index f502ec7ea8..0000000000 --- a/test/zdtm/static/socket_udp-corked.c +++ /dev/null @@ -1,75 +0,0 @@ -#include "zdtmtst.h" - -const char *test_doc = "static test for UDP socket\n"; -const char *test_author = "Pavel Emelyanov \n"; - -/* Description: - * Create two tcp socket, server send asynchronous request on - * read data and client write data after migration - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for sockaddr_in and inet_ntoa() */ -#include -#include - -static int port = 8880; - -#define MSG1 "msg1" - -int main(int argc, char **argv) -{ - int ret, sk1; - socklen_t len = sizeof(struct sockaddr_in); - struct sockaddr_in addr1; - int opt; - - test_init(argc, argv); - - sk1 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sk1 < 0) { - pr_perror("Can't create socket"); - return 1; - } - - memset(&addr1, 0, sizeof(addr1)); - addr1.sin_family = AF_INET; - addr1.sin_addr.s_addr = inet_addr("127.0.0.1"); - addr1.sin_port = htons(port); - - ret = bind(sk1, (struct sockaddr *)&addr1, len); - if (ret < 0) { - pr_perror("Can't bind socket"); - return 1; - } - ret = connect(sk1, (struct sockaddr *)&addr1, len); - if (ret < 0) { - pr_perror("Can't connect"); - return 1; - } - - opt = 1; - if (setsockopt(sk1, SOL_UDP, UDP_CORK, &opt, sizeof(opt))) { - pr_perror("Unable to set UDP_CORK"); - return 1; - } - - if (write(sk1, MSG1, sizeof(MSG1)) != sizeof(MSG1)) { - pr_perror("write"); - return 1; - } - - test_daemon(); - test_waitsig(); - - pass(); - return 0; -} diff --git a/test/zdtm/static/socket_udp-corked.desc b/test/zdtm/static/socket_udp-corked.desc deleted file mode 100644 index ded89879a9..0000000000 --- a/test/zdtm/static/socket_udp-corked.desc +++ /dev/null @@ -1 +0,0 @@ -{'flags': 'crfail'} diff --git a/test/zdtm/static/socket_udp_repair.c b/test/zdtm/static/socket_udp_repair.c new file mode 100644 index 0000000000..5db48e388e --- /dev/null +++ b/test/zdtm/static/socket_udp_repair.c @@ -0,0 +1,175 @@ +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Test for C/R UDP socket's queue\n"; +const char *test_author = "Bui Quang Minh \n"; + +/* Description: + * Checkpoint/restore a corked UDP socket with 2 packets in send queue + * and 2 packets in recv queue + */ + +#define PORT 3000 + +#define MSG1_1 "msg1_1" +#define MSG1_2 "msg1_2" +#define MSG2 "msg2" +#define MSG3 "msg_3" + +int main(int argc, char **argv) +{ + int ret, sk1, sk2, sk3, aux; + struct sockaddr_in addr1, addr2, addr3, addr; + unsigned int addr_len; + char recv_buffer[256], buffer[256]; + + test_init(argc, argv); + + sk1 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sk1 < 0) { + pr_perror("Can't create socket"); + return 1; + } + + sk2 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sk2 < 0) { + pr_perror("Can't create socket"); + return 1; + } + + sk3 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sk3 < 0) { + pr_perror("Can't create socket"); + return 1; + } + + memset(&addr1, 0, sizeof(addr1)); + addr1.sin_family = AF_INET; + addr1.sin_port = htons(PORT); + addr1.sin_addr.s_addr = inet_addr("127.0.0.1"); + ret = bind(sk1, (struct sockaddr *)&addr1, sizeof(addr1)); + if (ret < 0) { + pr_perror("Can't bind socket"); + return 1; + } + + memset(&addr2, 0, sizeof(addr2)); + addr2.sin_family = AF_INET; + addr2.sin_port = htons(PORT + 1); + addr2.sin_addr.s_addr = inet_addr("127.0.0.1"); + ret = bind(sk2, (struct sockaddr *)&addr2, sizeof(addr2)); + if (ret < 0) { + pr_perror("Can't bind socket"); + return 1; + } + + memset(&addr3, 0, sizeof(addr3)); + addr3.sin_family = AF_INET; + addr3.sin_port = htons(PORT + 2); + addr3.sin_addr.s_addr = inet_addr("127.0.0.1"); + ret = bind(sk3, (struct sockaddr *)&addr3, sizeof(addr3)); + if (ret < 0) { + pr_perror("Can't bind socket"); + return 1; + } + + ret = sendto(sk2, MSG2, sizeof(MSG2), 0, (struct sockaddr *)&addr1, sizeof(addr1)); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + ret = sendto(sk3, MSG3, sizeof(MSG3), 0, (struct sockaddr *)&addr1, sizeof(addr1)); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + aux = 1; + if (setsockopt(sk1, SOL_UDP, UDP_CORK, &aux, sizeof(aux))) { + pr_perror("Can't set UDP_CORK"); + return 1; + } + + ret = sendto(sk1, MSG1_1, sizeof(MSG1_1), 0, (struct sockaddr *)&addr3, sizeof(addr3)); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + ret = sendto(sk1, MSG1_2, sizeof(MSG1_2), 0, (struct sockaddr *)&addr3, sizeof(addr3)); + if (ret < 0) { + pr_perror("Can't send"); + return 1; + } + + close(sk2); + + test_daemon(); + test_waitsig(); + + aux = 0; + if (setsockopt(sk1, SOL_UDP, UDP_CORK, &aux, sizeof(aux))) { + fail("Can't unset UDP_CORK"); + return 1; + } + + addr_len = sizeof(addr); + ret = recvfrom(sk3, recv_buffer, sizeof(recv_buffer), 0, (struct sockaddr *)&addr, &addr_len); + if (ret < 0) { + fail("Can't receive corked packet"); + return 1; + } + + memcpy(buffer, MSG1_1, sizeof(MSG1_1)); + memcpy(buffer + sizeof(MSG1_1), MSG1_2, sizeof(MSG1_2)); + if (ret != sizeof(MSG1_1) + sizeof(MSG1_2) || memcmp(recv_buffer, buffer, ret)) { + fail("Message 1 mismatch"); + return 1; + } + + if (addr_len != sizeof(struct sockaddr_in) || memcmp(&addr1, &addr, addr_len)) { + fail("Wrong peer"); + return 1; + } + + ret = recvfrom(sk1, recv_buffer, sizeof(recv_buffer), 0, (struct sockaddr *)&addr, &addr_len); + if (ret < 0) { + fail("Can't receive MSG2"); + return 1; + } + + if (ret != sizeof(MSG2) || memcmp(recv_buffer, MSG2, sizeof(MSG2))) { + fail("Message 2 mismatch"); + return 1; + } + + if (addr_len != sizeof(struct sockaddr_in) || memcmp(&addr2, &addr, addr_len)) { + fail("Wrong peer 2"); + return 1; + } + + ret = recvfrom(sk1, recv_buffer, sizeof(recv_buffer), 0, (struct sockaddr *)&addr, &addr_len); + if (ret < 0) { + fail("Can't receive MSG3"); + return 1; + } + + if (ret != sizeof(MSG3) || memcmp(recv_buffer, MSG3, sizeof(MSG3))) { + fail("Message 3 mismatch"); + return 1; + } + + if (addr_len != sizeof(struct sockaddr_in) || memcmp(&addr3, &addr, addr_len)) { + fail("Wrong peer 3"); + return 1; + } + + pass(); + + return 0; +} diff --git a/test/zdtm/static/socket_udp_repair.desc b/test/zdtm/static/socket_udp_repair.desc new file mode 100644 index 0000000000..e00480e2e4 --- /dev/null +++ b/test/zdtm/static/socket_udp_repair.desc @@ -0,0 +1 @@ +{'flags': 'suid', 'feature': 'udp_repair'}