diff options
author | glebius <glebius@FreeBSD.org> | 2013-02-11 10:58:22 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2013-02-11 10:58:22 +0000 |
commit | a47c0295c5e9d047b28372a33fcabe99a178107f (patch) | |
tree | a4b3a19176d84f646cb98e85f72832bbb0fa72ae /sys/net | |
parent | c990c7deec1df4c9024ad3f642005c53e9d7f9c9 (diff) | |
download | FreeBSD-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.c | 24 | ||||
-rw-r--r-- | sys/net/if_var.h | 2 |
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); |