Date: Mon, 11 Feb 2013 10:58:22 +0000 (UTC) From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r246659 - in head/sys: net netinet Message-ID: <201302111058.r1BAwM5r060844@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302111058.r1BAwM5r060844>