📄 kernel_sunos5.c
字号:
#ifdef KSTAT_DATA_INT32 /* Solaris 2.6 and up */ case KSTAT_DATA_INT32: *(Counter *)v = d->value.i32; DEBUGMSGTL(("kernel_sunos5", "value: %d\n", d->value.i32)); break; case KSTAT_DATA_UINT32: *(Counter *)v = d->value.ui32; DEBUGMSGTL(("kernel_sunos5", "value: %u\n", d->value.ui32)); break; case KSTAT_DATA_INT64: *(int64_t *)v = d->value.i64; DEBUGMSGTL(("kernel_sunos5", "value: %ld\n", d->value.i64)); break; case KSTAT_DATA_UINT64: *(uint64_t *)v = d->value.ui64; DEBUGMSGTL(("kernel_sunos5", "value: %lu\n", d->value.ui64)); break;#else case KSTAT_DATA_LONG: *(Counter *)v = d->value.l; DEBUGMSGTL(("kernel_sunos5", "value: %ld\n", d->value.l)); break; case KSTAT_DATA_ULONG: *(Counter *)v = d->value.ul; DEBUGMSGTL(("kernel_sunos5", "value: %lu\n", d->value.ul)); break; case KSTAT_DATA_LONGLONG: *(Counter *)v = d->value.ll; DEBUGMSGTL(("kernel_sunos5", "value: %lld\n", (long)d->value.ll)); break; case KSTAT_DATA_ULONGLONG: *(Counter *)v = d->value.ull; DEBUGMSGTL(("kernel_sunos5", "value: %llu\n", (unsigned long)d->value.ull)); break;#endif case KSTAT_DATA_FLOAT: *(float *)v = d->value.f; DEBUGMSGTL(("kernel_sunos5", "value: %f\n", d->value.f)); break; case KSTAT_DATA_DOUBLE: *(double *)v = d->value.d; DEBUGMSGTL(("kernel_sunos5", "value: %f\n", d->value.d)); break; default: DEBUGMSGTL(("kernel_sunos5", "Unknown type in kstat data: %s %s %d\n", statname, varname, d->data_type)); ret = -3; goto Return; /* Invalid data type */ } ret = 0; /* Success */ goto Return; } } ret = -4; /* Name not found */Return: return (ret);}/* * get MIB-II statistics. It maintaines a simple cache which buffers * the last read block of MIB statistics (which may contain the whole * table). It calls *comp to compare every entry with an entry pointed * by arg. *comp should return 0 if comparison is successful. * Req_type may be GET_FIRST, GET_EXACT, GET_NEXT. * If search is successful getMibstat returns 0, otherwise 1. */intgetMibstat(mibgroup_e grid, void *resp, size_t entrysize, req_e req_type, int (*comp)(void *, void *), void *arg){ int ret, rc=-1, mibgr, mibtb, cache_valid; size_t length; mibcache *cachep; found_e result = NOT_FOUND; void* ep; /* * We assume that Mibcache is initialized in mibgroup_e enum order * so we don't check the validity of index here. */ DEBUGMSGTL(("kernel_sunos5", "getMibstat (%d, *, %d, %d, *, *)\n", grid, entrysize, req_type)); cachep = &Mibcache[grid]; mibgr = Mibmap[grid].group; mibtb = Mibmap[grid].table; if (cachep->cache_addr == (void *)-1) /* Hasn't been initialized yet */ init_mibcache_element(cachep); if (cachep->cache_size == 0) { /* Memory allocation problems */ cachep->cache_addr = resp; /* So use caller supplied address instead of cache */ cachep->cache_size = entrysize; cachep->cache_last_found = 0; } if (req_type != GET_NEXT) cachep->cache_last_found = 0; cache_valid = (time(NULL) - cachep->cache_time) > cachep->cache_ttl ? 0 : 1; DEBUGMSGTL(("kernel_sunos5", "... cache_valid %d time %ld ttl %d now %ld\n", cache_valid, cachep->cache_time, cachep->cache_ttl, time (NULL))); if (cache_valid) { /* Is it really? */ if (cachep->cache_comp != (void *) comp || cachep->cache_arg != arg) cache_valid = 0; /* Nope. */ } if (cache_valid) { /* Entry is valid, let's try to find a match */ if (req_type == GET_NEXT) { result = getentry(req_type, (void *) ((char *) cachep->cache_addr + (cachep->cache_last_found * entrysize)), cachep->cache_length - (cachep->cache_last_found * entrysize), entrysize, &ep, comp, arg); } else { result = getentry(req_type, cachep->cache_addr, cachep->cache_length, entrysize, &ep, comp, arg); } } if ((cache_valid == 0) || (result == NOT_FOUND) || ((result == NEED_NEXT) && cachep->cache_flags&CACHE_MOREDATA)) { /* * Either the cache is old, or we haven't found * anything, or need the next item which hasn't been read yet. * In any case, fill the cache up and try to find our entry. */ if (grid == MIB_INTERFACES) rc = getif((mib2_ifEntry_t *)cachep->cache_addr, cachep->cache_size, req_type, (mib2_ifEntry_t *)&ep, &length, comp, arg); else rc = getmib(mibgr, mibtb, cachep->cache_addr, cachep->cache_size, entrysize, req_type, &ep, &length, comp, arg); if (rc >= 0) { /* Cache has been filled up */ cachep->cache_time = time(NULL); cachep->cache_length = length; if (rc == 1) /* Found but there are more unread data */ cachep->cache_flags |= CACHE_MOREDATA; else cachep->cache_flags &= ~CACHE_MOREDATA; cachep->cache_comp = (void *) comp; cachep->cache_arg = arg; } else { cachep->cache_comp = NULL; cachep->cache_arg = NULL; } } DEBUGMSGTL(("kernel_sunos5", "... result %d rc %d\n", result, rc)); if (result == FOUND || rc == 0 || rc == 1) { /* Entry has been found, deliver it */ if (resp != (void *)NULL) (void)memcpy(resp, ep, entrysize); ret = 0; cachep->cache_last_found = ((char *) ep - (char *) cachep->cache_addr) / entrysize; } else ret = 1; /* Not found */ DEBUGMSGTL(("kernel_sunos5", "... getMibstat returns %d\n", ret)); return (ret);}/* Get a MIB-II entry from the buffer buffaddr, which satisfies * the criterion, computed by (*comp), which gets arg as the first * argument and pointer to the current position in the buffer as the * second. If found entry is pointed by resp. */static found_egetentry(req_e req_type, void *bufaddr, size_t len, size_t entrysize, void *resp, int (*comp)(void *, void *), void *arg){ void *bp = bufaddr, **rp = resp; int previous_found = 0; /* Here we have to perform address arithmetic with pointer to void. Ugly... */ for (; len != 0; len -= entrysize, bp = (char *)bp + entrysize) { if (rp != (void *)NULL) *rp = bp; if ((req_type == GET_FIRST) || ((req_type == GET_NEXT) && previous_found)) { return (FOUND); } if ((*comp)(arg, bp) == 0) { if (req_type == GET_EXACT) { return (FOUND); } else { /* GET_NEXT */ previous_found++; continue; } } } if (previous_found) return (NEED_NEXT); else return (NOT_FOUND);}/* * Initialize a cache element. It allocates the memory * and sets the time stamp to invalidate the element. */static voidinit_mibcache_element(mibcache *cp){ if (cp == (mibcache *)NULL) return; if (cp->cache_size) cp->cache_addr = malloc(cp->cache_size); cp->cache_time = time(NULL) - 100*cp->cache_ttl; /* In the past */ cp->cache_comp = NULL; cp->cache_arg = NULL;}/* Get MIB-II statistics from the Solaris kernel. It uses undocumented interface to TCP/IP streams modules, which provides extended MIB-II for the following groups: ip, icmp, tcp, udp, egp. Usage: groupname, subgroupname are from <inet/mib2.h>, size%sizeof(statbuf) == 0, entrysize should be exact size of MIB-II entry, req_type: GET_FIRST - get the first entry in the buffer GET_EXACT - get exact match GET_NEXT - get next entry after the exact match (*comp) is a compare function, provided by the caller, which gets arg as the first argument and pointer to the current entry as th second. If compared, should return 0 and found entry will be pointed by resp. If search is successful and no more data to read, it returns 0, if successful and there is more data -- 1, if not found and end of data -- 2, any other errors -- < 0 (negative error numbers are pretty random). NOTE: needs to be protected by a mutex in reentrant environment */static intgetmib(int groupname, int subgroupname, void *statbuf, size_t size, size_t entrysize, req_e req_type, void *resp, size_t *length, int (*comp)(void *, void *), void *arg){ int rc, ret = 0, flags; char buf[BUFSIZE]; struct strbuf strbuf; struct T_optmgmt_req *tor = (struct T_optmgmt_req *) buf; struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *) buf; struct T_error_ack *tea = (struct T_error_ack *) buf; struct opthdr *req; found_e result = FOUND; DEBUGMSGTL(("kernel_sunos5", "...... getmib (%d, %d, ...)\n", groupname, subgroupname)); /* Open the stream driver and push all MIB-related modules */ if (sd == -1) { /* First time */ if ((sd = open(STREAM_DEV, O_RDWR)) == -1) { ret = -1; goto Return; } if (ioctl(sd, I_PUSH, "arp") == -1) { ret = -1; goto Return; } if (ioctl(sd, I_PUSH, "tcp") == -1) { ret = -1; goto Return; } if (ioctl(sd, I_PUSH, "udp") == -1) { ret = -1; goto Return; } DEBUGMSGTL(("kernel_sunos5", "...... modules pushed OK\n")); } /* First, use bigger buffer, to accelerate skipping unwanted messages */ strbuf.buf = buf; strbuf.maxlen = BUFSIZE; tor->PRIM_type = T_OPTMGMT_REQ; tor->OPT_offset = sizeof(struct T_optmgmt_req); tor->OPT_length = sizeof(struct opthdr);#ifdef MI_T_CURRENT tor->MGMT_flags = MI_T_CURRENT; /* Solaris < 2.6 */#else tor->MGMT_flags = T_CURRENT; /* Solaris 2.6 */#endif req = (struct opthdr *) (tor + 1); req->level = groupname; req->name = subgroupname; req->len = 0; strbuf.len = tor->OPT_length + tor->OPT_offset; flags = 0; if ((rc = putmsg(sd, &strbuf, NULL, flags))) { ret = -2; goto Return; } req = (struct opthdr *) (toa + 1); for (;;) { flags = 0; if ((rc = getmsg(sd, &strbuf, NULL, &flags)) == -1) { ret = -EIO; break; } if (rc == 0 && strbuf.len >= sizeof(struct T_optmgmt_ack) && toa->PRIM_type == T_OPTMGMT_ACK && toa->MGMT_flags == T_SUCCESS && req->len == 0) { ret = 2; break; } if (strbuf.len >= sizeof(struct T_error_ack) && tea->PRIM_type == T_ERROR_ACK) { ret = -((tea->TLI_error == TSYSERR)?tea->UNIX_error:EPROTO); /* Protocol error */ break; } if (rc != MOREDATA || strbuf.len < sizeof(struct T_optmgmt_ack) || toa->PRIM_type != T_OPTMGMT_ACK || toa->MGMT_flags != T_SUCCESS) { ret = -ENOMSG; /* No more messages */ break; } /* The order in which we get the statistics is determined by the kernel and not by the group name, so we have to loop until we get the required statistics. */ if (req->level != groupname || req->name != subgroupname) { strbuf.maxlen = BUFSIZE; strbuf.buf = buf; do { rc = getmsg(sd, NULL, &strbuf, &flags); } while (rc == MOREDATA) ; continue; } /* Now when we found our stat, switch buffer to a caller-provided one. Manipulating the size of it one can control performance, reducing the number of getmsg calls */ strbuf.buf = statbuf; strbuf.maxlen = size; strbuf.len = 0; flags = 0; do { rc = getmsg(sd, NULL, &strbuf, &flags); switch (rc) { case -1: rc = -ENOSR; goto Return; default: rc = -ENODATA; goto Return; case MOREDATA: case 0: if (req_type == GET_NEXT && result == NEED_NEXT) /* End of buffer, so "next" is the first item in the next buffer */ req_type = GET_FIRST; result = getentry(req_type, (void *)strbuf.buf, strbuf.len, entrysize, resp, comp, arg); *length = strbuf.len; /* To use in caller for cacheing */ break; } } while (rc == MOREDATA && result != FOUND); if (result == FOUND) { /* Search is successful */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -