Patch to address a scalability issue when using dnsmasq in Openstack, that causes DHCP to be extremely slow. This patch was developed in-house. Since it is Solaris-specific, it is not suitable for upstream. diff --git a/src/dhcp-common.c b/src/dhcp-common.c index befd8a0..4573730 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -550,6 +550,58 @@ void bindtodevice(char *device, int fd) errno != EPERM) die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET); } +#elif defined(HAVE_SOLARIS_NETWORK) +int which_ifindex(void) +{ + /* If we are doing DHCP on exactly one interface, and using Solaris, we want + * to limit packet transmission/reception to that interface using IP_BOUND_IF + * for IPv4 and IPV6_BOUND_IF for IPv6. This is for the use case of OpenStack, + * which runs a new dnsmasq instance for each network it creates. Without this + * socket option, each of the dnsmasq process would unnecessarily process + * packets that arrive on other interfaces as well, thus slowing down the + * entire DHCP process. + */ + + struct irec *iface, *found; + struct iname *if_tmp; + + if (!daemon->if_names) + return -1; + + for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next) + if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*'))) + return -1; + + for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next) + if (iface->dhcp_ok) + { + if (!found) + found = iface; + else if (strcmp(found->name, iface->name) != 0) + return -1; /* more than one. */ + } + + if (found) + return found->index; + + return -1; +} + +void bindtoif(int ifindex, int fd, int is_dhcp6) +{ + if (is_dhcp6) + { + if (setsockopt(fd, IPPROTO_IPV6, IPV6_BOUND_IF, (char *)&ifindex, sizeof(ifindex)) == -1 && + errno != EPERM) + die(_("failed to set IPv6_BOUND_IF on DHCP socket: %s"), NULL, EC_BADNET); + } + else + { + if (setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex)) == -1 && + errno != EPERM) + die(_("failed to set IP_BOUND_IF on DHCP socket: %s"), NULL, EC_BADNET); + } +} #endif static const struct opttab_t { --- a/src/dnsmasq.c 2023-02-02 21:24:24.000000000 +0100 +++ dnsmasq-2.89/src/dnsmasq.c 2023-05-12 10:54:02.094077940 +0200 @@ -66,6 +66,10 @@ #else int bind_fallback = 0; #endif +#if defined(HAVE_SOLARIS_NETWORK) + int bound_ifindex = -1; + int did_bind = 0; +#endif #if defined(HAVE_DHCP) || defined(HAVE_DHCP6) struct dhcp_context *context; struct dhcp_relay *relay; @@ -985,6 +989,10 @@ if (netlink_warn) my_syslog(LOG_WARNING, netlink_warn); # endif +# ifdef HAVE_SOLARIS_NETWORK + if (did_bind) + my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface index %d"), bound_ifindex); +# endif /* after dhcp_construct_contexts */ if (daemon->dhcp || daemon->doing_dhcp6) @@ -1103,6 +1111,23 @@ if (daemon->pxefd != -1) poll_listen(daemon->pxefd, POLLIN); } +#elif defined(HAVE_SOLARIS_NETWORK) && defined(HAVE_DHCP) + bound_ifindex = which_ifindex(); + + if (daemon->dhcp) + { + if (!daemon->relay4 && bound_ifindex >= 0) + { + bindtoif(bound_ifindex, daemon->dhcpfd, 0); + did_bind = 1; + } + + if (daemon->enable_pxe && bound_ifindex >= 0) + { + bindtoif(bound_ifindex, daemon->pxefd, 0); + did_bind = 1; + } + } #endif #ifdef HAVE_DHCP6 --- a/src/dnsmasq.h 2023-02-02 21:24:24.000000000 +0100 +++ dnsmasq-2.89/src/dnsmasq.h 2023-05-12 11:04:20.988219658 +0200 @@ -153,6 +153,8 @@ #include #elif defined(HAVE_SOLARIS_NETWORK) #include +int which_ifindex(void); +void bindtoif(int ifindex, int fd, int is_dhcp6); #endif /* Backwards compat with 2.83 */