24623299 hundreds of dnsmasq processes causes DHCP to never succeed
authorVardhnee Ramanujam Ravi <vardhnee.ramanujam.ravi@oracle.com>
Mon, 26 Sep 2016 16:23:01 -0700
changeset 6979 93dcf1920c71
parent 6978 14cbeb78966a
child 6982 d3b6a08a1ea2
24623299 hundreds of dnsmasq processes causes DHCP to never succeed
components/dnsmasq/patches/05_dhcp_bind_fix.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/dnsmasq/patches/05_dhcp_bind_fix.patch	Mon Sep 26 16:23:01 2016 -0700
@@ -0,0 +1,139 @@
+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 */