Print this page
Warning about DCE lifetimes
coyright fix
gdamore's feedback
7185 IP DCEs leak from halted non-global zones
@@ -20,10 +20,11 @@
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright 2017, OmniTI Computer Consulting, Inc. All rights reserved.
*/
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/strsun.h>
@@ -88,10 +89,14 @@
* return failure;
* }
*
* Note that for IPv6 link-local addresses we record the ifindex since the
* link-locals are not globally unique.
+ *
+ * DCEs can remain for an arbitrarily long time, until memory pressure or
+ * too-deep hash buckets (see dce_lookup_and_add*()) enable the reclaim thread
+ * to actually remove DCEs from the cache.
*/
/*
* Hash bucket structure for DCEs
*/
@@ -324,16 +329,41 @@
rw_init(&ipst->ips_dce_hash_v6[i].dcb_lock, NULL, RW_DEFAULT,
NULL);
}
}
+/*
+ * Given a DCE hash bucket, unlink DCE entries from it. Some callers need
+ * ifindex-specific matching, others don't. Don't overload ifindex to indicate
+ * specificity, just indicate so explicitly.
+ */
+static void
+dce_bucket_clean(dcb_t *dcb, boolean_t specific_ifindex, uint_t ifindex)
+{
+ dce_t *dce, *nextdce;
+
+ rw_enter(&dcb->dcb_lock, RW_WRITER);
+
+ for (dce = dcb->dcb_dce; dce != NULL; dce = nextdce) {
+ nextdce = dce->dce_next;
+ if ((!specific_ifindex) || dce->dce_ifindex == ifindex) {
+ dce_delete_locked(dcb, dce);
+ dce_refrele(dce);
+ }
+ }
+
+ rw_exit(&dcb->dcb_lock);
+}
+
void
dce_stack_destroy(ip_stack_t *ipst)
{
int i;
for (i = 0; i < ipst->ips_dce_hashsize; i++) {
+ dce_bucket_clean(&ipst->ips_dce_hash_v4[i], B_FALSE, 0);
rw_destroy(&ipst->ips_dce_hash_v4[i].dcb_lock);
+ dce_bucket_clean(&ipst->ips_dce_hash_v6[i], B_FALSE, 0);
rw_destroy(&ipst->ips_dce_hash_v6[i].dcb_lock);
}
kmem_free(ipst->ips_dce_hash_v4,
ipst->ips_dce_hashsize * sizeof (dcb_t));
ipst->ips_dce_hash_v4 = NULL;
@@ -953,22 +983,9 @@
*/
void
dce_cleanup(uint_t ifindex, ip_stack_t *ipst)
{
uint_t i;
- dcb_t *dcb;
- dce_t *dce, *nextdce;
- for (i = 0; i < ipst->ips_dce_hashsize; i++) {
- dcb = &ipst->ips_dce_hash_v6[i];
- rw_enter(&dcb->dcb_lock, RW_WRITER);
-
- for (dce = dcb->dcb_dce; dce != NULL; dce = nextdce) {
- nextdce = dce->dce_next;
- if (dce->dce_ifindex == ifindex) {
- dce_delete_locked(dcb, dce);
- dce_refrele(dce);
- }
- }
- rw_exit(&dcb->dcb_lock);
- }
+ for (i = 0; i < ipst->ips_dce_hashsize; i++)
+ dce_bucket_clean(&ipst->ips_dce_hash_v6[i], B_TRUE, ifindex);
}