1
0
mirror of https://github.com/prometheus-community/windows_exporter.git synced 2025-04-18 19:24:05 +03:00

dhcp: add dhcp scope stats (#1840)

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke 2025-01-20 11:03:03 +00:00 committed by GitHub
parent d31ce0507c
commit 5836a7dbf2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 973 additions and 195 deletions

View File

@ -2,49 +2,177 @@
The dhcp collector exposes DHCP Server metrics
|||
-|-
Metric name prefix | `dhcp`
Data source | Perflib
Classes | `DHCP Server`
Enabled by default? | No
| | |
|---------------------|---------------|
| Metric name prefix | `dhcp` |
| Data source | Perflib |
| Classes | `DHCP Server` |
| Enabled by default? | No |
## Flags
None
### `--collector.dhcp.enabled`
Comma-separated list of collectors to use. Defaults to all, if not specified.
## Metrics
Name | Description | Type | Labels
-----|-------------|------|-------
`packets_received_total` | Total number of packets received by the DHCP server | counter | None
`duplicates_dropped_total` | Total number of duplicate packets received by the DHCP server | counter | None
`packets_expired_total` | Total number of packets expired in the DHCP server message queue | counter | None
`active_queue_length` | Number of packets in the processing queue of the DHCP server | gauge | None
`conflict_check_queue_length` | Number of packets in the DHCP server queue waiting on conflict detection (ping) | gauge | None
`discovers_total` | Total DHCP Discovers received by the DHCP server | counter | None
`offers_total` | Total DHCP Offers sent by the DHCP server | counter | None
`requests_total` | Total DHCP Requests received by the DHCP server | counter | None
`informs_total` | Total DHCP Informs received by the DHCP server | counter | None
`acks_total` | Total DHCP Acks sent by the DHCP server | counter | None
`nacks_total` | Total DHCP Nacks sent by the DHCP server | counter | None
`declines_total` | Total DHCP Declines received by the DHCP server | counter | None
`releases_total` | Total DHCP Releases received by the DHCP server | counter | None
`offer_queue_length` | Number of packets in the offer queue of the DHCP server | gauge | None
`denied_due_to_match_total` | Total number of DHCP requests denied, based on matches from the Deny List | gauge | None
`denied_due_to_nonmatch_total` | Total number of DHCP requests denied, based on non-matches from the Allow List | gauge | None
`failover_bndupd_sent_total` | Number of DHCP failover Binding Update messages sent | counter | None
`failover_bndupd_received_total` | Number of DHCP failover Binding Update messages received | counter | None
`failover_bndack_sent_total` | Number of DHCP failover Binding Ack messages sent | counter | None
`failover_bndack_received_total` | Number of DHCP failover Binding Ack messages received | counter | None
`failover_bndupd_pending_in_outbound_queue` | Number of pending outbound DHCP failover Binding Update messages | counter | None
`failover_transitions_communicationinterrupted_state_total` | Total number of transitions into COMMUNICATION INTERRUPTED state | counter | None
`failover_transitions_partnerdown_state_total` | Total number of transitions into PARTNER DOWN state | counter | None
`failover_transitions_recover_total` | Total number of transitions into RECOVER state | counter | None
`failover_bndupd_dropped_total` | Total number of DHCP faileover Binding Updates dropped | counter | None
| Name | Description | Type | Labels |
|--------------------------------------------------------------------------|--------------------------------------------------------------------------------|---------|-----------------------------------------------------|
| `windows_dhcp_ack_total` | Total DHCP Acks sent by the DHCP server | counter | None |
| `windows_dhcp_denied_due_to_match_total` | Total number of DHCP requests denied, based on matches from the Deny List | gauge | None |
| `windows_dhcp_denied_due_to_nonmatch_total` | Total number of DHCP requests denied, based on non-matches from the Allow List | gauge | None |
| `windows_dhcp_declines_total` | Total DHCP Declines received by the DHCP server | counter | None |
| `windows_dhcp_discovers_total` | Total DHCP Discovers received by the DHCP server | counter | None |
| `windows_dhcp_failover_bndack_received_total` | Number of DHCP failover Binding Ack messages received | counter | None |
| `windows_dhcp_failover_bndack_sent_total` | Number of DHCP failover Binding Ack messages sent | counter | None |
| `windows_dhcp_failover_bndupd_dropped_total` | Total number of DHCP failover Binding Updates dropped | counter | None |
| `windows_dhcp_failover_bndupd_received_total` | Number of DHCP failover Binding Update messages received | counter | None |
| `windows_dhcp_failover_bndupd_sent_total` | Number of DHCP failover Binding Update messages sent | counter | None |
| `windows_dhcp_failover_bndupd_pending_in_outbound_queue` | Number of pending outbound DHCP failover Binding Update messages | counter | None |
| `windows_dhcp_failover_transitions_communicationinterrupted_state_total` | Total number of transitions into COMMUNICATION INTERRUPTED state | counter | None |
| `windows_dhcp_failover_transitions_partnerdown_state_total` | Total number of transitions into PARTNER DOWN state | counter | None |
| `windows_dhcp_failover_transitions_recover_total` | Total number of transitions into RECOVER state | counter | None |
| `windows_dhcp_informs_total` | Total DHCP Informs received by the DHCP server | counter | None |
| `windows_dhcp_nacks_total` | Total DHCP Nacks sent by the DHCP server | counter | None |
| `windows_dhcp_offers_total` | Total DHCP Offers sent by the DHCP server | counter | None |
| `windows_dhcp_packets_expired_total` | Total number of packets expired in the DHCP server message queue | counter | None |
| `windows_dhcp_packets_received_total` | Total number of packets received by the DHCP server | counter | None |
| `windows_dhcp_pending_offers_total` | Total number of pending offers in the DHCP server | counter | None |
| `windows_dhcp_releases_total` | Total DHCP Releases received by the DHCP server | counter | None |
| `windows_dhcp_requests_total` | Total DHCP Requests received by the DHCP server | counter | None |
| `windows_dhcp_scope_addresses_free_on_this_server` | DHCP Scope free addresses on this server | gauge | `scope` |
| `windows_dhcp_scope_addresses_free_on_partner_server` | DHCP Scope free addresses on partner server | gauge | `scope` |
| `windows_dhcp_scope_addresses_free` | DHCP Scope free addresses | gauge | `scope` |
| `windows_dhcp_scope_addresses_in_use_on_this_server` | DHCP Scope addresses in use on this server | gauge | `scope` |
| `windows_dhcp_scope_addresses_in_use_on_partner_server` | DHCP Scope addresses in use on partner server | gauge | `scope` |
| `windows_dhcp_scope_addresses_in_use` | DHCP Scope addresses in use | gauge | `scope` |
| `windows_dhcp_scope_info` | DHCP Scope information | gauge | `name`, `superscope_name`, `superscope_id`, `scope` |
| `windows_dhcp_scope_pending_offers` | DHCP Scope pending offers | gauge | `scope` |
| `windows_dhcp_scope_reserved_address` | DHCP Scope reserved addresses | gauge | `scope` |
| `windows_dhcp_scope_state` | DHCP Scope state | gauge | `scope`, `state` |
### Example metric
_This collector does not yet have explained examples, we would appreciate your help adding them!_
```
# HELP windows_dhcp_acks_total Total DHCP Acks sent by the DHCP server (AcksTotal)
# TYPE windows_dhcp_acks_total counter
windows_dhcp_acks_total 0
# HELP windows_dhcp_active_queue_length Number of packets in the processing queue of the DHCP server (ActiveQueueLength)
# TYPE windows_dhcp_active_queue_length gauge
windows_dhcp_active_queue_length 0
# HELP windows_dhcp_conflict_check_queue_length Number of packets in the DHCP server queue waiting on conflict detection (ping). (ConflictCheckQueueLength)
# TYPE windows_dhcp_conflict_check_queue_length gauge
windows_dhcp_conflict_check_queue_length 0
# HELP windows_dhcp_declines_total Total DHCP Declines received by the DHCP server (DeclinesTotal)
# TYPE windows_dhcp_declines_total counter
windows_dhcp_declines_total 0
# HELP windows_dhcp_denied_due_to_match_total Total number of DHCP requests denied, based on matches from the Deny list (DeniedDueToMatch)
# TYPE windows_dhcp_denied_due_to_match_total counter
windows_dhcp_denied_due_to_match_total 0
# HELP windows_dhcp_denied_due_to_nonmatch_total Total number of DHCP requests denied, based on non-matches from the Allow list (DeniedDueToNonMatch)
# TYPE windows_dhcp_denied_due_to_nonmatch_total counter
windows_dhcp_denied_due_to_nonmatch_total 0
# HELP windows_dhcp_discovers_total Total DHCP Discovers received by the DHCP server (DiscoversTotal)
# TYPE windows_dhcp_discovers_total counter
windows_dhcp_discovers_total 0
# HELP windows_dhcp_duplicates_dropped_total Total number of duplicate packets received by the DHCP server (DuplicatesDroppedTotal)
# TYPE windows_dhcp_duplicates_dropped_total counter
windows_dhcp_duplicates_dropped_total 0
# HELP windows_dhcp_failover_bndack_received_total Number of DHCP fail over Binding Ack messages received (FailoverBndackReceivedTotal)
# TYPE windows_dhcp_failover_bndack_received_total counter
windows_dhcp_failover_bndack_received_total 0
# HELP windows_dhcp_failover_bndack_sent_total Number of DHCP fail over Binding Ack messages sent (FailoverBndackSentTotal)
# TYPE windows_dhcp_failover_bndack_sent_total counter
windows_dhcp_failover_bndack_sent_total 0
# HELP windows_dhcp_failover_bndupd_dropped_total Total number of DHCP fail over Binding Updates dropped (FailoverBndupdDropped)
# TYPE windows_dhcp_failover_bndupd_dropped_total counter
windows_dhcp_failover_bndupd_dropped_total 0
# HELP windows_dhcp_failover_bndupd_pending_in_outbound_queue Number of pending outbound DHCP fail over Binding Update messages (FailoverBndupdPendingOutboundQueue)
# TYPE windows_dhcp_failover_bndupd_pending_in_outbound_queue gauge
windows_dhcp_failover_bndupd_pending_in_outbound_queue 0
# HELP windows_dhcp_failover_bndupd_received_total Number of DHCP fail over Binding Update messages received (FailoverBndupdReceivedTotal)
# TYPE windows_dhcp_failover_bndupd_received_total counter
windows_dhcp_failover_bndupd_received_total 0
# HELP windows_dhcp_failover_bndupd_sent_total Number of DHCP fail over Binding Update messages sent (FailoverBndupdSentTotal)
# TYPE windows_dhcp_failover_bndupd_sent_total counter
windows_dhcp_failover_bndupd_sent_total 0
# HELP windows_dhcp_failover_transitions_communicationinterrupted_state_total Total number of transitions into COMMUNICATION INTERRUPTED state (FailoverTransitionsCommunicationinterruptedState)
# TYPE windows_dhcp_failover_transitions_communicationinterrupted_state_total counter
windows_dhcp_failover_transitions_communicationinterrupted_state_total 0
# HELP windows_dhcp_failover_transitions_partnerdown_state_total Total number of transitions into PARTNER DOWN state (FailoverTransitionsPartnerdownState)
# TYPE windows_dhcp_failover_transitions_partnerdown_state_total counter
windows_dhcp_failover_transitions_partnerdown_state_total 0
# HELP windows_dhcp_failover_transitions_recover_total Total number of transitions into RECOVER state (FailoverTransitionsRecoverState)
# TYPE windows_dhcp_failover_transitions_recover_total counter
windows_dhcp_failover_transitions_recover_total 0
# HELP windows_dhcp_informs_total Total DHCP Informs received by the DHCP server (InformsTotal)
# TYPE windows_dhcp_informs_total counter
windows_dhcp_informs_total 0
# HELP windows_dhcp_nacks_total Total DHCP Nacks sent by the DHCP server (NacksTotal)
# TYPE windows_dhcp_nacks_total counter
windows_dhcp_nacks_total 0
# HELP windows_dhcp_offer_queue_length Number of packets in the offer queue of the DHCP server (OfferQueueLength)
# TYPE windows_dhcp_offer_queue_length gauge
windows_dhcp_offer_queue_length 0
# HELP windows_dhcp_offers_total Total DHCP Offers sent by the DHCP server (OffersTotal)
# TYPE windows_dhcp_offers_total counter
windows_dhcp_offers_total 0
# HELP windows_dhcp_packets_expired_total Total number of packets expired in the DHCP server message queue (PacketsExpiredTotal)
# TYPE windows_dhcp_packets_expired_total counter
windows_dhcp_packets_expired_total 0
# HELP windows_dhcp_packets_received_total Total number of packets received by the DHCP server (PacketsReceivedTotal)
# TYPE windows_dhcp_packets_received_total counter
windows_dhcp_packets_received_total 0
# HELP windows_dhcp_releases_total Total DHCP Releases received by the DHCP server (ReleasesTotal)
# TYPE windows_dhcp_releases_total counter
windows_dhcp_releases_total 0
# HELP windows_dhcp_requests_total Total DHCP Requests received by the DHCP server (RequestsTotal)
# TYPE windows_dhcp_requests_total counter
windows_dhcp_requests_total 0
# HELP windows_dhcp_scope_addresses_free_total DHCP Scope free addresses
# TYPE windows_dhcp_scope_addresses_free_total gauge
windows_dhcp_scope_addresses_free_total{scope="10.11.12.0/25"} 0
windows_dhcp_scope_addresses_free_total{scope="172.16.0.0/24"} 0
windows_dhcp_scope_addresses_free_total{scope="192.168.0.0/24"} 231
# HELP windows_dhcp_scope_addresses_in_use_total DHCP Scope addresses in use
# TYPE windows_dhcp_scope_addresses_in_use_total gauge
windows_dhcp_scope_addresses_in_use_total{scope="10.11.12.0/25"} 0
windows_dhcp_scope_addresses_in_use_total{scope="172.16.0.0/24"} 0
windows_dhcp_scope_addresses_in_use_total{scope="192.168.0.0/24"} 0
# HELP windows_dhcp_scope_info DHCP Scope information
# TYPE windows_dhcp_scope_info gauge
windows_dhcp_scope_info{name="SUBSUPERSCOPE",scope="172.16.0.0/24",superscope_id="2",superscope_name="SUPERSCOPE"} 1
windows_dhcp_scope_info{name="TEST",scope="192.168.0.0/24",superscope_id="0",superscope_name=""} 1
windows_dhcp_scope_info{name="TEST2",scope="10.11.12.0/25",superscope_id="2",superscope_name="SUPERSCOPE"} 1
# HELP windows_dhcp_scope_pending_offers_total DHCP Scope pending offers
# TYPE windows_dhcp_scope_pending_offers_total gauge
windows_dhcp_scope_pending_offers_total{scope="10.11.12.0/25"} 0
windows_dhcp_scope_pending_offers_total{scope="172.16.0.0/24"} 0
windows_dhcp_scope_pending_offers_total{scope="192.168.0.0/24"} 0
# HELP windows_dhcp_scope_reserved_address_total DHCP Scope reserved addresses
# TYPE windows_dhcp_scope_reserved_address_total gauge
windows_dhcp_scope_reserved_address_total{scope="10.11.12.0/25"} 0
windows_dhcp_scope_reserved_address_total{scope="172.16.0.0/24"} 0
windows_dhcp_scope_reserved_address_total{scope="192.168.0.0/24"} 2
# HELP windows_dhcp_scope_state DHCP Scope state
# TYPE windows_dhcp_scope_state gauge
windows_dhcp_scope_state{scope="10.11.12.0/25",state="Disabled"} 1
windows_dhcp_scope_state{scope="10.11.12.0/25",state="DisabledSwitched"} 0
windows_dhcp_scope_state{scope="10.11.12.0/25",state="Enabled"} 0
windows_dhcp_scope_state{scope="10.11.12.0/25",state="EnabledSwitched"} 0
windows_dhcp_scope_state{scope="10.11.12.0/25",state="InvalidState"} 0
windows_dhcp_scope_state{scope="172.16.0.0/24",state="Disabled"} 1
windows_dhcp_scope_state{scope="172.16.0.0/24",state="DisabledSwitched"} 0
windows_dhcp_scope_state{scope="172.16.0.0/24",state="Enabled"} 0
windows_dhcp_scope_state{scope="172.16.0.0/24",state="EnabledSwitched"} 0
windows_dhcp_scope_state{scope="172.16.0.0/24",state="InvalidState"} 0
windows_dhcp_scope_state{scope="192.168.0.0/24",state="Disabled"} 0
windows_dhcp_scope_state{scope="192.168.0.0/24",state="DisabledSwitched"} 0
windows_dhcp_scope_state{scope="192.168.0.0/24",state="Enabled"} 1
windows_dhcp_scope_state{scope="192.168.0.0/24",state="EnabledSwitched"} 0
windows_dhcp_scope_state{scope="192.168.0.0/24",state="InvalidState"} 0
```
## Useful queries
_This collector does not yet have any useful queries added, we would appreciate your help adding them!_

View File

@ -19,6 +19,10 @@ If given, an interface name needs to match the include regexp in order for the c
If given, an interface name needs to *not* match the exclude regexp in order for the corresponding metrics to be reported
### `--collector.net.enabled`
Comma-separated list of collectors to use. Defaults to all, if not specified.
## Metrics
Name | Description | Type | Labels

View File

@ -10,7 +10,9 @@ The netframework collector exposes metrics about dotnet framework.
## Flags
None
### `--collector.netframework.enabled`
Comma-separated list of collectors to use. Defaults to all, if not specified.
## Metrics

View File

@ -16,22 +16,39 @@
package dhcp
import (
"errors"
"fmt"
"log/slog"
"slices"
"strconv"
"strings"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/dhcpsapi"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/pdh"
"github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus"
)
const Name = "dhcp"
const (
Name = "dhcp"
type Config struct{}
subCollectorServerMetrics = "server_metrics"
subCollectorScopeMetrics = "scope_metrics"
)
type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"`
}
//nolint:gochecknoglobals
var ConfigDefaults = Config{}
var ConfigDefaults = Config{
CollectorsEnabled: []string{
subCollectorServerMetrics,
subCollectorScopeMetrics,
},
}
// A Collector is a Prometheus Collector perflib DHCP metrics.
type Collector struct {
@ -65,6 +82,17 @@ type Collector struct {
packetsReceivedTotal *prometheus.Desc
releasesTotal *prometheus.Desc
requestsTotal *prometheus.Desc
scopeInfo *prometheus.Desc
scopeState *prometheus.Desc
scopeAddressesFreeTotal *prometheus.Desc
scopeAddressesFreeOnPartnerServerTotal *prometheus.Desc
scopeAddressesFreeOnThisServerTotal *prometheus.Desc
scopeAddressesInUseTotal *prometheus.Desc
scopeAddressesInUseOnPartnerServerTotal *prometheus.Desc
scopeAddressesInUseOnThisServerTotal *prometheus.Desc
scopePendingOffersTotal *prometheus.Desc
scopeReservedAddressTotal *prometheus.Desc
}
func New(config *Config) *Collector {
@ -72,6 +100,10 @@ func New(config *Config) *Collector {
config = &ConfigDefaults
}
if config.CollectorsEnabled == nil {
config.CollectorsEnabled = ConfigDefaults.CollectorsEnabled
}
c := &Collector{
config: *config,
}
@ -79,8 +111,26 @@ func New(config *Config) *Collector {
return c
}
func NewWithFlags(_ *kingpin.Application) *Collector {
return &Collector{}
func NewWithFlags(app *kingpin.Application) *Collector {
c := &Collector{
config: ConfigDefaults,
}
c.config.CollectorsEnabled = make([]string, 0)
var collectorsEnabled string
app.Flag(
"collector.dhcp.enabled",
"Comma-separated list of collectors to use. Defaults to all, if not specified.",
).Default(strings.Join(ConfigDefaults.CollectorsEnabled, ",")).StringVar(&collectorsEnabled)
app.Action(func(*kingpin.ParseContext) error {
c.config.CollectorsEnabled = strings.Split(collectorsEnabled, ",")
return nil
})
return c
}
func (c *Collector) GetName() string {
@ -88,7 +138,9 @@ func (c *Collector) GetName() string {
}
func (c *Collector) Close() error {
c.perfDataCollector.Close()
if slices.Contains(c.config.CollectorsEnabled, subCollectorServerMetrics) {
c.perfDataCollector.Close()
}
return nil
}
@ -96,166 +148,258 @@ func (c *Collector) Close() error {
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
var err error
c.perfDataCollector, err = pdh.NewCollector[perfDataCounterValues](pdh.CounterTypeRaw, "DHCP Server", nil)
if err != nil {
return fmt.Errorf("failed to create DHCP Server collector: %w", err)
if slices.Contains(c.config.CollectorsEnabled, subCollectorServerMetrics) {
c.perfDataCollector, err = pdh.NewCollector[perfDataCounterValues](pdh.CounterTypeRaw, "DHCP Server", nil)
if err != nil {
return fmt.Errorf("failed to create DHCP Server collector: %w", err)
}
c.packetsReceivedTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "packets_received_total"),
"Total number of packets received by the DHCP server (PacketsReceivedTotal)",
nil,
nil,
)
c.duplicatesDroppedTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "duplicates_dropped_total"),
"Total number of duplicate packets received by the DHCP server (DuplicatesDroppedTotal)",
nil,
nil,
)
c.packetsExpiredTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "packets_expired_total"),
"Total number of packets expired in the DHCP server message queue (PacketsExpiredTotal)",
nil,
nil,
)
c.activeQueueLength = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "active_queue_length"),
"Number of packets in the processing queue of the DHCP server (ActiveQueueLength)",
nil,
nil,
)
c.conflictCheckQueueLength = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "conflict_check_queue_length"),
"Number of packets in the DHCP server queue waiting on conflict detection (ping). (ConflictCheckQueueLength)",
nil,
nil,
)
c.discoversTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "discovers_total"),
"Total DHCP Discovers received by the DHCP server (DiscoversTotal)",
nil,
nil,
)
c.offersTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "offers_total"),
"Total DHCP Offers sent by the DHCP server (OffersTotal)",
nil,
nil,
)
c.requestsTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "requests_total"),
"Total DHCP Requests received by the DHCP server (RequestsTotal)",
nil,
nil,
)
c.informsTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "informs_total"),
"Total DHCP Informs received by the DHCP server (InformsTotal)",
nil,
nil,
)
c.acksTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "acks_total"),
"Total DHCP Acks sent by the DHCP server (AcksTotal)",
nil,
nil,
)
c.nACKsTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "nacks_total"),
"Total DHCP Nacks sent by the DHCP server (NacksTotal)",
nil,
nil,
)
c.declinesTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "declines_total"),
"Total DHCP Declines received by the DHCP server (DeclinesTotal)",
nil,
nil,
)
c.releasesTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "releases_total"),
"Total DHCP Releases received by the DHCP server (ReleasesTotal)",
nil,
nil,
)
c.offerQueueLength = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "offer_queue_length"),
"Number of packets in the offer queue of the DHCP server (OfferQueueLength)",
nil,
nil,
)
c.deniedDueToMatch = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "denied_due_to_match_total"),
"Total number of DHCP requests denied, based on matches from the Deny list (DeniedDueToMatch)",
nil,
nil,
)
c.deniedDueToNonMatch = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "denied_due_to_nonmatch_total"),
"Total number of DHCP requests denied, based on non-matches from the Allow list (DeniedDueToNonMatch)",
nil,
nil,
)
c.failoverBndUpdSentTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndupd_sent_total"),
"Number of DHCP fail over Binding Update messages sent (FailoverBndupdSentTotal)",
nil,
nil,
)
c.failoverBndUpdReceivedTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndupd_received_total"),
"Number of DHCP fail over Binding Update messages received (FailoverBndupdReceivedTotal)",
nil,
nil,
)
c.failoverBndAckSentTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndack_sent_total"),
"Number of DHCP fail over Binding Ack messages sent (FailoverBndackSentTotal)",
nil,
nil,
)
c.failoverBndAckReceivedTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndack_received_total"),
"Number of DHCP fail over Binding Ack messages received (FailoverBndackReceivedTotal)",
nil,
nil,
)
c.failoverBndUpdPendingOutboundQueue = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndupd_pending_in_outbound_queue"),
"Number of pending outbound DHCP fail over Binding Update messages (FailoverBndupdPendingOutboundQueue)",
nil,
nil,
)
c.failoverTransitionsCommunicationInterruptedState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_transitions_communicationinterrupted_state_total"),
"Total number of transitions into COMMUNICATION INTERRUPTED state (FailoverTransitionsCommunicationinterruptedState)",
nil,
nil,
)
c.failoverTransitionsPartnerDownState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_transitions_partnerdown_state_total"),
"Total number of transitions into PARTNER DOWN state (FailoverTransitionsPartnerdownState)",
nil,
nil,
)
c.failoverTransitionsRecoverState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_transitions_recover_total"),
"Total number of transitions into RECOVER state (FailoverTransitionsRecoverState)",
nil,
nil,
)
c.failoverBndUpdDropped = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndupd_dropped_total"),
"Total number of DHCP fail over Binding Updates dropped (FailoverBndupdDropped)",
nil,
nil,
)
}
c.packetsReceivedTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "packets_received_total"),
"Total number of packets received by the DHCP server (PacketsReceivedTotal)",
nil,
nil,
)
c.duplicatesDroppedTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "duplicates_dropped_total"),
"Total number of duplicate packets received by the DHCP server (DuplicatesDroppedTotal)",
nil,
nil,
)
c.packetsExpiredTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "packets_expired_total"),
"Total number of packets expired in the DHCP server message queue (PacketsExpiredTotal)",
nil,
nil,
)
c.activeQueueLength = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "active_queue_length"),
"Number of packets in the processing queue of the DHCP server (ActiveQueueLength)",
nil,
nil,
)
c.conflictCheckQueueLength = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "conflict_check_queue_length"),
"Number of packets in the DHCP server queue waiting on conflict detection (ping). (ConflictCheckQueueLength)",
nil,
nil,
)
c.discoversTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "discovers_total"),
"Total DHCP Discovers received by the DHCP server (DiscoversTotal)",
nil,
nil,
)
c.offersTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "offers_total"),
"Total DHCP Offers sent by the DHCP server (OffersTotal)",
nil,
nil,
)
c.requestsTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "requests_total"),
"Total DHCP Requests received by the DHCP server (RequestsTotal)",
nil,
nil,
)
c.informsTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "informs_total"),
"Total DHCP Informs received by the DHCP server (InformsTotal)",
nil,
nil,
)
c.acksTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "acks_total"),
"Total DHCP Acks sent by the DHCP server (AcksTotal)",
nil,
nil,
)
c.nACKsTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "nacks_total"),
"Total DHCP Nacks sent by the DHCP server (NacksTotal)",
nil,
nil,
)
c.declinesTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "declines_total"),
"Total DHCP Declines received by the DHCP server (DeclinesTotal)",
nil,
nil,
)
c.releasesTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "releases_total"),
"Total DHCP Releases received by the DHCP server (ReleasesTotal)",
nil,
nil,
)
c.offerQueueLength = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "offer_queue_length"),
"Number of packets in the offer queue of the DHCP server (OfferQueueLength)",
nil,
nil,
)
c.deniedDueToMatch = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "denied_due_to_match_total"),
"Total number of DHCP requests denied, based on matches from the Deny list (DeniedDueToMatch)",
nil,
nil,
)
c.deniedDueToNonMatch = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "denied_due_to_nonmatch_total"),
"Total number of DHCP requests denied, based on non-matches from the Allow list (DeniedDueToNonMatch)",
nil,
nil,
)
c.failoverBndUpdSentTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndupd_sent_total"),
"Number of DHCP fail over Binding Update messages sent (FailoverBndupdSentTotal)",
nil,
nil,
)
c.failoverBndUpdReceivedTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndupd_received_total"),
"Number of DHCP fail over Binding Update messages received (FailoverBndupdReceivedTotal)",
nil,
nil,
)
c.failoverBndAckSentTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndack_sent_total"),
"Number of DHCP fail over Binding Ack messages sent (FailoverBndackSentTotal)",
nil,
nil,
)
c.failoverBndAckReceivedTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndack_received_total"),
"Number of DHCP fail over Binding Ack messages received (FailoverBndackReceivedTotal)",
nil,
nil,
)
c.failoverBndUpdPendingOutboundQueue = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndupd_pending_in_outbound_queue"),
"Number of pending outbound DHCP fail over Binding Update messages (FailoverBndupdPendingOutboundQueue)",
nil,
nil,
)
c.failoverTransitionsCommunicationInterruptedState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_transitions_communicationinterrupted_state_total"),
"Total number of transitions into COMMUNICATION INTERRUPTED state (FailoverTransitionsCommunicationinterruptedState)",
nil,
nil,
)
c.failoverTransitionsPartnerDownState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_transitions_partnerdown_state_total"),
"Total number of transitions into PARTNER DOWN state (FailoverTransitionsPartnerdownState)",
nil,
nil,
)
c.failoverTransitionsRecoverState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_transitions_recover_total"),
"Total number of transitions into RECOVER state (FailoverTransitionsRecoverState)",
nil,
nil,
)
c.failoverBndUpdDropped = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "failover_bndupd_dropped_total"),
"Total number of DHCP fail over Binding Updates dropped (FailoverBndupdDropped)",
nil,
nil,
)
if slices.Contains(c.config.CollectorsEnabled, subCollectorScopeMetrics) {
c.scopeInfo = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_info"),
"DHCP Scope information",
[]string{"name", "superscope_name", "superscope_id", "scope"},
nil,
)
c.scopeState = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_state"),
"DHCP Scope state",
[]string{"scope", "state"},
nil,
)
c.scopeAddressesFreeTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_addresses_free"),
"DHCP Scope free addresses",
[]string{"scope"},
nil,
)
c.scopeAddressesFreeOnPartnerServerTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_addresses_free_on_partner_server"),
"DHCP Scope free addresses on partner server",
[]string{"scope"},
nil,
)
c.scopeAddressesFreeOnThisServerTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_addresses_free_on_this_server"),
"DHCP Scope free addresses on this server",
[]string{"scope"},
nil,
)
c.scopeAddressesInUseTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_addresses_in_use"),
"DHCP Scope addresses in use",
[]string{"scope"},
nil,
)
c.scopeAddressesInUseOnPartnerServerTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_addresses_in_use_on_partner_server"),
"DHCP Scope addresses in use on partner server",
[]string{"scope"},
nil,
)
c.scopeAddressesInUseOnThisServerTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_addresses_in_use_on_this_server"),
"DHCP Scope addresses in use on this server",
[]string{"scope"},
nil,
)
c.scopePendingOffersTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_pending_offers"),
"DHCP Scope pending offers",
[]string{"scope"},
nil,
)
c.scopeReservedAddressTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "scope_reserved_address"),
"DHCP Scope reserved addresses",
[]string{"scope"},
nil,
)
}
return nil
}
func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
var errs []error
if slices.Contains(c.config.CollectorsEnabled, subCollectorServerMetrics) {
if err := c.collectServerMetrics(ch); err != nil {
errs = append(errs, err)
}
}
if slices.Contains(c.config.CollectorsEnabled, subCollectorScopeMetrics) {
if err := c.collectScopeMetrics(ch); err != nil {
errs = append(errs, err)
}
}
return errors.Join(errs...)
}
func (c *Collector) collectServerMetrics(ch chan<- prometheus.Metric) error {
err := c.perfDataCollector.Collect(&c.perfDataObject)
if err != nil {
return fmt.Errorf("failed to collect DHCP Server metrics: %w", err)
@ -413,3 +557,113 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
return nil
}
func (c *Collector) collectScopeMetrics(ch chan<- prometheus.Metric) error {
dhcpScopes, err := dhcpsapi.GetDHCPV4ScopeStatistics()
if err != nil {
return fmt.Errorf("failed to get DHCP scopes: %w", err)
}
for _, scope := range dhcpScopes {
scopeID := scope.ScopeIPAddress.String()
ch <- prometheus.MustNewConstMetric(
c.scopeInfo,
prometheus.GaugeValue,
1,
scope.Name,
scope.SuperScopeName,
strconv.Itoa(int(scope.SuperScopeNumber)),
scopeID,
)
for state, name := range dhcpsapi.DHCP_SUBNET_STATE_NAMES {
metric := 0.0
if state == scope.State {
metric = 1.0
}
ch <- prometheus.MustNewConstMetric(
c.scopeState,
prometheus.GaugeValue,
metric,
scopeID,
name,
)
}
if scope.AddressesFree != -1 {
ch <- prometheus.MustNewConstMetric(
c.scopeAddressesFreeTotal,
prometheus.GaugeValue,
scope.AddressesFree,
scopeID,
)
}
if scope.AddressesFreeOnPartnerServer != -1 {
ch <- prometheus.MustNewConstMetric(
c.scopeAddressesFreeOnPartnerServerTotal,
prometheus.GaugeValue,
scope.AddressesFreeOnPartnerServer,
scopeID,
)
}
if scope.AddressesFreeOnThisServer != -1 {
ch <- prometheus.MustNewConstMetric(
c.scopeAddressesFreeOnThisServerTotal,
prometheus.GaugeValue,
scope.AddressesFreeOnThisServer,
scopeID,
)
}
if scope.AddressesInUse != -1 {
ch <- prometheus.MustNewConstMetric(
c.scopeAddressesInUseTotal,
prometheus.GaugeValue,
scope.AddressesInUse,
scopeID,
)
}
if scope.AddressesInUseOnPartnerServer != -1 {
ch <- prometheus.MustNewConstMetric(
c.scopeAddressesInUseOnPartnerServerTotal,
prometheus.GaugeValue,
scope.AddressesInUseOnPartnerServer,
scopeID,
)
}
if scope.AddressesInUseOnThisServer != -1 {
ch <- prometheus.MustNewConstMetric(
c.scopeAddressesInUseOnThisServerTotal,
prometheus.GaugeValue,
scope.AddressesInUseOnThisServer,
scopeID,
)
}
if scope.PendingOffers != -1 {
ch <- prometheus.MustNewConstMetric(
c.scopePendingOffersTotal,
prometheus.GaugeValue,
scope.PendingOffers,
scopeID,
)
}
if scope.ReservedAddress != -1 {
ch <- prometheus.MustNewConstMetric(
c.scopeReservedAddressTotal,
prometheus.GaugeValue,
scope.ReservedAddress,
scopeID,
)
}
}
return nil
}

View File

@ -0,0 +1,214 @@
package dhcpsapi
import (
"errors"
"fmt"
"net"
"unsafe"
"golang.org/x/sys/windows"
)
//nolint:gochecknoglobals
var (
modDhcpServer = windows.NewLazySystemDLL("dhcpsapi.dll")
procDhcpGetSubnetInfo = modDhcpServer.NewProc("DhcpGetSubnetInfo")
procDhcpGetSuperScopeInfoV4 = modDhcpServer.NewProc("DhcpGetSuperScopeInfoV4")
procDhcpRpcFreeMemory = modDhcpServer.NewProc("DhcpRpcFreeMemory")
procDhcpV4EnumSubnetReservations = modDhcpServer.NewProc("DhcpV4EnumSubnetReservations")
procDhcpV4FailoverGetScopeStatistics = modDhcpServer.NewProc("DhcpV4FailoverGetScopeStatistics")
procDhcpGetMibInfoV5 = modDhcpServer.NewProc("DhcpGetMibInfoV5")
)
func GetDHCPV4ScopeStatistics() ([]DHCPV4Scope, error) {
var mibInfo *DHCP_MIB_INFO_V5
if err := dhcpGetMibInfoV5(&mibInfo); err != nil {
return nil, err
}
defer dhcpRpcFreeMemory(unsafe.Pointer(mibInfo))
subnetScopeInfos := make(map[DHCP_IP_ADDRESS]DHCP_SUBNET_MIB_INFO_V5, mibInfo.Scopes)
subnetMIBScopeInfos := unsafe.Slice(mibInfo.ScopeInfo, mibInfo.Scopes)
for _, subnetMIBScopeInfo := range subnetMIBScopeInfos {
subnetScopeInfos[subnetMIBScopeInfo.Subnet] = subnetMIBScopeInfo
}
var superScopeTable *DHCP_SUPER_SCOPE_TABLE
if err := dhcpGetSuperScopeInfoV4(&superScopeTable); err != nil {
return nil, err
} else if superScopeTable == nil {
return nil, errors.New("dhcpGetSuperScopeInfoV4 returned nil")
}
defer dhcpRpcFreeMemory(unsafe.Pointer(superScopeTable))
scopes := make([]DHCPV4Scope, 0, superScopeTable.Count)
subnets := unsafe.Slice(superScopeTable.Entries, superScopeTable.Count)
var errs []error
for _, subnet := range subnets {
if err := (func() error {
var subnetInfo *DHCP_SUBNET_INFO
err := dhcpGetSubnetInfo(subnet.SubnetAddress, &subnetInfo)
if err != nil {
return fmt.Errorf("failed to get subnet info: %w", err)
}
defer dhcpRpcFreeMemory(unsafe.Pointer(subnetInfo))
scope := DHCPV4Scope{
Name: subnetInfo.SubnetName.String(),
SuperScopeName: subnet.SuperScopeName.String(),
ScopeIPAddress: net.IPNet{IP: subnetInfo.SubnetAddress.IPv4(), Mask: subnetInfo.SubnetMask.IPv4Mask()},
SuperScopeNumber: subnet.SuperScopeNumber,
State: subnetInfo.SubnetState,
AddressesFree: -1,
AddressesFreeOnPartnerServer: -1,
AddressesFreeOnThisServer: -1,
AddressesInUse: -1,
AddressesInUseOnPartnerServer: -1,
AddressesInUseOnThisServer: -1,
PendingOffers: -1,
ReservedAddress: -1,
}
if subnetScopeInfo, ok := subnetScopeInfos[subnetInfo.SubnetAddress]; ok {
scope.AddressesInUse = float64(subnetScopeInfo.NumAddressesInUse)
scope.AddressesFree = float64(subnetScopeInfo.NumAddressesFree)
scope.PendingOffers = float64(subnetScopeInfo.NumPendingOffers)
}
subnetReservationCount, err := dhcpV4EnumSubnetReservations(subnet.SubnetAddress)
if err != nil {
return fmt.Errorf("failed to get subnet reservation count: %w", err)
} else {
scope.ReservedAddress = float64(subnetReservationCount)
}
var subnetStatistics *DHCP_FAILOVER_STATISTICS
err = dhcpV4FailoverGetScopeStatistics(subnet.SubnetAddress, &subnetStatistics)
defer dhcpRpcFreeMemory(unsafe.Pointer(subnetStatistics))
if err == nil {
scope.AddressesFree = float64(subnetStatistics.AddrFree)
scope.AddressesInUse = float64(subnetStatistics.AddrInUse)
scope.AddressesFreeOnPartnerServer = float64(subnetStatistics.PartnerAddrFree)
scope.AddressesInUseOnPartnerServer = float64(subnetStatistics.PartnerAddrInUse)
scope.AddressesFreeOnThisServer = float64(subnetStatistics.ThisAddrFree)
scope.AddressesInUseOnThisServer = float64(subnetStatistics.ThisAddrInUse)
} else if !errors.Is(err, ERROR_DHCP_FO_SCOPE_NOT_IN_RELATIONSHIP) {
return fmt.Errorf("failed to get subnet statistics: %w", err)
}
scopes = append(scopes, scope)
return nil
})(); err != nil {
errs = append(errs, err)
}
}
return scopes, errors.Join(errs...)
}
// dhcpGetSubnetInfo https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpgetsubnetinfo
func dhcpGetSubnetInfo(subnetAddress DHCP_IP_ADDRESS, subnetInfo **DHCP_SUBNET_INFO) error {
ret, _, _ := procDhcpGetSubnetInfo.Call(
0,
uintptr(subnetAddress),
uintptr(unsafe.Pointer(subnetInfo)),
)
if ret != 0 {
return fmt.Errorf("dhcpGetSubnetInfo failed with code %w", windows.Errno(ret))
}
return nil
}
// dhcpV4FailoverGetScopeStatistics https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpv4failovergetscopestatistics
func dhcpV4FailoverGetScopeStatistics(scopeId DHCP_IP_ADDRESS, stats **DHCP_FAILOVER_STATISTICS) error {
ret, _, _ := procDhcpV4FailoverGetScopeStatistics.Call(
0,
uintptr(scopeId),
uintptr(unsafe.Pointer(stats)),
)
if ret != 0 {
return fmt.Errorf("dhcpV4FailoverGetScopeStatistics failed with code %w", windows.Errno(ret))
}
return nil
}
// dhcpGetSuperScopeInfoV4 https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpgetsuperscopeinfov4
func dhcpGetSuperScopeInfoV4(superScopeTable **DHCP_SUPER_SCOPE_TABLE) error {
ret, _, _ := procDhcpGetSuperScopeInfoV4.Call(
0,
uintptr(unsafe.Pointer(superScopeTable)),
)
if ret != 0 {
return fmt.Errorf("dhcpGetSuperScopeInfoV4 failed with code %w", windows.Errno(ret))
}
return nil
}
// dhcpGetMibInfoV5 https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpgetmibinfov5
func dhcpGetMibInfoV5(mibInfo **DHCP_MIB_INFO_V5) error {
ret, _, _ := procDhcpGetMibInfoV5.Call(
0,
uintptr(unsafe.Pointer(mibInfo)),
)
if ret != 0 {
return fmt.Errorf("dhcpGetMibInfoV5 failed with code %w", windows.Errno(ret))
}
return nil
}
// dhcpV4EnumSubnetReservations https://learn.microsoft.com/en-us/windows/win32/api/dhcpsapi/nf-dhcpsapi-dhcpv4enumsubnetreservations
func dhcpV4EnumSubnetReservations(subnetAddress DHCP_IP_ADDRESS) (uint32, error) {
var (
elementsRead uint32
elementsTotal uint32
elementsInfo uintptr
resumeHandle *windows.Handle
)
ret, _, _ := procDhcpV4EnumSubnetReservations.Call(
0,
uintptr(subnetAddress),
uintptr(unsafe.Pointer(&resumeHandle)),
0,
uintptr(unsafe.Pointer(&elementsInfo)),
uintptr(unsafe.Pointer(&elementsRead)),
uintptr(unsafe.Pointer(&elementsTotal)),
)
dhcpRpcFreeMemory(unsafe.Pointer(elementsInfo))
if !errors.Is(windows.Errno(ret), windows.ERROR_MORE_DATA) && !errors.Is(windows.Errno(ret), windows.ERROR_NO_MORE_ITEMS) {
return 0, fmt.Errorf("dhcpV4EnumSubnetReservations failed with code %w", windows.Errno(ret))
}
return elementsRead + elementsTotal, nil
}
func dhcpRpcFreeMemory(pointer unsafe.Pointer) {
if uintptr(pointer) == 0 {
return
}
//nolint:dogsled
_, _, _ = procDhcpRpcFreeMemory.Call(uintptr(pointer))
}

View File

@ -0,0 +1,24 @@
package dhcpsapi
import (
"errors"
"testing"
"github.com/stretchr/testify/require"
"golang.org/x/sys/windows"
)
func TestGetDHCPV4ScopeStatistics(t *testing.T) {
t.Parallel()
if procDhcpGetSuperScopeInfoV4.Find() != nil {
t.Skip("DhcpGetSuperScopeInfoV4 is not available")
}
_, err := GetDHCPV4ScopeStatistics()
if errors.Is(err, windows.Errno(1753)) {
t.Skip(err.Error())
}
require.NoError(t, err)
}

View File

@ -0,0 +1,137 @@
package dhcpsapi
import (
"encoding/binary"
"net"
"github.com/prometheus-community/windows_exporter/internal/headers/win32api"
"golang.org/x/sys/windows"
)
//nolint:gochecknoglobals
var ERROR_DHCP_FO_SCOPE_NOT_IN_RELATIONSHIP = windows.Errno(20116)
type DHCPV4Scope struct {
Name string
State DHCP_SUBNET_STATE
SuperScopeName string
SuperScopeNumber uint32
ScopeIPAddress net.IPNet
AddressesFree float64
AddressesFreeOnPartnerServer float64
AddressesFreeOnThisServer float64
AddressesInUse float64
AddressesInUseOnPartnerServer float64
AddressesInUseOnThisServer float64
PendingOffers float64
ReservedAddress float64
}
type (
DHCP_IP_ADDRESS win32api.DWORD
DHCP_IP_MASK win32api.DWORD
)
func (ip DHCP_IP_ADDRESS) IPv4() net.IP {
ipBytes := make([]byte, 4)
binary.BigEndian.PutUint32(ipBytes, uint32(ip))
return ipBytes
}
func (ip DHCP_IP_MASK) IPv4Mask() net.IPMask {
ipBytes := make([]byte, 4)
binary.BigEndian.PutUint32(ipBytes, uint32(ip))
return ipBytes
}
type DHCP_SUPER_SCOPE_TABLE struct {
Count win32api.DWORD
Entries *DHCP_SUPER_SCOPE_TABLE_ENTRY
}
type DHCP_SUPER_SCOPE_TABLE_ENTRY struct {
SubnetAddress DHCP_IP_ADDRESS
SuperScopeNumber win32api.DWORD
NextInSuperScope win32api.DWORD
SuperScopeName win32api.LPWSTR
}
// DHCP_SUBNET_INFO https://learn.microsoft.com/de-de/windows/win32/api/dhcpsapi/ns-dhcpsapi-dhcp_subnet_info
type DHCP_SUBNET_INFO struct {
SubnetAddress DHCP_IP_ADDRESS
SubnetMask DHCP_IP_MASK
SubnetName win32api.LPWSTR
SubnetComment win32api.LPWSTR
PrimaryHost DHCP_HOST_INFO
SubnetState DHCP_SUBNET_STATE
}
type DHCP_HOST_INFO struct {
IpAddress DHCP_IP_ADDRESS
NetBiosName win32api.LPWSTR
HostName win32api.LPWSTR
}
// DHCP_SUBNET_STATE https://learn.microsoft.com/de-de/windows/win32/api/dhcpsapi/ne-dhcpsapi-dhcp_subnet_state
type DHCP_SUBNET_STATE uint32
const (
DhcpSubnetEnabled DHCP_SUBNET_STATE = 0
DhcpSubnetDisabled DHCP_SUBNET_STATE = 1
DhcpSubnetEnabledSwitched DHCP_SUBNET_STATE = 2
DhcpSubnetDisabledSwitched DHCP_SUBNET_STATE = 3
DhcpSubnetInvalidState DHCP_SUBNET_STATE = 4
)
//nolint:gochecknoglobals
var DHCP_SUBNET_STATE_NAMES = map[DHCP_SUBNET_STATE]string{
DhcpSubnetEnabled: "Enabled",
DhcpSubnetDisabled: "Disabled",
DhcpSubnetEnabledSwitched: "EnabledSwitched",
DhcpSubnetDisabledSwitched: "DisabledSwitched",
DhcpSubnetInvalidState: "InvalidState",
}
type DHCP_FAILOVER_STATISTICS struct {
NumAddr win32api.DWORD
AddrFree win32api.DWORD
AddrInUse win32api.DWORD
PartnerAddrFree win32api.DWORD
ThisAddrFree win32api.DWORD
PartnerAddrInUse win32api.DWORD
ThisAddrInUse win32api.DWORD
}
type DHCP_MIB_INFO_V5 struct {
Discovers win32api.DWORD
Offers win32api.DWORD
Requests win32api.DWORD
Acks win32api.DWORD
Naks win32api.DWORD
Declines win32api.DWORD
Releases win32api.DWORD
ServerStartTime win32api.DATE_TIME
QtnNumLeases win32api.DWORD
QtnPctQtnLeases win32api.DWORD
QtnProbationLeases win32api.DWORD
QtnNonQtnLeases win32api.DWORD
QtnExemptLeases win32api.DWORD
QtnCapableClients win32api.DWORD
QtnIASErrors win32api.DWORD
DelayedOffers win32api.DWORD
ScopesWithDelayedOffers win32api.DWORD
Scopes win32api.DWORD
ScopeInfo *DHCP_SUBNET_MIB_INFO_V5
}
type DHCP_SUBNET_MIB_INFO_V5 struct {
Subnet DHCP_IP_ADDRESS
NumAddressesInUse win32api.DWORD
NumAddressesFree win32api.DWORD
NumPendingOffers win32api.DWORD
}

View File

@ -0,0 +1,15 @@
package win32api
import "golang.org/x/sys/windows"
type (
DATE_TIME = windows.Filetime
DWORD = uint32
LPWSTR struct {
*uint16
}
)
func (s LPWSTR) String() string {
return windows.UTF16PtrToString(s.uint16)
}