Print this page
More stats to SIOCIPFCFWCFG and add SIOCIPFCFWNEWSZ to affect ring-buffer size.
        
*** 95,112 ****
   * but for now keep the ring buffer simple and stupid.
   */
  
  /* Must be a power of 2, to be bitmaskable, and must be countable by a uint_t */
  
! #define IPF_CFW_RING_BUFS       1024
! #define IPF_CFW_RING_MASK (IPF_CFW_RING_BUFS - 1)
  
  /* Assume C's init-to-zero is sufficient for these types... */
  static kmutex_t cfw_ringlock;
  static kcondvar_t cfw_ringcv;
  
! static cfwev_t cfw_evring[IPF_CFW_RING_BUFS];
  /* If these are equal, we're either empty or full. */
  static uint_t cfw_ringstart, cfw_ringend;
  static boolean_t cfw_ringfull;  /* Tell the difference here! */
  static uint64_t cfw_evreports;
  static uint64_t cfw_evdrops;
--- 95,116 ----
   * but for now keep the ring buffer simple and stupid.
   */
  
  /* Must be a power of 2, to be bitmaskable, and must be countable by a uint_t */
  
! #define IPF_CFW_DEFAULT_RING_BUFS       1024
! #define IPF_CFW_MIN_RING_BUFS           8
! #define IPF_CFW_MAX_RING_BUFS           (1U << 31U)
  
  /* Assume C's init-to-zero is sufficient for these types... */
  static kmutex_t cfw_ringlock;
  static kcondvar_t cfw_ringcv;
  
! static cfwev_t *cfw_ring;       /* NULL by default. */
! static uint32_t cfw_ringsize;   /* 0 by default, number of array elements. */
! static uint32_t cfw_ringmask;   /* 0 by default. */
! 
  /* If these are equal, we're either empty or full. */
  static uint_t cfw_ringstart, cfw_ringend;
  static boolean_t cfw_ringfull;  /* Tell the difference here! */
  static uint64_t cfw_evreports;
  static uint64_t cfw_evdrops;
*** 121,140 ****
  ipf_cfwev_report(cfwev_t *event)
  {
          mutex_enter(&cfw_ringlock);
          if (cfw_ringfull) {
                  cfw_ringstart++;
!                 cfw_ringstart &= IPF_CFW_RING_MASK;
                  cfw_ringend++;
!                 cfw_ringend &= IPF_CFW_RING_MASK;
                  DTRACE_PROBE(ipf__cfw__evdrop);
                  cfw_evdrops++;
!                 cfw_evring[cfw_ringend] = *event;
          } else {
!                 cfw_evring[cfw_ringend] = *event;
                  cfw_ringend++;
!                 cfw_ringend &= IPF_CFW_RING_MASK;
                  cfw_ringfull = (cfw_ringend == cfw_ringstart);
          }
          cfw_evreports++;
          cv_broadcast(&cfw_ringcv);
          mutex_exit(&cfw_ringlock);
--- 125,144 ----
  ipf_cfwev_report(cfwev_t *event)
  {
          mutex_enter(&cfw_ringlock);
          if (cfw_ringfull) {
                  cfw_ringstart++;
!                 cfw_ringstart &= cfw_ringmask;
                  cfw_ringend++;
!                 cfw_ringend &= cfw_ringmask;
                  DTRACE_PROBE(ipf__cfw__evdrop);
                  cfw_evdrops++;
!                 cfw_ring[cfw_ringend] = *event;
          } else {
!                 cfw_ring[cfw_ringend] = *event;
                  cfw_ringend++;
!                 cfw_ringend &= cfw_ringmask;
                  cfw_ringfull = (cfw_ringend == cfw_ringstart);
          }
          cfw_evreports++;
          cv_broadcast(&cfw_ringcv);
          mutex_exit(&cfw_ringlock);
*** 162,172 ****
                          mutex_exit(&cfw_ringlock);
                          return (B_FALSE);
                  }
          }
  
!         *event = cfw_evring[cfw_ringstart];
          cfw_ringstart++;
          cfw_ringstart &= IPF_CFW_RING_MASK;
          cfw_ringfull = B_FALSE;
          mutex_exit(&cfw_ringlock);
          return (B_TRUE);
--- 166,176 ----
                          mutex_exit(&cfw_ringlock);
                          return (B_FALSE);
                  }
          }
  
!         *event = cfw_ring[cfw_ringstart];
          cfw_ringstart++;
          cfw_ringstart &= IPF_CFW_RING_MASK;
          cfw_ringfull = B_FALSE;
          mutex_exit(&cfw_ringlock);
          return (B_TRUE);
*** 212,232 ****
          int timeout_tries = cfw_timeout_tries;
  
          mutex_enter(&cfw_ringlock);
  
          /* Silly reality checks */
!         ASSERT3U(cfw_ringstart, <, IPF_CFW_RING_BUFS);
!         ASSERT3U(cfw_ringend, <, IPF_CFW_RING_BUFS);
  
          /*
           * Can goto here again if caller wants blocking. NOTE that
           * num_requested may have been decremented and consumed may have been
           * incremented if we arrive here via a goto after a cv_wait.
           */
  from_the_top:
          if (cfw_ringstart > cfw_ringend || cfw_ringfull)
