19158668 associating a new floating ip removes existing ipnat rules and re-adds them
authorGirish Moodalbail <Girish.Moodalbail@oracle.COM>
Mon, 07 Jul 2014 13:15:12 -0700
changeset 1987 6fa18b7a0af6
parent 1986 ec77e9bb9f57
child 1988 3484dcf6fb86
19158668 associating a new floating ip removes existing ipnat rules and re-adds them 19146728 missing an upstream utility 'dhcp_release' needed by instance termination
components/dnsmasq/dnsmasq.p5m
components/dnsmasq/patches/02_compile_dhcp_release.patch
components/openstack/neutron/files/agent/evs_l3_agent.py
components/openstack/neutron/files/agent/solaris/dhcp.py
--- a/components/dnsmasq/dnsmasq.p5m	Mon Jul 07 04:16:19 2014 -0700
+++ b/components/dnsmasq/dnsmasq.p5m	Mon Jul 07 13:15:12 2014 -0700
@@ -42,7 +42,8 @@
 file files/dnsmasq.prof_attr \
     path=etc/security/prof_attr.d/service:network:dnsmasq group=sys
 file files/dnsmasq.xml path=lib/svc/manifest/network/dnsmasq.xml
-file /usr/sbin/dnsmasq path=usr/lib/inet/dnsmasq
+file path=usr/lib/inet/dhcp_release
+file usr/sbin/dnsmasq path=usr/lib/inet/dnsmasq
 file path=usr/share/locale/de/LC_MESSAGES/dnsmasq.mo
 file path=usr/share/locale/es/LC_MESSAGES/dnsmasq.mo
 file path=usr/share/locale/fi/LC_MESSAGES/dnsmasq.mo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/dnsmasq/patches/02_compile_dhcp_release.patch	Mon Jul 07 13:15:12 2014 -0700
