1515#include "systemstats_private.h"
1616
1717#include <stdint.h>
18+ #include <stddef.h>
1819#include <sys/types.h>
1920#include <dirent.h>
2021#include <ctype.h>
@@ -71,6 +72,41 @@ netsnmp_access_systemstats_arch_init(void)
7172 UdpLite: 0 0 0 0 0 0 0 0 0
7273*/
7374
75+ static struct {
76+ const char * name ;
77+ int avail_idx ; /* -1 means no columnAvail[] index */
78+ int offset ; /* -1 means no field in netsnmp_ipstats for that value */
79+ int type ; /* 0 - u_long, 1 - struct counter64 */
80+ } systemstats_v4_ip_fields [] = {
81+ {"Forwarding" , -1 , -1 , 0 },
82+ {"DefaultTTL" , -1 , -1 , 0 },
83+ {"InReceives" , IPSYSTEMSTATSTABLE_HCINRECEIVES , offsetof(netsnmp_ipstats , HCInReceives ), 1 },
84+ {"InHdrErrors" , IPSYSTEMSTATSTABLE_INHDRERRORS , offsetof(netsnmp_ipstats , InHdrErrors ), 0 },
85+ {"InAddrErrors" , IPSYSTEMSTATSTABLE_INADDRERRORS , offsetof(netsnmp_ipstats , InAddrErrors ), 0 },
86+ {"ForwDatagrams" , IPSYSTEMSTATSTABLE_HCOUTFORWDATAGRAMS , offsetof(netsnmp_ipstats , HCOutForwDatagrams ), 1 },
87+ {"InUnknownProtos" , IPSYSTEMSTATSTABLE_INUNKNOWNPROTOS , offsetof(netsnmp_ipstats , InUnknownProtos ), 0 },
88+ {"InDiscards" , IPSYSTEMSTATSTABLE_INDISCARDS , offsetof(netsnmp_ipstats , InDiscards ), 0 },
89+ {"InDelivers" , IPSYSTEMSTATSTABLE_HCINDELIVERS , offsetof(netsnmp_ipstats , HCInDelivers ), 1 },
90+ {"OutRequests" , IPSYSTEMSTATSTABLE_HCOUTREQUESTS , offsetof(netsnmp_ipstats , HCOutRequests ), 1 },
91+ {"OutDiscards" , IPSYSTEMSTATSTABLE_HCOUTDISCARDS , offsetof(netsnmp_ipstats , HCOutDiscards ), 1 },
92+ {"OutNoRoutes" , IPSYSTEMSTATSTABLE_HCOUTNOROUTES , offsetof(netsnmp_ipstats , HCOutNoRoutes ), 1 },
93+ {"ReasmTimeout" , -1 , -1 , 0 },
94+ {"ReasmReqds" , IPSYSTEMSTATSTABLE_REASMREQDS , offsetof(netsnmp_ipstats , ReasmReqds ), 0 },
95+ {"ReasmOKs" , IPSYSTEMSTATSTABLE_REASMOKS , offsetof(netsnmp_ipstats , ReasmOKs ), 0 },
96+ {"ReasmFails" , IPSYSTEMSTATSTABLE_REASMFAILS , offsetof(netsnmp_ipstats , ReasmFails ), 0 },
97+ {"FragOKs" , IPSYSTEMSTATSTABLE_HCOUTFRAGOKS , offsetof(netsnmp_ipstats , HCOutFragOKs ), 1 },
98+ {"FragFails" , IPSYSTEMSTATSTABLE_HCOUTFRAGFAILS , offsetof(netsnmp_ipstats , HCOutFragFails ), 1 },
99+ {"FragCreates" , IPSYSTEMSTATSTABLE_HCOUTFRAGCREATES , offsetof(netsnmp_ipstats , HCOutFragCreates ), 1 },
100+ {"OutTransmits" , -1 , -1 , 0 },
101+ };
102+
103+ #define SYSTEMSTATS_V4_IP_FIELD_COUNT \
104+ (sizeof(systemstats_v4_ip_fields) / sizeof(systemstats_v4_ip_fields[0]))
105+
106+ static int systemstats_v4_ip_fields_prepared ;
107+
108+ /* really found fields in header (index + 1); 0 means not found */
109+ static int systemstats_v4_ip_fields_idx [SYSTEMSTATS_V4_IP_FIELD_COUNT + 5 /*some extra space*/ ];
74110
75111/*
76112 *
@@ -121,10 +157,12 @@ _systemstats_v4(netsnmp_container* container, u_int load_flags)
121157 FILE * devin ;
122158 char line [1024 ];
123159 netsnmp_systemstats_entry * entry = NULL ;
124- int scan_count , expected_scan_count ;
160+ int scan_count = 0 ;
125161 char * stats , * start = line ;
126162 int len ;
127- unsigned long long scan_vals [20 ];
163+ unsigned long long scan_val ;
164+ char * field , * ptr , * saveptr ;
165+ int idx = 0 ;
128166
129167 DEBUGMSGTL (("access:systemstats:container:arch" , "load v4 (flags %x)\n" ,
130168 load_flags ));
@@ -142,41 +180,71 @@ _systemstats_v4(netsnmp_container* container, u_int load_flags)
142180 }
143181
144182 /*
145- * skip header, but make sure it's the length we expect.. .
183+ * Parse header and compare column labels .
146184 */
147- NETSNMP_IGNORE_RESULT (fgets (line , sizeof (line ), devin ));
185+ start = fgets (line , sizeof (line ), devin );
186+ if (!start ) {
187+ fclose (devin );
188+ snmp_log_perror ("systemstats_linux: cannot read /proc/net/snmp" );
189+ return -3 ;
190+ }
191+
148192 len = strlen (line );
149- switch (len ) {
150- case 224 :
151- expected_scan_count = 19 ;
152- break ;
153- case 237 :
154- expected_scan_count = 20 ;
155- break ;
156- default :
193+ if (len && line [len - 1 ] == '\n' )
194+ line [len - 1 ] = '\0' ;
195+
196+ if (strncmp (start , "Ip: " , 4 ) || len < 224 ) {
157197 fclose (devin );
158- snmp_log (LOG_ERR , "systemstats_linux: unexpected header length in /proc/net/snmp."
159- " %d not in { 224, 237 } \n" , len );
198+ snmp_log (LOG_ERR , "systemstats_linux: unexpected header in %s\n" , "/proc/net/snmp" );
160199 return -4 ;
200+ } else {
201+ start += sizeof ("Ip: " ) - 1 ;
202+ }
203+
204+ if (systemstats_v4_ip_fields_prepared == 0 ) {
205+ int found = 0 ;
206+
207+ for (ptr = start ; ; ptr = NULL ) {
208+ field = strtok_r (ptr , " " , & saveptr );
209+ if (!field )
210+ break ;
211+ for (int i = 0 ; i < SYSTEMSTATS_V4_IP_FIELD_COUNT ; ++ i ) {
212+ if (!strcmp (field , systemstats_v4_ip_fields [i ].name )) {
213+ systemstats_v4_ip_fields_idx [idx ] = i + 1 ;
214+ found ++ ;
215+ break ;
216+ }
217+ }
218+ idx ++ ;
219+ if (idx >= sizeof (systemstats_v4_ip_fields_idx ) /
220+ sizeof (systemstats_v4_ip_fields_idx [0 ])) {
221+ snmp_log (LOG_ERR , "systemstats_linux: known fields array overflow - report this as a net-snmp bug and include the kernel version\n" );
222+ break ;
223+ }
224+ }
225+ if (found != idx )
226+ snmp_log (LOG_ERR ,
227+ "systemstats_linux: found only %d known fields of %d in %s\n" ,
228+ found , idx , "/proc/net/snmp" );
229+ systemstats_v4_ip_fields_prepared = found ;
161230 }
162231
163232 /*
164233 * This file provides the statistics for each systemstats.
165234 * Read in each line in turn, isolate the systemstats name
166- * and retrieve (or create) the corresponding data structure.
235+ * and retrieve (or create) the corresponding data structure.
167236 */
168237 start = fgets (line , sizeof (line ), devin );
169238 fclose (devin );
170239 if (start ) {
171-
172240 len = strlen (line );
173241 if (len && line [len - 1 ] == '\n' )
174242 line [len - 1 ] = '\0' ;
175243
176244 while (* start && * start == ' ' )
177245 start ++ ;
178246
179- if (( !* start ) || (( stats = strrchr (start , ':' )) == NULL ) ) {
247+ if (!* start || (stats = strrchr (start , ':' )) == NULL ) {
180248 snmp_log (LOG_ERR ,
181249 "systemstats data format error 1, line ==|%s|\n" , line );
182250 return -4 ;
@@ -190,9 +258,8 @@ _systemstats_v4(netsnmp_container* container, u_int load_flags)
190258
191259 entry = netsnmp_access_systemstats_entry_create (1 , 0 ,
192260 "ipSystemStatsTable.ipv4" );
193- if ( NULL == entry ) {
261+ if (! entry )
194262 return -3 ;
195- }
196263
197264 /*
198265 * OK - we've now got (or created) the data structure for
@@ -202,72 +269,50 @@ _systemstats_v4(netsnmp_container* container, u_int load_flags)
202269 * data structure accordingly.
203270 */
204271
205- memset (scan_vals , 0x0 , sizeof (scan_vals ));
206- scan_count = sscanf (stats ,
207- "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu"
208- "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu" ,
209- & scan_vals [0 ],& scan_vals [1 ],& scan_vals [2 ],
210- & scan_vals [3 ],& scan_vals [4 ],& scan_vals [5 ],
211- & scan_vals [6 ],& scan_vals [7 ],& scan_vals [8 ],
212- & scan_vals [9 ],& scan_vals [10 ],& scan_vals [11 ],
213- & scan_vals [12 ],& scan_vals [13 ],& scan_vals [14 ],
214- & scan_vals [15 ],& scan_vals [16 ],& scan_vals [17 ],
215- & scan_vals [18 ],& scan_vals [19 ]);
272+ for (ptr = stats , len = 0 ; ; ptr = NULL , len ++ ) {
273+ char * e ;
274+
275+ if (!(field = strtok_r (ptr , " " , & saveptr )))
276+ break ;
277+ scan_val = strtoull (field , & e , 10 );
278+ if (field == e || * e != '\0' )
279+ continue ;
280+ if (len >= sizeof (systemstats_v4_ip_fields_idx ) /
281+ sizeof (systemstats_v4_ip_fields_idx [0 ])) {
282+ snmp_log (LOG_ERR , "systemstats_linux: known fields array overflow - report this as a net-snmp bug and include the kernel version\n" );
283+ break ;
284+ }
285+ if (systemstats_v4_ip_fields_idx [len ] == 0 )
286+ continue ;
287+ idx = systemstats_v4_ip_fields_idx [len ] - 1 ;
288+ scan_count ++ ;
289+ if (systemstats_v4_ip_fields [idx ].offset != -1 ) {
290+ int offset = systemstats_v4_ip_fields [idx ].offset ;
291+
292+ if (systemstats_v4_ip_fields [idx ].type == 0 ) {
293+ u_long * u = (u_long * )((void * )& entry -> stats + offset );
294+ * u = scan_val ;
295+ } else {
296+ struct counter64 * s = (struct counter64 * )((void * )& entry -> stats + offset );
297+ s -> low = scan_val & 0xffffffff ;
298+ s -> high = scan_val >> 32 ;
299+ }
300+ }
301+ if (systemstats_v4_ip_fields [idx ].avail_idx != -1 ) {
302+ entry -> stats .columnAvail [systemstats_v4_ip_fields [idx ].avail_idx ] = 1 ;
303+ }
304+ }
305+
216306 DEBUGMSGTL (("access:systemstats" , " read %d values\n" , scan_count ));
217307
218- if (scan_count != expected_scan_count ) {
308+ if (scan_count != systemstats_v4_ip_fields_prepared ) {
219309 snmp_log (LOG_ERR ,
220310 "error scanning systemstats data (expected %d, got %d)\n" ,
221- expected_scan_count , scan_count );
311+ systemstats_v4_ip_fields_prepared , scan_count );
222312 netsnmp_access_systemstats_entry_free (entry );
223313 return -4 ;
224314 }
225- /* entry->stats. = scan_vals[0]; / * Forwarding */
226- /* entry->stats. = scan_vals[1]; / * DefaultTTL */
227- entry -> stats .HCInReceives .low = scan_vals [2 ] & 0xffffffff ;
228- entry -> stats .HCInReceives .high = scan_vals [2 ] >> 32 ;
229- entry -> stats .InHdrErrors = scan_vals [3 ];
230- entry -> stats .InAddrErrors = scan_vals [4 ];
231- entry -> stats .HCOutForwDatagrams .low = scan_vals [5 ] & 0xffffffff ;
232- entry -> stats .HCOutForwDatagrams .high = scan_vals [5 ] >> 32 ;
233- entry -> stats .InUnknownProtos = scan_vals [6 ];
234- entry -> stats .InDiscards = scan_vals [7 ];
235- entry -> stats .HCInDelivers .low = scan_vals [8 ] & 0xffffffff ;
236- entry -> stats .HCInDelivers .high = scan_vals [8 ] >> 32 ;
237- entry -> stats .HCOutRequests .low = scan_vals [9 ] & 0xffffffff ;
238- entry -> stats .HCOutRequests .high = scan_vals [9 ] >> 32 ;
239- entry -> stats .HCOutDiscards .low = scan_vals [10 ] & 0xffffffff ;
240- entry -> stats .HCOutDiscards .high = scan_vals [10 ] >> 32 ;
241- entry -> stats .HCOutNoRoutes .low = scan_vals [11 ] & 0xffffffff ;
242- entry -> stats .HCOutNoRoutes .high = scan_vals [11 ] >> 32 ;
243- /* entry->stats. = scan_vals[12]; / * ReasmTimeout */
244- entry -> stats .ReasmReqds = scan_vals [13 ];
245- entry -> stats .ReasmOKs = scan_vals [14 ];
246- entry -> stats .ReasmFails = scan_vals [15 ];
247- entry -> stats .HCOutFragOKs .low = scan_vals [16 ] & 0xffffffff ;
248- entry -> stats .HCOutFragOKs .high = scan_vals [16 ] >> 32 ;
249- entry -> stats .HCOutFragFails .low = scan_vals [17 ] & 0xffffffff ;
250- entry -> stats .HCOutFragFails .high = scan_vals [17 ] >> 32 ;
251- entry -> stats .HCOutFragCreates .low = scan_vals [18 ] & 0xffffffff ;
252- entry -> stats .HCOutFragCreates .high = scan_vals [18 ] >> 32 ;
253- /* entry->stats. = scan_vals[19]; / * OutTransmits */
254-
255- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_HCINRECEIVES ] = 1 ;
256- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_INHDRERRORS ] = 1 ;
257- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_INADDRERRORS ] = 1 ;
258- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_HCOUTFORWDATAGRAMS ] = 1 ;
259- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_INUNKNOWNPROTOS ] = 1 ;
260- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_INDISCARDS ] = 1 ;
261- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_HCINDELIVERS ] = 1 ;
262- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_HCOUTREQUESTS ] = 1 ;
263- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_HCOUTDISCARDS ] = 1 ;
264- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_HCOUTNOROUTES ] = 1 ;
265- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_REASMREQDS ] = 1 ;
266- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_REASMOKS ] = 1 ;
267- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_REASMFAILS ] = 1 ;
268- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_HCOUTFRAGOKS ] = 1 ;
269- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_HCOUTFRAGFAILS ] = 1 ;
270- entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_HCOUTFRAGCREATES ] = 1 ;
315+
271316 entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_DISCONTINUITYTIME ] = 1 ;
272317 entry -> stats .columnAvail [IPSYSTEMSTATSTABLE_REFRESHRATE ] = 1 ;
273318
0 commit comments