summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSowmini Varadhan <Sowmini.Varadhan@Sun.COM>2009-05-07 20:59:19 -0400
committerSowmini Varadhan <Sowmini.Varadhan@Sun.COM>2009-05-07 20:59:19 -0400
commit3efde6d032b3bcd6957e912c3f2a59253f28a9dc (patch)
treee31ab073589d1ffc6df0d74d9b18d54e40d87654
parent19b41302109b7a894f3f97e06ca4a0222a238b14 (diff)
downloadillumos-joyent-3efde6d032b3bcd6957e912c3f2a59253f28a9dc.tar.gz
6834698 IPv6 point-to-point ipifs can no longer share source addresses
6834157 libdladm leaks memory in dladm_get_single_mac_stat()
-rw-r--r--usr/src/lib/libdladm/common/libdlstat.c10
-rw-r--r--usr/src/uts/common/inet/ip.h2
-rw-r--r--usr/src/uts/common/inet/ip/ip6_if.c36
-rw-r--r--usr/src/uts/common/inet/ip_ndp.h6
4 files changed, 37 insertions, 17 deletions
diff --git a/usr/src/lib/libdladm/common/libdlstat.c b/usr/src/lib/libdladm/common/libdlstat.c
index b4c2c38692..e69c9d8934 100644
--- a/usr/src/lib/libdladm/common/libdlstat.c
+++ b/usr/src/lib/libdladm/common/libdlstat.c
@@ -654,11 +654,6 @@ dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid,
kstat_t *ksp;
dladm_phys_attr_t dpap;
- if ((kcp = kstat_open()) == NULL) {
- warn("kstat_open operation failed");
- return (-1);
- }
-
if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
&media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK)
return (status);
@@ -676,6 +671,11 @@ dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid,
if (status != DLADM_STATUS_OK)
return (status);
+ if ((kcp = kstat_open()) == NULL) {
+ warn("kstat_open operation failed");
+ return (-1);
+ }
+
/*
* The kstat query could fail if the underlying MAC
* driver was already detached.
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index f39eff0246..0b2b70c5be 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -1278,7 +1278,7 @@ typedef struct ipif_s {
ipif_was_dup : 1, /* DAD had failed */
ipif_joined_allhosts : 1, /* allhosts joined */
- ipif_added_nce:1, /* nce added for local address */
+ ipif_added_nce : 1, /* nce added for local address */
ipif_pad_to_31 : 26;
uint_t ipif_seqid; /* unique index across all ills */
diff --git a/usr/src/uts/common/inet/ip/ip6_if.c b/usr/src/uts/common/inet/ip/ip6_if.c
index 92c1eed048..b592fc0cd1 100644
--- a/usr/src/uts/common/inet/ip/ip6_if.c
+++ b/usr/src/uts/common/inet/ip/ip6_if.c
@@ -1586,17 +1586,34 @@ ipif_ndp_up(ipif_t *ipif, boolean_t initial)
ill->ill_name));
ipif->ipif_addr_ready = 1;
ipif->ipif_added_nce = 1;
+ nce->nce_ipif_cnt++;
break;
case EINPROGRESS:
ip1dbg(("ipif_ndp_up: running DAD now for %s\n",
ill->ill_name));
ipif->ipif_added_nce = 1;
+ nce->nce_ipif_cnt++;
break;
case EEXIST:
- NCE_REFRELE(nce);
ip1dbg(("ipif_ndp_up: NCE already exists for %s\n",
ill->ill_name));
- goto fail;
+ if ((ipif->ipif_flags & IPIF_POINTOPOINT) == 0) {
+ NCE_REFRELE(nce);
+ goto fail;
+ }
+ /*
+ * Duplicate local addresses are permissible for
+ * IPIF_POINTOPOINT interfaces which will get marked
+ * IPIF_UNNUMBERED later in
+ * ip_addr_availability_check().
+ *
+ * The nce_ipif_cnt field tracks the number of
+ * ipifs that have nce_addr as their local address.
+ */
+ ipif->ipif_addr_ready = 1;
+ ipif->ipif_added_nce = 1;
+ nce->nce_ipif_cnt++;
+ break;
default:
ip1dbg(("ipif_ndp_up: NCE creation failed for %s\n",
ill->ill_name));
@@ -1644,13 +1661,14 @@ ipif_ndp_down(ipif_t *ipif)
B_TRUE,
&ipif->ipif_v6lcl_addr,
B_FALSE);
- if (nce != NULL) {
- ndp_delete(nce);
- NCE_REFRELE(nce);
- }
+ if (nce == NULL)
+ goto no_nce;
+ if (--nce->nce_ipif_cnt == 0)
+ ndp_delete(nce); /* last ipif for nce */
ipif->ipif_added_nce = 0;
+ NCE_REFRELE(nce);
}
-
+no_nce:
/*
* Make IPMP aware of the deleted data address.
*/
@@ -3221,8 +3239,8 @@ ipif_up_done_v6(ipif_t *ipif)
* which is the expected error code.
*
* Note that, for the non-XRESOLV case, ipif_ndp_down() will
- * only delete an nce in the case when one was actually created
- * by ipif_ndp_up(), as indicated by the ipif_added_nce bit.
+ * only delete the nce in the case when the nce_ipif_cnt drops
+ * to 0.
*/
if (err == EADDRINUSE) {
if (ipif->ipif_ill->ill_flags & ILLF_XRESOLV) {
diff --git a/usr/src/uts/common/inet/ip_ndp.h b/usr/src/uts/common/inet/ip_ndp.h
index 2211e52c2b..c1a48b1f1a 100644
--- a/usr/src/uts/common/inet/ip_ndp.h
+++ b/usr/src/uts/common/inet/ip_ndp.h
@@ -96,6 +96,8 @@ typedef struct nce_s {
boolean_t nce_trace_disable; /* True when alloc fails */
list_t nce_cb;
uint_t nce_cb_walker_cnt;
+ uint_t nce_ipif_cnt; /* number of ipifs with the nce_addr */
+ /* as their local address */
} nce_t;
/*
@@ -113,8 +115,8 @@ typedef struct nce_s {
* Locking notes:
* ndp_g_lock protects neighbor cache tables access and
* insertion/removal of cache entries into/from these tables.
- * nce_lock protects nce_pcnt, nce_rcnt, nce_qd_mp nce_state,
- * nce_res_mp, nce_refcnt and nce_last.
+ * nce_lock protects nce_pcnt, nce_rcnt, nce_qd_mp nce_state, nce_res_mp,
+ * nce_refcnt, nce_last, and nce_cb_walker_cnt.
* nce_refcnt is incremented for every ire pointing to this nce and
* every time ndp_lookup() finds an nce.
* Should there be a need to obtain nce_lock and ndp_g_lock, ndp_g_lock is