svn commit: r271460 - user/ae/inet6/tools/tools/ipv6sasdebug

Andrey V. Elsukov ae at FreeBSD.org
Fri Sep 12 10:08:13 UTC 2014


Author: ae
Date: Fri Sep 12 10:08:11 2014
New Revision: 271460
URL: http://svnweb.freebsd.org/changeset/base/271460

Log:
  Add utility for debugging IPv6 source address selection algorithm.
  It uses the kernel code and emulates algorithm with debug output.

Added:
  user/ae/inet6/tools/tools/ipv6sasdebug/
  user/ae/inet6/tools/tools/ipv6sasdebug/Makefile   (contents, props changed)
  user/ae/inet6/tools/tools/ipv6sasdebug/ctl.c   (contents, props changed)
  user/ae/inet6/tools/tools/ipv6sasdebug/main.c   (contents, props changed)
  user/ae/inet6/tools/tools/ipv6sasdebug/stub.c   (contents, props changed)
  user/ae/inet6/tools/tools/ipv6sasdebug/stub.h   (contents, props changed)

Added: user/ae/inet6/tools/tools/ipv6sasdebug/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ae/inet6/tools/tools/ipv6sasdebug/Makefile	Fri Sep 12 10:08:11 2014	(r271460)
@@ -0,0 +1,26 @@
+# $FreeBSD$
+
+.PATH:		${.CURDIR}/../../../sys/netinet6 
+
+BINDIR?=	/usr/bin
+
+PROG=		ipv6sasdebug
+MAN=
+
+SRCS=		main.c stub.c ctl.c in6_src.c
+SRCS+=		opt_inet.h opt_inet6.h opt_mpath.h
+CLEANFILES+=	opt_inet.h opt_inet6.h opt_mpath.h
+
+CFLAGS+=	-I${.CURDIR}
+CFLAGS+=	-I${.CURDIR}/../../../sys
+
+opt_inet.h:
+	echo "#define INET 1" > opt_inet.h
+
+opt_inet6.h:
+	echo "#define INET6 1" > opt_inet6.h
+
+opt_mpath.h:
+	echo "#include \"stub.h\"" > opt_mpath.h
+
+.include <bsd.prog.mk>

