svn commit: r186121 - head/sys/net

Kip Macy kmacy at FreeBSD.org
Mon Dec 15 06:53:09 UTC 2008


Author: kmacy
Date: Mon Dec 15 06:53:09 2008
New Revision: 186121
URL: http://svn.freebsd.org/changeset/base/186121

Log:
  Add arpv2 management code

Added:
  head/sys/net/if_llatbl.c   (contents, props changed)
  head/sys/net/if_llatbl.h   (contents, props changed)

Added: head/sys/net/if_llatbl.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/net/if_llatbl.c	Mon Dec 15 06:53:09 2008	(r186121)
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
+ * Copyright (c) 2004-2008 Qing Li. All rights reserved.
+ * Copyright (c) 2008 Kip Macy. 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 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 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 "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/syslog.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/vimage.h>
+
+#include <vm/uma.h>
+
+#include <netinet/in.h>
+#include <net/if_llatbl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <netinet/if_ether.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
+
+static	SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables);
+
+extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *,
+	u_char *);
+
+/*
+ * Dump arp state for a specific address family.
+ */
+int
+lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
+{
+	struct lltable *llt;
+	int error = 0;
+
+	IFNET_RLOCK();
+	SLIST_FOREACH(llt, &lltables, llt_link) {
+		if (llt->llt_af == af) {
+			error = llt->llt_dump(llt, wr);
+			if (error != 0)
+				goto done;
+		}
+	}
+done:
+	IFNET_RUNLOCK();
+	return (error);
+}
+
+/*
+ * Deletes an address from the address table.
+ * This function is called by the timer functions
+ * such as arptimer() and nd6_llinfo_timer(), and
+ * the caller does the locking.
+ */
+void
+llentry_free(struct llentry *lle)
+{
+	
+	LLE_WLOCK_ASSERT(lle);
+	LIST_REMOVE(lle, lle_next);
+
+	if (lle->la_hold != NULL)
+		m_freem(lle->la_hold);
+
+	LLE_FREE_LOCKED(lle);
+}
+
+/*
+ * Free all entries from given table and free itself.
+ * Since lltables collects from all of the intefaces,
+ * the caller of this function must acquire IFNET_WLOCK().
+ */
+void
+lltable_free(struct lltable *llt)
+{
+	struct llentry *lle, *next;
+	int i;
+
+	KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
+
+	IFNET_WLOCK();
+	SLIST_REMOVE(&lltables, llt, lltable, llt_link);
+	IFNET_WUNLOCK();
+
+	for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
+		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
+
+			callout_drain(&lle->la_timer);
+			LLE_WLOCK(lle);
+			llentry_free(lle);
+		}
+	}
+
+	free(llt, M_LLTABLE);
+}
+
+void
+lltable_drain(int af)
+{
+	struct lltable	*llt;
+	struct llentry	*lle;
+	register int i;
+
+	IFNET_RLOCK();
+	SLIST_FOREACH(llt, &lltables, llt_link) {
+		if (llt->llt_af != af)
+			continue;
+
+		for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
+			LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
+				if (lle->la_hold) {
+					m_freem(lle->la_hold);
+					lle->la_hold = NULL;
+				}
+			}
+		}
+	}
+	IFNET_RUNLOCK();
+}
+
+/*
+ * Create a new lltable.
+ */
+struct lltable *
+lltable_init(struct ifnet *ifp, int af)
+{
+	struct lltable *llt;
+	register int i;
+
+	llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK);
+	if (llt == NULL)
+		return (NULL);
+
+	llt->llt_af = af;
+	llt->llt_ifp = ifp;
+	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++)
+		LIST_INIT(&llt->lle_head[i]);
+
+	IFNET_WLOCK();
+	SLIST_INSERT_HEAD(&lltables, llt, llt_link);
+	IFNET_WUNLOCK();
+
+	return (llt);
+}
+
+/*
+ * Called in route_output when adding/deleting a route to an interface.
+ */
+int
+lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
+{
+	struct sockaddr_dl *dl =
+	    (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY];
+	struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
+	struct ifnet *ifp;
+	struct lltable *llt;
+	struct llentry *lle;
+	u_int laflags = 0, flags = 0;
+	int error = 0;
+
+	if (dl == NULL || dl->sdl_family != AF_LINK) {
+		log(LOG_INFO, "%s: invalid dl\n", __func__);
+		return EINVAL;
+	}
+	ifp = ifnet_byindex(dl->sdl_index);
+	if (ifp == NULL) {
+		log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n",
+		    __func__, dl->sdl_index);
+		return EINVAL;
+	}
+
+	switch (rtm->rtm_type) {
+	case RTM_ADD:
+		if (rtm->rtm_flags & RTF_ANNOUNCE) {
+			flags |= LLE_PUB;
+#ifdef INET
+			if (dst->sa_family == AF_INET && 
+			    ((struct sockaddr_inarp *)dst)->sin_other != 0) {
+				struct rtentry *rt = rtalloc1(dst, 0, 0);
+				if (rt == NULL || !(rt->rt_flags & RTF_HOST)) {
+					log(LOG_INFO, "%s: RTM_ADD publish "
+					    "(proxy only) is invalid\n",
+					    __func__);
+					RTFREE(rt);
+					return EINVAL;
+				}
+				RTFREE(rt);
+
+				flags |= LLE_PROXY;
+			}
+#endif
+		}
+		flags |= LLE_CREATE;
+		break;
+
+	case RTM_DELETE:
+		flags |= LLE_DELETE;
+		break;
+
+	case RTM_CHANGE:
+		break;
+
+	default:
+		return EINVAL; /* XXX not implemented yet */
+	}
+
+	/* XXX linked list may be too expensive */
+	IFNET_RLOCK();
+	SLIST_FOREACH(llt, &lltables, llt_link) {
+		if (llt->llt_af == dst->sa_family &&
+		    llt->llt_ifp == ifp)
+			break;
+	}
+	IFNET_RUNLOCK();
+	KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n"));
+
+	if (flags && LLE_CREATE)
+		flags |= LLE_EXCLUSIVE;
+	
+	IF_AFDATA_LOCK(ifp);
+	lle = lla_lookup(llt, flags, dst);
+	IF_AFDATA_UNLOCK(ifp);
+	if (LLE_IS_VALID(lle)) {
+		if (flags & LLE_CREATE) {
+			/*
+			 * If we delay the delete, then a subsequent
+			 * "arp add" should look up this entry, reset the
+			 * LLE_DELETED flag, and reset the expiration timer
+			 */
+			bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen);
+			lle->la_flags |= LLE_VALID;
+			lle->la_flags &= ~LLE_DELETED;
+#ifdef INET6
+			/*
+			 * ND6
+			 */
+			if (dst->sa_family == AF_INET6)
+				lle->ln_state = ND6_LLINFO_REACHABLE;
+#endif
+			/*
+			 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST)
+			 */
+
+			if (rtm->rtm_rmx.rmx_expire == 0) {
+				lle->la_flags |= LLE_STATIC;
+				lle->la_expire = 0;
+			} else
+				lle->la_expire = rtm->rtm_rmx.rmx_expire;
+			laflags = lle->la_flags;
+			LLE_WUNLOCK(lle);
+#ifdef INET
+			/*  gratuious ARP */
+			if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) {
+				arprequest(ifp, 
+				    &((struct sockaddr_in *)dst)->sin_addr,
+				    &((struct sockaddr_in *)dst)->sin_addr,
+				    ((laflags & LLE_PROXY) ?
+					(u_char *)IF_LLADDR(ifp) :
+					(u_char *)LLADDR(dl)));
+			}
+#endif
+		} else {
+			if (flags & LLE_EXCLUSIVE)
+				LLE_WUNLOCK(lle);
+			else
+				LLE_RUNLOCK(lle);
+		}
+	} else if ((lle == NULL) && (flags & LLE_DELETE))
+		error = EINVAL;
+
+
+	return (error);
+}

