Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137068032
D3573.id8745.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
D3573.id8745.diff
View Options
Index: head/sys/net/if_llatbl.h
===================================================================
--- head/sys/net/if_llatbl.h
+++ head/sys/net/if_llatbl.h
@@ -135,10 +135,9 @@
const struct sockaddr *l3addr);
typedef struct llentry *(llt_alloc_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_delete_t)(struct lltable *, struct llentry *);
typedef void (llt_prefix_free_t)(struct lltable *,
- const struct sockaddr *prefix, const struct sockaddr *mask, u_int flags);
+ const struct sockaddr *addr, const struct sockaddr *mask, u_int flags);
typedef int (llt_dump_entry_t)(struct lltable *, struct llentry *,
struct sysctl_req *);
typedef uint32_t (llt_hash_t)(const struct llentry *, uint32_t);
@@ -162,7 +161,7 @@
llt_lookup_t *llt_lookup;
llt_alloc_t *llt_alloc_entry;
- llt_delete_t *llt_delete;
+ llt_delete_t *llt_delete_entry;
llt_prefix_free_t *llt_prefix_free;
llt_dump_entry_t *llt_dump_entry;
llt_hash_t *llt_hash;
@@ -212,6 +211,8 @@
struct llentry *lltable_alloc_entry(struct lltable *llt, u_int flags,
const struct sockaddr *l4addr);
void lltable_free_entry(struct lltable *llt, struct llentry *lle);
+int lltable_delete_addr(struct lltable *llt, u_int flags,
+ const struct sockaddr *l3addr);
void lltable_link_entry(struct lltable *llt, struct llentry *lle);
void lltable_unlink_entry(struct lltable *llt, struct llentry *lle);
void lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa);
@@ -230,14 +231,6 @@
return (llt->llt_lookup(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>
Index: head/sys/net/if_llatbl.c
===================================================================
--- head/sys/net/if_llatbl.c
+++ head/sys/net/if_llatbl.c
@@ -186,7 +186,7 @@
}
struct prefix_match_data {
- const struct sockaddr *prefix;
+ const struct sockaddr *addr;
const struct sockaddr *mask;
struct llentries dchain;
u_int flags;
@@ -199,7 +199,7 @@
pmd = (struct prefix_match_data *)farg;
- if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) {
+ if (llt->llt_match_prefix(pmd->addr, pmd->mask, pmd->flags, lle)) {
LLE_WLOCK(lle);
LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
}
@@ -208,14 +208,14 @@
}
static void
-htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
+htable_prefix_free(struct lltable *llt, const struct sockaddr *addr,
const struct sockaddr *mask, u_int flags)
{
struct llentry *lle, *next;
struct prefix_match_data pmd;
bzero(&pmd, sizeof(pmd));
- pmd.prefix = prefix;
+ pmd.addr = addr;
pmd.mask = mask;
pmd.flags = flags;
LIST_INIT(&pmd.dchain);
@@ -427,8 +427,42 @@
}
#endif
+/*
+ * Deletes an address from given lltable.
+ * Used for userland interaction to remove
+ * individual entries. Skips entries added by OS.
+ */
+int
+lltable_delete_addr(struct lltable *llt, u_int flags,
+ const struct sockaddr *l3addr)
+{
+ struct llentry *lle;
+ struct ifnet *ifp;
+
+ ifp = llt->llt_ifp;
+ IF_AFDATA_WLOCK(ifp);
+ lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr);
+
+ if (lle == NULL) {
+ IF_AFDATA_WUNLOCK(ifp);
+ return (ENOENT);
+ }
+ if ((lle->la_flags & LLE_IFADDR) != 0 && (flags & LLE_IFADDR) == 0) {
+ IF_AFDATA_WUNLOCK(ifp);
+ LLE_WUNLOCK(lle);
+ return (EPERM);
+ }
+
+ lltable_unlink_entry(llt, lle);
+ IF_AFDATA_WUNLOCK(ifp);
+
+ llt->llt_delete_entry(llt, lle);
+
+ return (0);
+}
+
void
-lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask,
+lltable_prefix_free(int af, struct sockaddr *addr, struct sockaddr *mask,
u_int flags)
{
struct lltable *llt;
@@ -438,7 +472,7 @@
if (llt->llt_af != af)
continue;
- llt->llt_prefix_free(llt, prefix, mask, flags);
+ llt->llt_prefix_free(llt, addr, mask, flags);
}
LLTABLE_RUNLOCK();
}
@@ -651,10 +685,7 @@
break;
case RTM_DELETE:
- IF_AFDATA_WLOCK(ifp);
- error = lla_delete(llt, 0, dst);
- IF_AFDATA_WUNLOCK(ifp);
- return (error == 0 ? 0 : ENOENT);
+ return (lltable_delete_addr(llt, 0, dst));
default:
error = EINVAL;
Index: head/sys/netinet/if_ether.h
===================================================================
--- head/sys/netinet/if_ether.h
+++ head/sys/netinet/if_ether.h
@@ -120,7 +120,6 @@
const struct in_addr *, u_char *);
void arp_ifinit(struct ifnet *, struct ifaddr *);
void arp_ifinit2(struct ifnet *, struct ifaddr *, u_char *);
-void arp_ifscrub(struct ifnet *, uint32_t);
#endif
#endif
Index: head/sys/netinet/if_ether.c
===================================================================
--- head/sys/netinet/if_ether.c
+++ head/sys/netinet/if_ether.c
@@ -140,26 +140,6 @@
.nh_policy = NETISR_POLICY_SOURCE,
};
-#ifdef AF_INET
-/*
- * called by in_scrubprefix() to remove entry from the table when
- * the interface goes away
- */
-void
-arp_ifscrub(struct ifnet *ifp, uint32_t addr)
-{
- struct sockaddr_in addr4;
-
- bzero((void *)&addr4, sizeof(addr4));
- addr4.sin_len = sizeof(addr4);
- addr4.sin_family = AF_INET;
- addr4.sin_addr.s_addr = addr;
- IF_AFDATA_WLOCK(ifp);
- lla_delete(LLTABLE(ifp), LLE_IFADDR, (struct sockaddr *)&addr4);
- IF_AFDATA_WUNLOCK(ifp);
-}
-#endif
-
/*
* Timeout routine. Age arp_tab entries periodically.
*/
Index: head/sys/netinet/in.c
===================================================================
--- head/sys/netinet/in.c
+++ head/sys/netinet/in.c
@@ -724,6 +724,38 @@
}
/*
+ * Removes either all lle entries for given @ia, or lle
+ * corresponding to @ia address.
+ */
+static void
+in_scrubprefixlle(struct in_ifaddr *ia, int all, u_int flags)
+{
+ struct sockaddr_in addr, mask;
+ struct sockaddr *saddr, *smask;
+ struct ifnet *ifp;
+
+ /*
+ * remove all L2 entries on the given prefix
+ */
+ saddr = (struct sockaddr *)&addr;
+ bzero(&addr, sizeof(addr));
+ addr.sin_len = sizeof(addr);
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = ntohl(ia->ia_addr.sin_addr.s_addr);
+ smask = (struct sockaddr *)&mask;
+ bzero(&mask, sizeof(mask));
+ mask.sin_len = sizeof(mask);
+ mask.sin_family = AF_INET;
+ mask.sin_addr.s_addr = ia->ia_subnetmask;
+ ifp = ia->ia_ifp;
+
+ if (all)
+ lltable_prefix_free(AF_INET, saddr, smask, flags);
+ else
+ lltable_delete_addr(LLTABLE(ifp), LLE_IFADDR, saddr);
+}
+
+/*
* If there is no other address in the system that can serve a route to the
* same prefix, remove the route. Hand over the route to the new address
* otherwise.
@@ -735,7 +767,6 @@
struct in_ifaddr *ia;
struct in_addr prefix, mask, p, m;
int error = 0;
- struct sockaddr_in prefix0, mask0;
/*
* Remove the loopback route to the interface address.
@@ -757,11 +788,6 @@
error = ifa_del_loopback_route((struct ifaddr *)target,
(struct sockaddr *)&target->ia_addr);
}
-
- if (!(target->ia_ifp->if_flags & IFF_NOARP))
- /* remove arp cache */
- arp_ifscrub(target->ia_ifp,
- IA_SIN(target)->sin_addr.s_addr);
}
if (rtinitflags(target)) {
@@ -817,6 +843,9 @@
else
log(LOG_INFO, "in_scrubprefix: err=%d, old prefix delete failed\n",
error);
+ /* Scrub all entries IFF interface is different */
+ in_scrubprefixlle(target, target->ia_ifp != ia->ia_ifp,
+ flags);
error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
rtinitflags(ia) | RTF_UP);
if (error == 0)
@@ -833,16 +862,7 @@
/*
* 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, flags);
+ in_scrubprefixlle(target, 1, flags);
/*
* As no-one seem to have this prefix, we can remove the route.
@@ -1001,22 +1021,38 @@
return (&lle->base);
}
-#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
- (((ntohl((d).s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
+#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \
+ ((((d).s_addr ^ (a).s_addr) & (m).s_addr)) == 0 )
static int
-in_lltable_match_prefix(const struct sockaddr *prefix,
- const struct sockaddr *mask, u_int flags, struct llentry *lle)
+in_lltable_match_prefix(const struct sockaddr *saddr,
+ const struct sockaddr *smask, u_int flags, struct llentry *lle)
{
- const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
- const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
+ struct in_addr addr, mask, lle_addr;
- /*
- * (flags & LLE_STATIC) means deleting all entries
- * including static ARP entries.
- */
- if (IN_ARE_MASKED_ADDR_EQUAL(lle->r_l3addr.addr4, pfx, msk) &&
- ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
+ addr = ((const struct sockaddr_in *)saddr)->sin_addr;
+ mask = ((const struct sockaddr_in *)smask)->sin_addr;
+ lle_addr.s_addr = ntohl(lle->r_l3addr.addr4.s_addr);
+
+ if (IN_ARE_MASKED_ADDR_EQUAL(lle_addr, addr, mask) == 0)
+ return (0);
+
+ if (lle->la_flags & LLE_IFADDR) {
+
+ /*
+ * Delete LLE_IFADDR records IFF address & flag matches.
+ * Note that addr is the interface address within prefix
+ * being matched.
+ * Note also we should handle 'ifdown' cases without removing
+ * ifaddr macs.
+ */
+ if (addr.s_addr == lle_addr.s_addr && (flags & LLE_STATIC) != 0)
+ return (1);
+ return (0);
+ }
+
+ /* flags & LLE_STATIC means deleting both dynamic and static entries */
+ if ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))
return (1);
return (0);
@@ -1166,39 +1202,16 @@
return (lle);
}
-static int
-in_lltable_delete(struct lltable *llt, u_int flags,
- const struct sockaddr *l3addr)
+static void
+in_lltable_delete_entry(struct lltable *llt, struct llentry *lle)
{
- const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
- struct llentry *lle;
-
- IF_AFDATA_WLOCK_ASSERT(llt->llt_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->la_flags |= LLE_DELETED;
+ EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
#ifdef DIAGNOSTIC
- log(LOG_INFO, "interface address is missing from cache = %p in delete\n", lle);
+ log(LOG_INFO, "ifaddr cache = %p is deleted\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);
+ llentry_free(lle);
}
static struct llentry *
@@ -1334,7 +1347,7 @@
llt->llt_lookup = in_lltable_lookup;
llt->llt_alloc_entry = in_lltable_alloc;
- llt->llt_delete = in_lltable_delete;
+ llt->llt_delete_entry = in_lltable_delete_entry;
llt->llt_dump_entry = in_lltable_dump_entry;
llt->llt_hash = in_lltable_hash;
llt->llt_fill_sa_entry = in_lltable_fill_sa_entry;
Index: head/sys/netinet/ip_carp.c
===================================================================
--- head/sys/netinet/ip_carp.c
+++ head/sys/netinet/ip_carp.c
@@ -985,7 +985,7 @@
case AF_INET6:
ifa_del_loopback_route(ifa,
(struct sockaddr *)&ifatoia6(ifa)->ia_addr);
- nd6_rem_ifa_lle(ifatoia6(ifa));
+ nd6_rem_ifa_lle(ifatoia6(ifa), 1);
break;
#endif
}
Index: head/sys/netinet6/in6.c
===================================================================
--- head/sys/netinet6/in6.c
+++ head/sys/netinet6/in6.c
@@ -1307,9 +1307,6 @@
/* stop DAD processing */
nd6_dad_stop(ifa);
- /* Remove local address entry from lltable. */
- nd6_rem_ifa_lle(ia);
-
/* Leave multicast groups. */
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
@@ -1333,6 +1330,7 @@
in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
{
char ip6buf[INET6_ADDRSTRLEN];
+ int remove_lle;
IF_ADDR_WLOCK(ifp);
TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
@@ -1353,15 +1351,21 @@
* Release the reference to the base prefix. There should be a
* positive reference.
*/
+ remove_lle = 0;
if (ia->ia6_ndpr == NULL) {
nd6log((LOG_NOTICE,
"in6_unlink_ifa: autoconf'ed address "
"%s has no prefix\n", ip6_sprintf(ip6buf, IA6_IN6(ia))));
} else {
ia->ia6_ndpr->ndpr_refcnt--;
+ /* Do not delete lles within prefix if refcont != 0 */
+ if (ia->ia6_ndpr->ndpr_refcnt == 0)
+ remove_lle = 1;
ia->ia6_ndpr = NULL;
}
+ nd6_rem_ifa_lle(ia, remove_lle);
+
/*
* Also, if the address being removed is autoconf'ed, call
* pfxlist_onlink_check() since the release might affect the status of
@@ -2081,15 +2085,33 @@
}
static int
-in6_lltable_match_prefix(const struct sockaddr *prefix,
- const struct sockaddr *mask, u_int flags, struct llentry *lle)
+in6_lltable_match_prefix(const struct sockaddr *saddr,
+ const struct sockaddr *smask, u_int flags, struct llentry *lle)
{
- const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
- const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
+ const struct in6_addr *addr, *mask, *lle_addr;
+
+ addr = &((const struct sockaddr_in6 *)saddr)->sin6_addr;
+ mask = &((const struct sockaddr_in6 *)smask)->sin6_addr;
+ lle_addr = &lle->r_l3addr.addr6;
+
+ if (IN6_ARE_MASKED_ADDR_EQUAL(lle_addr, addr, mask) == 0)
+ return (0);
+
+ if (lle->la_flags & LLE_IFADDR) {
+
+ /*
+ * Delete LLE_IFADDR records IFF address & flag matches.
+ * Note that addr is the interface address within prefix
+ * being matched.
+ */
+ if (IN6_ARE_ADDR_EQUAL(addr, lle_addr) &&
+ (flags & LLE_STATIC) != 0)
+ return (1);
+ return (0);
+ }
- if (IN6_ARE_MASKED_ADDR_EQUAL(&lle->r_l3addr.addr6,
- &pfx->sin6_addr, &msk->sin6_addr) &&
- ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
+ /* flags & LLE_STATIC means deleting both dynamic and static entries */
+ if ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))
return (1);
return (0);
@@ -2200,36 +2222,16 @@
return (lle);
}
-static int
-in6_lltable_delete(struct lltable *llt, u_int flags,
- const struct sockaddr *l3addr)
+static void
+in6_lltable_delete_entry(struct lltable *llt, struct llentry *lle)
{
- const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
- struct llentry *lle;
-
- IF_AFDATA_LOCK_ASSERT(llt->llt_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);
+ 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);
- }
-
- return (0);
+ llentry_free(lle);
}
static struct llentry *
@@ -2369,7 +2371,7 @@
llt->llt_lookup = in6_lltable_lookup;
llt->llt_alloc_entry = in6_lltable_alloc;
- llt->llt_delete = in6_lltable_delete;
+ llt->llt_delete_entry = in6_lltable_delete_entry;
llt->llt_dump_entry = in6_lltable_dump_entry;
llt->llt_hash = in6_lltable_hash;
llt->llt_fill_sa_entry = in6_lltable_fill_sa_entry;
Index: head/sys/netinet6/nd6.h
===================================================================
--- head/sys/netinet6/nd6.h
+++ head/sys/netinet6/nd6.h
@@ -427,7 +427,7 @@
struct sockaddr_in6 *);
int nd6_need_cache(struct ifnet *);
int nd6_add_ifa_lle(struct in6_ifaddr *);
-void nd6_rem_ifa_lle(struct in6_ifaddr *);
+void nd6_rem_ifa_lle(struct in6_ifaddr *, int);
int nd6_storelladdr(struct ifnet *, struct mbuf *,
const struct sockaddr *, u_char *, uint32_t *);
Index: head/sys/netinet6/nd6.c
===================================================================
--- head/sys/netinet6/nd6.c
+++ head/sys/netinet6/nd6.c
@@ -2245,23 +2245,26 @@
}
/*
- * Removes ALL lle records for interface address prefix.
- * XXXME: That's probably not we really want to do, we need
- * to remove address record only and keep other records
- * until we determine if given prefix is really going
- * to be removed.
+ * Removes either all lle entries for given @ia, or lle
+ * corresponding to @ia address.
*/
void
-nd6_rem_ifa_lle(struct in6_ifaddr *ia)
+nd6_rem_ifa_lle(struct in6_ifaddr *ia, int all)
{
struct sockaddr_in6 mask, addr;
+ struct sockaddr *saddr, *smask;
struct ifnet *ifp;
ifp = ia->ia_ifa.ifa_ifp;
memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr));
memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask));
- lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr,
- (struct sockaddr *)&mask, LLE_STATIC);
+ saddr = (struct sockaddr *)&addr;
+ smask = (struct sockaddr *)&mask;
+
+ if (all != 0)
+ lltable_prefix_free(AF_INET6, saddr, smask, LLE_STATIC);
+ else
+ lltable_delete_addr(LLTABLE6(ifp), LLE_IFADDR, saddr);
}
/*
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 22, 2:10 AM (7 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25870840
Default Alt Text
D3573.id8745.diff (17 KB)
Attached To
Mode
D3573: Rework lle deletion process.
Attached
Detach File
Event Timeline
Log In to Comment