Added: user/ae/inet6/tools/tools/ipv6sasdebug/ctl.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ae/inet6/tools/tools/ipv6sasdebug/ctl.c	Fri Sep 12 10:08:11 2014	(r271460)
@@ -0,0 +1,263 @@
+/*-
+ * Copyright (c) 2014 Andrey V. Elsukov <ae at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_var.h>
+#define	_WANT_RTENTRY
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/ip_carp.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <err.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern int sock6;
+extern int V_ip6_use_deprecated;
+extern int V_ip6_prefer_tempaddr;
+extern int V_ip6_defhlim;
+extern int in6_mask2len(struct in6_addr *, u_char *);
+extern struct ifnet* ifnet_byname(const char *name);
+static struct carpreq carp[CARP_MAXVHID];
+static int has_carp = 0;
+
+void
+ifnet_getcarpstatus(const char *name)
+{
+	struct ifreq req;
+
+	if (has_carp)
+		return;
+	memset(&req, 0, sizeof(req));
+	memset(carp, 0, sizeof(struct carpreq) * CARP_MAXVHID);
+	strncpy(req.ifr_name, name, sizeof(req.ifr_name));
+	req.ifr_ifru.ifru_data = (caddr_t)carp;
+	carp[0].carpr_count = CARP_MAXVHID;
+	if (ioctl(sock6, SIOCGVH, &req) < 0)
+		return;
+	has_carp = 1;
+}
+
+int
+carp_master(uint8_t vhid)
+{
+	int i;
+
+	if (has_carp == 0)
+		return (0);
+	for (i = 0; i < carp[0].carpr_count; i++)
+		if (carp[i].carpr_vhid == vhid)
+			return (carp[i].carpr_state == CARP_MAXSTATE);
+	return (0);
+}
+
+int
+ifnet_getflags(const char *name, struct sockaddr_in6 *addr)
+{
+	struct ifreq req;
+
+	memset(&req, 0, sizeof(req));
+	strncpy(req.ifr_name, name, sizeof(req.ifr_name));
+	if (ioctl(sock6, SIOCGIFFLAGS, &req) < 0)
+		err(EXIT_FAILURE, "ioctl(SIOCGIFFLAGS)");
+	return ((req.ifr_flags & 0xffff) | (req.ifr_flagshigh << 16));
+}
+
+void
+ifnet_getndinfo(const char *name, uint32_t *linkmtu, uint32_t *maxmtu,
+    uint32_t *flags, uint8_t *chlim)
+{
+	struct in6_ndireq req;
+
+	strncpy(req.ifname, name, sizeof(req.ifname));
+	if (ioctl(sock6, SIOCGIFINFO_IN6, &req) < 0)
+		err(EXIT_FAILURE, "ioctl(SIOCGIFINFO_IN6)");
+	*linkmtu = req.ndi.linkmtu;
+	*maxmtu = req.ndi.maxmtu;
+	*flags = req.ndi.flags;
+	*chlim = req.ndi.chlim;
+}
+
+int
+addr_getflags(const char *name, struct sockaddr_in6 *addr)
+{
+	struct in6_ifreq req;
+
+	strncpy(req.ifr_name, name, sizeof(req.ifr_name));
+	req.ifr_ifru.ifru_addr = *addr;
+	if (ioctl(sock6, SIOCGIFAFLAG_IN6, &req) < 0)
+		err(EXIT_FAILURE, "ioctl(SIOCGIFAFLAG_IN6)");
+	return (req.ifr_ifru.ifru_flags6);
+}
+
+void
+addr_getlifetime(const char *name, struct sockaddr_in6 *addr,
+    struct in6_addrlifetime *lt)
+{
+	struct in6_ifreq req;
+
+	strncpy(req.ifr_name, name, sizeof(req.ifr_name));
+	req.ifr_ifru.ifru_addr = *addr;
+	if (ioctl(sock6, SIOCGIFALIFETIME_IN6, &req) < 0)
+		err(EXIT_FAILURE, "ioctl(SIOCGIFALIFETIME_IN6)");
+	*lt = req.ifr_ifru.ifru_lifetime;
+}
+
+void
+v_getsysctl(void)
+{
+	size_t len;
+
+	len = sizeof(V_ip6_use_deprecated);
+	if (sysctlbyname("net.inet6.ip6.use_deprecated",
+	    &V_ip6_use_deprecated, &len, NULL, 0) == -1)
+		err(EXIT_FAILURE, "net.inet6.ip6.use_deprecated");
+
+	len = sizeof(V_ip6_prefer_tempaddr);
+	if (sysctlbyname("net.inet6.ip6.prefer_tempaddr",
+	    &V_ip6_prefer_tempaddr, &len, NULL, 0) == -1)
+		err(EXIT_FAILURE, "net.inet6.ip6.prefer_tempaddr");
+
+	len = sizeof(V_ip6_defhlim);
+	if (sysctlbyname("net.inet6.ip6.hlim",
+	    &V_ip6_defhlim, &len, NULL, 0) == -1)
+		err(EXIT_FAILURE, "net.inet6.ip6.hlim");
+}
+
+void
+addrsel_policy_populate(int add(struct in6_addrpolicy *), int debug)
+{
+	struct in6_addrpolicy *pp, *p;
+	size_t len;
+	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
+	char buf[NI_MAXHOST + IFNAMSIZ + 10];
+
+	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) < 0)
+		err(EXIT_FAILURE, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
+	if ((pp = malloc(len)) == NULL)
+		err(EXIT_FAILURE, "malloc");
+	if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), pp, &len, NULL, 0) < 0)
+		err(EXIT_FAILURE, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
+	if (debug)
+		printf("\nIPv6 address selection policy table:\n"
+		    "%-30s %5s %5s %8s\n", "Prefix", "Prec", "Label", "Use");
+	for (p = pp; p < pp + len/sizeof(*p); p++) {
+		add(p);
+		if (debug) {
+			if (getnameinfo((struct sockaddr *)&p->addr,
+			    sizeof(p->addr), buf, sizeof(buf), NULL, 0,
+			    NI_NUMERICHOST) != 0)
+				continue;
+			snprintf(buf, sizeof(buf), "%s/%d", buf,
+			    in6_mask2len(&p->addrmask.sin6_addr, NULL));
+			printf("%-30s %5d %5d %8llu\n", buf, p->preced,
+			    p->label, (unsigned long long)p->use);
+		}
+	}
+	free(pp);
+}
+
+struct {
+	struct rt_msghdr	m_rtm;
+	char			m_space[512];
+} m_rtmsg;
+
+void
+in6_rtalloc(struct route_in6 *ro, u_int fibnum)
+{
+	static int seq = 0;
+	struct rtentry *rt;
+	struct sockaddr_dl *ifp;
+	struct sockaddr_in6 *sa6;
+	char *cp = m_rtmsg.m_space;
+	pid_t pid;
+	int i, l, s;
+
+	s = socket(PF_ROUTE, SOCK_RAW, 0);
+	if (s < 0)
+		err(EXIT_FAILURE, "socket(PF_ROUTE)");
+	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
+
+#define rtm m_rtmsg.m_rtm
+	rtm.rtm_type = RTM_GET;
+	rtm.rtm_version = RTM_VERSION;
+	rtm.rtm_seq = ++seq;
+	rtm.rtm_addrs = RTA_DST | RTA_IFP;
+
+	sa6 = (struct sockaddr_in6 *)cp;
+	*sa6 = ro->ro_dst;
+	rtm.rtm_msglen = sizeof(m_rtmsg.m_rtm) + SA_SIZE(sa6);
+	l = write(s, (char *)&m_rtmsg, rtm.rtm_msglen);
+	if (l < 0)
+		err(EXIT_FAILURE, "write()");
+	pid = getpid();
+	do {
+		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+	} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
+	if (l < 0)
+		err(EXIT_FAILURE, "read()");
+	close(s);
+	ro->ro_rt = NULL;
+	if (rtm.rtm_errno != 0 || (rtm.rtm_addrs &
+	    (RTA_GATEWAY | RTA_IFP)) != (RTA_GATEWAY | RTA_IFP))
+		return;
+	for (i = 1; i < RTA_IFP; i <<= 1) {
+		if ((i & rtm.rtm_addrs) == 0)
+			continue;
+		if (i == RTA_GATEWAY)
+			sa6 = (struct sockaddr_in6 *)cp;
+		cp += SA_SIZE(cp);
+	}
+	ifp = (struct sockaddr_dl *)cp;
+	if (sa6->sin6_family != AF_INET6)
+		return;
+	if (ifp->sdl_family != AF_LINK ||
+	    ifp->sdl_nlen == 0)
+		return;
+	ifp->sdl_data[ifp->sdl_nlen] = '\0';
+	if ((rt = calloc(1, sizeof(*rt))) == NULL)
+		return;
+	if ((rt->rt_gateway = calloc(1, sizeof(*sa6))) == NULL)
+		err(EXIT_FAILURE, "calloc()");
+	memcpy(rt->rt_gateway, sa6, sizeof(*sa6));
+	rt->rt_fibnum = fibnum;
+	rt->rt_ifp = ifnet_byname(ifp->sdl_data);
+	ro->ro_rt = rt;
+}

Added: user/ae/inet6/tools/tools/ipv6sasdebug/main.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ae/inet6/tools/tools/ipv6sasdebug/main.c	Fri Sep 12 10:08:11 2014	(r271460)
@@ -0,0 +1,236 @@
+/*-
+ * Copyright (c) 2014 Andrey V. Elsukov <ae at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <ifaddrs.h>
+#include <libutil.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include "stub.h"
+
+static SLIST_HEAD(, ifnet) iflist = SLIST_HEAD_INITIALIZER(iflist);
+const struct sockaddr_in6 sa6_any = { sizeof(sa6_any), AF_INET6, 0, 0,
+    IN6ADDR_ANY_INIT, 0 };
+struct in6_ifaddrhead V_in6_ifaddrhead = TAILQ_HEAD_INITIALIZER(V_in6_ifaddrhead);
+int V_ip6_use_deprecated;
+int V_ip6_prefer_tempaddr;
+int V_ip6_defhlim;
+int sock6;
+
+const char *
+ip6_sprintf(char *buf, const struct in6_addr *addr)
+{
+
+	return (inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN));
+}
+
+struct ifnet*
+ifnet_byindex(uint32_t index)
+{
+	struct ifnet *ifp;
+
+	SLIST_FOREACH(ifp, &iflist, if_link)
+	    if (ifp->if_index == index)
+		    return (ifp);
+	return (NULL);
+}
+
+struct ifnet*
+ifnet_byname(const char *name)
+{
+	struct ifnet *ifp;
+
+	SLIST_FOREACH(ifp, &iflist, if_link)
+	    if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
+		    return (ifp);
+	ifp = calloc(1, sizeof(struct ifnet));
+	if (ifp == NULL)
+		return (NULL);
+	SLIST_INSERT_HEAD(&iflist, ifp, if_link);
+	TAILQ_INIT(&ifp->if_addrhead);
+	strlcpy(ifp->if_xname, name, IFNAMSIZ);
+	ifp->if_flags = ifnet_getflags(name);
+	ifp->if_index = if_nametoindex(name);
+	ifnet_getndinfo(name, &ifp->if_ndifinfo.linkmtu,
+	    &ifp->if_ndifinfo.maxmtu, &ifp->if_ndifinfo.flags,
+	    &ifp->if_ndifinfo.chlim);
+	ifnet_getcarpstatus(name);
+	return (ifp);
+}
+
+static void
+addr_add(char *name, struct ifaddrs *ifa)
+{
+	struct ifnet *ifp;
+	struct in6_ifaddr *ia;
+	struct sockaddr_in6 *addr;
+	struct if_data *ifd;
+
+	ifp = ifnet_byname(name);
+	if (ifp == NULL)
+		return;
+	addr = (struct sockaddr_in6 *)ifa->ifa_addr;
+	ia = calloc(1, sizeof(struct in6_ifaddr));
+	TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
+	TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link);
+	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+	ia->ia_ifp = ifp;
+	ia->ia_addr = *addr;
+	ia->ia6_flags = addr_getflags(name, addr);
+	if (ifa->ifa_data != NULL) {
+		ifd = ifa->ifa_data;
+		ia->ia_ifa.ifa_carp = ifd->ifi_vhid;
+	}
+	addr_getlifetime(name, addr, &ia->ia6_lifetime);
+}
+
+static int
+addrselpolicy_add(struct in6_addrpolicy *p)
+{
+
+	return (in6_src_ioctl(SIOCAADDRCTL_POLICY, (caddr_t)p));
+}
+
+static void
+debug_list(void)
+{
+	struct ifnet *ifp;
+	struct in6_ifaddr *ia;
+	struct ifaddr *ifa;
+	char buf[NI_MAXHOST + IFNAMSIZ + 1];
+
+	printf("List of IPv6 interfaces:\n");
+	SLIST_FOREACH(ifp, &iflist, if_link) {
+		printf("%s: <%04x>\n", ifp->if_xname, ifp->if_flags);
+		printf("\tlinkmtu %d, maxmtu %d, hlim %d, ND <%04x>\n",
+		    ifp->if_ndifinfo.linkmtu, ifp->if_ndifinfo.maxmtu,
+		    ifp->if_ndifinfo.chlim, ifp->if_ndifinfo.flags);
+		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
+			printf("\tinet6 %s\n", ip6_sprintf(buf,
+			    &((struct sockaddr_in6 *)
+				    ifa->ifa_addr)->sin6_addr));
+	}
+	printf("\nList of IPv6 addresses:\n");
+	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
+		getnameinfo((struct sockaddr *)&ia->ia_addr, sizeof(ia->ia_addr),
+		    buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+		printf("%s <%04x>\n", buf, ia->ia6_flags);
+	}
+	printf("\nSysctl variables:\n");
+	printf("%s: %d\n", "net.inet6.ip6.use_deprecated", V_ip6_use_deprecated);
+	printf("%s: %d\n", "net.inet6.ip6.prefer_tempaddr", V_ip6_prefer_tempaddr);
+	printf("%s: %d\n", "net.inet6.ip6.hlim", V_ip6_defhlim);
+}
+
+static void
+usage(void)
+{
+
+	printf("ipv6sasdebug [-vh] <IPv6 destination address>\n");
+	printf("\t-v	show collected information related to IPv6 SAS\n");
+	printf("\t-h	show usage message\n");
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	struct addrinfo hints, *res, *res0;
+	struct sockaddr_in6 dst;
+	struct in6_addr src;
+	struct ifaddrs *ifap, *ifa;
+	struct ifnet *ifp;
+	int debug, ch, error;
+	char buf[INET6_ADDRSTRLEN];
+
+	debug = 0;
+	while ((ch = getopt(argc, argv, ":vh")) != -1) {
+		switch (ch) {
+		case 'v':
+			debug = 1;
+			break;
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1)
+		usage();
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_INET6;
+	hints.ai_flags = AI_NUMERICHOST;
+	error = getaddrinfo(argv[0], NULL, &hints, &res0);
+	if (error != 0)
+		err(EXIT_FAILURE, "%s", gai_strerror(error));
+	for (res = res0; res; res = res->ai_next)
+		if (res->ai_addr->sa_family == AF_INET6) {
+			dst = *(struct sockaddr_in6 *)res->ai_addr;
+			break;
+		}
+	freeaddrinfo(res0);
+
+	v_getsysctl();
+	sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
+	if (sock6 < 0)
+		err(EXIT_FAILURE, "socket");
+	if (getifaddrs(&ifap) != 0)
+		err(EXIT_FAILURE, "getifaddrs");
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr->sa_family != AF_INET6)
+			continue;
+		addr_add(ifa->ifa_name, ifa);
+	}
+	freeifaddrs(ifap);
+	close(sock6);
+
+	if (debug)
+		debug_list();
+	/* Populate the address selection policy table */
+	addrsel_policy_init();
+	addrsel_policy_populate(addrselpolicy_add, debug);
+
+	ifp = NULL;
+	error = in6_selectsrc(&dst, NULL, NULL, NULL, NULL, &ifp, &src);
+	if (error == 0) {
+		printf("\nin6_selectsrc returned %s address and %s"
+		    " outgoing interface.\n", ip6_sprintf(buf, &src),
+		    ifp->if_xname);
+	} else {
+		printf("in6_selectsrc() failed\n");
+	}
+	return (0);
+}

