Date: Tue, 25 Nov 2008 17:17:59 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 153536 for review Message-ID: <200811251717.mAPHHxeX088794@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=153536 Change 153536 by sam@sam_ebb on 2008/11/25 17:17:41 Refactor code along adress family-boundaries: o move af-specific code into the protocol area and add methods to the llatbl o rewrite the public api's to use per-af methods instead of handling in common code w/ switch statements, etc. o restructure llatbl entries so af-specific state is managed in private code; this allows us, for example, to not take a hit for ipv6 addresses in the ipv4 data structures o expose the l3 address in table entries with macros for those cases where public access is required (should still be limited to within af code) o rename sysctl_dumparp to lltable_sysctl_dumparp o remove private zone for lltable entries; just use malloc for now Tested with ipv4. Compiles+boots w/ ipv6 but haven't tested operation. Needs more work: e.g. the lookup method added last and may make the rtcheck and new methods unneeded. Per-af code should probably move to new files in netinet and netinet6; it's in in.c and in6.c for the moment. L3_ADDR* macros probably need to be renamed to something less common. Reviewed by: qingli Affected files ... .. //depot/projects/arp-v2/src/sys/net/if_llatbl.c#9 edit .. //depot/projects/arp-v2/src/sys/net/if_llatbl.h#6 edit .. //depot/projects/arp-v2/src/sys/net/rtsock.c#8 edit .. //depot/projects/arp-v2/src/sys/netinet/if_ether.c#19 edit .. //depot/projects/arp-v2/src/sys/netinet/in.c#7 edit .. //depot/projects/arp-v2/src/sys/netinet6/in6.c#9 edit .. //depot/projects/arp-v2/src/sys/netinet6/nd6.c#9 edit .. //depot/projects/arp-v2/src/sys/netinet6/nd6_nbr.c#8 edit Differences ... ==== //depot/projects/arp-v2/src/sys/net/if_llatbl.c#9 (text+ko) ==== @@ -53,145 +53,16 @@ MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); -static uma_zone_t llezone; static SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables); -int sysctl_dumparp(int af, struct sysctl_req *wr); extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *, u_char *); -/* ARGSUSED*/ -static void -lla_init(void *dummy __unused) -{ - /* - * create uma zone for L2/L3 cache - */ - llezone = uma_zcreate("llentry", sizeof(struct llentry), NULL, NULL, - NULL, NULL, UMA_ALIGN_PTR, 0); -} -SYSINIT(lla, SI_SUB_INIT_IF, SI_ORDER_FIRST, lla_init, NULL); - -static int -dump_llcache(struct lltable *llt, int af, struct sysctl_req *wr) -{ - struct ifnet *ifp = llt->llt_ifp; - struct llentry *lle; - struct rt_msghdr *rtm = NULL; - struct sockaddr_dl *sdl = NULL; - uint8_t *msg = NULL; - int msgsize = 0; - int error = 0; - int i; -#ifdef INET - struct { - struct rt_msghdr rtm; - struct sockaddr_inarp sin; - struct sockaddr_dl sdl; - } arpc; -#endif -#ifdef INET6 - struct { - struct rt_msghdr rtm; - struct sockaddr_in6 sin6; - struct sockaddr_dl sdl; - } ndpc; -#endif - - switch (af) { -#ifdef INET - case AF_INET: - rtm = &arpc.rtm; - sdl = &arpc.sdl; - msgsize = sizeof(arpc); - msg = (uint8_t *)&arpc; - break; -#endif -#ifdef INET6 - case AF_INET6: - rtm = &ndpc.rtm; - sdl = &ndpc.sdl; - msgsize = sizeof(ndpc); - msg = (uint8_t *)&ndpc; - break; -#endif - default: - printf("%s: unknown address family", __func__); - return EINVAL; - } - - /* XXXXX - * current IFNET_RLOCK() is mapped to IFNET_WLOCK() - * so it is okay to use this ASSERT, change it when - * IFNET lock is finalized - */ - IFNET_WLOCK_ASSERT(); - - for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { - LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { - if (lle->la_flags & LLE_DELETED) /* skip deleted entries */ - continue; - /* - * produce a msg made of: - * struct rt_msghdr; - * struct sockaddr_inarp; (IPv4) struct sockaddr_in6 (IPv6) - * struct sockaddr_dl; - */ - bzero(msg, msgsize); - rtm->rtm_msglen = msgsize; - - switch (af) { -#ifdef INET - case AF_INET: - arpc.sin.sin_family = AF_INET; - arpc.sin.sin_len = sizeof(arpc.sin); - arpc.sin.sin_addr.s_addr = lle->l3_addr4.sin_addr.s_addr; - break; -#endif -#ifdef INET6 - case AF_INET6: - ndpc.sin6.sin6_family = AF_INET6; - ndpc.sin6.sin6_len = sizeof(ndpc.sin6); - bcopy(&lle->l3_addr6, &ndpc.sin6, lle->l3_addr6.sin6_len); - break; -#endif - } - /* publish */ - if (lle->la_flags & LLE_PUB) { - rtm->rtm_flags |= RTF_ANNOUNCE; - /* proxy only */ - if ((af == AF_INET) && (lle->la_flags & LLE_PROXY)) - arpc.sin.sin_other = SIN_PROXY; - } - - if (lle->la_flags & LLE_VALID) { /* valid MAC */ - sdl->sdl_family = AF_LINK; - sdl->sdl_len = sizeof(*sdl); - sdl->sdl_alen = ifp->if_addrlen; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = ifp->if_type; - bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); - } - rtm->rtm_rmx.rmx_expire = - lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; - rtm->rtm_flags |= (RTF_LLINFO | RTF_HOST); - if (lle->la_flags & LLE_STATIC) - rtm->rtm_flags |= RTF_STATIC; - rtm->rtm_index = ifp->if_index; - error = SYSCTL_OUT(wr, msg, msgsize); - if (error) - break; - } - } - - return (error); -} - /* - * glue to dump arp tables + * Dump arp state for a specific address family. */ int -sysctl_dumparp(int af, struct sysctl_req *wr) +lltable_sysctl_dumparp(int af, struct sysctl_req *wr) { struct lltable *llt; int error = 0; @@ -199,7 +70,7 @@ IFNET_RLOCK(); SLIST_FOREACH(llt, &lltables, llt_link) { if (llt->llt_af == af) { - error = dump_llcache(llt, af, wr); + error = llt->llt_dump(llt, wr); if (error != 0) goto done; } @@ -215,17 +86,16 @@ * such as arptimer() and nd6_llinfo_timer(), and * the caller does the locking. */ -int +void llentry_free(struct llentry *lle) { - KASSERT(lle != NULL, ("%s: lle is NULL", __func__)); + struct lltable *llt = lle->lle_tbl; LIST_REMOVE(lle, lle_next); if (lle->la_hold != NULL) m_freem(lle->la_hold); - uma_zfree(llezone, lle); - return 0; + llt->llt_free(llt, lle); } /* @@ -233,9 +103,10 @@ * Since lltables collects from all of the intefaces, * the caller of this function must acquire IFNET_WLOCK(). */ -void lltable_free(struct lltable *llt) +void +lltable_free(struct lltable *llt) { - struct llentry *lle; + struct llentry *lle, *next; int i; KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); @@ -245,7 +116,7 @@ IFNET_WUNLOCK(); for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { - LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { + LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { callout_drain(&lle->la_timer); llentry_free(lle); } @@ -278,7 +149,6 @@ IFNET_RUNLOCK(); } - /* * Create a new lltable. */ @@ -304,141 +174,14 @@ return (llt); } - -/* - * Generic link layer address lookup function, replacement - * of the old "arplookup" - */ -struct llentry * -lla_lookup(struct lltable *llt, u_int flags, struct sockaddr *l3addr) -{ - struct ifnet *ifp; - struct llentry *lle; - struct llentries *lleh; - struct rtentry *rt; - u_int hashkey; -#ifdef INET6 - char ip6buf[INET6_ADDRSTRLEN]; -#endif - - KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); - KASSERT(l3addr != NULL, ("%s: L3 address is NULL", __func__)); - - ifp = llt->llt_ifp; - switch (l3addr->sa_family) { -#ifdef INET - case AF_INET: - hashkey = ((struct sockaddr_in *)l3addr)->sin_addr.s_addr; - break; -#endif -#ifdef INET6 - case AF_INET6: - hashkey = ((struct sockaddr_in6 *)l3addr)->sin6_addr.s6_addr32[3]; - break; -#endif - default: - return NULL; - } - - lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; - LIST_FOREACH(lle, lleh, lle_next) { - if (lle->la_flags & LLE_DELETED) - continue; - if (bcmp((void *)&lle->l3_addr, l3addr, l3addr->sa_len) == 0) - break; - } - - if (lle == NULL) { - if (!(flags & LLE_CREATE)) - return (NULL); - - /* - * a route that covers the given address must have been - * installed 1st because we are doing a resolution - */ - if (!(flags & LLE_IFADDR)) { - rt = rtalloc1(l3addr, 0, 0); - if ((rt == NULL) || (rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) { -#ifdef INET6 - if (l3addr->sa_family == AF_INET6) { - /* - * Creating a ND6 cache for an IPv6 neighbor - * that is not covered by our own prefix. - */ - struct ifaddr *ifa = - ifaof_ifpforaddr((struct sockaddr *)l3addr, ifp); - if (ifa != NULL) { - if (rt) - rtfree(rt); - goto lla_lookup_1; - } - } -#endif - switch (l3addr->sa_family) { -#ifdef INET - case AF_INET: - log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n", \ - inet_ntoa(((struct sockaddr_in *)l3addr)->sin_addr)); - break; -#endif -#ifdef INET6 - case AF_INET6: - log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", \ - ip6_sprintf(ip6buf, &((struct sockaddr_in6 *)l3addr)->sin6_addr)); - break; -#endif - - } - if (rt) - rtfree(rt); - return (NULL); - } - rtfree(rt); - } -#ifdef INET6 -lla_lookup_1: -#endif - lle = uma_zalloc(llezone, M_DONTWAIT | M_ZERO); - if (lle == NULL) { - log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); - return (NULL); - } - - callout_init(&lle->la_timer, CALLOUT_MPSAFE); - - /* qing - * For IPv4 this will trigger "arpresolve" to generate - * an ARP request - */ - lle->la_expire = time_second; /* mark expired */ - lle->la_flags = flags & ~LLE_CREATE; - - bcopy(l3addr, &lle->l3_addr, l3addr->sa_len); - - if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { - bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); - lle->la_flags |= (LLE_VALID | LLE_STATIC); - } - - lle->lle_tbl = llt; - lle->lle_head = lleh; - LIST_INSERT_HEAD(lleh, lle, lle_next); - } else { - if (flags & LLE_DELETE) - lle->la_flags = LLE_DELETED; - } - - return (lle); -} - - /* * 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_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; ==== //depot/projects/arp-v2/src/sys/net/if_llatbl.h#6 (text+ko) ==== @@ -31,6 +31,7 @@ #include <netinet/in.h> struct ifnet; +struct sysctl_req; struct rt_msghdr; struct rt_addrinfo; @@ -51,24 +52,24 @@ uint16_t ln_router; time_t ln_ntick; union { - struct sockaddr_in addr4; - struct sockaddr_in6 addr6; - } l3_addr; - 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 ln_timer_ch lle_timer.ln_timer_ch #define la_timer lle_timer.la_timer -#define l3_addr4 l3_addr.addr4 -#define l3_addr6 l3_addr.addr6 +/* 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 ? */ @@ -79,11 +80,21 @@ #endif struct lltable { - SLIST_ENTRY(lltable) llt_link; - struct llentries lle_head[LLTBL_HASHTBL_SIZE]; - int llt_af; - struct ifnet *llt_ifp; + 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. @@ -100,11 +111,21 @@ #define LLATBL_HASH(key, mask) \ (((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask) -struct llentry *lla_lookup(struct lltable *, u_int, struct sockaddr *); -int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *); -int llentry_free(struct llentry *); - 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_ */ ==== //depot/projects/arp-v2/src/sys/net/rtsock.c#8 (text+ko) ==== @@ -109,8 +109,6 @@ struct rt_metrics *out); static void rt_dispatch(struct mbuf *, const struct sockaddr *); -extern int sysctl_dumparp(int af, struct sysctl_req *wr); - static void rts_init(void) { @@ -1311,7 +1309,7 @@ * take care of llinfo entries */ if (w.w_op == NET_RT_FLAGS && (RTF_LLINFO & w.w_arg)) - error = sysctl_dumparp(af, w.w_req); + error = lltable_sysctl_dumparp(af, w.w_req); break; case NET_RT_IFLIST: ==== //depot/projects/arp-v2/src/sys/netinet/if_ether.c#19 (text+ko) ==== @@ -614,8 +614,7 @@ la->la_asked = 0; la->la_preempt = V_arp_maxtries; if (la->la_hold) { - (*ifp->if_output)(ifp, la->la_hold, - (struct sockaddr *)&la->l3_addr4, NULL); + (*ifp->if_output)(ifp, la->la_hold, L3_ADDR(la), NULL); la->la_hold = 0; } } ==== //depot/projects/arp-v2/src/sys/netinet/in.c#7 (text+ko) ==== @@ -1019,11 +1019,207 @@ in_purgemaddrs(ifp); } +#include <sys/syslog.h> +#include <net/if_dl.h> +#include <netinet/if_ether.h> + +struct in_llentry { + struct llentry base; + struct sockaddr_in l3_addr4; +}; + +static struct llentry * +in_lltable_new(const struct sockaddr *l3addr, u_int flags) +{ + struct in_llentry *lle; + + lle = malloc(sizeof(struct in_llentry), M_LLTABLE, M_DONTWAIT | M_ZERO); + if (lle == NULL) /* NB: caller generates msg */ + return NULL; + + callout_init(&lle->base.la_timer, CALLOUT_MPSAFE); + /* qing + * For IPv4 this will trigger "arpresolve" to generate + * an ARP request + */ + lle->base.la_expire = time_second; /* mark expired */ + lle->l3_addr4 = *(const struct sockaddr_in *)l3addr; + + return &lle->base; +} + +/* + * 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. + */ +static void +in_lltable_free(struct lltable *llt, struct llentry *lle) +{ + free(lle, M_LLTABLE); +} + +static int +in_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr) +{ + struct rtentry *rt; + + KASSERT(l3addr->sa_family == AF_INET, + ("sin_family %d", l3addr->sa_family)); + + /* XXX rtalloc1 should take a const param */ + rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0); + if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) { + log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n", + inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr)); + if (rt != NULL) + rtfree(rt); + return EINVAL; + } + rtfree(rt); + return 0; +} + +static struct llentry * +in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + struct llentries *lleh; + u_int hashkey; + + KASSERT(l3addr->sa_family == AF_INET, + ("sin_family %d", l3addr->sa_family)); + + hashkey = sin->sin_addr.s_addr; + lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; + LIST_FOREACH(lle, lleh, lle_next) { + if (lle->la_flags & LLE_DELETED) + continue; + if (bcmp(L3_ADDR(lle), l3addr, sizeof(struct sockaddr_in)) == 0) + break; + } + + if (lle == NULL) { + if (!(flags & LLE_CREATE)) + return (NULL); + /* + * A route that covers the given address must have + * been installed 1st because we are doing a resolution, + * verify this. + */ + if (!(flags & LLE_IFADDR) && + in_lltable_rtcheck(ifp, l3addr) != 0) + return NULL; + + lle = in_lltable_new(l3addr, flags); + if (lle == NULL) { + log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); + return NULL; + } + lle->la_flags = flags & ~LLE_CREATE; + if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { + bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); + lle->la_flags |= (LLE_VALID | LLE_STATIC); + } + + lle->lle_tbl = llt; + lle->lle_head = lleh; + LIST_INSERT_HEAD(lleh, lle, lle_next); + } else { + if (flags & LLE_DELETE) + lle->la_flags = LLE_DELETED; + } + return lle; +} + +static int +in_lltable_dump(struct lltable *llt, struct sysctl_req *wr) +{ +#define SIN(lle) ((struct sockaddr_in *) L3_ADDR(lle)) + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + /* XXX stack use */ + struct { + struct rt_msghdr rtm; + struct sockaddr_inarp sin; + struct sockaddr_dl sdl; + } arpc; + int error, i; + + /* XXXXX + * current IFNET_RLOCK() is mapped to IFNET_WLOCK() + * so it is okay to use this ASSERT, change it when + * IFNET lock is finalized + */ + IFNET_WLOCK_ASSERT(); + + error = 0; + for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { + LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { + /* skip deleted entries */ + if (lle->la_flags & LLE_DELETED) + continue; + /* + * produce a msg made of: + * struct rt_msghdr; + * struct sockaddr_inarp; (IPv4) + * struct sockaddr_dl; + */ + bzero(&arpc, sizeof(arpc)); + arpc.rtm.rtm_msglen = sizeof(arpc); + + arpc.sin.sin_family = AF_INET; + arpc.sin.sin_len = sizeof(arpc.sin); + arpc.sin.sin_addr.s_addr = SIN(lle)->sin_addr.s_addr; + + /* publish */ + if (lle->la_flags & LLE_PUB) { + arpc.rtm.rtm_flags |= RTF_ANNOUNCE; + /* proxy only */ + if (lle->la_flags & LLE_PROXY) + arpc.sin.sin_other = SIN_PROXY; + } + + if (lle->la_flags & LLE_VALID) { /* valid MAC */ + struct sockaddr_dl *sdl = &arpc.sdl; + + sdl->sdl_family = AF_LINK; + sdl->sdl_len = sizeof(*sdl); + sdl->sdl_alen = ifp->if_addrlen; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); + } + arpc.rtm.rtm_rmx.rmx_expire = + lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; + arpc.rtm.rtm_flags |= RTF_LLINFO | RTF_HOST; + if (lle->la_flags & LLE_STATIC) + arpc.rtm.rtm_flags |= RTF_STATIC; + arpc.rtm.rtm_index = ifp->if_index; + error = SYSCTL_OUT(wr, &arpc, sizeof(arpc)); + if (error) + break; + } + } + return error; +#undef SIN +} + void * in_domifattach(struct ifnet *ifp) { struct lltable *llt = lltable_init(ifp, AF_INET); + if (llt != NULL) { + llt->llt_new = in_lltable_new; + llt->llt_free = in_lltable_free; + llt->llt_rtcheck = in_lltable_rtcheck; + llt->llt_lookup = in_lltable_lookup; + llt->llt_dump = in_lltable_dump; + } return (llt); } ==== //depot/projects/arp-v2/src/sys/netinet6/in6.c#9 (text+ko) ==== @@ -2098,6 +2098,197 @@ } } +#include <sys/sysctl.h> + +struct in6_llentry { + struct llentry base; + struct sockaddr_in6 l3_addr6; +}; + +static struct llentry * +in6_lltable_new(const struct sockaddr *l3addr, u_int flags) +{ + struct in6_llentry *lle; + + lle = malloc(sizeof(struct in6_llentry), M_LLTABLE, + M_DONTWAIT | M_ZERO); + if (lle == NULL) /* NB: caller generates msg */ + return NULL; + + callout_init(&lle->base.ln_timer_ch, CALLOUT_MPSAFE); + lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr; + + return &lle->base; +} + +/* + * 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. + */ +static void +in6_lltable_free(struct lltable *llt, struct llentry *lle) +{ + free(lle, M_LLTABLE); +} + +static int +in6_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr) +{ + struct rtentry *rt; + char ip6buf[INET6_ADDRSTRLEN]; + + KASSERT(l3addr->sa_family == AF_INET6, + ("sin_family %d", l3addr->sa_family)); + + /* XXX rtalloc1 should take a const param */ + rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0); + if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) { + struct ifaddr *ifa; + /* + * Create an ND6 cache for an IPv6 neighbor + * that is not covered by our own prefix. + */ + /* XXX ifaof_ifpforaddr should take a const param */ + ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp); + if (ifa != NULL) { + if (rt != NULL) + rtfree(rt); + return 0; + } + log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", + ip6_sprintf(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr)); + if (rt != NULL) + rtfree(rt); + return EINVAL; + } + rtfree(rt); + return 0; +} + +static struct llentry * +in6_lltable_lookup(struct lltable *llt, u_int flags, + const struct sockaddr *l3addr) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + struct llentries *lleh; + u_int hashkey; + + KASSERT(l3addr->sa_family == AF_INET6, + ("sin_family %d", l3addr->sa_family)); + + hashkey = sin6->sin6_addr.s6_addr32[3]; + lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; + LIST_FOREACH(lle, lleh, lle_next) { + if (lle->la_flags & LLE_DELETED) + continue; + if (bcmp(L3_ADDR(lle), l3addr, l3addr->sa_len) == 0) + break; + } + + if (lle == NULL) { + if (!(flags & LLE_CREATE)) + return (NULL); + /* + * A route that covers the given address must have + * been installed 1st because we are doing a resolution, + * verify this. + */ + if (!(flags & LLE_IFADDR) && + in6_lltable_rtcheck(ifp, l3addr) != 0) + return NULL; + + lle = in6_lltable_new(l3addr, flags); + if (lle == NULL) { + log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); + return NULL; + } + lle->la_flags = flags & ~LLE_CREATE; + if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { + bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); + lle->la_flags |= (LLE_VALID | LLE_STATIC); + } + + lle->lle_tbl = llt; + lle->lle_head = lleh; + LIST_INSERT_HEAD(lleh, lle, lle_next); + } else { + if (flags & LLE_DELETE) + lle->la_flags = LLE_DELETED; + } + return lle; +} + +static int +in6_lltable_dump(struct lltable *llt, struct sysctl_req *wr) +{ + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + /* XXX stack use */ + struct { + struct rt_msghdr rtm; + struct sockaddr_in6 sin6; + struct sockaddr_dl sdl; + } ndpc; + int i, error; + + /* XXXXX + * current IFNET_RLOCK() is mapped to IFNET_WLOCK() + * so it is okay to use this ASSERT, change it when + * IFNET lock is finalized + */ + IFNET_WLOCK_ASSERT(); + + error = 0; + for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { + LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { + /* skip deleted entries */ + if (lle->la_flags & LLE_DELETED) + continue; + /* + * produce a msg made of: + * struct rt_msghdr; + * struct sockaddr_in6 (IPv6) + * struct sockaddr_dl; + */ + bzero(&ndpc, sizeof(ndpc)); + ndpc.rtm.rtm_msglen = sizeof(ndpc); + + ndpc.sin6.sin6_family = AF_INET6; + ndpc.sin6.sin6_len = sizeof(ndpc.sin6); + bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle)); + + /* publish */ + if (lle->la_flags & LLE_PUB) + ndpc.rtm.rtm_flags |= RTF_ANNOUNCE; + + if (lle->la_flags & LLE_VALID) { /* valid MAC */ + struct sockaddr_dl *sdl = &ndpc.sdl; + + sdl->sdl_family = AF_LINK; + sdl->sdl_len = sizeof(*sdl); + sdl->sdl_alen = ifp->if_addrlen; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); + } + ndpc.rtm.rtm_rmx.rmx_expire = + lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; + ndpc.rtm.rtm_flags |= RTF_LLINFO | RTF_HOST; + if (lle->la_flags & LLE_STATIC) + ndpc.rtm.rtm_flags |= RTF_STATIC; + ndpc.rtm.rtm_index = ifp->if_index; + error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); + if (error) + break; + } + } + return error; +} + void * in6_domifattach(struct ifnet *ifp) { @@ -2118,6 +2309,13 @@ ext->nd_ifinfo = nd6_ifattach(ifp); ext->scope6_id = scope6_ifattach(ifp); ext->lltable = lltable_init(ifp, AF_INET6); + if (ext->lltable != NULL) { + ext->lltable->llt_new = in6_lltable_new; + ext->lltable->llt_free = in6_lltable_free; + ext->lltable->llt_rtcheck = in6_lltable_rtcheck; + ext->lltable->llt_lookup = in6_lltable_lookup; + ext->lltable->llt_dump = in6_lltable_dump; + } return ext; } ==== //depot/projects/arp-v2/src/sys/netinet6/nd6.c#9 (text+ko) ==== @@ -61,6 +61,7 @@ #include <netinet/in.h> #include <net/if_llatbl.h> +#define L3_ADDR_SIN6(le) ((struct sockaddr_in6 *) L3_ADDR(le)) #include <netinet/if_ether.h> #include <netinet6/in6_var.h> #include <netinet/ip6.h> @@ -444,7 +445,7 @@ } ndi = ND_IFINFO(ifp); - dst = &ln->l3_addr6.sin6_addr; + dst = &L3_ADDR_SIN6(ln)->sin6_addr; if ((ln->la_flags & LLE_STATIC) || (ln->la_expire > time_second)) { IF_AFDATA_UNLOCK(ifp); @@ -963,7 +964,7 @@ if (!V_ip6_forwarding) { int s; s = splnet(); - dr = defrouter_lookup(&ln->l3_addr6.sin6_addr, ln->lle_tbl->llt_ifp); + dr = defrouter_lookup(&L3_ADDR_SIN6(ln)->sin6_addr, ln->lle_tbl->llt_ifp); if (dr != NULL && dr->expire && ln->ln_state == ND6_LLINFO_STALE && gc) { @@ -994,7 +995,7 @@ * is in the Default Router List. * See a corresponding comment in nd6_na_input(). */ - rt6_flush( &ln->l3_addr6.sin6_addr, ln->lle_tbl->llt_ifp); + rt6_flush(&L3_ADDR_SIN6(ln)->sin6_addr, ln->lle_tbl->llt_ifp); } if (dr) { @@ -1454,7 +1455,7 @@ * just set the 2nd argument as the * 1st one. */ - nd6_output(ifp, ifp, m_hold, &ln->l3_addr6, NULL); + nd6_output(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL); } } } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { ==== //depot/projects/arp-v2/src/sys/netinet6/nd6_nbr.c#8 (text+ko) ==== @@ -64,6 +64,7 @@ #include <netinet/in.h> #include <netinet/in_var.h> >>> TRUNCATED FOR MAIL (1000 lines) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200811251717.mAPHHxeX088794>