[BACK]Return to ip_input.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/netinet/ip_input.c between version 1.189 and 1.195

version 1.189, 2003/12/04 19:38:24 version 1.195, 2003/12/14 01:14:24
Line 236  uint16_t ip_id;
Line 236  uint16_t ip_id;
 struct pfil_head inet_pfil_hook;  struct pfil_head inet_pfil_hook;
 #endif  #endif
   
 struct ipqhead ipq;  /*
    * Cached copy of nmbclusters. If nbclusters is different,
    * recalculate IP parameters derived from nmbclusters.
    */
   static int      ip_nmbclusters;                 /* copy of nmbclusters */
   static void     ip_nmbclusters_changed __P((void));     /* recalc limits */
   
   #define CHECK_NMBCLUSTER_PARAMS()                               \
   do {                                                            \
           if (__predict_false(ip_nmbclusters != nmbclusters))     \
                   ip_nmbclusters_changed();                       \
   } while (/*CONSTCOND*/0)
   
   /* IP datagram reassembly queues (hashed) */
   #define IPREASS_NHASH_LOG2      6
   #define IPREASS_NHASH           (1 << IPREASS_NHASH_LOG2)
   #define IPREASS_HMASK           (IPREASS_NHASH - 1)
   #define IPREASS_HASH(x,y) \
           (((((x) & 0xF) | ((((x) >> 8) & 0xF) << 4)) ^ (y)) & IPREASS_HMASK)
   struct ipqhead ipq[IPREASS_NHASH];
 int     ipq_locked;  int     ipq_locked;
 int     ip_nfragpackets = 0;  static int      ip_nfragpackets;        /* packets in reass queue */
 int     ip_maxfragpackets = 200;  static int      ip_nfrags;              /* total fragments in reass queues */
   
   int     ip_maxfragpackets = 200;        /* limit on packets. XXX sysctl */
   int     ip_maxfrags;                    /* limit on fragments. XXX sysctl */
   
   
   /*
    * Additive-Increase/Multiplicative-Decrease (AIMD) strategy for
    * IP reassembly queue buffer managment.
    *
    * We keep a count of total IP fragments (NB: not fragmented packets!)
    * awaiting reassembly (ip_nfrags) and a limit (ip_maxfrags) on fragments.
    * If ip_nfrags exceeds ip_maxfrags the limit, we drop half the
    * total fragments in  reassembly queues.This AIMD policy avoids
    * repeatedly deleting single packets under heavy fragmentation load
    * (e.g., from lossy NFS peers).
    */
   static u_int    ip_reass_ttl_decr __P((u_int ticks));
   static void     ip_reass_drophalf __P((void));
   
   
 static __inline int ipq_lock_try __P((void));  static __inline int ipq_lock_try __P((void));
 static __inline void ipq_unlock __P((void));  static __inline void ipq_unlock __P((void));
Line 339  struct mowner ip_tx_mowner = { "internet
Line 377  struct mowner ip_tx_mowner = { "internet
 #endif  #endif
   
 /*  /*
    * Compute IP limits derived from the value of nmbclusters.
    */
   static void
   ip_nmbclusters_changed(void)
   {
           ip_maxfrags = nmbclusters / 4;
           ip_nmbclusters =  nmbclusters;
   }
   
   /*
  * IP initialization: fill in IP protocol switch table.   * IP initialization: fill in IP protocol switch table.
  * All protocols not implemented in kernel go to raw IP protocol handler.   * All protocols not implemented in kernel go to raw IP protocol handler.
  */   */
Line 363  ip_init()
Line 411  ip_init()
                 if (pr->pr_domain->dom_family == PF_INET &&                  if (pr->pr_domain->dom_family == PF_INET &&
                     pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)                      pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW)
                         ip_protox[pr->pr_protocol] = pr - inetsw;                          ip_protox[pr->pr_protocol] = pr - inetsw;
         LIST_INIT(&ipq);  
           for (i = 0; i < IPREASS_NHASH; i++)
                   LIST_INIT(&ipq[i]);
   
         ip_id = time.tv_sec & 0xfffff;          ip_id = time.tv_sec & 0xfffff;
   
         ipintrq.ifq_maxlen = ipqmaxlen;          ipintrq.ifq_maxlen = ipqmaxlen;
           ip_nmbclusters_changed();
   
         TAILQ_INIT(&in_ifaddrhead);          TAILQ_INIT(&in_ifaddrhead);
         in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IFADDR,          in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, M_IFADDR,
             M_WAITOK, &in_ifaddrhash);              M_WAITOK, &in_ifaddrhash);
