diff options
| author | georges <none@none> | 2008-05-30 10:00:54 -0700 |
|---|---|---|
| committer | georges <none@none> | 2008-05-30 10:00:54 -0700 |
| commit | 0a5d959f9c1912b74a08b175147e350039f161f9 (patch) | |
| tree | 4c323e54685b6d64b188c793edf2919d1108586a /usr/src | |
| parent | f9b62eacbfd4012fd23fb60123be899ada20c450 (diff) | |
| download | illumos-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.h | 14 | ||||
| -rw-r--r-- | usr/src/uts/common/inet/ip/ip.c | 8 | ||||
| -rw-r--r-- | usr/src/uts/common/inet/ip/ip6.c | 8 | ||||
| -rw-r--r-- | usr/src/uts/common/inet/ip/ip_if.c | 14 |
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); |
