Print this page
More stats to SIOCIPFCFWCFG and add SIOCIPFCFWNEWSZ to affect ring-buffer size.
@@ -95,18 +95,22 @@
* 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)
+#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_evring[IPF_CFW_RING_BUFS];
+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,20 +125,20 @@
ipf_cfwev_report(cfwev_t *event)
{
mutex_enter(&cfw_ringlock);
if (cfw_ringfull) {
cfw_ringstart++;
- cfw_ringstart &= IPF_CFW_RING_MASK;
+ cfw_ringstart &= cfw_ringmask;
cfw_ringend++;
- cfw_ringend &= IPF_CFW_RING_MASK;
+ cfw_ringend &= cfw_ringmask;
DTRACE_PROBE(ipf__cfw__evdrop);
cfw_evdrops++;
- cfw_evring[cfw_ringend] = *event;
+ cfw_ring[cfw_ringend] = *event;
} else {
- cfw_evring[cfw_ringend] = *event;
+ cfw_ring[cfw_ringend] = *event;
cfw_ringend++;
- cfw_ringend &= IPF_CFW_RING_MASK;
+ cfw_ringend &= cfw_ringmask;
cfw_ringfull = (cfw_ringend == cfw_ringstart);
}
cfw_evreports++;
cv_broadcast(&cfw_ringcv);
mutex_exit(&cfw_ringlock);
@@ -162,11 +166,11 @@
mutex_exit(&cfw_ringlock);
return (B_FALSE);
}
}
- *event = cfw_evring[cfw_ringstart];
+ *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,21 +216,21 @@
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);
+ 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 = IPF_CFW_RING_BUFS - cfw_ringstart;
+ 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,38 +238,38 @@
/* Nothing (more) to consume, return! */
goto bail;
}
ASSERT(contig_size + cfw_ringstart == cfw_ringend ||
- contig_size + cfw_ringstart == IPF_CFW_RING_BUFS);
+ contig_size + cfw_ringstart == cfw_ringsize);
if (num_requested < contig_size)
contig_size = num_requested;
- cb_consumed = cfw_many_cb(&(cfw_evring[cfw_ringstart]), contig_size,
+ 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 & IPF_CFW_RING_MASK) == cfw_ringstart);
+ ASSERT((cfw_ringstart & cfw_ringmask) == cfw_ringstart);
goto bail;
}
ASSERT(cb_consumed == contig_size);
- cfw_ringstart &= IPF_CFW_RING_MASK; /* In case of wraparound. */
+ 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_evring[cfw_ringstart]),
+ 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,34 +501,96 @@
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)
+ if (cmd != SIOCIPFCFWCFG && cmd != SIOCIPFCFWNEWSZ)
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;
+ 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,10 +641,16 @@
#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)
{
}