Added: user/ae/inet6/tools/tools/ipv6sasdebug/stub.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ae/inet6/tools/tools/ipv6sasdebug/stub.c	Fri Sep 12 10:08:11 2014	(r271460)
@@ -0,0 +1,189 @@
+/*-
+ * Copyright (c) 2014 Andrey V. Elsukov <ae at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stub.h"
+
+void
+ifa_free(void *ifa)
+{
+
+}
+
+void
+ifa_ref(void *ifa)
+{
+
+}
+
+int
+in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp,
+    struct ucred *cred, int lookupflags)
+{
+
+	return (EINVAL);
+}
+
+int
+in_pcbinshash(struct inpcb *inp)
+{
+
+	return (EINVAL);
+}
+
+int
+prison_local_ip6(struct ucred *cred, const struct sockaddr_in6 *ia6,
+    int v6only)
+{
+
+	return (EAFNOSUPPORT);
+}
+
+int
+prison_check_ip6(struct ucred *cred, const struct sockaddr_in6 *ia6)
+{
+
+	return (EAFNOSUPPORT);
+}
+
+int
+prison_saddrsel_ip6(struct ucred *cred, const struct sockaddr_in6 *ia6)
+{
+
+	return (EAFNOSUPPORT);
+}
+
+/* Copy from netinet6/in6.c */
+int
+in6_mask2len(struct in6_addr *mask, u_char *lim0)
+{
+	int x = 0, y;
+	u_char *lim = lim0, *p;
+
+	/* ignore the scope_id part */
+	if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask))
+		lim = (u_char *)mask + sizeof(*mask);
+	for (p = (u_char *)mask; p < lim; x++, p++) {
+		if (*p != 0xff)
+			break;
+	}
+	y = 0;
+	if (p < lim) {
+		for (y = 0; y < 8; y++) {
+			if ((*p & (0x80 >> y)) == 0)
+				break;
+		}
+	}
+
+	/*
+	 * when the limit pointer is given, do a stricter check on the
+	 * remaining bits.
+	 */
+	if (p < lim) {
+		if (y != 0 && (*p & (0x00ff >> y)) != 0)
+			return (-1);
+		for (p = p + 1; p < lim; p++)
+			if (*p != 0)
+				return (-1);
+	}
+
+	return (x * 8 + y);
+}
+
+int
+in6_matchlen(struct in6_addr *src, struct in6_addr *dst)
+{
+	int match = 0;
+	u_char *s = (u_char *)src, *d = (u_char *)dst;
+	u_char *lim = s + 16, r;
+
+	while (s < lim)
+		if ((r = (*d++ ^ *s++)) != 0) {
+			while (r < 128) {
+				match++;
+				r <<= 1;
+			}
+			break;
+		} else
+			match += 8;
+	return (match);
+}
+
+struct in6_ifaddr *
+in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid)
+{
+	struct in6_ifaddr *ia;
+
+	TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) {
+		if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), addr)) {
+			if (zoneid != 0 &&
+			    zoneid != ia->ia_addr.sin6_scope_id)
+				continue;
+			break;
+		}
+	}
+	return (ia);
+}
+/* Copy from netinet6/scope6.c */
+struct ifnet*
+in6_getlinkifnet(uint32_t zoneid)
+{
+
+	return (ifnet_byindex(zoneid));
+}
+
+uint32_t
+in6_getscopezone(const struct ifnet *ifp, int scope)
+{
+
+	if (scope == __IPV6_ADDR_SCOPE_INTFACELOCAL ||
+	    scope == __IPV6_ADDR_SCOPE_LINKLOCAL)
+		return (ifp->if_index);
+	return (0);
+}
+
+int
+in6_addrscope(const struct in6_addr *addr)
+{
+
+	if (IN6_IS_ADDR_MULTICAST(addr))
+		return (__IPV6_ADDR_MC_SCOPE(addr));
+	if (IN6_IS_ADDR_LINKLOCAL(addr) ||
+	    IN6_IS_ADDR_LOOPBACK(addr))
+		return (__IPV6_ADDR_SCOPE_LINKLOCAL);
+	return (__IPV6_ADDR_SCOPE_GLOBAL);
+}
+
+int
+ifa_preferred(struct ifaddr *cur, struct ifaddr *next)
+{
+
+	return (cur->ifa_carp && (!next->ifa_carp ||
+	    (carp_master(next->ifa_carp) && !carp_master(cur->ifa_carp))));
+}
+
+

