Author: qingli
Date: Wed May 20 21:07:15 2009
New Revision: 192476
URL: http://svn.freebsd.org/changeset/base/192476

Log:
  When an interface address is removed and the last prefix
  route is also being deleted, the link-layer address table
  (arp or nd6) will flush those L2 llinfo entries that match
  the removed prefix.
  
  Reviewed by:  kmacy

Modified:
  head/sys/net/if_llatbl.c
  head/sys/net/if_llatbl.h
  head/sys/netinet/in.c
  head/sys/netinet6/in6.c

Modified: head/sys/net/if_llatbl.c
==============================================================================
--- head/sys/net/if_llatbl.c    Wed May 20 21:04:41 2009        (r192475)
+++ head/sys/net/if_llatbl.c    Wed May 20 21:07:15 2009        (r192476)
@@ -195,6 +195,23 @@ lltable_drain(int af)
        IFNET_RUNLOCK();
 }
 
+void
+lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask)
+{
+       struct lltable *llt;
+
+       IFNET_RLOCK();
+       SLIST_FOREACH(llt, &lltables, llt_link) {
+               if (llt->llt_af != af)
+                       continue;
+
+               llt->llt_prefix_free(llt, prefix, mask);
+       }
+       IFNET_RUNLOCK();
+}
+
+
+
 /*
  * Create a new lltable.
  */

Modified: head/sys/net/if_llatbl.h
==============================================================================
--- head/sys/net/if_llatbl.h    Wed May 20 21:04:41 2009        (r192475)
+++ head/sys/net/if_llatbl.h    Wed May 20 21:07:15 2009        (r192476)
@@ -147,6 +147,9 @@ struct lltable {
 
        struct llentry *        (*llt_new)(const struct sockaddr *, u_int);
        void                    (*llt_free)(struct lltable *, struct llentry *);
+       void                    (*llt_prefix_free)(struct lltable *,
+                                   const struct sockaddr *prefix,
+                                   const struct sockaddr *mask);
        struct llentry *        (*llt_lookup)(struct lltable *, u_int flags,
                                    const struct sockaddr *l3addr);
        int                     (*llt_rtcheck)(struct ifnet *,
@@ -174,6 +177,8 @@ MALLOC_DECLARE(M_LLTABLE);
 
 struct lltable *lltable_init(struct ifnet *, int);
 void           lltable_free(struct lltable *);
+void           lltable_prefix_free(int, struct sockaddr *, 
+                       struct sockaddr *);
 void           lltable_drain(int);
 int            lltable_sysctl_dumparp(int, struct sysctl_req *);
 

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c       Wed May 20 21:04:41 2009        (r192475)
+++ head/sys/netinet/in.c       Wed May 20 21:07:15 2009        (r192476)
@@ -1013,6 +1013,7 @@ in_scrubprefix(struct in_ifaddr *target)
        struct in_ifaddr *ia;
        struct in_addr prefix, mask, p;
        int error;
+       struct sockaddr_in prefix0, mask0;
        struct rt_addrinfo info;
        struct sockaddr_dl null_sdl;
 
@@ -1082,6 +1083,20 @@ in_scrubprefix(struct in_ifaddr *target)
        }
 
        /*
+        * remove all L2 entries on the given prefix
+        */
+       bzero(&prefix0, sizeof(prefix0));
+       prefix0.sin_len = sizeof(prefix0);
+       prefix0.sin_family = AF_INET;
+       prefix0.sin_addr.s_addr = target->ia_subnet;
+       bzero(&mask0, sizeof(mask0));
+       mask0.sin_len = sizeof(mask0);
+       mask0.sin_family = AF_INET;
+       mask0.sin_addr.s_addr = target->ia_subnetmask;
+       lltable_prefix_free(AF_INET, (struct sockaddr *)&prefix0, 
+                           (struct sockaddr *)&mask0);
+
+       /*
         * As no-one seem to have this prefix, we can remove the route.
         */
        rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
@@ -1232,6 +1247,34 @@ in_lltable_free(struct lltable *llt, str
        free(lle, M_LLTABLE);
 }
 
+
+#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m)      (                       \
+           (((ntohl((d)->sin_addr.s_addr) ^ (a)->sin_addr.s_addr) & 
(m)->sin_addr.s_addr)) == 0 )
+
+static void
+in_lltable_prefix_free(struct lltable *llt, 
+                      const struct sockaddr *prefix,
+                      const struct sockaddr *mask)
+{
+       const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
+       const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
+       struct llentry *lle, *next;
+       register int i;
+
+       for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
+               LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
+
+                       if (IN_ARE_MASKED_ADDR_EQUAL((struct sockaddr_in 
*)L3_ADDR(lle), 
+                                                    pfx, msk)) {
+                               callout_drain(&lle->la_timer);
+                               LLE_WLOCK(lle);
+                               llentry_free(lle);
+                       }
+               }
+       }
+}
+
+
 static int
 in_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
 {
@@ -1422,6 +1465,7 @@ in_domifattach(struct ifnet *ifp)
        if (llt != NULL) {
                llt->llt_new = in_lltable_new;
                llt->llt_free = in_lltable_free;
+               llt->llt_prefix_free = in_lltable_prefix_free;
                llt->llt_rtcheck = in_lltable_rtcheck;
                llt->llt_lookup = in_lltable_lookup;
                llt->llt_dump = in_lltable_dump;

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c     Wed May 20 21:04:41 2009        (r192475)
+++ head/sys/netinet6/in6.c     Wed May 20 21:07:15 2009        (r192476)
@@ -2284,6 +2284,30 @@ in6_lltable_free(struct lltable *llt, st
        free(lle, M_LLTABLE);
 }
 
+static void
+in6_lltable_prefix_free(struct lltable *llt, 
+                       const struct sockaddr *prefix,
+                       const struct sockaddr *mask)
+{
+       const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
+       const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
+       struct llentry *lle, *next;
+       register int i;
+
+       for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
+               LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
+                       if (IN6_ARE_MASKED_ADDR_EQUAL(
+                                   &((struct sockaddr_in6 
*)L3_ADDR(lle))->sin6_addr, 
+                                   &pfx->sin6_addr, 
+                                   &msk->sin6_addr)) {
+                               callout_drain(&lle->la_timer);
+                               LLE_WLOCK(lle);
+                               llentry_free(lle);
+                       }
+               }
+       }
+}
+
 static int
 in6_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
 {
@@ -2490,6 +2514,7 @@ in6_domifattach(struct ifnet *ifp)
        if (ext->lltable != NULL) {
                ext->lltable->llt_new = in6_lltable_new;
                ext->lltable->llt_free = in6_lltable_free;
+               ext->lltable->llt_prefix_free = in6_lltable_prefix_free;
                ext->lltable->llt_rtcheck = in6_lltable_rtcheck;
                ext->lltable->llt_lookup = in6_lltable_lookup;
                ext->lltable->llt_dump = in6_lltable_dump;
_______________________________________________
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