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.
--- dnsmasq-2.75/src/dhcp-common.c 2015-07-30 12:59:07.000000000 -0700
+++ new/src/dhcp-common.c 2016-09-22 15:12:02.104708123 -0700
@@ -493,6 +493,58 @@
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 {
--- dnsmasq-2.75/src/dnsmasq.h 2016-09-22 15:20:19.502011580 -0700
+++ new/src/dnsmasq.h 2016-09-22 13:17:03.865473011 -0700
@@ -1464,6 +1464,9 @@
#ifdef HAVE_LINUX_NETWORK
char *whichdevice(void);
void bindtodevice(char *device, int fd);
+#elif defined(HAVE_SOLARIS_NETWORK)
+int which_ifindex(void);
+void bindtoif(int ifindex, int fd, int is_dhcp6);
#endif
# ifdef HAVE_DHCP6
void display_opts6(void);
--- dnsmasq-2.75/src/dnsmasq.c 2015-07-30 12:59:07.000000000 -0700
+++ new/src/dnsmasq.c 2016-09-22 15:20:03.040122945 -0700
@@ -54,6 +54,10 @@
char *bound_device = NULL;
int did_bind = 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;
@@ -306,6 +310,23 @@
did_bind = 1;
}
}
+#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
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
@@ -314,6 +335,12 @@
bindtodevice(bound_device, daemon->dhcp6fd);
did_bind = 1;
}
+#elif defined(HAVE_SOLARIS_NETWORK) && defined(HAVE_DHCP6)
+ if (daemon->doing_dhcp6 && !daemon->relay6 && bound_ifindex >= 0)
+ {
+ bindtoif(bound_ifindex, daemon->dhcp6fd, 1);
+ did_bind = 1;
+ }
#endif
}
else
@@ -788,6 +815,9 @@
# ifdef HAVE_LINUX_NETWORK
if (did_bind)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
+# elif defined(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_contruct_contexts */