Added: head/sys/net/if_llatbl.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/net/if_llatbl.h	Mon Dec 15 06:53:09 2008	(r186121)
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
+ * Copyright (c) 2004-2008 Qing Li. All rights reserved.
+ * Copyright (c) 2008 Kip Macy. 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 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 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$");
+
+#ifndef	_NET_IF_LLATBL_H_
+#define	_NET_IF_LLATBL_H_
+
+#include <sys/_rwlock.h>
+#include <netinet/in.h>
+
+struct ifnet;
+struct sysctl_req;
+struct rt_msghdr;
+struct rt_addrinfo;
+
+struct llentry;
+LIST_HEAD(llentries, llentry);
+
+/*
+ * Code referencing llentry must at least hold
+ * a shared lock
+ */
+struct llentry {
+	LIST_ENTRY(llentry)	 lle_next;
+	struct rwlock		 lle_lock;
+	struct lltable		 *lle_tbl;
+	struct llentries	 *lle_head;
+	struct mbuf		 *la_hold;
+	time_t			 la_expire;
+	uint16_t		 la_flags;    
+	uint16_t		 la_asked;
+	uint16_t		 la_preempt;
+	uint16_t		 ln_byhint;
+	int16_t			 ln_state;	/* IPv6 has ND6_LLINFO_NOSTATE == -2 */
+	uint16_t		 ln_router; 
+	time_t			 ln_ntick;
+	int			 lle_refcnt;
+				 
+	union {
+		uint64_t	mac_aligned;
+		uint16_t	mac16[3];
+	} ll_addr;
+
+	/* XXX af-private? */
+	union {
+		struct callout	ln_timer_ch;
+		struct callout  la_timer;
+	} lle_timer;
+	/* NB: struct sockaddr must immediately follow */
+};
+
+#define	LLE_WLOCK(lle)		rw_wlock(&(lle)->lle_lock)
+#define	LLE_RLOCK(lle)		rw_rlock(&(lle)->lle_lock)
+#define	LLE_WUNLOCK(lle)	rw_wunlock(&(lle)->lle_lock)
+#define	LLE_RUNLOCK(lle)	rw_runlock(&(lle)->lle_lock)
+#define	LLE_DOWNGRADE(lle)	rw_downgrade(&(lle)->lle_lock)
+#define	LLE_TRY_UPGRADE(lle)	rw_try_upgrade(&(lle)->lle_lock)
+#define	LLE_LOCK_INIT(lle)	rw_init_flags(&(lle)->lle_lock, "lle", RW_DUPOK)
+#define	LLE_WLOCK_ASSERT(lle)	rw_assert(&(lle)->lle_lock, RA_WLOCKED)
+
+#define LLE_IS_VALID(lle)	(((lle) != NULL) && ((lle) != (void *)-1))
+
+#define	LLE_ADDREF(lle) do {					\
+	LLE_WLOCK_ASSERT(lle);					\
+	KASSERT((lle)->lle_refcnt >= 0,				\
+		("negative refcnt %d", (lle)->lle_refcnt));	\
+	(lle)->lle_refcnt++;					\
+} while (0)
+
+#define	LLE_REMREF(lle)	do {					\
+	LLE_WLOCK_ASSERT(lle);					\
+	KASSERT((lle)->lle_refcnt > 1,				\
+		("bogus refcnt %d", (lle)->lle_refcnt));	\
+	(lle)->lle_refcnt--;					\
+} while (0)
+
+#define	LLE_FREE_LOCKED(lle) do {				\
+	if ((lle)->lle_refcnt <= 1)				\
+		(lle)->lle_tbl->llt_free((lle)->lle_tbl, (lle));\
+	else {							\
+		(lle)->lle_refcnt--;				\
+		LLE_WUNLOCK(lle);				\
+	}							\
+	/* guard against invalid refs */			\
+	lle = 0;						\
+} while (0)
+
+#define	LLE_FREE(lle) do {					\
+	LLE_WLOCK(lle);						\
+	if ((lle)->lle_refcnt <= 1)				\
+		(lle)->lle_tbl->llt_free((lle)->lle_tbl, (lle));\
+	else {							\
+		(lle)->lle_refcnt--;				\
+		LLE_WUNLOCK(lle);				\
+	}							\
+	/* guard against invalid refs */			\
+	lle = 0;						\
+} while (0)
+
+
+#define	ln_timer_ch	lle_timer.ln_timer_ch
+#define	la_timer	lle_timer.la_timer
+
+/* XXX bad name */
+#define	L3_ADDR(lle)	((struct sockaddr *)(&lle[1]))
+#define	L3_ADDR_LEN(lle)	(((struct sockaddr *)(&lle[1]))->sa_len)
+
+#ifndef LLTBL_HASHTBL_SIZE
+#define	LLTBL_HASHTBL_SIZE	32	/* default 32 ? */
+#endif
+
+#ifndef LLTBL_HASHMASK
+#define	LLTBL_HASHMASK	(LLTBL_HASHTBL_SIZE - 1)
+#endif
+
+struct lltable {
+	SLIST_ENTRY(lltable)	llt_link;
+	struct llentries	lle_head[LLTBL_HASHTBL_SIZE];
+	int			llt_af;
+	struct ifnet		*llt_ifp;
+
+	struct llentry *	(*llt_new)(const struct sockaddr *, u_int);
+	void			(*llt_free)(struct lltable *, struct llentry *);
+	struct llentry *	(*llt_lookup)(struct lltable *, u_int flags,
+				    const struct sockaddr *l3addr);
+	int			(*llt_rtcheck)(struct ifnet *,
+				    const struct sockaddr *);
+	int			(*llt_dump)(struct lltable *,
+				     struct sysctl_req *);
+};
+MALLOC_DECLARE(M_LLTABLE);
+
+/*
+ * flags to be passed to arplookup.
+ */
+#define	LLE_DELETED	0x0001	/* entry must be deleted */
+#define	LLE_STATIC	0x0002	/* entry is static */
+#define	LLE_IFADDR	0x0004	/* entry is interface addr */
+#define	LLE_VALID	0x0008	/* ll_addr is valid */
+#define	LLE_PROXY	0x0010	/* proxy entry ??? */
+#define	LLE_PUB		0x0020	/* publish entry ??? */
+#define	LLE_DELETE	0x4000	/* delete on a lookup - match LLE_IFADDR */
+#define	LLE_CREATE	0x8000	/* create on a lookup miss */
+#define	LLE_EXCLUSIVE	0x2000	/* return lle xlocked  */
+
+#define LLATBL_HASH(key, mask) \
+	(((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask)
+
+struct lltable *lltable_init(struct ifnet *, int);
+void		lltable_free(struct lltable *);
+void		lltable_drain(int);
+int		lltable_sysctl_dumparp(int, struct sysctl_req *);
+
+void		llentry_free(struct llentry *);
+
+/*
+ * Generic link layer address lookup function.
+ */
+static __inline struct llentry *
+lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
+{
+	return llt->llt_lookup(llt, flags, l3addr);
+}
+
+int		lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *);
+#endif  /* _NET_IF_LLATBL_H_ */


More information about the svn-src-all mailing list