diff options
Diffstat (limited to 'usr/src/uts/common/inet')
-rw-r--r-- | usr/src/uts/common/inet/ip.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip6_if.c | 36 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip_ndp.h | 6 |
3 files changed, 32 insertions, 12 deletions
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 |