changeset 3772:b3393c8d9cc3

6523767 off-link hosts often rendered unreachable under IPMP
author sangeeta
date Wed, 07 Mar 2007 09:31:31 -0800
parents fa0dd56c3b50
children 19ce51f14e6a
files usr/src/uts/common/inet/ip/ip_ire.c usr/src/uts/common/inet/ip/ip_ndp.c usr/src/uts/common/inet/ip_ire.h
diffstat 3 files changed, 43 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip/ip_ire.c	Wed Mar 07 02:40:53 2007 -0800
+++ b/usr/src/uts/common/inet/ip/ip_ire.c	Wed Mar 07 09:31:31 2007 -0800
@@ -73,6 +73,7 @@
 
 #include <sys/tsol/label.h>
 #include <sys/tsol/tnet.h>
+#include <sys/dlpi.h>
 
 struct kmem_cache *rt_entry_cache;
 
@@ -6704,6 +6705,31 @@
 	kmem_free(ire_mp, sizeof (ire_t) + sizeof (frtn_t));
 }
 
+/*
+ * The mp passed to this function is typically res_mp.
+ * Note that res_mp field can contain the request (ie AR_ENTRY_QUERY)
+ * or the response (ie DL_UNITDATA_REQ). So in case of the
+ * forwarding path, there is a small window of time between the two
+ * when the forwarding path creates an unresolved nce and the
+ * ip_newroute path finds this and uses this in the creation of an
+ * ire cache. To account for this possible race case we we check
+ * for DL_UNITDATA_REQ to make sure this is indeed the response.
+ */
+boolean_t
+ire_nce_valid_dlureq_mp(mblk_t *mp)
+{
+	dl_unitdata_req_t *dlur;
+
+	if (mp == NULL)
+		return (B_FALSE);
+	dlur = (dl_unitdata_req_t *)mp->b_rptr;
+	if ((DB_TYPE(mp) == M_PROTO) &&
+	    (dlur->dl_primitive == DL_UNITDATA_REQ)) {
+		return (B_TRUE);
+	} else {
+		return (B_FALSE);
+	}
+}
 
 /*
  * create the neighbor cache entry  nce_t for  IRE_CACHE and
@@ -6777,10 +6803,15 @@
 		nce_state = ND_REACHABLE;
 		nce_flags = NCE_F_PERMANENT;
 	} else {
-		if (fp_mp != NULL)
+		/* Make sure you have the response and not the request. */
+		if (ire_nce_valid_dlureq_mp(res_mp)) {
 			nce_state = ND_REACHABLE;
-		else
+		} else {
 			nce_state = ND_INITIAL;
+			if (fp_mp)
+				freemsg(fp_mp);
+			fp_mp = NULL;
+		}
 		nce_flags = 0;
 	}
 
@@ -6818,8 +6849,9 @@
 	}
 #if DEBUG
 	/*
-	 * if an nce_fp_mp was passed in, we should be picking up an
-	 * existing nce_t in the ND_REACHABLE state.
+	 * If an nce_fp_mp was passed in by ndp_lookup_then_add()
+	 * we should be picking up an existing nce_t in
+	 * the ND_REACHABLE state.
 	 */
 	mutex_enter(&arpce->nce_lock);
 	ASSERT(arpce->nce_fp_mp == NULL || arpce->nce_state == ND_REACHABLE);
--- a/usr/src/uts/common/inet/ip/ip_ndp.c	Wed Mar 07 02:40:53 2007 -0800
+++ b/usr/src/uts/common/inet/ip/ip_ndp.c	Wed Mar 07 09:31:31 2007 -0800
@@ -3276,8 +3276,12 @@
 	int res;
 
 	ASSERT(ill != NULL);
-	if (nce->nce_fp_mp != NULL) {
-		/* Already contains fastpath info */
+	if ((nce->nce_fp_mp != NULL) ||
+	    !(ire_nce_valid_dlureq_mp(nce->nce_res_mp))) {
+		/*
+		 * Already contains fastpath info or nce is not
+		 * resolved, so cant process fastpath yet.
+		 */
 		return;
 	}
 	if (nce->nce_res_mp != NULL) {
--- a/usr/src/uts/common/inet/ip_ire.h	Wed Mar 07 02:40:53 2007 -0800
+++ b/usr/src/uts/common/inet/ip_ire.h	Wed Mar 07 09:31:31 2007 -0800
@@ -371,6 +371,7 @@
 extern boolean_t	ire_match_args(ire_t *, ipaddr_t, ipaddr_t, ipaddr_t,
     int, const ipif_t *, zoneid_t, uint32_t, const struct ts_label_s *, int);
 extern  int	ire_nce_init(ire_t *, mblk_t *, mblk_t *);
+extern  boolean_t	ire_nce_valid_dlureq_mp(mblk_t *);
 extern  boolean_t	ire_walk_ill_match(uint_t, uint_t, ire_t *, ill_t *,
     zoneid_t, ip_stack_t *);