!                 contig_size = IPF_CFW_RING_BUFS - cfw_ringstart;
          else if (cfw_ringstart < cfw_ringend)
                  contig_size = cfw_ringend - cfw_ringstart;
          else if (block && cv_wait_sig(&cfw_ringcv, &cfw_ringlock)) {
                  /* Maybe something to consume now, try again. */
                  goto from_the_top;
--- 216,236 ----
          int timeout_tries = cfw_timeout_tries;
  
          mutex_enter(&cfw_ringlock);
  
          /* Silly reality checks */
!         ASSERT3U(cfw_ringstart, <, cfw_ringsize);
!         ASSERT3U(cfw_ringend, <, cfw_ringsize);
  
          /*
           * Can goto here again if caller wants blocking. NOTE that
           * num_requested may have been decremented and consumed may have been
           * incremented if we arrive here via a goto after a cv_wait.
           */
  from_the_top:
          if (cfw_ringstart > cfw_ringend || cfw_ringfull)
!                 contig_size = cfw_ringsize - cfw_ringstart;
          else if (cfw_ringstart < cfw_ringend)
                  contig_size = cfw_ringend - cfw_ringstart;
          else if (block && cv_wait_sig(&cfw_ringcv, &cfw_ringlock)) {
                  /* Maybe something to consume now, try again. */
                  goto from_the_top;
*** 234,271 ****
                  /* Nothing (more) to consume, return! */
                  goto bail;
          }
  
          ASSERT(contig_size + cfw_ringstart == cfw_ringend ||
!             contig_size + cfw_ringstart == IPF_CFW_RING_BUFS);
  
          if (num_requested < contig_size)
                  contig_size = num_requested;
  
!         cb_consumed = cfw_many_cb(&(cfw_evring[cfw_ringstart]), contig_size,
              cbarg);
          ASSERT(cb_consumed <= contig_size);
          cfw_ringstart += cb_consumed;
          consumed += cb_consumed;
          cfw_ringfull = (cfw_ringfull && cb_consumed == 0);
          if (cb_consumed < contig_size) {
                  /* Caller clearly had a problem. Reality check and bail. */
!                 ASSERT((cfw_ringstart & IPF_CFW_RING_MASK) == cfw_ringstart);
                  goto bail;
          }
          ASSERT(cb_consumed == contig_size);
!         cfw_ringstart &= IPF_CFW_RING_MASK;     /* In case of wraparound. */
          num_requested -= contig_size;
  
          if (num_requested > 0 && cfw_ringstart != cfw_ringend) {
                  /* We must have wrapped around the end of the buffer! */
                  ASSERT(cfw_ringstart == 0);
                  ASSERT(!cfw_ringfull);
                  contig_size = cfw_ringend;
                  if (num_requested < contig_size)
                          contig_size = num_requested;
!                 cb_consumed = cfw_many_cb(&(cfw_evring[cfw_ringstart]),
                      contig_size, cbarg);
                  cfw_ringstart += cb_consumed;
                  consumed += cb_consumed;
                  if (cb_consumed < contig_size) {
                          /*
--- 238,275 ----
                  /* Nothing (more) to consume, return! */
                  goto bail;
          }
  
          ASSERT(contig_size + cfw_ringstart == cfw_ringend ||
!             contig_size + cfw_ringstart == cfw_ringsize);
  
          if (num_requested < contig_size)
                  contig_size = num_requested;
  
!         cb_consumed = cfw_many_cb(&(cfw_ring[cfw_ringstart]), contig_size,
              cbarg);
          ASSERT(cb_consumed <= contig_size);
          cfw_ringstart += cb_consumed;
          consumed += cb_consumed;
          cfw_ringfull = (cfw_ringfull && cb_consumed == 0);
          if (cb_consumed < contig_size) {
                  /* Caller clearly had a problem. Reality check and bail. */
!                 ASSERT((cfw_ringstart & cfw_ringmask) == cfw_ringstart);
                  goto bail;
          }
          ASSERT(cb_consumed == contig_size);
!         cfw_ringstart &= cfw_ringmask;  /* In case of wraparound. */
          num_requested -= contig_size;
  
          if (num_requested > 0 && cfw_ringstart != cfw_ringend) {
                  /* We must have wrapped around the end of the buffer! */
                  ASSERT(cfw_ringstart == 0);
                  ASSERT(!cfw_ringfull);
                  contig_size = cfw_ringend;
                  if (num_requested < contig_size)
                          contig_size = num_requested;
!                 cb_consumed = cfw_many_cb(&(cfw_ring[cfw_ringstart]),
                      contig_size, cbarg);
                  cfw_ringstart += cb_consumed;
                  consumed += cb_consumed;
                  if (cb_consumed < contig_size) {
                          /*
*** 497,530 ****
                  return (0);
  
          return (num_avail);
  }
  
  /* ARGSUSED */
  int
  ipf_cfwlog_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cp,
      int *rp)
  {
          ipfcfwcfg_t cfginfo;
          int error;
  
!         if (cmd != SIOCIPFCFWCFG)
                  return (EIO);
  
          if (crgetzoneid(cp) != GLOBAL_ZONEID)
                  return (EACCES);
  
- #ifdef notyet
          error = COPYIN((caddr_t)data, (caddr_t)&cfginfo, sizeof (cfginfo));
          if (error != 0)
                  return (EFAULT);
-         /* TODO: Resize ring buffer based on cfginfo.ipfcfwc_evringsize. */
- #endif
  
          cfginfo.ipfcfwc_maxevsize = sizeof (cfwev_t);
!         cfginfo.ipfcfwc_evringsize = IPF_CFW_RING_BUFS;
  
          error = COPYOUT((caddr_t)&cfginfo, (caddr_t)data, sizeof (cfginfo));
          if (error != 0)
                  return (EFAULT);
  
          return (0);
--- 501,596 ----
                  return (0);
  
          return (num_avail);
  }
  
+ int
+ ipf_cfw_ring_resize(uint32_t newsize)
+ {
+         ASSERT(MUTEX_HELD(&cfw_ringlock) || newsize == IPF_CFW_RING_ALLOCATE ||
+             newsize == IPF_CFW_RING_DESTROY);
+ 
+         if (newsize == IPF_CFW_RING_ALLOCATE) {
+                 if (cfw_ring != NULL)
+                         return (EBUSY);
+                 newsize = IPF_CFW_DEFAULT_RING_BUFS;
+                 /* Fall through to allocating a new ring buffer. */
+         } else {
+                 /* We may be called during error cleanup, so be liberal here. */
+                 if (cfw_ring == NULL && newsize == IPF_CFW_RING_DESTROY)
+                         return (0);
+                 kmem_free(cfw_ring, cfw_ringsize * sizeof (cfwev_t));
+                 cfw_ring = NULL;
+                 if (cfw_ringfull) {
+                         cfw_evdrops += cfw_ringsize;
+                 } else if (cfw_ringstart > cfw_ringend) {
+                         cfw_evdrops += cfw_ringend +
+                             (cfw_ringsize - cfw_ringstart);
+                 } else {
+                         cfw_evdrops += cfw_ringend - cfw_ringstart;
+                 }
+                 cfw_ringsize = cfw_ringmask = cfw_ringstart = cfw_ringend = 0;
+                 cfw_ringfull = B_FALSE;
+ 
+                 if (newsize == IPF_CFW_RING_DESTROY)
+                         return (0);
+                 /*
+                  * Keep the reports & drops around because if we're just
+                  * resizing, we need to know what we lost.
+                  */
+         }
+ 
+         ASSERT(ISP2(newsize));
+         cfw_ring = kmem_alloc(newsize * sizeof (cfwev_t), KM_SLEEP);
+         /* KM_SLEEP means we always succeed. */
+         cfw_ringsize = newsize;
+         cfw_ringmask = cfw_ringsize - 1;
+ 
+         return (0);
+ }
+ 
  /* ARGSUSED */
  int
  ipf_cfwlog_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cp,
      int *rp)
  {
          ipfcfwcfg_t cfginfo;
          int error;
  
!         if (cmd != SIOCIPFCFWCFG && cmd != SIOCIPFCFWNEWSZ)
                  return (EIO);
  
          if (crgetzoneid(cp) != GLOBAL_ZONEID)
                  return (EACCES);
  
          error = COPYIN((caddr_t)data, (caddr_t)&cfginfo, sizeof (cfginfo));
          if (error != 0)
                  return (EFAULT);
  
          cfginfo.ipfcfwc_maxevsize = sizeof (cfwev_t);
!         mutex_enter(&cfw_ringlock);
!         cfginfo.ipfcfwc_evreports = cfw_evreports;
!         cfginfo.ipfcfwc_evdrops = cfw_evdrops;
!         if (cmd == SIOCIPFCFWNEWSZ) {
!                 uint32_t newsize = cfginfo.ipfcfwc_evringsize;
  
+                 /* Do ioctl parameter checking here, then call the resizer. */
+                 if (newsize < IPF_CFW_MIN_RING_BUFS ||
+                     newsize > IPF_CFW_MAX_RING_BUFS || !ISP2(newsize)) {
+                         error = EINVAL;
+                 } else {
+                         error = ipf_cfw_ring_resize(cfginfo.ipfcfwc_evringsize);
+                 }
+         } else {
+                 error = 0;
+         }
+         cfginfo.ipfcfwc_evringsize = cfw_ringsize;
+         mutex_exit(&cfw_ringlock);
+ 
+         if (error != 0)
+                 return (error);
+ 
          error = COPYOUT((caddr_t)&cfginfo, (caddr_t)data, sizeof (cfginfo));
          if (error != 0)
                  return (EFAULT);
  
          return (0);
*** 575,584 ****
--- 641,656 ----
  
  #else
  
  /* Blank stubs to satisfy userland's test compilations. */
  
+ int
+ ipf_cfw_ring_resize(uint32_t a)
+ {
+         return (0);
+ }
+ 
  void
  ipf_log_cfwlog(struct ipstate *a, uint_t b, ipf_stack_t *c)
  {
  }