/* * Host Resources MIB - proc processor group implementation - hr_proc.c * */ #include #if HAVE_STDLIB_H #include #endif #if HAVE_STRING_H #include #else #include #endif #include #include "host_res.h" #include "hr_proc.h" #include #include #include "ucd-snmp/loadave.h" #define HRPROC_MONOTONICALLY_INCREASING /********************* * * Kernel & interface information, * and internal forward declarations * *********************/ extern void Init_HR_Proc(void); extern int Get_Next_HR_Proc(void); const char *describe_proc(int); int header_hrproc(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); #ifdef linux void detect_hrproc(void); #endif #ifdef solaris2 #define MAX_NUM_HRPROC 128 /* will handle up to 128 processors */ #include #include hrtime_t update_time = NULL; static int ncpus = 0; /* derived from kstat system_misc ncpus*/ struct cpuinfo { int id; char state[10]; int state_begin; char cpu_type[15]; char fpu_type[15]; int clock_MHz; }; /* derived from kstat cpu_info*/ static struct cpuinfo cpu[MAX_NUM_HRPROC]; static char proc_description[96]; /* buffer to hold description of current cpu*/ extern void kstat_CPU(void); int proc_status(int); #else #define MAX_NUM_HRPROC 32 char proc_descriptions[MAX_NUM_HRPROC][BUFSIZ]; #endif /*solaris 2*/ /********************* * * Initialisation & common implementation functions * *********************/ static int HRP_index; static int HRP_max_index = 1; #define HRPROC_ID 1 #define HRPROC_LOAD 2 struct variable4 hrproc_variables[] = { {HRPROC_ID, ASN_OBJECT_ID, RONLY, var_hrproc, 2, {1, 1}}, {HRPROC_LOAD, ASN_INTEGER, RONLY, var_hrproc, 2, {1, 2}} }; oid hrproc_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 3, 3 }; void init_hr_proc(void) { init_device[HRDEV_PROC] = Init_HR_Proc; next_device[HRDEV_PROC] = Get_Next_HR_Proc; device_descr[HRDEV_PROC] = describe_proc; #ifdef solaris2 device_status[HRDEV_PROC] = proc_status; update_time = NULL; #endif #ifdef HRPROC_MONOTONICALLY_INCREASING dev_idx_inc[HRDEV_PROC] = 1; #endif #ifdef linux detect_hrproc(); #endif REGISTER_MIB("host/hr_proc", hrproc_variables, variable4, hrproc_variables_oid); } /* * header_hrproc(... * Arguments: * vp IN - pointer to variable entry that points here * name IN/OUT - IN/name requested, OUT/name found * length IN/OUT - length of IN/OUT oid's * exact IN - TRUE if an exact match was requested * var_len OUT - length of variable or 0 if function returned * write_method * */ int header_hrproc(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { #define HRPROC_ENTRY_NAME_LENGTH 11 oid newname[MAX_OID_LEN]; int proc_idx, LowIndex = -1; int result; DEBUGMSGTL(("host/hr_proc", "var_hrproc: ")); DEBUGMSGOID(("host/hr_proc", name, *length)); DEBUGMSG(("host/hr_proc", " %d\n", exact)); memcpy((char *) newname, (char *) vp->name, vp->namelen * sizeof(oid)); /* * Find "next" proc entry */ Init_HR_Proc(); for (;;) { proc_idx = Get_Next_HR_Proc(); if (proc_idx == -1) break; newname[HRPROC_ENTRY_NAME_LENGTH] = proc_idx; result = snmp_oid_compare(name, *length, newname, vp->namelen + 1); if (exact && (result == 0)) { LowIndex = proc_idx; /* * Save processor status information */ break; } if ((!exact && (result < 0)) && (LowIndex == -1 || proc_idx < LowIndex)) { LowIndex = proc_idx; /* * Save processor status information */ #ifdef HRPROC_MONOTONICALLY_INCREASING break; #endif } } if (LowIndex == -1) { DEBUGMSGTL(("host/hr_proc", "... index out of range\n")); return (MATCH_FAILED); } memcpy((char *) name, (char *) newname, (vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; *write_method = 0; *var_len = sizeof(long); /* default to 'long' results */ DEBUGMSGTL(("host/hr_proc", "... get proc stats ")); DEBUGMSGOID(("host/hr_proc", name, *length)); DEBUGMSG(("host/hr_proc", "\n")); return LowIndex; } /********************* * * System specific implementation functions * *********************/ u_char * var_hrproc(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int proc_idx; double avenrun[3]; proc_idx = header_hrproc(vp, name, length, exact, var_len, write_method); if (proc_idx == MATCH_FAILED) return NULL; if (try_getloadavg(&avenrun[0], sizeof(avenrun) / sizeof(avenrun[0])) == -1) return NULL; switch (vp->magic) { case HRPROC_ID: *var_len = nullOidLen; return (u_char *) nullOid; case HRPROC_LOAD: #if NO_DUMMY_VALUES return NULL; #endif long_return = avenrun[0] * 100; /* 1 minute average */ if (long_return > 100) long_return = 100; return (u_char *) & long_return; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_hrproc\n", vp->magic)); } return NULL; } /********************* * * Internal implementation functions * *********************/ void Init_HR_Proc(void) { #ifdef solaris2 hrtime_t current_time; #endif HRP_index = 0; #ifdef solaris2 current_time = gethrtime(); if (current_time > update_time + 2000000000) { /* two seconds */ kstat_CPU(); update_time = gethrtime(); } #endif } int Get_Next_HR_Proc(void) { if (HRP_index < HRP_max_index) return (HRDEV_PROC << HRDEV_TYPE_SHIFT) + HRP_index++; else return -1; } const char * describe_proc(int idx) { #ifdef _SC_CPU_VERSION int result; result = sysconf(_SC_CPU_VERSION); switch (result) { case CPU_HP_MC68020: return (" Motorola MC68020 "); case CPU_HP_MC68030: return (" Motorola MC68030 "); case CPU_HP_MC68040: return (" Motorola MC68040 "); case CPU_PA_RISC1_0: return (" HP PA-RISC 1.0 "); case CPU_PA_RISC1_1: return (" HP PA-RISC 1.1 "); case CPU_PA_RISC1_2: return (" HP PA-RISC 1.2 "); case CPU_PA_RISC2_0: return (" HP PA-RISC 2.0 "); default: return ("An electronic chip with an HP label"); } #elif linux return (proc_descriptions[idx & HRDEV_TYPE_MASK]); #elif solaris2 int cidx = idx & HRDEV_TYPE_MASK; snprintf(proc_description,sizeof(proc_description)-1, "CPU %d Sun %d MHz %s with %s FPU %s", cpu[cidx].id,cpu[cidx].clock_MHz,cpu[cidx].cpu_type,cpu[cidx].fpu_type,cpu[cidx].state); return proc_description; #else return ("An electronic chip that makes the computer work."); #endif } #ifdef linux void detect_hrproc(void) { int i; char tmpbuf[BUFSIZ], *cp; FILE *fp; /* * Clear the buffers... */ for ( i=0 ; i= MAX_NUM_HRPROC) { i--; break; } } } HRP_max_index = i; fclose(fp); return; } #endif /* linux */ #ifdef solaris2 void kstat_CPU(void) { /* this routine asks the OS for the number of CPU's and uses that value * to set HRP_max_index for later use. Then it asks the OS for * specific details of each CPU. In Solaris, you cannot trust the * first CPU to be 0 or for CPU 0 to even exist, hence there is a * CPU id, state, cpu type, fpu type, state_begin (what does this do??) * and CPU speed. Results are stuffed into the cpu array (see above). * * In keeping with the spirit of the RFC, the number and index of CPU's * is considered to be constant. Hence, if you start yanking or adding * CPU modules eg. on a V880, you will need to start and stop the daemon. */ int i_cpu = -1; int i,old_ncpus; kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *ks_data; old_ncpus = ncpus; for (i = 0; i < ncpus; i++) { strncpy(cpu[i].state,"missing",sizeof(cpu[i].state)); cpu[i].state[sizeof(cpu[i].state)-1]='\0'; /* null terminate */ cpu[i].id = 999999; cpu[i].clock_MHz = 999999; strncpy(cpu[i].cpu_type,"missing",sizeof(cpu[i].cpu_type)); cpu[i].state[sizeof(cpu[i].cpu_type)-1]='\0'; /* null terminate */ strncpy(cpu[i].fpu_type,"missing",sizeof(cpu[i].fpu_type)); cpu[i].state[sizeof(cpu[i].cpu_type)-1]='\0'; /* null terminate */ } getKstat("system_misc", "ncpus", &ncpus); if (ncpus > old_ncpus){ HRP_max_index = ncpus; /* the MIB says to retain indexes */ } if ((old_ncpus != ncpus)&&(old_ncpus != 0)) { if (ncpus > old_ncpus){ snmp_log(LOG_NOTICE, "hr_proc: Cool ! Number of CPUs increased, must be hot-pluggable.\n"); } else { snmp_log(LOG_NOTICE, "hr_proc: Lost at least one CPU, RIP.\n"); } } if ((kc = kstat_open()) == NULL) { DEBUGMSGTL(("hr_proc", "kstat_open failed")); } else { for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { if (ksp->ks_type == KSTAT_TYPE_NAMED && strcmp(ksp->ks_module, "cpu_info") == 0 && strcmp(ksp->ks_class, "misc") == 0) { if (kstat_read(kc, ksp, NULL) == -1) { DEBUGMSGTL(("hr_proc", "kstat_read failed")); } else { i_cpu++; i = 0; cpu[i_cpu].id = ksp->ks_instance; for (ks_data = ksp->ks_data; i < ksp->ks_ndata; i++, ks_data++) { if (strcmp(ks_data->name,"state")==0) { strncpy(cpu[i_cpu].state,ks_data->value.c,sizeof(cpu[i_cpu].state)); cpu[i_cpu].state[sizeof(cpu[i_cpu].state)-1]='\0'; /* null terminate */ continue; } else if (strcmp(ks_data->name,"state_begin")==0) { cpu[i_cpu].state_begin=ks_data->value.i32; continue; } else if (strcmp(ks_data->name,"cpu_type")==0) { strncpy(cpu[i_cpu].cpu_type,ks_data->value.c,sizeof(cpu[i_cpu].cpu_type)); cpu[i_cpu].state[sizeof(cpu[i_cpu].cpu_type)-1]='\0'; /* null terminate */ continue; } else if (strcmp(ks_data->name,"fpu_type")==0) { strncpy(cpu[i_cpu].fpu_type,ks_data->value.c,sizeof(cpu[i_cpu].fpu_type)); cpu[i_cpu].state[sizeof(cpu[i_cpu].fpu_type)-1]='\0'; /* null terminate */ continue; } else if (strcmp(ks_data->name,"clock_MHz")==0) { cpu[i_cpu].clock_MHz=ks_data->value.i32; continue; } else { DEBUGMSGTL(("hr_proc","kstat unexpected cpu parameter")); } } } } } } kstat_close(kc); } int proc_status(int idx) { /* * hrDeviceStatus OBJECT-TYPE * SYNTAX INTEGER { * unknown(1), running(2), warning(3), testing(4), down(5) * } */ int cidx = idx & HRDEV_TYPE_MASK; if (strcmp(cpu[cidx].state,"on-line")==0) { return 2; /* running */ } else if (strcmp(cpu[cidx].state,"off-line")==0) { return 5; /* down */ } else if (strcmp(cpu[cidx].state,"missing")==0) { return 3; /* warning, went missing, see above */ } else if (strcmp(cpu[cidx].state,"testing")==0) { return 4; /* somebody must be testing code up above */ } else { return 1; /* unknown */ } } #endif /* solaris2 */