16824703 net-snmp can't get "hrProcessorLoad" dynamically after change the No. of CPUs.
authorMohana Rao Gorai <mohana.gorai@oracle.com>
Tue, 23 Sep 2014 22:02:00 -0700
changeset 2107 1cda4e19a209
parent 2106 adb848b3a7d4
child 2108 6145b31310ca
16824703 net-snmp can't get "hrProcessorLoad" dynamically after change the No. of CPUs.
components/net-snmp/patches/049.16824703.dyn_cpu.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/net-snmp/patches/049.16824703.dyn_cpu.patch	Tue Sep 23 22:02:00 2014 -0700
@@ -0,0 +1,284 @@
+--- a/include/net-snmp/agent/hardware/cpu.h	2014-06-09 04:44:56.766491669 -0700
++++ b/include/net-snmp/agent/hardware/cpu.h	2014-06-09 04:45:47.845551969 -0700
+@@ -52,6 +52,11 @@
+      netsnmp_cpu_info *next;
+ };
+ 
++    /* Auxilary structure used for updating the new cpu list */
++struct cpu_idx {
++	int idx;
++	struct cpu_idx *next;
++};
+ 
+     /*
+      * Possibly not all needed ??
+@@ -60,6 +65,7 @@
+ netsnmp_cpu_info *netsnmp_cpu_get_next( netsnmp_cpu_info* );
+ netsnmp_cpu_info *netsnmp_cpu_get_byIdx(  int,   int );
+ netsnmp_cpu_info *netsnmp_cpu_get_byName( char*, int );
++int netsnmp_update_cpu_list( struct cpu_idx * ); /* returns the number of deleted cpus */
+ 
+ netsnmp_cache *netsnmp_cpu_get_cache( void );
+ int netsnmp_cpu_load( void );
+--- a/agent/mibgroup/hardware/cpu/cpu.c	2014-06-09 04:44:56.766855758 -0700
++++ b/agent/mibgroup/hardware/cpu/cpu.c	2014-06-19 05:07:54.648759853 -0700
+@@ -244,3 +244,59 @@
+     cpu2->pageIn     = cpu->pageIn;
+     cpu2->pageOut    = cpu->pageOut;
+ }
++
++    /*
++     * Updates the cpu list, keeping the cpus whose indices are passed
++     * assumes the passed linked list of indices is sorted in ascending order
++     * returns the number of deleted cpus
++     */
++int netsnmp_update_cpu_list( struct cpu_idx *new_cpu_list )
++{
++    netsnmp_cpu_info *prev, *current, *temp1, *temp2;
++    int n=0;
++    netsnmp_cpu_info *cpu;
++
++    for( prev=current=_cpu_head; current && new_cpu_list ;
++        current=current->next, new_cpu_list=new_cpu_list->next ) {
++        if ( current->idx == new_cpu_list->idx ) {
++            prev=current;
++        } else {
++            current=current->next;
++            while ( current && (current->idx != new_cpu_list->idx) )
++                current = current->next;
++            if ( !current ) {
++                /*This shouldn't happen. Something went really wrong */
++                return -1;
++            }
++
++            temp1 = prev->next;
++            prev->next = current;
++            prev = current;
++                /* remove the unassigned cpus */
++            while ( temp1 != current ) {
++                temp2 = temp1;
++                temp1 = temp1->next;
++                n++;
++                SNMP_FREE(temp2->history);
++                SNMP_FREE(temp2);
++            }
++        }
++    } /*end of for */
++
++    if ( !current && new_cpu_list ) {
++        /* This shouldn't happen. */
++        return -1;
++    }
++
++    /* Delete the unassigned trailing cpus from the list */
++    while ( current ) {
++        temp2 = current;
++        current = current->next;
++        n++;
++        SNMP_FREE(temp2->history);
++        SNMP_FREE(temp2);
++     }
++     prev->next = NULL;
++     return n;
++}
++
+--- a/agent/mibgroup/hardware/cpu/cpu_kstat.c	2014-06-09 04:44:56.766680662 -0700
++++ b/agent/mibgroup/hardware/cpu/cpu_kstat.c	2014-06-19 04:53:47.176189429 -0700
+@@ -17,16 +17,16 @@
+ extern kstat_ctl_t  *kstat_fd;
+ extern int           cpu_num;
+ int _cpu_status(char *state);
++static void add_new_kstat_cpu_entry(kstat_t *ksp);
++static struct cpu_idx * add_cpu_idx(struct cpu_idx * head, int idx);
+ 
+     /*
+      * Initialise the list of CPUs on the system
+      *   (including descriptions)
+      */
+ void init_cpu_kstat( void ) {
+-    int               i, n=0, clock, state_begin;
+-    char              ctype[15], ftype[15], state[10];
++    int               n=0;
+     kstat_t          *ksp;
+-    kstat_named_t    *ks_data;
+     netsnmp_cpu_info *cpu = netsnmp_cpu_get_byIdx( -1, 1 );
+     strcpy(cpu->name, "Overall CPU statistics");
+ 
+@@ -41,36 +41,50 @@
+         if ((strcmp(ksp->ks_module, "cpu_info") == 0) &&
+             (strcmp(ksp->ks_class,  "misc"    ) == 0)) {
+             kstat_read(kstat_fd, ksp, NULL );
++            add_new_kstat_cpu_entry(ksp);
+             n++;
+-            clock = 999999;
+-            memset(ctype, 0, sizeof(ctype));
+-            memset(ftype, 0, sizeof(ftype));
+-            memset(state, 0, sizeof(state));
+-            for (i=0, ks_data = ksp->ks_data; i < ksp->ks_ndata; i++, ks_data++) {
+-                if ( strcmp( ks_data->name, "state" ) == 0 ) {
+-                    strncpy( state, ks_data->value.c, sizeof(state));
+-                    state[sizeof(state)-1] = '\0';
+-                } else if ( strcmp( ks_data->name, "state_begin" ) == 0 ) {
+-                    state_begin = ks_data->value.i32;
+-                } else if ( strcmp( ks_data->name, "cpu_type" ) == 0 ) {
+-                    strncpy( ctype, ks_data->value.c, sizeof(ctype));
+-                    state[sizeof(ctype)-1] = '\0';
+-                } else if ( strcmp( ks_data->name, "fpu_type" ) == 0 ) {
+-                    strncpy( ftype, ks_data->value.c, sizeof(ftype));
+-                    state[sizeof(ftype)-1] = '\0';
+-                } else if ( strcmp( ks_data->name, "clock_MHz" ) == 0 ) {
+-                    clock = ks_data->value.i32;
+-                }
+-            }
+-            i   = ksp->ks_instance;
+-            cpu = netsnmp_cpu_get_byIdx( i, 1 );
+-            sprintf( cpu->name,  "cpu%d", i );
+-            sprintf( cpu->descr, "CPU %d Sun %d MHz %s with %s FPU %s",
+-                                 i, clock, ctype, ftype, state  );
+-            cpu->status = _cpu_status(state); /* XXX - or in 'n_c_a_load' ? */
+         }
+     }
+-    cpu_num = i;
++    cpu_num = n;
++}
++
++
++    /*
++     * adds the new cpu entry to the exisitng list
++     */
++static void
++add_new_kstat_cpu_entry( kstat_t *ksp ) {
++    int i, clock, state_begin;
++    char ctype[15], ftype[15], state[10];
++    kstat_named_t    *ks_data;
++    netsnmp_cpu_info *cpu;
++
++    clock = 999999;
++    memset(ctype, 0, sizeof(ctype));
++    memset(ftype, 0, sizeof(ftype));
++    memset(state, 0, sizeof(state));
++
++    for (i=0, ks_data = ksp->ks_data; i < ksp->ks_ndata; i++, ks_data++) {
++        if ( strcmp( ks_data->name, "state" ) == 0 ) {
++            strncpy( state, ks_data->value.c, sizeof(state));
++            state[sizeof(state)-1] = '\0';
++        } else if ( strcmp( ks_data->name, "state_begin" ) == 0 ) {
++            state_begin = ks_data->value.i32;
++        } else if ( strcmp( ks_data->name, "cpu_type" ) == 0 ) {
++            strncpy( ctype, ks_data->value.c, sizeof(ctype));
++            ctype[sizeof(ctype)-1] = '\0';
++        } else if ( strcmp( ks_data->name, "fpu_type" ) == 0 ) {
++            strncpy( ftype, ks_data->value.c, sizeof(ftype));
++            ftype[sizeof(ftype)-1] = '\0';
++        } else if ( strcmp( ks_data->name, "clock_MHz" ) == 0 ) {
++            clock = ks_data->value.i32;
++        }
++    }
++    i   = ksp->ks_instance;
++    cpu = netsnmp_cpu_get_byIdx( i, 1 );
++    sprintf( cpu->name,  "cpu%d", i );
++    sprintf( cpu->descr, "CPU %d Sun %d MHz %s with %s FPU %s", i, clock, ctype, ftype, state  );
++    cpu->status = _cpu_status(state);
+ }
+ 
+ 
+@@ -78,11 +92,12 @@
+      * Load the latest CPU usage statistics
+      */
+ int netsnmp_cpu_arch_load( netsnmp_cache *cache, void *magic ) {
+-    int               i=1;
++    int               i=1, n=0;
+     kstat_t          *ksp;
+     cpu_stat_t        cs;
+     netsnmp_cpu_info *cpu = netsnmp_cpu_get_byIdx( -1, 0 );
+     netsnmp_cpu_info *cpu2;
++    struct cpu_idx *new_cpu_list = NULL, *temp_cpu_idx;
+ 
+         /* Clear overall stats, ready for summing individual CPUs */
+     cpu->user_ticks = 0;
+@@ -97,6 +112,32 @@
+ 
+     kstat_chain_update( kstat_fd );
+     DEBUGMSGTL(("cpu", "cpu_kstat load\n "));
++
++    /*
++     * The stats update is three step.
++     * First - add in the new cpus' info to the linked list
++     */
++    for (ksp = kstat_fd->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
++        if (ksp->ks_flags & KSTAT_FLAG_INVALID)
++            continue;
++        if ((strcmp(ksp->ks_module, "cpu_info") == 0) &&
++            (strcmp(ksp->ks_class,  "misc"    ) == 0)) {
++            kstat_read(kstat_fd, ksp, NULL );
++            i = ksp->ks_instance;
++            new_cpu_list = add_cpu_idx( new_cpu_list, i);
++            cpu2 = netsnmp_cpu_get_byIdx( i, 0 );
++            if ( !cpu2 ) {
++                add_new_kstat_cpu_entry(ksp);
++                n++;
++            }
++        }
++    }
++
++
++    /* Second - update the CPU list to reflect new kernel structures */
++    n -= netsnmp_update_cpu_list( new_cpu_list );
++
++    /* Third - for updating stats for the new CPU set */
+     for (ksp = kstat_fd->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
+         if (ksp->ks_flags & KSTAT_FLAG_INVALID)
+             continue;
+@@ -104,7 +145,7 @@
+             i    = ksp->ks_instance;
+             cpu2 = netsnmp_cpu_get_byIdx( i, 0 );
+             if ( !cpu2 )
+-                    break;  /* or continue ?*/ /*Skip new CPUs */
++                    continue;  /* This shouldn't happen. Inconsistency in kstat CPU data */
+             if ((ksp->ks_type != KSTAT_TYPE_RAW) ||
+                 (ksp->ks_data_size != sizeof(cs))||
+                 (kstat_read(kstat_fd, ksp, &cs) == -1)) {
+@@ -138,9 +179,43 @@
+             cpu->nCtxSwitches += (unsigned long)cs.cpu_sysinfo.pswitch;
+         }
+     }
++    cpu_num += n;
++    /* Clean up the temporary CPU index list */
++    while(new_cpu_list) {
++        temp_cpu_idx = new_cpu_list;
++        new_cpu_list = new_cpu_list->next;
++        SNMP_FREE(temp_cpu_idx);
++    }
+     return 0;
+ }
+ 
++    /* returns the new head */
++static struct cpu_idx *
++add_cpu_idx(struct cpu_idx * head, int idx)
++{
++    struct cpu_idx *cpu_idx, *current;
++    cpu_idx = SNMP_MALLOC_TYPEDEF( struct cpu_idx );
++    if ( !cpu_idx ) {
++        DEBUGMSG(("cpu", "(cpu_idx creation failed)\n"));
++        return head;
++    }
++
++    cpu_idx->idx = idx;
++    if ( !head || head->idx > idx ) {
++        cpu_idx->next = head;
++        return cpu_idx;
++    }
++
++    for ( current=head; current; current=current->next ) {
++        if ( !current->next || current->next->idx > idx ) {
++            cpu_idx->next = current->next;
++            current->next = cpu_idx;
++            return head;
++        }
++    }
++
++}
++
+ int
+ _cpu_status( char *state)
+ {