huatuo/core/metrics/arp.go

122 lines
2.9 KiB
Go

// Copyright 2025 The HuaTuo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package collector
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"huatuo-bamai/internal/pod"
"huatuo-bamai/pkg/metric"
"huatuo-bamai/pkg/tracing"
)
var arpCachePath = "/proc/net/stat/arp_cache"
type arpCollector struct {
metric []*metric.Data
}
func init() {
tracing.RegisterEventTracing("arp", newArp)
}
func newArp() (*tracing.EventTracingAttr, error) {
return &tracing.EventTracingAttr{
TracingData: &arpCollector{
metric: []*metric.Data{
metric.NewGaugeData("entries", 0, "host init namespace", nil),
metric.NewGaugeData("total", 0, "arp_cache entries", nil),
},
},
Flag: tracing.FlagMetric,
}, nil
}
// NetStat contains statistics for all the counters from one file.
// should be exported for /proc/net/stat/ndisc_cache
type NetStat struct {
Stats map[string]uint64
Filename string
}
func parseNetstatCache(filePath string) (NetStat, error) {
netStat := NetStat{
Stats: make(map[string]uint64),
}
file, err := os.Open(filePath)
if err != nil {
return netStat, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
scanner.Scan()
// First string is always a header for stats
var headers []string
headers = append(headers, strings.Fields(scanner.Text())...)
// Fast path ...
scanner.Scan()
for num, counter := range strings.Fields(scanner.Text()) {
value, err := strconv.ParseUint(counter, 16, 64)
if err != nil {
return NetStat{}, err
}
netStat.Stats[headers[num]] = value
}
return netStat, nil
}
func (c *arpCollector) Update() ([]*metric.Data, error) {
arpMetric := []*metric.Data{}
containers, err := pod.GetNormalContainers()
if err != nil {
return nil, fmt.Errorf("GetNormalContainers: %w", err)
}
for _, container := range containers {
count, err := fileLineCounter(fmt.Sprintf("/proc/%d/net/arp", container.InitPid))
if err != nil {
return nil, err
}
arpMetric = append(arpMetric, metric.NewContainerGaugeData(container, "entries", float64(count-1), "arp for container and host", nil))
}
count, err := fileLineCounter("/proc/1/net/arp")
if err != nil {
return nil, err
}
stat, err := parseNetstatCache(arpCachePath)
if err != nil {
return nil, err
}
c.metric[0].Value = float64(count - 1)
c.metric[1].Value = float64(stat.Stats["entries"])
arpMetric = append(arpMetric, c.metric...)
return arpMetric, nil
}