Line 437  ip_input(struct mbuf *m)
Line 491  ip_input(struct mbuf *m)
         int downmatch;          int downmatch;
         int checkif;          int checkif;
         int srcrt = 0;          int srcrt = 0;
           u_int hash;
 #ifdef FAST_IPSEC  #ifdef FAST_IPSEC
         struct m_tag *mtag;          struct m_tag *mtag;
         struct tdb_ident *tdbi;          struct tdb_ident *tdbi;
Line 561  ip_input(struct mbuf *m)
Line 616  ip_input(struct mbuf *m)
                         m_adj(m, len - m->m_pkthdr.len);                          m_adj(m, len - m->m_pkthdr.len);
         }          }
   
 #if defined(IPSEC) || defined(FAST_IPSEC)  #if defined(IPSEC)
         /* ipflow (IP fast forwarding) is not compatible with IPsec. */          /* ipflow (IP fast forwarding) is not compatible with IPsec. */
         m->m_flags &= ~M_CANFASTFWD;          m->m_flags &= ~M_CANFASTFWD;
 #else  #else
Line 795  ip_input(struct mbuf *m)
Line 850  ip_input(struct mbuf *m)
                         ipstat.ips_cantforward++;                          ipstat.ips_cantforward++;
                         goto bad;                          goto bad;
                 }                  }
   
                   /*
                    * Peek at the outbound SP for this packet to determine if
                    * it's a Fast Forward candidate.
                    */
                   mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
                   if (mtag != NULL)
                           m->m_flags &= ~M_CANFASTFWD;
                   else {
                           s = splsoftnet();
                           sp = ipsec4_checkpolicy(m, IPSEC_DIR_OUTBOUND,
                               (IP_FORWARDING |
                                (ip_directedbcast ? IP_ALLOWBROADCAST : 0)),
                               &error, NULL);
                           if (sp != NULL) {
                                   m->m_flags &= ~M_CANFASTFWD;
                                   KEY_FREESP(&sp);
                           }
                           splx(s);
                   }
 #endif  /* FAST_IPSEC */  #endif  /* FAST_IPSEC */
   
                 ip_forward(m, srcrt);                  ip_forward(m, srcrt);
Line 823  ours:
Line 898  ours:
                  * of this datagram.                   * of this datagram.
                  */                   */
                 IPQ_LOCK();                  IPQ_LOCK();
                 LIST_FOREACH(fp, &ipq, ipq_q)                  hash = IPREASS_HASH(ip->ip_src.s_addr, ip->ip_id);
                   /* XXX LIST_FOREACH(fp, &ipq[hash], ipq_q) */
                   for (fp = LIST_FIRST(&ipq[hash]); fp != NULL;
                        fp = LIST_NEXT(fp, ipq_q)) {
                         if (ip->ip_id == fp->ipq_id &&                          if (ip->ip_id == fp->ipq_id &&
                             in_hosteq(ip->ip_src, fp->ipq_src) &&                              in_hosteq(ip->ip_src, fp->ipq_src) &&
                             in_hosteq(ip->ip_dst, fp->ipq_dst) &&                              in_hosteq(ip->ip_dst, fp->ipq_dst) &&
                             ip->ip_p == fp->ipq_p)                              ip->ip_p == fp->ipq_p)
                                 goto found;                                  goto found;
   
                   }
                 fp = 0;                  fp = 0;
 found:  found:
   
