summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorgeorges <none@none>2008-05-30 10:00:54 -0700
committergeorges <none@none>2008-05-30 10:00:54 -0700
commit0a5d959f9c1912b74a08b175147e350039f161f9 (patch)
tree4c323e54685b6d64b188c793edf2919d1108586a /usr/src
parentf9b62eacbfd4012fd23fb60123be899ada20c450 (diff)
downloadillumos-joyent-0a5d959f9c1912b74a08b175147e350039f161f9.tar.gz
6637163 ip_rput_fragment[_v6]() spuriously prunes valid frags due to unbounded inaccuracy of ill_frag_count
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/inet/ip.h14
-rw-r--r--usr/src/uts/common/inet/ip/ip.c8
-rw-r--r--usr/src/uts/common/inet/ip/ip6.c8
-rw-r--r--usr/src/uts/common/inet/ip/ip_if.c14
4 files changed, 16 insertions, 28 deletions
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index 9f55db6fb1..56b70f94f7 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -1895,17 +1895,9 @@ typedef struct ill_s {
*/
hook_nic_event_t *ill_nic_event_info;
- /*
- * Used for IP frag reassembly throttling on a per ILL basis.
- *
- * Note: frag_count is approximate, its added to and subtracted from
- * without any locking, so simultaneous load/modify/stores can
- * collide, also ill_frag_purge() recalculates its value by
- * summing all the ipfb_count's without locking out updates
- * to the ipfb's.
- */
+ /* Used for IP frag reassembly throttling on a per ILL basis. */
uint_t ill_ipf_gen; /* Generation of next fragment queue */
- uint_t ill_frag_count; /* Approx count of all mblk bytes */
+ uint_t ill_frag_count; /* Count of all reassembly mblk bytes */
uint_t ill_frag_free_num_pkts; /* num of fragmented packets to free */
clock_t ill_last_frag_clean_time; /* time when frag's were pruned */
int ill_type; /* From <net/if_types.h> */
@@ -2076,7 +2068,7 @@ typedef struct ill_s {
* ill_ip_muxid ipsq Not atomic
*
* ill_ipf_gen Not atomic
- * ill_frag_count Approx. not protected
+ * ill_frag_count atomics atomics
* ill_type ipsq + down ill only when ill is up
* ill_dlpi_multicast_state ill_lock ill_lock
* ill_dlpi_fastpath_state ill_lock ill_lock
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index 9bc7c17dd3..e606388752 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -12470,7 +12470,7 @@ reass_done:
/* Update per ipfb and ill byte counts */
ipfb->ipfb_count += ipf->ipf_count;
ASSERT(ipfb->ipfb_count > 0); /* Wraparound */
- ill->ill_frag_count += ipf->ipf_count;
+ atomic_add_32(&ill->ill_frag_count, ipf->ipf_count);
/* If the frag timer wasn't already going, start it. */
mutex_enter(&ill->ill_lock);
ill_frag_timer_start(ill);
@@ -12516,7 +12516,7 @@ reass_done:
/* Update per ipfb and ill byte counts */
ipfb->ipfb_count += msg_len;
ASSERT(ipfb->ipfb_count > 0); /* Wraparound */
- ill->ill_frag_count += msg_len;
+ atomic_add_32(&ill->ill_frag_count, msg_len);
if (frag_offset_flags & IPH_MF) {
/* More to come. */
ipf->ipf_end = end;
@@ -12541,7 +12541,7 @@ reass_done:
/* Update per ipfb and ill byte counts */
ipfb->ipfb_count += count;
ASSERT(ipfb->ipfb_count > 0); /* Wraparound */
- ill->ill_frag_count += count;
+ atomic_add_32(&ill->ill_frag_count, count);
}
if (ret == IP_REASS_PARTIAL) {
goto reass_done;
@@ -12580,7 +12580,7 @@ reass_done:
if (ipf != NULL)
ipf->ipf_ptphn = ipfp;
ipfp[0] = ipf;
- ill->ill_frag_count -= count;
+ atomic_add_32(&ill->ill_frag_count, -count);
ASSERT(ipfb->ipfb_count >= count);
ipfb->ipfb_count -= count;
ipfb->ipfb_frag_pkts--;
diff --git a/usr/src/uts/common/inet/ip/ip6.c b/usr/src/uts/common/inet/ip/ip6.c
index 622b33d65f..382944a369 100644
--- a/usr/src/uts/common/inet/ip/ip6.c
+++ b/usr/src/uts/common/inet/ip/ip6.c
@@ -8738,7 +8738,7 @@ ip_rput_frag_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h,
/* Update per ipfb and ill byte counts */
ipfb->ipfb_count += ipf->ipf_count;
ASSERT(ipfb->ipfb_count > 0); /* Wraparound */
- ill->ill_frag_count += ipf->ipf_count;
+ atomic_add_32(&ill->ill_frag_count, ipf->ipf_count);
/* If the frag timer wasn't already going, start it. */
mutex_enter(&ill->ill_lock);
ill_frag_timer_start(ill);
@@ -8785,7 +8785,7 @@ ip_rput_frag_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h,
/* Update per ipfb and ill byte counts */
ipfb->ipfb_count += msg_len;
ASSERT(ipfb->ipfb_count > 0); /* Wraparound */
- ill->ill_frag_count += msg_len;
+ atomic_add_32(&ill->ill_frag_count, msg_len);
if (more_frags) {
/* More to come. */
ipf->ipf_end = end;
@@ -8816,7 +8816,7 @@ ip_rput_frag_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h,
/* Update per ipfb and ill byte counts */
ipfb->ipfb_count += count;
ASSERT(ipfb->ipfb_count > 0); /* Wraparound */
- ill->ill_frag_count += count;
+ atomic_add_32(&ill->ill_frag_count, count);
}
if (ret == IP_REASS_PARTIAL) {
goto partial_reass_done;
@@ -8869,7 +8869,7 @@ ip_rput_frag_v6(queue_t *q, mblk_t *mp, ip6_t *ip6h,
if (ipf)
ipf->ipf_ptphn = ipfp;
ipfp[0] = ipf;
- ill->ill_frag_count -= count;
+ atomic_add_32(&ill->ill_frag_count, -count);
ASSERT(ipfb->ipfb_count >= count);
ipfb->ipfb_count -= count;
ipfb->ipfb_frag_pkts--;
diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c
index 91fdbb2adf..4ced342a60 100644
--- a/usr/src/uts/common/inet/ip/ip_if.c
+++ b/usr/src/uts/common/inet/ip/ip_if.c
@@ -3659,7 +3659,7 @@ ill_frag_timeout(ill_t *ill, time_t dead_interval)
IP_REASS_SET_END(mp, 0);
}
mp = ipf->ipf_mp->b_cont;
- ill->ill_frag_count -= ipf->ipf_count;
+ atomic_add_32(&ill->ill_frag_count, -ipf->ipf_count);
ASSERT(ipfb->ipfb_count >= ipf->ipf_count);
ipfb->ipfb_count -= ipf->ipf_count;
ASSERT(ipfb->ipfb_frag_pkts > 0);
@@ -3792,8 +3792,7 @@ ill_frag_prune(ill_t *ill, uint_t max_count)
}
/*
* While the reassembly list for this ILL is too big, prune a fragment
- * queue by age, oldest first. Note that the per ILL count is
- * approximate, while the per frag hash bucket counts are accurate.
+ * queue by age, oldest first.
*/
while (ill->ill_frag_count > max_count) {
int ix;
@@ -3812,12 +3811,9 @@ ill_frag_prune(ill_t *ill, uint_t max_count)
count += ipfb->ipfb_count;
mutex_exit(&ipfb->ipfb_lock);
}
- /* Refresh the per ILL count */
- ill->ill_frag_count = count;
- if (oipfb == NULL) {
- ill->ill_frag_count = 0;
+ if (oipfb == NULL)
break;
- }
+
if (count <= max_count)
return; /* Somebody beat us to it, nothing to do */
mutex_enter(&oipfb->ipfb_lock);
@@ -3852,7 +3848,7 @@ ill_frag_free_pkts(ill_t *ill, ipfb_t *ipfb, ipf_t *ipf, int free_cnt)
IP_REASS_SET_START(tmp, 0);
IP_REASS_SET_END(tmp, 0);
}
- ill->ill_frag_count -= count;
+ atomic_add_32(&ill->ill_frag_count, -count);
ASSERT(ipfb->ipfb_count >= count);
ipfb->ipfb_count -= count;
ASSERT(ipfb->ipfb_frag_pkts > 0);