diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -412,7 +412,7 @@ if (ratecheck(&lastprint, &interval)) printf("lb group port %d, limit reached\n", ntohs(grp->il_lport)); - return (0); + return (ENOBUFS); } /* Expand this local group. */ diff --git a/tests/sys/netinet/so_reuseport_lb_test.c b/tests/sys/netinet/so_reuseport_lb_test.c --- a/tests/sys/netinet/so_reuseport_lb_test.c +++ b/tests/sys/netinet/so_reuseport_lb_test.c @@ -238,10 +238,58 @@ } } +/* + * Check that the kernel enforces a limit on the LB group size. Currently that + * limit is 256 but it's not exported anywhere, so we have to hard-code that. + */ +ATF_TC_WITHOUT_HEAD(group_limit); +ATF_TC_BODY(group_limit, tc) +{ + const int max = 256 + 1; + struct sockaddr_in addr; + socklen_t slen; + int error, *sds; + uint16_t port; + + sds = calloc(max, sizeof(int)); + ATF_REQUIRE_MSG(sds != NULL, "calloc() failed: %s", strerror(errno)); + + for (int i = 0; i < max; i++) + sds[i] = lb_listen_socket(PF_INET, 0); + + port = htons(0); + for (int i = 0; i < max; i++) { + memset(&addr, 0, sizeof(addr)); + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + addr.sin_port = port; + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + slen = sizeof(addr); + error = bind(sds[i], (const struct sockaddr *)&addr, slen); + if (i < max - 1) { + ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", + strerror(errno)); + if (i == 0) { + memset(&addr, 0, sizeof(addr)); + error = getsockname(sds[0], + (struct sockaddr *)&addr, &slen); + ATF_REQUIRE_MSG(error == 0, + "getsockname() failed: %s", + strerror(errno)); + port = addr.sin_port; + } + } else { + ATF_REQUIRE_ERRNO(EAGAIN, error == -1); + } + } +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, basic_ipv4); ATF_TP_ADD_TC(tp, basic_ipv6); + ATF_TP_ADD_TC(tp, group_limit); return (atf_no_error()); }