2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 49 SNMP Interface */
12 #include "cache_snmp.h"
13 #include "CachePeer.h"
14 #include "CachePeers.h"
16 #include "mem/Meter.h"
17 #include "mem/Stats.h"
19 #include "neighbors.h"
20 #include "snmp_agent.h"
21 #include "snmp_core.h"
22 #include "SquidConfig.h"
23 #include "SquidMath.h"
25 #include "StatCounters.h"
28 #include "store/Controller.h"
29 #include "StoreStats.h"
33 /************************************************************************
35 SQUID MIB Implementation
37 ************************************************************************/
44 snmp_sysFn(variable_list
* Var
, snint
* ErrP
)
46 variable_list
*Answer
= nullptr;
48 debugs(49, 5, "snmp_sysFn: Processing request:" << snmpDebugOid(Var
->name
, Var
->name_length
, tmp
));
49 *ErrP
= SNMP_ERR_NOERROR
;
51 switch (Var
->name
[LEN_SQ_SYS
]) {
54 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
55 mem_node::StoreMemSize() >> 10,
60 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
61 Store::Root().currentSize() >> 10,
66 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
67 (int)(tvSubDsec(squid_start
, current_time
) * 100),
72 *ErrP
= SNMP_ERR_NOSUCHNAME
;
83 snmp_confFn(variable_list
* Var
, snint
* ErrP
)
85 variable_list
*Answer
= nullptr;
86 const char *cp
= nullptr;
87 debugs(49, 5, "snmp_confFn: Processing request with magic " << Var
->name
[8] << "!");
88 *ErrP
= SNMP_ERR_NOERROR
;
90 switch (Var
->name
[LEN_SQ_CONF
]) {
93 Answer
= snmp_var_new(Var
->name
, Var
->name_length
);
94 Answer
->type
= ASN_OCTET_STR
;
95 Answer
->val_len
= strlen(Config
.adminEmail
);
96 Answer
->val
.string
= (u_char
*) xstrdup(Config
.adminEmail
);
100 Answer
= snmp_var_new(Var
->name
, Var
->name_length
);
101 Answer
->type
= ASN_OCTET_STR
;
102 Answer
->val_len
= strlen(APP_SHORTNAME
);
103 Answer
->val
.string
= (u_char
*) xstrdup(APP_SHORTNAME
);
106 case CONF_VERSION_ID
:
107 Answer
= snmp_var_new(Var
->name
, Var
->name_length
);
108 Answer
->type
= ASN_OCTET_STR
;
109 Answer
->val_len
= strlen(VERSION
);
110 Answer
->val
.string
= (u_char
*) xstrdup(VERSION
);
115 switch (Var
->name
[LEN_SQ_CONF
+ 1]) {
118 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
119 (snint
) (Config
.memMaxSize
>> 20),
123 case CONF_ST_SWMAXSZ
:
124 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
125 (snint
) (Store::Root().maxSize() >> 20),
130 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
131 (snint
) Config
.Swap
.highWaterMark
,
136 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
137 (snint
) Config
.Swap
.lowWaterMark
,
142 *ErrP
= SNMP_ERR_NOSUCHNAME
;
149 Answer
= snmp_var_new(Var
->name
, Var
->name_length
);
151 if (!(cp
= Debug::debugOptions
))
154 Answer
->type
= ASN_OCTET_STR
;
156 Answer
->val_len
= strlen(cp
);
158 Answer
->val
.string
= (u_char
*) xstrdup(cp
);
163 Answer
= snmp_var_new(Var
->name
, Var
->name_length
);
165 cp
= uniqueHostname();
167 Answer
->type
= ASN_OCTET_STR
;
169 Answer
->val_len
= strlen(cp
);
171 Answer
->val
.string
= (u_char
*) xstrdup(cp
);
176 *ErrP
= SNMP_ERR_NOSUCHNAME
;
189 snmp_meshPtblFn(variable_list
* Var
, snint
* ErrP
)
191 variable_list
*Answer
= nullptr;
195 CachePeer
*p
= nullptr;
196 debugs(49, 5, "snmp_meshPtblFn: peer " << Var
->name
[LEN_SQ_MESH
+ 3] << " requested!");
197 *ErrP
= SNMP_ERR_NOERROR
;
199 u_int index
= Var
->name
[LEN_SQ_MESH
+ 3] ;
200 for (const auto &peer
: CurrentCachePeers()) {
201 if (peer
->index
== index
) {
202 laddr
= peer
->in_addr
;
209 *ErrP
= SNMP_ERR_NOSUCHNAME
;
213 switch (Var
->name
[LEN_SQ_MESH
+ 2]) {
214 case MESH_PTBL_INDEX
: { // XXX: Should be visible?
215 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
216 (snint
)p
->index
, SMI_INTEGER
);
222 Answer
= snmp_var_new(Var
->name
, Var
->name_length
);
223 Answer
->type
= ASN_OCTET_STR
;
224 Answer
->val_len
= strlen(cp
);
225 Answer
->val
.string
= (u_char
*) xstrdup(cp
);
229 case MESH_PTBL_ADDR_TYPE
: {
231 ival
= laddr
.isIPv4() ? INETADDRESSTYPE_IPV4
: INETADDRESSTYPE_IPV6
;
232 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
236 case MESH_PTBL_ADDR
: {
237 Answer
= snmp_var_new(Var
->name
, Var
->name_length
);
238 // InetAddress doesn't have its own ASN.1 type,
239 // like IpAddr does (SMI_IPADDRESS)
241 Answer
->type
= ASN_OCTET_STR
;
242 char host
[MAX_IPSTRLEN
];
243 laddr
.toStr(host
,MAX_IPSTRLEN
);
244 Answer
->val_len
= strlen(host
);
245 Answer
->val
.string
= (u_char
*) xstrdup(host
);
250 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
251 (snint
) p
->http_port
,
256 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
262 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
267 case MESH_PTBL_STATE
:
268 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
269 (snint
) neighborUp(p
),
274 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
279 case MESH_PTBL_PACKED
:
280 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
281 p
->stats
.pings_acked
,
285 case MESH_PTBL_FETCHES
:
286 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
292 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
298 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
299 p
->stats
.ignored_replies
,
303 case MESH_PTBL_KEEPAL_S
:
304 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
305 p
->stats
.n_keepalives_sent
,
309 case MESH_PTBL_KEEPAL_R
:
310 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
311 p
->stats
.n_keepalives_recv
,
316 *ErrP
= SNMP_ERR_NOSUCHNAME
;
324 snmp_prfSysFn(variable_list
* Var
, snint
* ErrP
)
326 variable_list
*Answer
= nullptr;
328 static struct rusage rusage
;
329 debugs(49, 5, "snmp_prfSysFn: Processing request with magic " << Var
->name
[LEN_SQ_PRF
+ 1] << "!");
330 *ErrP
= SNMP_ERR_NOERROR
;
332 switch (Var
->name
[LEN_SQ_PRF
+ 1]) {
335 squid_getrusage(&rusage
);
336 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
337 rusage_pagefaults(&rusage
),
342 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
347 case PERF_SYS_MEMUSAGE
: {
348 Mem::PoolStats stats
;
349 Mem::GlobalStats(stats
);
350 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
351 (snint
) stats
.meter
->alloc
.currentLevel() >> 10,
356 case PERF_SYS_CPUTIME
:
357 squid_getrusage(&rusage
);
358 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
359 (snint
) rusage_cputime(&rusage
),
363 case PERF_SYS_CPUUSAGE
:
364 squid_getrusage(&rusage
);
365 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
366 (snint
) Math::doublePercent(rusage_cputime(&rusage
), tvSubDsec(squid_start
, current_time
)),
370 case PERF_SYS_MAXRESSZ
:
371 squid_getrusage(&rusage
);
372 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
373 (snint
) rusage_maxrss(&rusage
),
377 case PERF_SYS_CURLRUEXP
:
378 /* No global LRU info anymore */
379 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
384 case PERF_SYS_CURUNLREQ
:
385 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
386 (snint
) statCounter
.unlink
.requests
,
390 case PERF_SYS_CURUNUSED_FD
:
391 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
392 (snint
) Squid_MaxFD
- Number_FD
,
396 case PERF_SYS_CURRESERVED_FD
:
397 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
402 case PERF_SYS_CURUSED_FD
:
403 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
408 case PERF_SYS_CURMAX_FD
:
409 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
414 case PERF_SYS_NUMOBJCNT
: {
415 StoreInfoStats stats
;
416 Store::Root().getStats(stats
);
417 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
418 (snint
) (stats
.mem
.count
+ stats
.swap
.count
),
424 *ErrP
= SNMP_ERR_NOSUCHNAME
;
432 snmp_prfProtoFn(variable_list
* Var
, snint
* ErrP
)
434 variable_list
*Answer
= nullptr;
435 static StatCounters
*f
= nullptr;
436 static StatCounters
*l
= nullptr;
439 debugs(49, 5, "snmp_prfProtoFn: Processing request with magic " << Var
->name
[LEN_SQ_PRF
] << "!");
440 *ErrP
= SNMP_ERR_NOERROR
;
442 switch (Var
->name
[LEN_SQ_PRF
+ 1]) {
444 case PERF_PROTOSTAT_AGGR
: /* cacheProtoAggregateStats */
446 switch (Var
->name
[LEN_SQ_PRF
+ 2]) {
448 case PERF_PROTOSTAT_AGGR_HTTP_REQ
:
449 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
450 (snint
) statCounter
.client_http
.requests
,
454 case PERF_PROTOSTAT_AGGR_HTTP_HITS
:
455 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
456 (snint
) statCounter
.client_http
.hits
,
460 case PERF_PROTOSTAT_AGGR_HTTP_ERRORS
:
461 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
462 (snint
) statCounter
.client_http
.errors
,
466 case PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN
:
467 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
468 (snint
) statCounter
.client_http
.kbytes_in
.kb
,
472 case PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT
:
473 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
474 (snint
) statCounter
.client_http
.kbytes_out
.kb
,
478 case PERF_PROTOSTAT_AGGR_ICP_S
:
479 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
480 (snint
) statCounter
.icp
.pkts_sent
,
484 case PERF_PROTOSTAT_AGGR_ICP_R
:
485 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
486 (snint
) statCounter
.icp
.pkts_recv
,
490 case PERF_PROTOSTAT_AGGR_ICP_SKB
:
491 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
492 (snint
) statCounter
.icp
.kbytes_sent
.kb
,
496 case PERF_PROTOSTAT_AGGR_ICP_RKB
:
497 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
498 (snint
) statCounter
.icp
.kbytes_recv
.kb
,
502 case PERF_PROTOSTAT_AGGR_REQ
:
503 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
504 (snint
) statCounter
.server
.all
.requests
,
508 case PERF_PROTOSTAT_AGGR_ERRORS
:
509 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
510 (snint
) statCounter
.server
.all
.errors
,
514 case PERF_PROTOSTAT_AGGR_KBYTES_IN
:
515 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
516 (snint
) statCounter
.server
.all
.kbytes_in
.kb
,
520 case PERF_PROTOSTAT_AGGR_KBYTES_OUT
:
521 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
522 (snint
) statCounter
.server
.all
.kbytes_out
.kb
,
526 case PERF_PROTOSTAT_AGGR_CURSWAP
:
527 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
528 (snint
) Store::Root().currentSize() >> 10,
532 case PERF_PROTOSTAT_AGGR_CLIENTS
:
533 Answer
= snmp_var_new_integer(Var
->name
, Var
->name_length
,
534 (snint
) statCounter
.client_http
.clients
,
539 *ErrP
= SNMP_ERR_NOSUCHNAME
;
545 case PERF_PROTOSTAT_MEDIAN
:
547 if (Var
->name_length
== LEN_SQ_PRF
+ 5)
548 minutes
= Var
->name
[LEN_SQ_PRF
+ 4];
552 if ((minutes
< 1) || (minutes
> 60))
557 l
= snmpStatGet(minutes
);
559 debugs(49, 8, "median: min= " << minutes
<< ", " << Var
->name
[LEN_SQ_PRF
+ 3] << " l= " << l
<< " , f = " << f
);
560 debugs(49, 8, "median: l= " << l
<< " , f = " << f
);
562 switch (Var
->name
[LEN_SQ_PRF
+ 3]) {
564 case PERF_MEDIAN_TIME
:
568 case PERF_MEDIAN_HTTP_ALL
:
569 x
= statHistDeltaMedian(l
->client_http
.allSvcTime
,
570 f
->client_http
.allSvcTime
);
573 case PERF_MEDIAN_HTTP_MISS
:
574 x
= statHistDeltaMedian(l
->client_http
.missSvcTime
,
575 f
->client_http
.missSvcTime
);
578 case PERF_MEDIAN_HTTP_NM
:
579 x
= statHistDeltaMedian(l
->client_http
.nearMissSvcTime
,
580 f
->client_http
.nearMissSvcTime
);
583 case PERF_MEDIAN_HTTP_HIT
:
584 x
= statHistDeltaMedian(l
->client_http
.hitSvcTime
,
585 f
->client_http
.hitSvcTime
);
588 case PERF_MEDIAN_ICP_QUERY
:
589 x
= statHistDeltaMedian(l
->icp
.querySvcTime
, f
->icp
.querySvcTime
);
592 case PERF_MEDIAN_ICP_REPLY
:
593 x
= statHistDeltaMedian(l
->icp
.replySvcTime
, f
->icp
.replySvcTime
);
596 case PERF_MEDIAN_DNS
:
597 x
= statHistDeltaMedian(l
->dns
.svcTime
, f
->dns
.svcTime
);
600 case PERF_MEDIAN_RHR
:
601 x
= statRequestHitRatio(minutes
);
604 case PERF_MEDIAN_BHR
:
605 x
= statByteHitRatio(minutes
);
608 case PERF_MEDIAN_HTTP_NH
:
609 x
= statHistDeltaMedian(l
->client_http
.nearHitSvcTime
,
610 f
->client_http
.nearHitSvcTime
);
614 *ErrP
= SNMP_ERR_NOSUCHNAME
;
618 return snmp_var_new_integer(Var
->name
, Var
->name_length
,
623 *ErrP
= SNMP_ERR_NOSUCHNAME
;