@@ -0,0 +1,221 @@
+Add hooks to compile contrib/wrt/dhcp_release.c. This utility is used to
+send a DHCPRELEASE message to tell the local DHCP server to delete a
+particular lease.
+
+Solaris doesn't support AF_NETLINK, so use getifaddrs() to determine the
+IP address of an interface on which Dnsmasq process is listening.
+
+This patch was developed in-house. Since it is Solaris-specific it is not
+suitable for upstream.
+
+--- dnsmasq-2.68/Makefile	2013-12-08 07:58:29.000000000 -0800
++++ NEW/Makefile	2014-07-06 20:06:34.886232993 -0700
[email protected]@ -19,6 +19,7 @@
+ # Variables you may well want to override.
+ 
+ PREFIX        = /usr/local
++LIBDIR        = $(PREFIX)/lib/inet
+ BINDIR        = $(PREFIX)/sbin
+ MANDIR        = $(PREFIX)/share/man
+ LOCALEDIR     = $(PREFIX)/share/locale
[email protected]@ -43,6 +44,7 @@
+ SRC = src
+ PO  = po
+ MAN = man
++WRT = contrib/wrt
+ 
+ #################################################################
+ 
[email protected]@ -67,6 +69,8 @@
+        helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
+        dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o domain.o
+ 
++dhcp_release_objs = dhcp_release.o
++
+ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
+        dns-protocol.h radv-protocol.h
+ 
[email protected]@ -75,11 +79,12 @@
+  top="$(top)" \
+  build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags)" \
+  build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs)" \
+- -f $(top)/Makefile dnsmasq 
++ -f $(top)/Makefile dnsmasq dhcp_release
+ 
+ mostly_clean :
+ 	rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot 
+-	rm -f $(BUILDDIR)/.configured $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq 
++	rm -f $(BUILDDIR)/.configured $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a \
++		$(BUILDDIR)/dnsmasq $(BUILDDIR)/dhcp_release
+ 
+ clean : mostly_clean
+ 	rm -f $(BUILDDIR)/dnsmasq_baseline
[email protected]@ -89,9 +94,11 @@
+ install : all install-common
+ 
+ install-common :
+-	$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
++	$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8 \
++		-d $(DESTDIR)/$(LIBDIR)
+ 	$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8 
+ 	$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
++	$(INSTALL) -m 755 $(BUILDDIR)/dhcp_release $(DESTDIR)$(LIBDIR)
+ 
+ all-i18n : $(BUILDDIR)
+ 	@cd $(BUILDDIR) && $(MAKE) \
[email protected]@ -99,7 +106,7 @@
+  i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
+  build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) `$(PKG_CONFIG) --cflags libidn`" \
+  build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) `$(PKG_CONFIG) --libs libidn`"  \
+- -f $(top)/Makefile dnsmasq
++ -f $(top)/Makefile dnsmasq dhcp_release
+ 	for f in `cd $(PO); echo *.po`; do \
+ 		cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
+ 	done
[email protected]@ -142,12 +149,18 @@
+ $(objs:.o=.c) $(hdrs):
+ 	ln -s $(top)/$(SRC)/[email protected] .
+ 
++$(dhcp_release_objs:.o=.c):
++	ln -s $(top)/$(WRT)/[email protected] .
++
+ .c.o:
+ 	$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<	
+ 
+ dnsmasq : .configured $(hdrs) $(objs)
+ 	$(CC) $(LDFLAGS) -o [email protected] $(objs) $(build_libs) $(LIBS) 
+ 
++dhcp_release : .configured $(hdrs) $(dhcp_release_objs)
++	$(CC) $(LDFLAGS) -o [email protected] $(dhcp_release_objs) $(build_libs) $(LIBS) 
++
+ dnsmasq.pot : $(objs:.o=.c) $(hdrs)
+ 	$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o [email protected] -i $(objs:.o=.c)
+ 
+--- dnsmasq-2.68/contrib/wrt/dhcp_release.c	2013-12-08 07:58:29.000000000 -0800
++++ NEW/contrib/wrt/dhcp_release.c	2014-07-04 14:57:37.992103839 -0700
[email protected]@ -33,6 +33,10 @@
+    The client-id is optional. If it is "*" then it treated as being missing.
+ */
+ 
++#if defined(__sun) || defined(__sun__)
++#define HAVE_SOLARIS_NETWORK
++#endif
++
+ #include <sys/types.h> 
+ #include <netinet/in.h>
+ #include <net/if.h>
[email protected]@ -44,9 +48,13 @@
+ #include <stdlib.h>
+ #include <net/if_arp.h>
+ #include <sys/ioctl.h>
++#ifdef HAVE_SOLARIS_NETWORK
++#include <ifaddrs.h>
++#else
+ #include <linux/types.h>
+ #include <linux/netlink.h>
+ #include <linux/rtnetlink.h>
++#endif
+ #include <errno.h>
+ 
+ #define DHCP_CHADDR_MAX          16
[email protected]@ -73,6 +81,7 @@
+   unsigned char options[308];
+ };
+ 
++#if !defined(HAVE_SOLARIS_NETWORK)
+ static struct iovec iov;
+ 
+ static int expand_buf(struct iovec *iov, size_t size)
[email protected]@ -139,6 +148,8 @@
+   return rc;
+ }
+ 
++#endif
++
+ static int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type)
+ {
+   int i = 0;
[email protected]@ -178,6 +189,7 @@
+   return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
+ }
+ 
++#if !defined(HAVE_SOLARIS_NETWORK)
+ static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
+ {
+   struct sockaddr_nl addr;
[email protected]@ -244,6 +256,7 @@
+  
+   exit(0);
+ }
++#endif
+ 
+ int main(int argc, char **argv)
+ { 
[email protected]@ -254,7 +267,11 @@
+   struct sockaddr_in dest;
+   struct ifreq ifr;
+   int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
++#ifdef HAVE_SOLARIS_NETWORK
++  int nl = 0;
++#else
+   int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
++#endif
+ 
+   if (argc < 4 || argc > 5)
+     { 
[email protected]@ -267,7 +284,8 @@
+       perror("cannot create socket");
+       exit(1);
+     }
+-  
++
++#if !defined(HAVE_SOLARIS_NETWORK)
+   /* This voodoo fakes up a packet coming from the correct interface, which really matters for 
+      a DHCP server */
+   strcpy(ifr.ifr_name, argv[1]);
[email protected]@ -276,11 +294,43 @@
+       perror("cannot setup interface");
+       exit(1);
+     }
+-  
++#endif
+   
+   lease.s_addr = inet_addr(argv[2]);
++#ifdef HAVE_SOLARIS_NETWORK
++  struct ifaddrs *ifp_head, *ifp;
++
++  if (getifaddrs(&ifp_head) < 0)
++    {
++      perror("could not retrieve IP addresses");
++      exit(1);
++    }
++  for (ifp = ifp_head; ifp != NULL; ifp = ifp->ifa_next) { 
++    if (ifp->ifa_addr->sa_family != AF_INET)
++      continue;
++    if (strcmp(ifp->ifa_name, argv[1]) == 0 &&
++        is_same_net(lease, ((struct sockaddr_in *)ifp->ifa_addr)->sin_addr,
++	((struct sockaddr_in *)ifp->ifa_netmask)->sin_addr))
++      break;
++    }
++  if (ifp == NULL) {
++    freeifaddrs(ifp_head);
++    exit(0);
++  }
++  memcpy(&server, &((struct sockaddr_in *)ifp->ifa_addr)->sin_addr,
++	sizeof(server));
++  /* bind to the socket */
++  if (bind(fd, ifp->ifa_addr, sizeof(struct sockaddr_in)) == -1)
++    {
++      freeifaddrs(ifp_head);
++      perror("cannot bind to socket");
++      exit(1);
++    }
++  freeifaddrs(ifp_head);
++#else
+   server = find_interface(lease, nl, if_nametoindex(argv[1]));
+-  
++#endif
++
+   memset(&packet, 0, sizeof(packet));
+  
+   packet.hlen = parse_hex(argv[3], packet.chaddr, DHCP_CHADDR_MAX, &mac_type);
--- a/components/openstack/neutron/files/agent/evs_l3_agent.py	Mon Jul 07 04:16:19 2014 -0700
+++ b/components/openstack/neutron/files/agent/evs_l3_agent.py	Mon Jul 07 13:15:12 2014 -0700
@@ -180,26 +180,29 @@
         ipintf = net_lib.IPInterface(ifname)
         ipaddr_list = ipintf.ipaddr_list()['static']
 
