diff --git a/src/knot/server/net.c b/src/knot/server/net.c index b3054d08666db51b0f166d4040263ebc9bb6283e..a55cb89d7433c743548254b1eacea93dee8845b7 100644 --- a/src/knot/server/net.c +++ b/src/knot/server/net.c @@ -81,6 +81,11 @@ int net_bound_socket(int type, struct sockaddr_storage *ss) int flag = 1; (void) setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); + /* Reuse port if available. */ +#if defined(SO_REUSEPORT) + (void) setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)); +#endif + /* Unlink UNIX socket if exists. */ if (ss->ss_family == AF_UNIX) { unlink(addr_str); diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c index 28d4b03719ac8a9c5f2a60078935891d7cba940b..fb94e127ef4f5cac9dbc0056028778da0b48b9f5 100644 --- a/src/knot/server/udp-handler.c +++ b/src/knot/server/udp-handler.c @@ -449,6 +449,30 @@ void __attribute__ ((constructor)) udp_master_init() #endif /* HAVE_RECVMMSG */ } +static void unbind_ifaces(ifacelist_t *ifaces, fd_set *set, int maxfd) +{ + ref_release((ref_t *)ifaces); +#if defined(SO_REUSEPORT) + for (int fd = 0; fd <= maxfd; ++fd) { + if (FD_ISSET(fd, set)) { + close(fd); + } + } +#endif + FD_ZERO(set); +} + +static int bind_iface(iface_t *iface, fd_set *set) +{ +#if defined(SO_REUSEPORT) + int fd = net_bound_socket(SOCK_DGRAM, &iface->addr); +#else + int fd = iface->fd[IO_UDP]; +#endif + FD_SET(fd, set); + return fd; +} + int udp_master(dthread_t *thread) { unsigned cpu = dt_online_cpus(); @@ -497,18 +521,16 @@ int udp_master(dthread_t *thread) /* Check handler state. */ if (knot_unlikely(*iostate & ServerReload)) { *iostate &= ~ServerReload; - maxfd = 0; - minfd = INT_MAX; - FD_ZERO(&fds); rcu_read_lock(); - ref_release((ref_t *)ref); + unbind_ifaces(ref, &fds, maxfd); + maxfd = 0; + minfd = INT_MAX; ref = handler->server->ifaces; if (ref) { iface_t *i = NULL; WALK_LIST(i, ref->l) { - int fd = i->fd[IO_UDP]; - FD_SET(fd, &fds); + int fd = bind_iface(i, &fds); maxfd = MAX(fd, maxfd); minfd = MIN(fd, minfd); } @@ -544,7 +566,7 @@ int udp_master(dthread_t *thread) } _udp_deinit(rq); - ref_release((ref_t *)ref); + unbind_ifaces(ref, &fds, maxfd); mp_delete(udp.query_ctx.mm.ctx); return KNOT_EOK; }