Line 869  found:
Line 949  found:
                         ipqe->ipqe_mff = mff;                          ipqe->ipqe_mff = mff;
                         ipqe->ipqe_m = m;                          ipqe->ipqe_m = m;
                         ipqe->ipqe_ip = ip;                          ipqe->ipqe_ip = ip;
                         m = ip_reass(ipqe, fp);                          m = ip_reass(ipqe, fp, &ipq[hash]);
                         if (m == 0) {                          if (m == 0) {
                                 IPQ_UNLOCK();                                  IPQ_UNLOCK();
                                 return;                                  return;
Line 966  badcsum:
Line 1046  badcsum:
  * is given as fp; otherwise have to make a chain.   * is given as fp; otherwise have to make a chain.
  */   */
 struct mbuf *  struct mbuf *
 ip_reass(ipqe, fp)  ip_reass(ipqe, fp, ipqhead)
         struct ipqent *ipqe;          struct ipqent *ipqe;
         struct ipq *fp;          struct ipq *fp;
           struct ipqhead *ipqhead;
 {  {
         struct mbuf *m = ipqe->ipqe_m;          struct mbuf *m = ipqe->ipqe_m;
         struct ipqent *nq, *p, *q;          struct ipqent *nq, *p, *q;
Line 986  ip_reass(ipqe, fp)
Line 1067  ip_reass(ipqe, fp)
         m->m_data += hlen;          m->m_data += hlen;
         m->m_len -= hlen;          m->m_len -= hlen;
   
   #ifdef  notyet
           /* make sure fragment limit is up-to-date */
           CHECK_NMBCLUSTER_PARAMS();
   
           /* If we have too many fragments, drop the older half. */
           if (ip_nfrags >= ip_maxfrags)
                   ip_reass_drophalf(void);
   #endif
   
           /*
            * We are about to add a fragment; increment frag count.
            */
           ip_nfrags++;
   
         /*          /*
          * If first fragment to arrive, create a reassembly queue.           * If first fragment to arrive, create a reassembly queue.
          */           */
Line 1005  ip_reass(ipqe, fp)
Line 1100  ip_reass(ipqe, fp)
                     M_FTABLE, M_NOWAIT);                      M_FTABLE, M_NOWAIT);
                 if (fp == NULL)                  if (fp == NULL)
                         goto dropfrag;                          goto dropfrag;
                 LIST_INSERT_HEAD(&ipq, fp, ipq_q);                  LIST_INSERT_HEAD(ipqhead, fp, ipq_q);
                   fp->ipq_nfrags = 1;
                 fp->ipq_ttl = IPFRAGTTL;                  fp->ipq_ttl = IPFRAGTTL;
                 fp->ipq_p = ipqe->ipqe_ip->ip_p;                  fp->ipq_p = ipqe->ipqe_ip->ip_p;
                 fp->ipq_id = ipqe->ipqe_ip->ip_id;                  fp->ipq_id = ipqe->ipqe_ip->ip_id;
Line 1014  ip_reass(ipqe, fp)
Line 1110  ip_reass(ipqe, fp)
                 fp->ipq_dst = ipqe->ipqe_ip->ip_dst;                  fp->ipq_dst = ipqe->ipqe_ip->ip_dst;
                 p = NULL;                  p = NULL;
                 goto insert;                  goto insert;
           } else {
                   fp->ipq_nfrags++;
         }          }
   
         /*          /*
Line 1064  ip_reass(ipqe, fp)
Line 1162  ip_reass(ipqe, fp)
                 m_freem(q->ipqe_m);                  m_freem(q->ipqe_m);
                 TAILQ_REMOVE(&fp->ipq_fragq, q, ipqe_q);                  TAILQ_REMOVE(&fp->ipq_fragq, q, ipqe_q);
                 pool_put(&ipqent_pool, q);                  pool_put(&ipqent_pool, q);
                   fp->ipq_nfrags--;
                   ip_nfrags--;
         }          }
   
 insert:  insert:
Line 1109  insert:
Line 1209  insert:
                 pool_put(&ipqent_pool, q);                  pool_put(&ipqent_pool, q);
                 m_cat(m, t);                  m_cat(m, t);
         }          }
           ip_nfrags -= fp->ipq_nfrags;
   
         /*          /*
          * Create header for new ip packet by           * Create header for new ip packet by
Line 1134  insert:
Line 1235  insert:
         return (m);          return (m);
   
 dropfrag:  dropfrag:
           if (fp != 0)
                   fp->ipq_nfrags--;
           ip_nfrags--;
         ipstat.ips_fragdropped++;          ipstat.ips_fragdropped++;
         m_freem(m);          m_freem(m);
         pool_put(&ipqent_pool, ipqe);          pool_put(&ipqent_pool, ipqe);
Line 1149  ip_freef(fp)
Line 1253  ip_freef(fp)
         struct ipq *fp;          struct ipq *fp;
 {  {
         struct ipqent *q, *p;          struct ipqent *q, *p;
           u_int nfrags = 0;
   
         IPQ_LOCK_CHECK();          IPQ_LOCK_CHECK();
   
         for (q = TAILQ_FIRST(&fp->ipq_fragq); q != NULL; q = p) {          for (q = TAILQ_FIRST(&fp->ipq_fragq); q != NULL; q = p) {
                 p = TAILQ_NEXT(q, ipqe_q);                  p = TAILQ_NEXT(q, ipqe_q);
                 m_freem(q->ipqe_m);                  m_freem(q->ipqe_m);
                   nfrags++;
                 TAILQ_REMOVE(&fp->ipq_fragq, q, ipqe_q);                  TAILQ_REMOVE(&fp->ipq_fragq, q, ipqe_q);
                 pool_put(&ipqent_pool, q);                  pool_put(&ipqent_pool, q);
         }          }
   
           if (nfrags != fp->ipq_nfrags)
               printf("ip_freef: nfrags %d != %d\n", fp->ipq_nfrags, nfrags);
           ip_nfrags -= nfrags;
         LIST_REMOVE(fp, ipq_q);          LIST_REMOVE(fp, ipq_q);
         FREE(fp, M_FTABLE);          FREE(fp, M_FTABLE);
         ip_nfragpackets--;          ip_nfragpackets--;
 }  }
   
 /*  /*
    * IP reassembly TTL machinery for  multiplicative drop.
    */
   static u_int    fragttl_histo[(IPFRAGTTL+1)];
   
   
   /*
    * Decrement TTL of all reasembly queue entries by `ticks'.
    * Count number of distinct fragments (as opposed to partial, fragmented
    * datagrams) in the reassembly queue.  While we  traverse the entire
    * reassembly queue, compute and return the median TTL over all fragments.
    */
   static u_int
   ip_reass_ttl_decr(u_int ticks)
   {
           u_int i, nfrags, median;
           struct ipq *fp, *nfp;
           u_int dropfraction, keepfraction;
   
           nfrags = 0;
           memset(fragttl_histo, 0, sizeof fragttl_histo);
   
           for (i = 0; i < IPREASS_NHASH; i++) {
                   for (fp = LIST_FIRST(&ipq[i]); fp != NULL; fp = nfp) {
                           fp->ipq_ttl = ((fp->ipq_ttl  <= ticks) ?
                                          0 : fp->ipq_ttl - ticks);
                           nfp = LIST_NEXT(fp, ipq_q);
                           if (fp->ipq_ttl == 0) {
                                   ipstat.ips_fragtimeout++;
                                   ip_freef(fp);
                           } else {
                                   nfrags += fp->ipq_nfrags;
                                   fragttl_histo[fp->ipq_ttl] += fp->ipq_nfrags;
                           }
                   }
           }
   
           KASSERT(ip_nfrags == nfrags);
   
           /* Find median (or other drop fraction) in histogram. */
           dropfraction = (ip_nfrags / 2);
           keepfraction = ip_nfrags - dropfraction;
           for (i = IPFRAGTTL, median = 0; i >= 0; i--) {
                   median +=  fragttl_histo[i];
                   if (median >= keepfraction)
                           break;
           }
   
           /* Return TTL of median (or other fraction). */
           return (u_int)i;
   }
   
   void
   ip_reass_drophalf(void)
   {
   
           u_int median_ticks;
           /*
            * Compute median TTL of all fragments, and count frags
            * with that TTL or lower (roughly half of all fragments).
            */
           median_ticks = ip_reass_ttl_decr(0);
   
           /* Drop half. */
           median_ticks = ip_reass_ttl_decr(median_ticks);
   
   }
   
   /*
  * IP timer processing;   * IP timer processing;
  * if a timer expires on a reassembly   * if a timer expires on a reassembly
  * queue, discard it.   * queue, discard it.
Line 1171  ip_freef(fp)
Line 1349  ip_freef(fp)
 void  void
 ip_slowtimo()  ip_slowtimo()
 {  {
         struct ipq *fp, *nfp;          static u_int dropscanidx = 0;
           u_int i;
           u_int median_ttl;
         int s = splsoftnet();          int s = splsoftnet();
   
         IPQ_LOCK();          IPQ_LOCK();
         for (fp = LIST_FIRST(&ipq); fp != NULL; fp = nfp) {  
                 nfp = LIST_NEXT(fp, ipq_q);          /* Age TTL of all fragments by 1 tick .*/
                 if (--fp->ipq_ttl == 0) {          median_ttl = ip_reass_ttl_decr(1);
                         ipstat.ips_fragtimeout++;  
                         ip_freef(fp);          /* make sure fragment limit is up-to-date */
                 }          CHECK_NMBCLUSTER_PARAMS();
         }  
           /* If we have too many fragments, drop the older half. */
           if (ip_nfrags > ip_maxfrags)
                   ip_reass_ttl_decr(median_ttl);
   
         /*          /*
          * If we are over the maximum number of fragments           * If we are over the maximum number of fragmented packets
          * (due to the limit being lowered), drain off           * (due to the limit being lowered), drain off
          * enough to get down to the new limit.           * enough to get down to the new limit. Start draining
            * from the reassembly hashqueue most recently drained.
          */           */
         if (ip_maxfragpackets < 0)          if (ip_maxfragpackets < 0)
                 ;                  ;
         else {          else {
                 while (ip_nfragpackets > ip_maxfragpackets && LIST_FIRST(&ipq))                  int wrapped = 0;
                         ip_freef(LIST_FIRST(&ipq));  
                   i = dropscanidx;
                   while (ip_nfragpackets > ip_maxfragpackets && wrapped == 0) {
                           while (LIST_FIRST(&ipq[i]) != NULL)
                                   ip_freef(LIST_FIRST(&ipq[i]));
                           if (++i >= IPREASS_NHASH) {
                                   i = 0;
                           }
                           /*
                            * Dont scan forever even if fragment counters are
                            * wrong: stop after scanning entire reassembly queue.
                            */
                           if (i == dropscanidx)
                               wrapped = 1;
                   }
                   dropscanidx = i;
         }          }
         IPQ_UNLOCK();          IPQ_UNLOCK();
 #ifdef GATEWAY  #ifdef GATEWAY
Line 1214  ip_drain()
Line 1414  ip_drain()
         if (ipq_lock_try() == 0)          if (ipq_lock_try() == 0)
                 return;                  return;
   
         while (LIST_FIRST(&ipq) != NULL) {          /*
                 ipstat.ips_fragdropped++;           * Drop half the total fragments now. If more mbufs are needed,
                 ip_freef(LIST_FIRST(&ipq));           *  we will be called again soon.
         }           */
           ip_reass_drophalf();
   
         IPQ_UNLOCK();          IPQ_UNLOCK();
 }  }

Legend:
Removed from v.1.189  
changed lines
  Added in v.1.195

CVSweb <webmaster@jp.NetBSD.org>