Added: user/ae/inet6/tools/tools/ipv6sasdebug/stub.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/ae/inet6/tools/tools/ipv6sasdebug/stub.h	Fri Sep 12 10:08:11 2014	(r271460)
@@ -0,0 +1,240 @@
+/*-
+ * Copyright (c) 2014 Andrey V. Elsukov <ae at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/mutex.h>
+
+#define	_SYS_SYSTM_H_
+#define	_SYS_RMLOCK_H_
+#define	_NET_IF_LLATBL_H_
+#define	_NETINET_IN_VAR_H_
+#define	_NETINET6_IN6_VAR_H_
+#define	_NETINET6_ND6_H_
+#define	_NET_IF_VAR_H_
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#define	_WANT_RTENTRY
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* net/vnet.h */
+#define	VNET_DEFINE(type, var)		type var
+#define	VNET(var)			var
+#define	IS_DEFAULT_VNET(v)		1
+
+/* netinet6/nd6.h */
+#define	ND_IFINFO(ifp)		(&(ifp)->if_ndifinfo)
+#define	ND6_IFF_PERFORMNUD	0x1
+#define	ND6_IFF_ACCEPT_RTADV	0x2
+#define	ND6_IFF_IFDISABLED	0x8
+#define	ND6_IFF_DONT_SET_IFROUTE 0x10
+#define	ND6_IFF_AUTO_LINKLOCAL	0x20
+#define	ND6_IFF_NO_RADR		0x40
+#define	ND6_IFF_NO_PREFER_IFACE	0x80
+
+struct nd_ifinfo {
+	uint32_t		linkmtu;
+	uint32_t		maxmtu;
+	uint32_t		flags;
+	uint8_t			chlim;
+};
+
+/* net/if_var.h */
+TAILQ_HEAD(ifaddrhead, ifaddr);
+struct ifnet {
+	uint32_t		if_index;
+	int			if_flags;
+
+	char			if_xname[IFNAMSIZ];
+	struct ifaddrhead	if_addrhead;
+	struct nd_ifinfo	if_ndifinfo;
+	SLIST_ENTRY(ifnet)	if_link;
+};
+
+struct ifaddr {
+	struct sockaddr		*ifa_addr;
+	struct ifnet		*ifa_ifp;
+	uint8_t			ifa_carp;
+	TAILQ_ENTRY(ifaddr)	ifa_link;
+};
+
+/* netinet6/in6.h */
+#define	IN6_IS_ADDR_MC_INTFACELOCAL	IN6_IS_ADDR_MC_NODELOCAL
+#define	IPV6_ADDR_SCOPE_LINKLOCAL	__IPV6_ADDR_SCOPE_LINKLOCAL
+#define	IFA6_IS_DEPRECATED(ia)	\
+    ((ia)->ia6_lifetime.ia6t_preferred > (ia)->ia6_lifetime.ia6t_pltime)
+#define	IFA6_IS_VALID(ia) \
+    ((ia)->ia6_lifetime.ia6t_expire > (ia)->ia6_lifetime.ia6t_vltime)
+#define	s6_addr32			__u6_addr.__u6_addr32
+
+/* netinet6/in6_var.h */
+#define IN6_IFF_ANYCAST		0x01
+#define IN6_IFF_TENTATIVE	0x02
+#define IN6_IFF_DUPLICATED	0x04
+#define IN6_IFF_DETACHED	0x08
+#define IN6_IFF_DEPRECATED	0x10
+#define IN6_IFF_NODAD		0x20
+#define IN6_IFF_AUTOCONF	0x40
+#define IN6_IFF_TEMPORARY	0x80
+#define	IN6_IFF_PREFER_SOURCE	0x0100
+#define IN6_IFF_NOPFX		0x8000
+#define IN6_IFF_NOTREADY	(IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)
+#define	IN6_MASK_ADDR(a, m)     do { \
+	(a)->s6_addr32[0] &= (m)->s6_addr32[0]; \
+	(a)->s6_addr32[1] &= (m)->s6_addr32[1]; \
+	(a)->s6_addr32[2] &= (m)->s6_addr32[2]; \
+	(a)->s6_addr32[3] &= (m)->s6_addr32[3]; \
+} while (0)
+
+struct in6_addrlifetime {
+	time_t ia6t_expire;	/* valid lifetime expiration time */
+	time_t ia6t_preferred;	/* preferred lifetime expiration time */
+	u_int32_t ia6t_vltime;	/* valid lifetime */
+	u_int32_t ia6t_pltime;	/* prefix lifetime */
+};
+
+TAILQ_HEAD(in6_ifaddrhead, in6_ifaddr);
+struct in6_ifaddr {
+	struct ifaddr		ia_ifa;
+	TAILQ_ENTRY(in6_ifaddr)	ia_link;
+	struct sockaddr_in6	ia_addr;
+	struct in6_addrlifetime	ia6_lifetime;
+	int			ia6_flags;
+#define	ia_ifp			ia_ifa.ifa_ifp
+};
+
+#define IA6_IN6(ia)		(&((ia)->ia_addr.sin6_addr))
+#define IA6_SIN6(ia)		(&((ia)->ia_addr))
+#define	SIOCAADDRCTL_POLICY	0
+#define	SIOCDADDRCTL_POLICY	1
+#define IN6_ARE_SCOPE_CMP(a,b) ((a)-(b))
+#define IN6_ARE_SCOPE_EQUAL(a,b) ((a)==(b))
+
+struct in6_addrpolicy {
+	struct sockaddr_in6	addr;
+	struct sockaddr_in6	addrmask;
+	int			preced;
+	int			label;
+	uint64_t		use;
+};
+
+/* netinet6/ip6_var.h */
+#define	IP6STAT_INC(c)
+
+struct ucred {
+};
+
+#define	IPV6SASDEBUG(fmt, ...)	printf("%s: " fmt "\n", __func__, ##__VA_ARGS__)
+#define	KASSERT(exp, msg)
+#define	RO_RTFREE(ro)
+#define	RTFREE(rt)
+#define	INP_LOCK_ASSERT(pcb)
+#define	INP_WLOCK_ASSERT(pcb)
+#define	IF_ADDR_RLOCK(ifp)
+#define	IF_ADDR_RUNLOCK(ifp)
+#define	IN6_IFADDR_RLOCK()
+#define	IN6_IFADDR_RUNLOCK()
+#define	SYSCTL_DECL(n)
+#define	SYSCTL_NODE(n, i, m, f, h, d)	int sysctl_ ## m
+#define	SYSCTL_HANDLER_ARGS	struct sysctl_req *req
+#define	SYSCTL_OUT(r, p, l)	0
+struct sysctl_req {
+	void		*oldptr;
+	size_t		oldlen;
+	void		*newptr;
+	size_t		newlen;
+};
+
+#define	rw_assert(l,w)
+
+#define	mtx_init(m,n,t,o)
+#define	mtx_lock(m)
+#define	mtx_unlock(m)
+#define	mtx_assert(m, f)
+
+#define	sx_init(l, n)
+#define	sx_slock(l)
+#define	sx_sunlock(l)
+#define	sx_xlock(l)
+#define	sx_xunlock(l)
+
+#define	malloc(sz, t, f)	malloc((sz))
+#define	free(p, t)		free((p))
+
+struct ifnet *ifnet_byindex(uint32_t);
+int ifnet_getflags(const char *);
+void ifnet_getcarpstatus(const char *);
+void ifnet_getndinfo(const char *, uint32_t*, uint32_t*, uint32_t*, uint8_t*);
+int addr_getflags(const char *, struct sockaddr_in6 *);
+void addr_getlifetime(const char *, struct sockaddr_in6 *, struct in6_addrlifetime *);
+void v_getsysctl(void);
+int carp_master(uint8_t);
+
+void in6_rtalloc(struct route_in6 *, u_int);
+
+const char *ip6_sprintf(char *, const struct in6_addr *);
+struct in6_ifaddr *in6ifa_ifwithaddr(const struct in6_addr *, uint32_t);
+void ifa_free(void *);
+void ifa_ref(void *);
+
+int in6_addrscope(const struct in6_addr *);
+uint32_t in6_getscopezone(const struct ifnet *, int);
+int in6_matchlen(struct in6_addr *, struct in6_addr *);
+int in6_mask2len(struct in6_addr *, u_char *);
+int prison_check_ip6(struct ucred *, const struct sockaddr_in6 *);
+int prison_local_ip6(struct ucred *, const struct sockaddr_in6 *, int);
+int prison_saddrsel_ip6(struct ucred *, const struct sockaddr_in6 *);
+struct ifnet *in6_getlinkifnet(uint32_t);
+int in_pcb_lport(struct inpcb *, struct in_addr *, u_short *, struct ucred *, int);
+int in_pcbinshash(struct inpcb *);
+int ifa_preferred(struct ifaddr *, struct ifaddr *);
+
+void addrsel_policy_init(void);
+void addrsel_policy_populate(int (struct in6_addrpolicy *), int);
+int in6_src_ioctl(u_long, caddr_t);
+int in6_selectsrc(struct sockaddr_in6 *, struct ip6_pktopts *,
+    struct inpcb *, struct route_in6 *, struct ucred *,
+    struct ifnet **, struct in6_addr *);
+extern int V_ip6_use_deprecated;
+extern int V_ip6_prefer_tempaddr;
+extern int V_ip6_defhlim;
+extern const struct sockaddr_in6 sa6_any;
+extern struct in6_ifaddrhead V_in6_ifaddrhead;
+extern int has_carp;


More information about the svn-src-user mailing list