-        # Clear out all ipnat rules for floating ips
-        ri.ipfilters_manager.remove_nat_rules(ri.ipfilters_manager.ipv4['nat'])
-
         existing_cidrs = set([addr for addr in ipaddr_list])
         new_cidrs = set()
 
+        existing_nat_rules = [nat_rule for nat_rule in
+                              ri.ipfilters_manager.ipv4['nat']]
+        new_nat_rules = []
+
         # Loop once to ensure that floating ips are configured.
         for fip in ri.router.get(l3_constants.FLOATINGIP_KEY, []):
             fip_ip = fip['floating_ip_address']
             fip_cidr = str(fip_ip) + FLOATING_IP_CIDR_SUFFIX
-
             new_cidrs.add(fip_cidr)
+            fixed_cidr = str(fip['fixed_ip_address']) + '/32'
+            nat_rule = 'bimap %s %s -> %s' % (ifname, fixed_cidr, fip_cidr)
 
             if fip_cidr not in existing_cidrs:
                 ipintf.create_address(fip_cidr)
+                ri.ipfilters_manager.add_nat_rules([nat_rule])
+            new_nat_rules.append(nat_rule)
 
-            # Rebuild iptables rules for the floating ip.
-            fixed_cidr = str(fip['fixed_ip_address']) + '/32'
-            nat_rules = ['bimap %s %s -> %s' % (ifname, fixed_cidr, fip_cidr)]
-            ri.ipfilters_manager.add_nat_rules(nat_rules)
+        # remove all the old NAT rules
+        ri.ipfilters_manager.remove_nat_rules(list(set(existing_nat_rules) -
+                                              set(new_nat_rules)))
 
         # Clean up addresses that no longer belong on the gateway interface.
         for ip_cidr in existing_cidrs - new_cidrs:
--- a/components/openstack/neutron/files/agent/solaris/dhcp.py	Mon Jul 07 04:16:19 2014 -0700
+++ b/components/openstack/neutron/files/agent/solaris/dhcp.py	Mon Jul 07 13:15:12 2014 -0700
@@ -372,8 +372,11 @@
         utils.execute(cmd, self.root_helper)
 
     def release_lease(self, mac_address, removed_ips):
-        # TODO(gmoodalb): we need to support dnsmasq's dhcp_release
-        pass
+        """Release a DHCP lease."""
+        for ip in removed_ips or []:
+            cmd = ['/usr/lib/inet/dhcp_release', self.interface_name,
+                   ip, mac_address]
+            utils.execute(cmd, self.root_helper)
 
     def reload_allocations(self):
         """Rebuild the dnsmasq config and signal the dnsmasq to reload."""