Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Oct 2013 08:30:30 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r256597 - user/ae/inet6/sys/netinet6
Message-ID:  <201310160830.r9G8UUUS076184@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Wed Oct 16 08:30:30 2013
New Revision: 256597
URL: http://svnweb.freebsd.org/changeset/base/256597

Log:
  * Add srcaddrcmp() function to compare addresses using SAS Algorithm;
  * add srcaddr_choice and dstaddr_props structures to describe source
  and destination addresses;
  * remove old REPLACE, NEXT and BREAK macros;

Modified:
  user/ae/inet6/sys/netinet6/in6_src.c

Modified: user/ae/inet6/sys/netinet6/in6_src.c
==============================================================================
--- user/ae/inet6/sys/netinet6/in6_src.c	Wed Oct 16 08:24:06 2013	(r256596)
+++ user/ae/inet6/sys/netinet6/in6_src.c	Wed Oct 16 08:30:30 2013	(r256597)
@@ -151,27 +151,148 @@ static int in6_srcaddrscope(const struct
  * If necessary, this function lookups the routing table and returns
  * an entry to the caller for later use.
  */
-#define REPLACE(r) do {\
-	IP6STAT_INC(ip6s_sources_rule[(r)]); \
-	rule = (r);	\
-	/* { \
-	char ip6buf[INET6_ADDRSTRLEN], ip6b[INET6_ADDRSTRLEN]; \
-	printf("in6_selectsrc: replace %s with %s by %d\n", ia_best ? ip6_sprintf(ip6buf, &ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(ip6b, &ia->ia_addr.sin6_addr), (r)); \
-	} */ \
-	goto replace; \
-} while(0)
-#define NEXT(r) do {\
-	/* { \
-	char ip6buf[INET6_ADDRSTRLEN], ip6b[INET6_ADDRSTRLEN]; \
-	printf("in6_selectsrc: keep %s against %s by %d\n", ia_best ? ip6_sprintf(ip6buf, &ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(ip6b, &ia->ia_addr.sin6_addr), (r)); \
-	} */ \
-	goto next;		/* XXX: we can't use 'continue' here */ \
-} while(0)
-#define BREAK(r) do { \
-	IP6STAT_INC(ip6s_sources_rule[(r)]); \
-	rule = (r);	\
-	goto out;		/* XXX: we can't use 'break' here */ \
-} while(0)
+struct srcaddr_choice {
+	struct in6_ifaddr *ia;
+	int scope;
+	int label;
+	int prefixlen;
+	int rule;
+};
+struct dstaddr_props {
+	struct ifnet *ifp;
+	struct in6_addr *addr;
+	int scope;
+	int label;
+	int prefixlen;
+};
+
+#define	REPLACE(r)	{ rule = r; goto replace; }
+#define	NEXT(r)		{ rule = r; goto next; }
+
+static int
+srcaddrcmp(struct srcaddr_choice *c, struct in6_ifaddr *ia,
+    struct dstaddr_props *dst, struct ucred *cred,
+    struct ip6_pktopts *opts)
+{
+	int srcscope, rule, label, prefer_tempaddr, prefixlen;
+
+	/* Avoid unusable addresses */
+	if ((ia->ia6_flags & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED)) ||
+	    (ia->ia_ifp->if_flags & IFF_UP) == 0)
+		return (-1);
+	/*
+	 * In any case, multicast addresses and the unspecified address
+	 * MUST NOT be included in a candidate set.
+	 */
+	if (IN6_IS_ADDR_MULTICAST(IA6_IN6(ia)) ||
+	    IN6_IS_ADDR_UNSPECIFIED(IA6_IN6(ia)))
+		return (-1);
+	if (!V_ip6_use_deprecated && IFA6_IS_DEPRECATED(ia))
+		return (-1);
+	/* If jailed, only take addresses of the jail into account. */
+	if (cred != NULL && prison_check_ip6(cred, IA6_IN6(ia)) != 0)
+		return (-1);
+	/* Source address can not break the destination zone */
+	srcscope = in6_srcaddrscope(IA6_IN6(ia));
+	if (ia->ia_ifp != dst->ifp &&
+	    in6_getscopezone(ia->ia_ifp, srcscope) !=
+	    in6_getscopezone(dst->ifp, dst->scope))
+		return (-1);
+	label = ADDR_LABEL_NOTAPP;
+	prefixlen = -1;
+	/* Rule 1: Prefer same address. */
+	if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), dst->addr))
+		REPLACE(1);
+	/* Rule 2: Prefer appropriate scope. */
+	if (c->ia == NULL) {
+		dst->label = lookup_policy_label(dst->addr,
+		    in6_getscopezone(dst->ifp, dst->scope));
+		REPLACE(0);
+	}
+	if (IN6_ARE_SCOPE_CMP(c->scope, srcscope) < 0) {
+		if (IN6_ARE_SCOPE_CMP(c->scope, dst->scope) < 0)
+			REPLACE(2);
+		NEXT(2);
+	} else if (IN6_ARE_SCOPE_CMP(srcscope, c->scope) < 0) {
+		if (IN6_ARE_SCOPE_CMP(srcscope, dst->scope) < 0)
+			NEXT(2);
+		REPLACE(2);
+	}
+	/* Rule 3: Avoid deprecated addresses. */
+	if (!IFA6_IS_DEPRECATED(c->ia) && IFA6_IS_DEPRECATED(ia))
+		NEXT(3);
+	if (IFA6_IS_DEPRECATED(c->ia) && !IFA6_IS_DEPRECATED(ia))
+		REPLACE(3);
+	/*
+	 * Rule 4: Prefer home addresses.
+	 * XXX: This is a TODO.
+	 */
+	/* Rule 5: Prefer outgoing interface. */
+	if (c->ia->ia_ifp == dst->ifp && ia->ia_ifp != dst->ifp)
+		NEXT(5);
+	if (c->ia->ia_ifp != dst->ifp && ia->ia_ifp == dst->ifp)
+		REPLACE(5);
+	/*
+	 * Rule 5.5: Prefer addresses in a prefix advertised by
+	 * the next-hop.
+	 * XXX: not yet.
+	 */
+	/* Rule 6: Prefer matching label. */
+	if (dst->label != ADDR_LABEL_NOTAPP) {
+		c->label = lookup_policy_label(IA6_IN6(c->ia),
+		    in6_getscopezone(c->ia->ia_ifp, c->scope));
+		label = lookup_policy_label(IA6_IN6(ia),
+		    in6_getscopezone(ia->ia_ifp, srcscope));
+		if (c->label == dst->label && label != dst->label)
+			NEXT(6);
+		if (label == dst->label && c->label != dst->label)
+			REPLACE(6);
+	}
+	/* Rule 7: Prefer temporary addresses. */
+	if (opts == NULL ||
+	    opts->ip6po_prefer_tempaddr == IP6PO_TEMPADDR_SYSTEM)
+		prefer_tempaddr = V_ip6_prefer_tempaddr;
+	else if (opts->ip6po_prefer_tempaddr == IP6PO_TEMPADDR_NOTPREFER)
+		prefer_tempaddr = 0;
+	else
+		prefer_tempaddr = 1;
+	if ((c->ia->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&
+	    (ia->ia6_flags & IN6_IFF_TEMPORARY) == 0) {
+		if (prefer_tempaddr)
+			NEXT(7);
+		REPLACE(7);
+	}
+	if ((c->ia->ia6_flags & IN6_IFF_TEMPORARY) == 0 &&
+	    (ia->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
+		if (prefer_tempaddr)
+			REPLACE(7);
+		NEXT(7);
+	}
+	/* Rule 8: Use longest matching prefix. */
+	if (c->prefixlen < 0)
+		c->prefixlen = in6_matchlen(IA6_IN6(c->ia), dst->addr);
+	prefixlen = in6_matchlen(IA6_IN6(ia), dst->addr);
+	if (c->prefixlen > prefixlen)
+		NEXT(8);
+	if (prefixlen > c->prefixlen)
+		REPLACE(8);
+	return (-1);
+replace:
+	/* debug output */
+	c->ia = ia;
+	c->label = label;
+	c->scope = srcscope;
+	c->rule = rule;
+	c->prefixlen = prefixlen;
+	/* Update statistic */
+	IP6STAT_INC(ip6s_sources_rule[rule]);
+	return (rule);
+next:
+	/* debug output */
+	return (rule);
+}
+#undef	REPLACE
+#undef	NEXT
 
 int
 in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,



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