Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 25 Jan 2017 19:04:08 +0000 (UTC)
From:      Luiz Otavio O Souza <loos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r312770 - in head/sys: net netinet netinet6
Message-ID:  <201701251904.v0PJ48YF061428@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: loos
Date: Wed Jan 25 19:04:08 2017
New Revision: 312770
URL: https://svnweb.freebsd.org/changeset/base/312770

Log:
  After the in_control() changes in r257692, an existing address is
  (intentionally) deleted first and then completely added again (so all the
  events, announces and hooks are given a chance to run).
  
  This cause an issue with CARP where the existing CARP data structure is
  removed together with the last address for a given VHID, which will cause
  a subsequent fail when the address is later re-added.
  
  This change fixes this issue by adding a new flag to keep the CARP data
  structure when an address is not being removed.
  
  There was an additional issue with IPv6 CARP addresses, where the CARP data
  structure would never be removed after a change and lead to VHIDs which
  cannot be destroyed.
  
  Reviewed by:	glebius
  Obtained from:	pfSense
  MFC after:	2 weeks
  Sponsored by:	Rubicon Communications, LLC (Netgate)

Modified:
  head/sys/net/if.c
  head/sys/netinet/in.c
  head/sys/netinet/ip_carp.c
  head/sys/netinet/ip_carp.h
  head/sys/netinet6/in6.c

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Wed Jan 25 18:31:51 2017	(r312769)
+++ head/sys/net/if.c	Wed Jan 25 19:04:08 2017	(r312770)
@@ -145,7 +145,7 @@ int	(*carp_output_p)(struct ifnet *ifp, 
     const struct sockaddr *sa);
 int	(*carp_ioctl_p)(struct ifreq *, u_long, struct thread *);   
 int	(*carp_attach_p)(struct ifaddr *, int);
-void	(*carp_detach_p)(struct ifaddr *);
+void	(*carp_detach_p)(struct ifaddr *, bool);
 #endif
 #ifdef INET
 int	(*carp_iamatch_p)(struct ifaddr *, uint8_t **);

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c	Wed Jan 25 18:31:51 2017	(r312769)
+++ head/sys/netinet/in.c	Wed Jan 25 19:04:08 2017	(r312770)
@@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$");
 #include <netinet/udp_var.h>
 
 static int in_aifaddr_ioctl(u_long, caddr_t, struct ifnet *, struct thread *);
-static int in_difaddr_ioctl(caddr_t, struct ifnet *, struct thread *);
+static int in_difaddr_ioctl(u_long, caddr_t, struct ifnet *, struct thread *);
 
 static void	in_socktrim(struct sockaddr_in *);
 static void	in_purgemaddrs(struct ifnet *);
