svn commit: r246659 - in head/sys: net netinet

Gleb Smirnoff glebius at FreeBSD.org
Mon Feb 11 10:58:23 UTC 2013


Author: glebius
Date: Mon Feb 11 10:58:22 2013
New Revision: 246659
URL: http://svnweb.freebsd.org/changeset/base/246659

Log:
    Resolve source address selection in presense of CARP. Add a couple
  of helper functions:
  
  - carp_master()   - boolean function which is true if an address
  		    is in the MASTER state.
  - ifa_preferred() - boolean function that compares two addresses,
  		    and is aware of CARP.
  
    Utilize ifa_preferred() in ifa_ifwithnet().
  
    The previous version of patch also changed source address selection
  logic in jails using carp_master(), but we failed to negotiate this part
  with Bjoern. May be we will approach this problem again later.
  
  Reported & tested by:	Anton Yuzhaninov <citrin citrin.ru>
  Sponsored by:		Nginx, Inc

Modified:
  head/sys/net/if.c
  head/sys/net/if_var.h
  head/sys/netinet/ip_carp.c
  head/sys/netinet/ip_carp.h

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Mon Feb 11 10:14:12 2013	(r246658)
+++ head/sys/net/if.c	Mon Feb 11 10:58:22 2013	(r246659)
@@ -130,6 +130,7 @@ void	(*lagg_linkstate_p)(struct ifnet *i
 /* These are external hooks for CARP. */
 void	(*carp_linkstate_p)(struct ifnet *ifp);
 void	(*carp_demote_adj_p)(int, char *);
+int	(*carp_master_p)(struct ifaddr *);
 #if defined(INET) || defined(INET6)
 int	(*carp_forus_p)(struct ifnet *ifp, u_char *dhost);
 int	(*carp_output_p)(struct ifnet *ifp, struct mbuf *m,
@@ -1706,11 +1707,13 @@ next:				continue;
 				/*
 				 * If the netmask of what we just found
 				 * is more specific than what we had before
-				 * (if we had one) then remember the new one
-				 * before continuing to search
-				 * for an even better one.
+				 * (if we had one), or if the virtual status
+				 * of new prefix is better than of the old one,
+				 * then remember the new one before continuing
+				 * to search for an even better one.
 				 */
 				if (ifa_maybe == NULL ||
+				    ifa_preferred(ifa_maybe, ifa) ||
 				    rn_refines((caddr_t)ifa->ifa_netmask,
 				    (caddr_t)ifa_maybe->ifa_netmask)) {
 					if (ifa_maybe != NULL)
@@ -1782,6 +1785,21 @@ done:
 	return (ifa);
 }
 
+/*
+ * See whether new ifa is better than current one:
+ * 1) A non-virtual one is preferred over virtual.
+ * 2) A virtual in master state preferred over any other state.
+ *
+ * Used in several address selecting functions.
+ */
+int
+ifa_preferred(struct ifaddr *cur, struct ifaddr *next)
+{
+
+	return (cur->ifa_carp && (!next->ifa_carp ||
+	    ((*carp_master_p)(next) && !(*carp_master_p)(cur))));
+}
+
 #include <net/if_llatbl.h>
 
 /*

Modified: head/sys/net/if_var.h
==============================================================================
--- head/sys/net/if_var.h	Mon Feb 11 10:14:12 2013	(r246658)
+++ head/sys/net/if_var.h	Mon Feb 11 10:58:22 2013	(r246659)
@@ -939,8 +939,8 @@ struct	ifaddr *ifa_ifwithdstaddr(struct 
 struct	ifaddr *ifa_ifwithnet(struct sockaddr *, int);
 struct	ifaddr *ifa_ifwithroute(int, struct sockaddr *, struct sockaddr *);
 struct	ifaddr *ifa_ifwithroute_fib(int, struct sockaddr *, struct sockaddr *, u_int);
-
 struct	ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *);
+int	ifa_preferred(struct ifaddr *, struct ifaddr *);
 
 int	if_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen);
 

Modified: head/sys/netinet/ip_carp.c
==============================================================================
--- head/sys/netinet/ip_carp.c	Mon Feb 11 10:14:12 2013	(r246658)
+++ head/sys/netinet/ip_carp.c	Mon Feb 11 10:58:22 2013	(r246659)
@@ -969,6 +969,14 @@ carp_ifa_delroute(struct ifaddr *ifa)
 	}
 }
 
+int
+carp_master(struct ifaddr *ifa)
+{
+	struct carp_softc *sc = ifa->ifa_carp;
+
+	return (sc->sc_state == MASTER);
+}
+
 #ifdef INET
 /*
  * Broadcast a gratuitous ARP request containing
@@ -2072,6 +2080,7 @@ carp_mod_cleanup(void)
 	carp_forus_p = NULL;
 	carp_output_p = NULL;
 	carp_demote_adj_p = NULL;
+	carp_master_p = NULL;
 	mtx_unlock(&carp_mtx);
 	taskqueue_drain(taskqueue_swi, &carp_sendall_task);
 	mtx_destroy(&carp_mtx);
@@ -2092,6 +2101,7 @@ carp_mod_load(void)
 	carp_attach_p = carp_attach;
 	carp_detach_p = carp_detach;
 	carp_demote_adj_p = carp_demote_adj;
+	carp_master_p = carp_master;
 #ifdef INET6
 	carp_iamatch6_p = carp_iamatch6;
 	carp_macmatch6_p = carp_macmatch6;

Modified: head/sys/netinet/ip_carp.h
==============================================================================
--- head/sys/netinet/ip_carp.h	Mon Feb 11 10:14:12 2013	(r246658)
+++ head/sys/netinet/ip_carp.h	Mon Feb 11 10:58:22 2013	(r246659)
@@ -148,6 +148,7 @@ void		carp_carpdev_state(struct ifnet *)
 void		carp_input (struct mbuf *, int);
 int		carp6_input (struct mbuf **, int *, int);
 int		carp_output (struct ifnet *, struct mbuf *, struct sockaddr *);
+int		carp_master(struct ifaddr *);
 int		carp_iamatch(struct ifaddr *, uint8_t **);
 struct ifaddr	*carp_iamatch6(struct ifnet *, struct in6_addr *);
 caddr_t		carp_macmatch6(struct ifnet *, struct mbuf *, const struct in6_addr *);
@@ -160,6 +161,7 @@ extern int (*carp_attach_p)(struct ifadd
 extern void (*carp_detach_p)(struct ifaddr *);
 extern void (*carp_linkstate_p)(struct ifnet *);
 extern void (*carp_demote_adj_p)(int, char *);
+extern int (*carp_master_p)(struct ifaddr *);
 /* net/if_bridge.c net/if_ethersubr.c */
 extern int (*carp_forus_p)(struct ifnet *, u_char *);
 /* net/if_ethersubr.c */


More information about the svn-src-all mailing list