summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/uts/common/inet/ip.h11
-rw-r--r--usr/src/uts/common/inet/ip/ip_if.c54
-rw-r--r--usr/src/uts/common/inet/ip/ip_ire.c8
3 files changed, 48 insertions, 25 deletions
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index 3199a40bcb..5e4f19b23e 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -1429,10 +1429,13 @@ typedef struct ill_lso_capab_s ill_lso_capab_t;
#define ILL_LL_SUBNET_PENDING 0x01 /* Waiting for DL_INFO_ACK from drv */
#define ILL_CONDEMNED 0x02 /* No more new ref's to the ILL */
#define ILL_DL_UNBIND_IN_PROGRESS 0x04 /* UNBIND_REQ is sent */
-#define ILL_DOWN_IN_PROGRESS 0x08 /* ILL is going down - no new nce's */
-#define ILL_LL_BIND_PENDING 0x0020 /* XXX Reuse ILL_LL_SUBNET_PENDING ? */
-#define ILL_LL_UP 0x0040
-#define ILL_LL_DOWN 0x0080
+/*
+ * ILL_DOWN_IN_PROGRESS is set to ensure the following:
+ * - no packets are sent to the driver after the DL_UNBIND_REQ is sent,
+ * - no longstanding references will be acquired on objects that are being
+ * brought down.
+ */
+#define ILL_DOWN_IN_PROGRESS 0x08
/* Is this an ILL whose source address is used by other ILL's ? */
#define IS_USESRC_ILL(ill) \
diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c
index 5887e28c6b..aeda90fef6 100644
--- a/usr/src/uts/common/inet/ip/ip_if.c
+++ b/usr/src/uts/common/inet/ip/ip_if.c
@@ -1117,11 +1117,6 @@ ill_down_start(queue_t *q, mblk_t *mp)
ipif_t *ipif;
ASSERT(IAM_WRITER_ILL(ill));
- mutex_enter(&ill->ill_lock);
- ill->ill_state_flags |= ILL_DOWN_IN_PROGRESS;
- /* no more nce addition allowed */
- mutex_exit(&ill->ill_lock);
-
/*
* It is possible that some ioctl is already in progress while we
* received the M_ERROR / M_HANGUP in which case, we need to abort
@@ -13295,6 +13290,22 @@ ipif_down(ipif_t *ipif, queue_t *q, mblk_t *mp)
}
/*
+ * Removal of the last ipif from an ill may result in a DL_UNBIND
+ * being sent to the driver, and we must not send any data packets to
+ * the driver after the DL_UNBIND_REQ. To ensure this, all the
+ * ire and nce entries used in the data path will be cleaned
+ * up, and we also set the ILL_DOWN_IN_PROGRESS bit to make
+ * sure on new entries will be added until the ill is bound
+ * again. The ILL_DOWN_IN_PROGRESS bit is turned off upon
+ * receipt of a DL_BIND_ACK.
+ */
+ if (ill->ill_wq != NULL && !ill->ill_logical_down &&
+ ill->ill_ipif_up_count == 0 && ill->ill_ipif_dup_count == 0 &&
+ ill->ill_dl_up) {
+ ill->ill_state_flags |= ILL_DOWN_IN_PROGRESS;
+ }
+
+ /*
* Blow away memberships we established in ipif_multicast_up().
*/
ipif_multicast_down(ipif);
@@ -13599,6 +13610,7 @@ ipif_lookup_on_name(char *name, size_t namelen, boolean_t do_alloc,
ipif_t *ipif;
uint_t ire_type;
boolean_t did_alloc = B_FALSE;
+ char last;
/*
* If the caller wants to us to create the ipif, make sure we have a
@@ -13639,9 +13651,9 @@ ipif_lookup_on_name(char *name, size_t namelen, boolean_t do_alloc,
if (cp <= name) {
cp = endp;
- } else {
- *cp = '\0';
}
+ last = *cp;
+ *cp = '\0';
/*
* Look up the ILL, based on the portion of the name
@@ -13651,8 +13663,7 @@ ipif_lookup_on_name(char *name, size_t namelen, boolean_t do_alloc,
*/
ill = ill_lookup_on_name(name, do_alloc, isv6,
&did_alloc, ipst);
- if (cp != endp)
- *cp = IPIF_SEPARATOR_CHAR;
+ *cp = last;
if (ill == NULL)
return (NULL);
@@ -17733,9 +17744,16 @@ ill_set_phys_addr(ill_t *ill, mblk_t *mp)
}
ipsq_current_start(ipsq, ill->ill_ipif, 0);
+
+ /*
+ * Since we'll only do a logical down, we can't rely on ipif_down
+ * to turn on ILL_DOWN_IN_PROGRESS, or for the DL_BIND_ACK to reset
+ * ILL_DOWN_IN_PROGRESS. We instead manage this separately for this
+ * case, to quiesce ire's and nce's for ill_is_quiescent.
+ */
mutex_enter(&ill->ill_lock);
ill->ill_state_flags |= ILL_DOWN_IN_PROGRESS;
- /* no more nce addition allowed */
+ /* no more ire/nce addition allowed */
mutex_exit(&ill->ill_lock);
/*
@@ -17817,16 +17835,19 @@ ill_set_phys_addr_tail(ipsq_t *ipsq, queue_t *q, mblk_t *addrmp, void *dummy)
}
/*
+ * reset ILL_DOWN_IN_PROGRESS so that we can successfully add ires
+ * as we bring the ipifs up again.
+ */
+ mutex_enter(&ill->ill_lock);
+ ill->ill_state_flags &= ~ILL_DOWN_IN_PROGRESS;
+ mutex_exit(&ill->ill_lock);
+ /*
* If there are ipifs to bring up, ill_up_ipifs() will return
* EINPROGRESS, and ipsq_current_finish() will be called by
* ip_rput_dlpi_writer() or arp_bringup_done() when the last ipif is
* brought up.
*/
status = ill_up_ipifs(ill, q, addrmp);
- mutex_enter(&ill->ill_lock);
- if (ill->ill_dl_up)
- ill->ill_state_flags &= ~ILL_DOWN_IN_PROGRESS;
- mutex_exit(&ill->ill_lock);
if (status != EINPROGRESS)
ipsq_current_finish(ipsq);
}
@@ -17855,11 +17876,6 @@ ill_replumb(ill_t *ill, mblk_t *mp)
ipsq_current_start(ipsq, ill->ill_ipif, 0);
- mutex_enter(&ill->ill_lock);
- ill->ill_state_flags |= ILL_DOWN_IN_PROGRESS;
- /* no more nce addition allowed */
- mutex_exit(&ill->ill_lock);
-
/*
* If we can quiesce the ill, then continue. If not, then
* ill_replumb_tail() will be called from ipif_ill_refrele_tail().
diff --git a/usr/src/uts/common/inet/ip/ip_ire.c b/usr/src/uts/common/inet/ip/ip_ire.c
index 16b3b50380..88c104909c 100644
--- a/usr/src/uts/common/inet/ip/ip_ire.c
+++ b/usr/src/uts/common/inet/ip/ip_ire.c
@@ -1117,10 +1117,14 @@ ire_atomic_start(irb_t *irb_ptr, ire_t *ire)
mutex_enter(&ill->ill_lock);
/*
- * Don't allow IRE's to be created on dying ills.
+ * Don't allow IRE's to be created on dying ills, or on
+ * ill's for which the last ipif is going down, or ones which
+ * don't have even a single UP interface
*/
- if (ill->ill_state_flags & ILL_CONDEMNED) {
+ if ((ill->ill_state_flags &
+ (ILL_CONDEMNED|ILL_DOWN_IN_PROGRESS)) != 0) {
ire_atomic_end(irb_ptr, ire);
+ DTRACE_PROBE1(ire__add__on__dying__ill, ire_t *, ire);
return (ENXIO);
}