Author: melifaro
Date: Sat Aug  8 17:48:54 2015
New Revision: 286457
URL: https://svnweb.freebsd.org/changeset/base/286457

Log:
  MFP r274553:
  * Move lle creation/deletion from lla_lookup to separate functions:
    lla_lookup(LLE_CREATE) -> lla_create
    lla_lookup(LLE_DELETE) -> lla_delete
  lla_create now returns with LLE_EXCLUSIVE lock for lle.
  * Provide typedefs for new/existing lltable callbacks.
  
  Reviewed by:  ae

Modified:
  head/sys/net/if_llatbl.c
  head/sys/net/if_llatbl.h
  head/sys/netinet/if_ether.c
  head/sys/netinet/in.c
  head/sys/netinet/toecore.c
  head/sys/netinet6/in6.c
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6.h
Directory Properties:
  head/sys/   (props changed)

Modified: head/sys/net/if_llatbl.c
==============================================================================
--- head/sys/net/if_llatbl.c    Sat Aug  8 16:39:28 2015        (r286456)
+++ head/sys/net/if_llatbl.c    Sat Aug  8 17:48:54 2015        (r286457)
@@ -147,8 +147,7 @@ llentry_alloc(struct ifnet *ifp, struct 
        if ((la == NULL) &&
            (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
                IF_AFDATA_WLOCK(ifp);
-               la = lla_lookup(lt, (LLE_CREATE | LLE_EXCLUSIVE),
-                   (struct sockaddr *)dst);
+               la = lla_create(lt, 0, (struct sockaddr *)dst);
                IF_AFDATA_WUNLOCK(ifp);
        }
 
@@ -259,7 +258,7 @@ lltable_init(struct ifnet *ifp, int af)
 }
 
 /*
- * Called in route_output when adding/deleting a route to an interface.
+ * Called in route_output when rtm_flags contains RTF_LLDATA.
  */
 int
 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
@@ -270,8 +269,8 @@ lla_rt_output(struct rt_msghdr *rtm, str
        struct ifnet *ifp;
        struct lltable *llt;
        struct llentry *lle;
-       u_int laflags = 0, flags = 0;
-       int error = 0;
+       u_int laflags = 0;
+       int error;
 
        KASSERT(dl != NULL && dl->sdl_family == AF_LINK,
            ("%s: invalid dl\n", __func__));
@@ -283,24 +282,6 @@ lla_rt_output(struct rt_msghdr *rtm, str
                return EINVAL;
        }
 
-       switch (rtm->rtm_type) {
-       case RTM_ADD:
-               if (rtm->rtm_flags & RTF_ANNOUNCE)
-                       flags |= LLE_PUB;
-               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 */
        LLTABLE_RLOCK();
        SLIST_FOREACH(llt, &V_lltables, llt_link) {
@@ -311,58 +292,62 @@ lla_rt_output(struct rt_msghdr *rtm, str
        LLTABLE_RUNLOCK();
        KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n"));
 
-       if (flags & LLE_CREATE)
-               flags |= LLE_EXCLUSIVE;
+       error = 0;
 
-       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 |= (flags & LLE_PUB);
-                       lle->la_flags |= LLE_VALID;
-                       lle->la_flags &= ~LLE_DELETED;
+       switch (rtm->rtm_type) {
+       case RTM_ADD:
+               /* Add static LLE */
+               IF_AFDATA_WLOCK(ifp);
+               lle = lla_create(llt, 0, dst);
+               if (lle == NULL) {
+                       IF_AFDATA_WUNLOCK(ifp);
+                       return (ENOMEM);
+               }
+
+
+               bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen);
+               if ((rtm->rtm_flags & RTF_ANNOUNCE))
+                       lle->la_flags |= LLE_PUB;
+               lle->la_flags |= LLE_VALID;
 #ifdef INET6
-                       /*
-                        * ND6
-                        */
-                       if (dst->sa_family == AF_INET6)
-                               lle->ln_state = ND6_LLINFO_REACHABLE;
+               /*
+                * 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);
+               /*
+                * 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);
+               IF_AFDATA_WUNLOCK(ifp);
 #ifdef INET
-                       /* gratuitous ARP */
-                       if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
-                               arprequest(ifp,
-                                   &((struct sockaddr_in *)dst)->sin_addr,
-                                   &((struct sockaddr_in *)dst)->sin_addr,
-                                   (u_char *)LLADDR(dl));
+               /* gratuitous ARP */
+               if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
+                       arprequest(ifp,
+                           &((struct sockaddr_in *)dst)->sin_addr,
+                           &((struct sockaddr_in *)dst)->sin_addr,
+                           (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;
 
+               break;
+
+       case RTM_DELETE:
+               IF_AFDATA_WLOCK(ifp);
+               error = lla_delete(llt, 0, dst);
+               IF_AFDATA_WUNLOCK(ifp);
+               return (error == 0 ? 0 : ENOENT);
+
+       default:
+               error = EINVAL;
+       }
 
        return (error);
 }

Modified: head/sys/net/if_llatbl.h
==============================================================================
--- head/sys/net/if_llatbl.h    Sat Aug  8 16:39:28 2015        (r286456)
+++ head/sys/net/if_llatbl.h    Sat Aug  8 17:48:54 2015        (r286457)
@@ -144,25 +144,33 @@ struct llentry {
 #define        LLTBL_HASHMASK  (LLTBL_HASHTBL_SIZE - 1)
 #endif
 
+typedef        struct llentry *(llt_lookup_t)(struct lltable *, u_int flags,
+    const struct sockaddr *l3addr);
+typedef        struct llentry *(llt_create_t)(struct lltable *, u_int flags,
+    const struct sockaddr *l3addr);
+typedef        int (llt_delete_t)(struct lltable *, u_int flags,
+    const struct sockaddr *l3addr);
+typedef void (llt_prefix_free_t)(struct lltable *,
+    const struct sockaddr *prefix, const struct sockaddr *mask, u_int flags);
+typedef int (llt_dump_t)(struct lltable *, struct sysctl_req *);
+
 struct lltable {
        SLIST_ENTRY(lltable)    llt_link;
        struct llentries        lle_head[LLTBL_HASHTBL_SIZE];
        int                     llt_af;
        struct ifnet            *llt_ifp;
 
-       void                    (*llt_prefix_free)(struct lltable *,
-                                   const struct sockaddr *prefix,
-                                   const struct sockaddr *mask,
-                                   u_int flags);
-       struct llentry *        (*llt_lookup)(struct lltable *, u_int flags,
-                                   const struct sockaddr *l3addr);
-       int                     (*llt_dump)(struct lltable *,
-                                   struct sysctl_req *);
+       llt_lookup_t            *llt_lookup;
+       llt_create_t            *llt_create;
+       llt_delete_t            *llt_delete;
+       llt_prefix_free_t       *llt_prefix_free;
+       llt_dump_t              *llt_dump;
 };
+
 MALLOC_DECLARE(M_LLTABLE);
 
 /*
- * flags to be passed to arplookup.
+ * LLentry flags
  */
 #define        LLE_DELETED     0x0001  /* entry must be deleted */
 #define        LLE_STATIC      0x0002  /* entry is static */
@@ -170,9 +178,8 @@ MALLOC_DECLARE(M_LLTABLE);
 #define        LLE_VALID       0x0008  /* ll_addr is valid */
 #define        LLE_PUB         0x0020  /* publish entry ??? */
 #define        LLE_LINKED      0x0040  /* linked to lookup structure */
+/* LLE request flags */
 #define        LLE_EXCLUSIVE   0x2000  /* return lle xlocked  */
-#define        LLE_DELETE      0x4000  /* delete on a lookup - match 
LLE_IFADDR */
-#define        LLE_CREATE      0x8000  /* create on a lookup miss */
 
 #define LLATBL_HASH(key, mask) \
        (((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask)
@@ -196,9 +203,25 @@ struct llentry  *llentry_alloc(struct if
 static __inline struct llentry *
 lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
 {
-       return llt->llt_lookup(llt, flags, l3addr);
+
+       return (llt->llt_lookup(llt, flags, l3addr));
 }
 
+static __inline struct llentry *
+lla_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
+{
+
+       return (llt->llt_create(llt, flags, l3addr));
+}
+
+static __inline int
+lla_delete(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
+{
+
+       return (llt->llt_delete(llt, flags, l3addr));
+}
+
+
 int            lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *);
 
 #include <sys/eventhandler.h>

Modified: head/sys/netinet/if_ether.c
==============================================================================
--- head/sys/netinet/if_ether.c Sat Aug  8 16:39:28 2015        (r286456)
+++ head/sys/netinet/if_ether.c Sat Aug  8 17:48:54 2015        (r286457)
@@ -152,8 +152,7 @@ arp_ifscrub(struct ifnet *ifp, uint32_t 
        addr4.sin_family = AF_INET;
        addr4.sin_addr.s_addr = addr;
        IF_AFDATA_WLOCK(ifp);
-       lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR),
-           (struct sockaddr *)&addr4);
+       lla_delete(LLTABLE(ifp), LLE_IFADDR, (struct sockaddr *)&addr4);
        IF_AFDATA_WUNLOCK(ifp);
 }
 #endif
@@ -325,11 +324,12 @@ arpresolve(struct ifnet *ifp, int is_gw,
        u_int flags = 0;
        struct mbuf *curr = NULL;
        struct mbuf *next = NULL;
-       int error, renew;
+       int create, error, renew;
 
        if (pflags != NULL)
                *pflags = 0;
 
+       create = 0;
        if (m != NULL) {
                if (m->m_flags & M_BCAST) {
                        /* broadcast */
@@ -349,13 +349,14 @@ retry:
        IF_AFDATA_RUNLOCK(ifp);
        if ((la == NULL) && ((flags & LLE_EXCLUSIVE) == 0)
            && ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0)) {
-               flags |= (LLE_CREATE | LLE_EXCLUSIVE);
+               create = 1;
+               flags |= LLE_EXCLUSIVE;
                IF_AFDATA_WLOCK(ifp);
-               la = lla_lookup(LLTABLE(ifp), flags, dst);
+               la = lla_create(LLTABLE(ifp), flags, dst);
                IF_AFDATA_WUNLOCK(ifp);
        }
        if (la == NULL) {
-               if (flags & LLE_CREATE)
+               if (create != 0)
                        log(LOG_DEBUG,
                            "arpresolve: can't allocate llinfo for %s on %s\n",
                            inet_ntoa(SIN(dst)->sin_addr), ifp->if_xname);
@@ -578,7 +579,7 @@ in_arpinput(struct mbuf *m)
        int op, flags;
        int req_len;
        int bridged = 0, is_bridge = 0;
-       int carped;
+       int carped, create;
        struct sockaddr_in sin;
        sin.sin_len = sizeof(struct sockaddr_in);
        sin.sin_family = AF_INET;
@@ -729,10 +730,13 @@ match:
        sin.sin_len = sizeof(struct sockaddr_in);
        sin.sin_family = AF_INET;
        sin.sin_addr = isaddr;
-       flags = (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0;
-       flags |= LLE_EXCLUSIVE;
+       create = (itaddr.s_addr == myaddr.s_addr) ? 1 : 0;
+       flags = LLE_EXCLUSIVE;
        IF_AFDATA_LOCK(ifp);
-       la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin);
+       if (create != 0)
+               la = lla_create(LLTABLE(ifp), 0, (struct sockaddr *)&sin);
+       else
+               la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin);
        IF_AFDATA_UNLOCK(ifp);
        if (la != NULL) {
                /* the following is not an error when doing bridging */
@@ -947,14 +951,14 @@ arp_ifinit(struct ifnet *ifp, struct ifa
                 * that L2 entry as permanent
                 */
                IF_AFDATA_LOCK(ifp);
-               lle = lla_lookup(LLTABLE(ifp), (LLE_CREATE | LLE_IFADDR | 
LLE_STATIC),
+               lle = lla_create(LLTABLE(ifp), LLE_IFADDR | LLE_STATIC,
                                 (struct sockaddr *)IA_SIN(ifa));
                IF_AFDATA_UNLOCK(ifp);
                if (lle == NULL)
                        log(LOG_INFO, "arp_ifinit: cannot create arp "
                            "entry for interface address\n");
                else
-                       LLE_RUNLOCK(lle);
+                       LLE_WUNLOCK(lle);
        }
        ifa->ifa_rtrequest = NULL;
 }

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c       Sat Aug  8 16:39:28 2015        (r286456)
+++ head/sys/netinet/in.c       Sat Aug  8 17:48:54 2015        (r286457)
@@ -1107,6 +1107,117 @@ in_lltable_rtcheck(struct ifnet *ifp, u_
        return (0);
 }
 
+static inline struct llentry *
+in_lltable_find_dst(struct lltable *llt, struct in_addr dst)
+{
+       struct llentry *lle;
+       struct llentries *lleh;
+       struct sockaddr_in *sin;
+       u_int hashkey;
+
+       hashkey = dst.s_addr;
+       lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+       LIST_FOREACH(lle, lleh, lle_next) {
+               sin = satosin(L3_ADDR(lle));
+               if (lle->la_flags & LLE_DELETED)
+                       continue;
+               if (sin->sin_addr.s_addr == dst.s_addr)
+                       break;
+       }
+
+       return (lle);
+}
+
+static int
+in_lltable_delete(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;
+
+       IF_AFDATA_WLOCK_ASSERT(ifp);
+       KASSERT(l3addr->sa_family == AF_INET,
+           ("sin_family %d", l3addr->sa_family));
+
+       lle = in_lltable_find_dst(llt, sin->sin_addr);
+       if (lle == NULL) {
+#ifdef DIAGNOSTIC
+               log(LOG_INFO, "interface address is missing from cache = %p  in 
delete\n", lle);
+#endif
+               return (ENOENT);
+       }
+
+       if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
+               LLE_WLOCK(lle);
+               lle->la_flags |= LLE_DELETED;
+               EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
+#ifdef DIAGNOSTIC
+               log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
+#endif
+               if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
+                       llentry_free(lle);
+               else
+                       LLE_WUNLOCK(lle);
+       }
+
+       return (0);
+}
+
+static struct llentry *
+in_lltable_create(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;
+
+       IF_AFDATA_WLOCK_ASSERT(ifp);
+       KASSERT(l3addr->sa_family == AF_INET,
+           ("sin_family %d", l3addr->sa_family));
+
+       lle = in_lltable_find_dst(llt, sin->sin_addr);
+
+       if (lle != NULL) {
+               LLE_WLOCK(lle);
+               return (lle);
+       }
+
+       /* no existing record, we need to create new one */
+
+       /*
+        * 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, flags, 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;
+       if ((flags & LLE_IFADDR) == LLE_IFADDR) {
+               bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
+               lle->la_flags |= (LLE_VALID | LLE_STATIC);
+       }
+
+       hashkey = sin->sin_addr.s_addr;
+       lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+
+       lle->lle_tbl  = llt;
+       lle->lle_head = lleh;
+       lle->la_flags |= LLE_LINKED;
+       LIST_INSERT_HEAD(lleh, lle, lle_next);
+       LLE_WLOCK(lle);
+
+       return (lle);
+}
+
 /*
  * Return NULL if not found or marked for deletion.
  * If found return lle read locked.
@@ -1133,62 +1244,15 @@ in_lltable_lookup(struct lltable *llt, u
                if (sa2->sin_addr.s_addr == sin->sin_addr.s_addr)
                        break;
        }
-       if (lle == NULL) {
-#ifdef DIAGNOSTIC
-               if (flags & LLE_DELETE)
-                       log(LOG_INFO, "interface address is missing from cache 
= %p  in delete\n", lle);
-#endif
-               if (!(flags & LLE_CREATE))
-                       return (NULL);
-               IF_AFDATA_WLOCK_ASSERT(ifp);
-               /*
-                * 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, flags, l3addr) != 0)
-                       goto done;
-
-               lle = in_lltable_new(l3addr, flags);
-               if (lle == NULL) {
-                       log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
-                       goto done;
-               }
-               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;
-               lle->la_flags |= LLE_LINKED;
-               LIST_INSERT_HEAD(lleh, lle, lle_next);
-       } else if (flags & LLE_DELETE) {
-               if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
-                       LLE_WLOCK(lle);
-                       lle->la_flags |= LLE_DELETED;
-                       EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
-#ifdef DIAGNOSTIC
-                       log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
-#endif
-                       if ((lle->la_flags &
-                           (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
-                               llentry_free(lle);
-                       else
-                               LLE_WUNLOCK(lle);
-               }
-               lle = (void *)-1;
+       if (lle == NULL)
+               return (NULL);
+
+       if (flags & LLE_EXCLUSIVE)
+               LLE_WLOCK(lle);
+       else
+               LLE_RLOCK(lle);
 
-       }
-       if (LLE_IS_VALID(lle)) {
-               if (flags & LLE_EXCLUSIVE)
-                       LLE_WLOCK(lle);
-               else
-                       LLE_RLOCK(lle);
-       }
-done:
        return (lle);
 }
 
@@ -1279,6 +1343,8 @@ in_domifattach(struct ifnet *ifp)
        if (llt != NULL) {
                llt->llt_prefix_free = in_lltable_prefix_free;
                llt->llt_lookup = in_lltable_lookup;
+               llt->llt_create = in_lltable_create;
+               llt->llt_delete = in_lltable_delete;
                llt->llt_dump = in_lltable_dump;
        }
        ii->ii_llt = llt;

Modified: head/sys/netinet/toecore.c
==============================================================================
--- head/sys/netinet/toecore.c  Sat Aug  8 16:39:28 2015        (r286456)
+++ head/sys/netinet/toecore.c  Sat Aug  8 17:48:54 2015        (r286457)
@@ -463,8 +463,7 @@ restart:
        IF_AFDATA_RUNLOCK(ifp);
        if (lle == NULL) {
                IF_AFDATA_LOCK(ifp);
-               lle = nd6_lookup(&sin6->sin6_addr, ND6_CREATE | ND6_EXCLUSIVE,
-                   ifp);
+               lle = nd6_create(&sin6->sin6_addr, 0, ifp);
                IF_AFDATA_UNLOCK(ifp);
                if (lle == NULL)
                        return (ENOMEM); /* Couldn't create entry in cache. */

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c     Sat Aug  8 16:39:28 2015        (r286456)
+++ head/sys/netinet6/in6.c     Sat Aug  8 17:48:54 2015        (r286457)
@@ -2152,81 +2152,134 @@ in6_lltable_rtcheck(struct ifnet *ifp,
        return 0;
 }
 
-static struct llentry *
-in6_lltable_lookup(struct lltable *llt, u_int flags,
-       const struct sockaddr *l3addr)
+static inline struct llentry *
+in6_lltable_find_dst(struct lltable *llt, const struct in6_addr *dst)
 {
-       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
-       struct ifnet *ifp = llt->llt_ifp;
        struct llentry *lle;
        struct llentries *lleh;
+       const struct sockaddr_in6 *sin6;
        u_int hashkey;
 
-       IF_AFDATA_LOCK_ASSERT(ifp);
-       KASSERT(l3addr->sa_family == AF_INET6,
-           ("sin_family %d", l3addr->sa_family));
-
-       hashkey = sin6->sin6_addr.s6_addr32[3];
+       hashkey = dst->s6_addr32[3];
        lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
        LIST_FOREACH(lle, lleh, lle_next) {
-               struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle);
+               sin6 = (const struct sockaddr_in6 *)L3_ADDR(lle);
                if (lle->la_flags & LLE_DELETED)
                        continue;
-               if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr,
-                   sizeof(struct in6_addr)) == 0)
+               if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, dst))
                        break;
        }
 
-       if (lle == NULL) {
-               if (!(flags & LLE_CREATE))
-                       return (NULL);
-               IF_AFDATA_WLOCK_ASSERT(ifp);
-               /*
-                * 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, flags, 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);
-               }
+       return (lle);
+}
 
-               lle->lle_tbl  = llt;
-               lle->lle_head = lleh;
-               lle->la_flags |= LLE_LINKED;
-               LIST_INSERT_HEAD(lleh, lle, lle_next);
-       } else if (flags & LLE_DELETE) {
-               if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
-                       LLE_WLOCK(lle);
-                       lle->la_flags |= LLE_DELETED;
-                       EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
+static int
+in6_lltable_delete(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;
+
+       IF_AFDATA_LOCK_ASSERT(ifp);
+       KASSERT(l3addr->sa_family == AF_INET6,
+           ("sin_family %d", l3addr->sa_family));
+
+       lle = in6_lltable_find_dst(llt, &sin6->sin6_addr);
+
+       if (lle == NULL)
+               return (ENOENT);
+
+       if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
+               LLE_WLOCK(lle);
+               lle->la_flags |= LLE_DELETED;
+               EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
 #ifdef DIAGNOSTIC
-                       log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
+               log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
 #endif
-                       if ((lle->la_flags &
-                           (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
-                               llentry_free(lle);
-                       else
-                               LLE_WUNLOCK(lle);
-               }
-               lle = (void *)-1;
-       }
-       if (LLE_IS_VALID(lle)) {
-               if (flags & LLE_EXCLUSIVE)
-                       LLE_WLOCK(lle);
+               if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC)
+                       llentry_free(lle);
                else
-                       LLE_RLOCK(lle);
+                       LLE_WUNLOCK(lle);
        }
+
+       return (0);
+}
+
+static struct llentry *
+in6_lltable_create(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;
+
+       IF_AFDATA_WLOCK_ASSERT(ifp);
+       KASSERT(l3addr->sa_family == AF_INET6,
+           ("sin_family %d", l3addr->sa_family));
+
+       lle = in6_lltable_find_dst(llt, &sin6->sin6_addr);
+
+       if (lle != NULL) {
+               LLE_WLOCK(lle);
+               return (lle);
+       }
+
+       /*
+        * 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, flags, 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;
+       if ((flags & LLE_IFADDR) == LLE_IFADDR) {
+               bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
+               lle->la_flags |= (LLE_VALID | LLE_STATIC);
+       }
+
+       hashkey = sin6->sin6_addr.s6_addr32[3];
+       lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+
+       lle->lle_tbl  = llt;
+       lle->lle_head = lleh;
+       lle->la_flags |= LLE_LINKED;
+       LIST_INSERT_HEAD(lleh, lle, lle_next);
+       LLE_WLOCK(lle);
+
+       return (lle);
+}
+
+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;
+
+       IF_AFDATA_LOCK_ASSERT(ifp);
+       KASSERT(l3addr->sa_family == AF_INET6,
+           ("sin_family %d", l3addr->sa_family));
+
+       lle = in6_lltable_find_dst(llt, &sin6->sin6_addr);
+
+       if (lle == NULL)
+               return (NULL);
+
+       if (flags & LLE_EXCLUSIVE)
+               LLE_WLOCK(lle);
+       else
+               LLE_RLOCK(lle);
        return (lle);
 }
 
@@ -2340,6 +2393,8 @@ in6_domifattach(struct ifnet *ifp)
        if (ext->lltable != NULL) {
                ext->lltable->llt_prefix_free = in6_lltable_prefix_free;
                ext->lltable->llt_lookup = in6_lltable_lookup;
+               ext->lltable->llt_create = in6_lltable_create;
+               ext->lltable->llt_delete = in6_lltable_delete;
                ext->lltable->llt_dump = in6_lltable_dump;
        }
 

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c     Sat Aug  8 16:39:28 2015        (r286456)
+++ head/sys/netinet6/nd6.c     Sat Aug  8 17:48:54 2015        (r286457)
@@ -937,16 +937,33 @@ nd6_lookup(struct in6_addr *addr6, int f
 
        IF_AFDATA_LOCK_ASSERT(ifp);
 
-       llflags = 0;
-       if (flags & ND6_CREATE)
-           llflags |= LLE_CREATE;
-       if (flags & ND6_EXCLUSIVE)
-           llflags |= LLE_EXCLUSIVE;   
-       
+       llflags = (flags & ND6_EXCLUSIVE) ? LLE_EXCLUSIVE : 0;
        ln = lla_lookup(LLTABLE6(ifp), llflags, (struct sockaddr *)&sin6);
-       if ((ln != NULL) && (llflags & LLE_CREATE))
+
+       return (ln);
+}
+
+/*
+ * the caller acquires and releases the lock on the lltbls
+ * Returns the llentry wlocked
+ */
+struct llentry *
+nd6_create(struct in6_addr *addr6, int flags, struct ifnet *ifp)
+{
+       struct sockaddr_in6 sin6;
+       struct llentry *ln;
+
+       bzero(&sin6, sizeof(sin6));
+       sin6.sin6_len = sizeof(struct sockaddr_in6);
+       sin6.sin6_family = AF_INET6;
+       sin6.sin6_addr = *addr6;
+
+       IF_AFDATA_WLOCK_ASSERT(ifp);
+
+       ln = lla_create(LLTABLE6(ifp), 0, (struct sockaddr *)&sin6);
+       if (ln != NULL)
                ln->ln_state = ND6_LLINFO_NOSTATE;
-       
+
        return (ln);
 }
 
@@ -1664,7 +1681,7 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
        if (ln == NULL) {
                flags |= ND6_EXCLUSIVE;
                IF_AFDATA_LOCK(ifp);
-               ln = nd6_lookup(from, flags | ND6_CREATE, ifp);
+               ln = nd6_create(from, 0, ifp);
                IF_AFDATA_UNLOCK(ifp);
                is_newentry = 1;
        } else {
@@ -2020,7 +2037,6 @@ nd6_output_lle(struct ifnet *ifp, struct
     struct sockaddr_in6 *dst)
 {
        struct llentry *lle = NULL;
-       int flags = 0;
 
        KASSERT(m != NULL, ("NULL mbuf, nothing to send"));
        /* discard the packet if IPv6 operation is disabled on the interface */
@@ -2051,9 +2067,8 @@ nd6_output_lle(struct ifnet *ifp, struct
                         * the condition below is not very efficient.  But we 
believe
                         * it is tolerable, because this should be a rare case.
                         */
-                       flags = ND6_CREATE | ND6_EXCLUSIVE;
                        IF_AFDATA_LOCK(ifp);
-                       lle = nd6_lookup(&dst->sin6_addr, flags, ifp);
+                       lle = nd6_create(&dst->sin6_addr, 0, ifp);
                        IF_AFDATA_UNLOCK(ifp);
                }
        } 
@@ -2237,8 +2252,8 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia)
                return (0);
        IF_AFDATA_LOCK(ifp);
        ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
-       ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR |
-           LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr);
+       ln = lla_create(LLTABLE6(ifp), LLE_IFADDR,
+           (struct sockaddr *)&ia->ia_addr);
        IF_AFDATA_UNLOCK(ifp);
        if (ln != NULL) {
                ln->la_expire = 0;  /* for IPv6 this means permanent */

Modified: head/sys/netinet6/nd6.h
==============================================================================
--- head/sys/netinet6/nd6.h     Sat Aug  8 16:39:28 2015        (r286456)
+++ head/sys/netinet6/nd6.h     Sat Aug  8 17:48:54 2015        (r286457)
@@ -89,7 +89,6 @@ struct nd_ifinfo {
 #define ND6_IFF_NO_PREFER_IFACE        0x80 /* XXX: not related to ND. */
 #define ND6_IFF_NO_DAD         0x100
 
-#define        ND6_CREATE              LLE_CREATE
 #define        ND6_EXCLUSIVE           LLE_EXCLUSIVE
 
 #ifdef _KERNEL
@@ -407,7 +406,8 @@ int nd6_is_addr_neighbor(struct sockaddr
 void nd6_option_init(void *, int, union nd_opts *);
 struct nd_opt_hdr *nd6_option(union nd_opts *);
 int nd6_options(union nd_opts *);
-struct llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *);
+struct llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *);
+struct llentry *nd6_create(struct in6_addr *, int, struct ifnet *);
 void nd6_setmtu(struct ifnet *);
 void nd6_llinfo_settimer(struct llentry *, long);
 void nd6_llinfo_settimer_locked(struct llentry *, long);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to