@@ -245,7 +245,7 @@ in_control(struct socket *so, u_long cmd
 		break;
 	case SIOCDIFADDR:
 		sx_xlock(&in_control_sx);
-		error = in_difaddr_ioctl(data, ifp, td);
+		error = in_difaddr_ioctl(cmd, data, ifp, td);
 		sx_xunlock(&in_control_sx);
 		return (error);
 	case OSIOCAIFADDR:	/* 9.x compat */
@@ -390,7 +390,7 @@ in_aifaddr_ioctl(u_long cmd, caddr_t dat
 	IF_ADDR_RUNLOCK(ifp);
 
 	if (ia != NULL)
-		(void )in_difaddr_ioctl(data, ifp, td);
+		(void )in_difaddr_ioctl(cmd, data, ifp, td);
 
 	ifa = ifa_alloc(sizeof(struct in_ifaddr), M_WAITOK);
 	ia = (struct in_ifaddr *)ifa;
@@ -528,7 +528,7 @@ fail2:
 
 fail1:
 	if (ia->ia_ifa.ifa_carp)
-		(*carp_detach_p)(&ia->ia_ifa);
+		(*carp_detach_p)(&ia->ia_ifa, false);
 
 	IF_ADDR_WLOCK(ifp);
 	TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
@@ -545,7 +545,7 @@ fail1:
 }
 
 static int
-in_difaddr_ioctl(caddr_t data, struct ifnet *ifp, struct thread *td)
+in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
 {
 	const struct ifreq *ifr = (struct ifreq *)data;
 	const struct sockaddr_in *addr = (const struct sockaddr_in *)
@@ -618,7 +618,8 @@ in_difaddr_ioctl(caddr_t data, struct if
 	in_ifadown(&ia->ia_ifa, 1);
 
 	if (ia->ia_ifa.ifa_carp)
-		(*carp_detach_p)(&ia->ia_ifa);
+		(*carp_detach_p)(&ia->ia_ifa,
+		    (cmd == SIOCDIFADDR) ? false : true);
 
 	/*
 	 * If this is the last IPv4 address configured on this

Modified: head/sys/netinet/ip_carp.c
==============================================================================
--- head/sys/netinet/ip_carp.c	Wed Jan 25 18:31:51 2017	(r312769)
+++ head/sys/netinet/ip_carp.c	Wed Jan 25 19:04:08 2017	(r312770)
@@ -1969,7 +1969,7 @@ carp_attach(struct ifaddr *ifa, int vhid
 }
 
 void
-carp_detach(struct ifaddr *ifa)
+carp_detach(struct ifaddr *ifa, bool keep_cif)
 {
 	struct ifnet *ifp = ifa->ifa_ifp;
 	struct carp_if *cif = ifp->if_carp;
@@ -2015,12 +2015,13 @@ carp_detach(struct ifaddr *ifa)
 	carp_hmac_prepare(sc);
 	carp_sc_state(sc);
 
-	if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0)
+	if (!keep_cif && sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0)
 		carp_destroy(sc);
 	else
 		CARP_UNLOCK(sc);
 
-	CIF_FREE(cif);
+	if (!keep_cif)
+		CIF_FREE(cif);
 
 	sx_xunlock(&carp_sx);
 }

Modified: head/sys/netinet/ip_carp.h
==============================================================================
--- head/sys/netinet/ip_carp.h	Wed Jan 25 18:31:51 2017	(r312769)
+++ head/sys/netinet/ip_carp.h	Wed Jan 25 19:04:08 2017	(r312770)
@@ -138,7 +138,7 @@ struct carpreq {
 #ifdef _KERNEL
 int		carp_ioctl(struct ifreq *, u_long, struct thread *);
 int		carp_attach(struct ifaddr *, int);
-void		carp_detach(struct ifaddr *);
+void		carp_detach(struct ifaddr *, bool);
 void		carp_carpdev_state(struct ifnet *);
 int		carp_input(struct mbuf **, int *, int);
 int		carp6_input (struct mbuf **, int *, int);
@@ -154,7 +154,7 @@ int		carp_forus(struct ifnet *, u_char *
 /* net/if.c */
 extern int (*carp_ioctl_p)(struct ifreq *, u_long, struct thread *);
 extern int (*carp_attach_p)(struct ifaddr *, int);
-extern void (*carp_detach_p)(struct ifaddr *);
+extern void (*carp_detach_p)(struct ifaddr *, bool);
 extern void (*carp_linkstate_p)(struct ifnet *);
 extern void (*carp_demote_adj_p)(int, char *);
 extern int (*carp_master_p)(struct ifaddr *);

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Wed Jan 25 18:31:51 2017	(r312769)
+++ head/sys/netinet6/in6.c	Wed Jan 25 19:04:08 2017	(r312770)
@@ -554,8 +554,11 @@ in6_control(struct socket *so, u_long cm
 		 */
 		if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
 			goto out;
-		if (ia != NULL)
+		if (ia != NULL) {
+			if (ia->ia_ifa.ifa_carp)
+				(*carp_detach_p)(&ia->ia_ifa, true);
 			ifa_free(&ia->ia_ifa);
+		}
 		if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
 		    == NULL) {
 			/*
@@ -622,7 +625,7 @@ in6_control(struct socket *so, u_long cm
 			 */
 			if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) {
 				if (carp_attached)
-					(*carp_detach_p)(&ia->ia_ifa);
+					(*carp_detach_p)(&ia->ia_ifa, false);
 				goto out;
 			}
 		}
@@ -1243,7 +1246,7 @@ in6_purgeaddr(struct ifaddr *ifa)
 	int plen, error;
 
 	if (ifa->ifa_carp)
-		(*carp_detach_p)(ifa);
+		(*carp_detach_p)(ifa, false);
 
 	/*
 	 * Remove the loopback route to the interface address.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201701251904.v0PJ48YF061428>