diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 27b1fdd9bc8d..169d5e0fd74a 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -663,3 +663,91 @@ timevalfix(struct timeval *t1) t1->tv_usec -= 1000000; } } + +#ifndef timersub +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +/* + * ratecheck(): simple time-based rate-limit checking. see ratecheck(9) + * for usage and rationale. + */ +int +ratecheck(struct timeval *lasttime, const struct timeval *mininterval) +{ + struct timeval tv, delta; + int rv = 0; + + getmicrouptime(&tv); + timersub(&tv, lasttime, &delta); + + /* + * check for 0,0 is so that the message will be seen at least once, + * even if interval is huge. + */ + if (timevalcmp(&delta, mininterval, >=) || + (lasttime->tv_sec == 0 && lasttime->tv_usec == 0)) { + *lasttime = tv; + rv = 1; + } + + return (rv); +} + +/* + * ppsratecheck(): packets (or events) per second limitation. + */ +int +ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) +{ + struct timeval tv, delta; + int rv; + + getmicrouptime(&tv); + timersub(&tv, lasttime, &delta); + + /* + * check for 0,0 is so that the message will be seen at least once. + * if more than one second have passed since the last update of + * lasttime, reset the counter. + * + * we do increment *curpps even in *curpps < maxpps case, as some may + * try to use *curpps for stat purposes as well. + */ + if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || + delta.tv_sec >= 1) { + *lasttime = tv; + *curpps = 0; + rv = 1; + } else if (maxpps < 0) + rv = 1; + else if (*curpps < maxpps) + rv = 1; + else + rv = 0; + +#if 1 /*DIAGNOSTIC?*/ + /* be careful about wrap-around */ + if (*curpps + 1 > *curpps) + *curpps = *curpps + 1; +#else + /* + * assume that there's not too many calls to this function. + * not sure if the assumption holds, as it depends on *caller's* + * behavior, not the behavior of this function. + * IMHO it is wrong to make assumption on the caller's behavior, + * so the above #if is #if 1, not #ifdef DIAGNOSTIC. + */ + *curpps = *curpps + 1; +#endif + + return (rv); +} diff --git a/sys/sys/time.h b/sys/sys/time.h index 52b958b19b67..b77ad39fc688 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -302,6 +302,8 @@ void getmicrotime(struct timeval *tvp); /* Other functions */ int itimerdecr(struct itimerval *itp, int usec); int itimerfix(struct timeval *tv); +int ppsratecheck(struct timeval *, int *, int); +int ratecheck(struct timeval *, const struct timeval *); void timevaladd(struct timeval *t1, struct timeval *t2); void timevalsub(struct timeval *t1, struct timeval *t2); int tvtohz(struct timeval *tv);