summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2013-02-11 10:58:22 +0000
committerglebius <glebius@FreeBSD.org>2013-02-11 10:58:22 +0000
commita47c0295c5e9d047b28372a33fcabe99a178107f (patch)
treea4b3a19176d84f646cb98e85f72832bbb0fa72ae /sys/net
parentc990c7deec1df4c9024ad3f642005c53e9d7f9c9 (diff)
downloadFreeBSD-src-a47c0295c5e9d047b28372a33fcabe99a178107f.zip
FreeBSD-src-a47c0295c5e9d047b28372a33fcabe99a178107f.tar.gz
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
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c24
-rw-r--r--sys/net/if_var.h2
2 files changed, 22 insertions, 4 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 1c887cb..57bd4e1 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -130,6 +130,7 @@ void (*lagg_linkstate_p)(struct ifnet *ifp, int state);
/* 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>
/*
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 7fcbd38..6ccf364 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -939,8 +939,8 @@ struct ifaddr *ifa_ifwithdstaddr(struct sockaddr *);
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);
OpenPOWER on IntegriCloud