parent
d3478a207e
commit
664025d60c
@ -0,0 +1,85 @@ |
||||
// Copyright 2019 The Prometheus 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 procfs |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io/ioutil" |
||||
"net" |
||||
"strings" |
||||
) |
||||
|
||||
// ARPEntry contains a single row of the columnar data represented in
|
||||
// /proc/net/arp.
|
||||
type ARPEntry struct { |
||||
// IP address
|
||||
IPAddr net.IP |
||||
// MAC address
|
||||
HWAddr net.HardwareAddr |
||||
// Name of the device
|
||||
Device string |
||||
} |
||||
|
||||
// GatherARPEntries retrieves all the ARP entries, parse the relevant columns,
|
||||
// and then return a slice of ARPEntry's.
|
||||
func (fs FS) GatherARPEntries() ([]ARPEntry, error) { |
||||
data, err := ioutil.ReadFile(fs.proc.Path("net/arp")) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("error reading arp %s: %s", fs.proc.Path("net/arp"), err) |
||||
} |
||||
|
||||
return parseARPEntries(data) |
||||
} |
||||
|
||||
func parseARPEntries(data []byte) ([]ARPEntry, error) { |
||||
lines := strings.Split(string(data), "\n") |
||||
entries := make([]ARPEntry, 0) |
||||
var err error |
||||
const ( |
||||
expectedDataWidth = 6 |
||||
expectedHeaderWidth = 9 |
||||
) |
||||
for _, line := range lines { |
||||
columns := strings.Fields(line) |
||||
width := len(columns) |
||||
|
||||
if width == expectedHeaderWidth || width == 0 { |
||||
continue |
||||
} else if width == expectedDataWidth { |
||||
entry, err := parseARPEntry(columns) |
||||
if err != nil { |
||||
return []ARPEntry{}, fmt.Errorf("failed to parse ARP entry: %s", err) |
||||
} |
||||
entries = append(entries, entry) |
||||
} else { |
||||
return []ARPEntry{}, fmt.Errorf("%d columns were detected, but %d were expected", width, expectedDataWidth) |
||||
} |
||||
|
||||
} |
||||
|
||||
return entries, err |
||||
} |
||||
|
||||
func parseARPEntry(columns []string) (ARPEntry, error) { |
||||
ip := net.ParseIP(columns[0]) |
||||
mac := net.HardwareAddr(columns[3]) |
||||
|
||||
entry := ARPEntry{ |
||||
IPAddr: ip, |
||||
HWAddr: mac, |
||||
Device: columns[5], |
||||
} |
||||
|
||||
return entry, nil |
||||
} |
||||
@ -0,0 +1,131 @@ |
||||
// Copyright 2019 The Prometheus 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 procfs |
||||
|
||||
import ( |
||||
"bytes" |
||||
"fmt" |
||||
"io/ioutil" |
||||
"strconv" |
||||
"strings" |
||||
|
||||
"github.com/prometheus/procfs/internal/util" |
||||
) |
||||
|
||||
// Crypto holds info parsed from /proc/crypto.
|
||||
type Crypto struct { |
||||
Alignmask *uint64 |
||||
Async bool |
||||
Blocksize *uint64 |
||||
Chunksize *uint64 |
||||
Ctxsize *uint64 |
||||
Digestsize *uint64 |
||||
Driver string |
||||
Geniv string |
||||
Internal string |
||||
Ivsize *uint64 |
||||
Maxauthsize *uint64 |
||||
MaxKeysize *uint64 |
||||
MinKeysize *uint64 |
||||
Module string |
||||
Name string |
||||
Priority *int64 |
||||
Refcnt *int64 |
||||
Seedsize *uint64 |
||||
Selftest string |
||||
Type string |
||||
Walksize *uint64 |
||||
} |
||||
|
||||
// Crypto parses an crypto-file (/proc/crypto) and returns a slice of
|
||||
// structs containing the relevant info. More information available here:
|
||||
// https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html
|
||||
func (fs FS) Crypto() ([]Crypto, error) { |
||||
data, err := ioutil.ReadFile(fs.proc.Path("crypto")) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("error parsing crypto %s: %s", fs.proc.Path("crypto"), err) |
||||
} |
||||
crypto, err := parseCrypto(data) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("error parsing crypto %s: %s", fs.proc.Path("crypto"), err) |
||||
} |
||||
return crypto, nil |
||||
} |
||||
|
||||
func parseCrypto(cryptoData []byte) ([]Crypto, error) { |
||||
crypto := []Crypto{} |
||||
|
||||
cryptoBlocks := bytes.Split(cryptoData, []byte("\n\n")) |
||||
|
||||
for _, block := range cryptoBlocks { |
||||
var newCryptoElem Crypto |
||||
|
||||
lines := strings.Split(string(block), "\n") |
||||
for _, line := range lines { |
||||
if strings.TrimSpace(line) == "" || line[0] == ' ' { |
||||
continue |
||||
} |
||||
fields := strings.Split(line, ":") |
||||
key := strings.TrimSpace(fields[0]) |
||||
value := strings.TrimSpace(fields[1]) |
||||
vp := util.NewValueParser(value) |
||||
|
||||
switch strings.TrimSpace(key) { |
||||
case "async": |
||||
b, err := strconv.ParseBool(value) |
||||
if err == nil { |
||||
newCryptoElem.Async = b |
||||
} |
||||
case "blocksize": |
||||
newCryptoElem.Blocksize = vp.PUInt64() |
||||
case "chunksize": |
||||
newCryptoElem.Chunksize = vp.PUInt64() |
||||
case "digestsize": |
||||
newCryptoElem.Digestsize = vp.PUInt64() |
||||
case "driver": |
||||
newCryptoElem.Driver = value |
||||
case "geniv": |
||||
newCryptoElem.Geniv = value |
||||
case "internal": |
||||
newCryptoElem.Internal = value |
||||
case "ivsize": |
||||
newCryptoElem.Ivsize = vp.PUInt64() |
||||
case "maxauthsize": |
||||
newCryptoElem.Maxauthsize = vp.PUInt64() |
||||
case "max keysize": |
||||
newCryptoElem.MaxKeysize = vp.PUInt64() |
||||
case "min keysize": |
||||
newCryptoElem.MinKeysize = vp.PUInt64() |
||||
case "module": |
||||
newCryptoElem.Module = value |
||||
case "name": |
||||
newCryptoElem.Name = value |
||||
case "priority": |
||||
newCryptoElem.Priority = vp.PInt64() |
||||
case "refcnt": |
||||
newCryptoElem.Refcnt = vp.PInt64() |
||||
case "seedsize": |
||||
newCryptoElem.Seedsize = vp.PUInt64() |
||||
case "selftest": |
||||
newCryptoElem.Selftest = value |
||||
case "type": |
||||
newCryptoElem.Type = value |
||||
case "walksize": |
||||
newCryptoElem.Walksize = vp.PUInt64() |
||||
} |
||||
} |
||||
crypto = append(crypto, newCryptoElem) |
||||
} |
||||
return crypto, nil |
||||
} |
||||
@ -0,0 +1,91 @@ |
||||
// Copyright 2019 The Prometheus 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 procfs |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io/ioutil" |
||||
"strconv" |
||||
"strings" |
||||
) |
||||
|
||||
// For the proc file format details,
|
||||
// see https://elixir.bootlin.com/linux/v4.17/source/net/core/net-procfs.c#L162
|
||||
// and https://elixir.bootlin.com/linux/v4.17/source/include/linux/netdevice.h#L2810.
|
||||
|
||||
// SoftnetEntry contains a single row of data from /proc/net/softnet_stat
|
||||
type SoftnetEntry struct { |
||||
// Number of processed packets
|
||||
Processed uint |
||||
// Number of dropped packets
|
||||
Dropped uint |
||||
// Number of times processing packets ran out of quota
|
||||
TimeSqueezed uint |
||||
} |
||||
|
||||
// GatherSoftnetStats reads /proc/net/softnet_stat, parse the relevant columns,
|
||||
// and then return a slice of SoftnetEntry's.
|
||||
func (fs FS) GatherSoftnetStats() ([]SoftnetEntry, error) { |
||||
data, err := ioutil.ReadFile(fs.proc.Path("net/softnet_stat")) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("error reading softnet %s: %s", fs.proc.Path("net/softnet_stat"), err) |
||||
} |
||||
|
||||
return parseSoftnetEntries(data) |
||||
} |
||||
|
||||
func parseSoftnetEntries(data []byte) ([]SoftnetEntry, error) { |
||||
lines := strings.Split(string(data), "\n") |
||||
entries := make([]SoftnetEntry, 0) |
||||
var err error |
||||
const ( |
||||
expectedColumns = 11 |
||||
) |
||||
for _, line := range lines { |
||||
columns := strings.Fields(line) |
||||
width := len(columns) |
||||
if width == 0 { |
||||
continue |
||||
} |
||||
if width != expectedColumns { |
||||
return []SoftnetEntry{}, fmt.Errorf("%d columns were detected, but %d were expected", width, expectedColumns) |
||||
} |
||||
var entry SoftnetEntry |
||||
if entry, err = parseSoftnetEntry(columns); err != nil { |
||||
return []SoftnetEntry{}, err |
||||
} |
||||
entries = append(entries, entry) |
||||
} |
||||
|
||||
return entries, nil |
||||
} |
||||
|
||||
func parseSoftnetEntry(columns []string) (SoftnetEntry, error) { |
||||
var err error |
||||
var processed, dropped, timeSqueezed uint64 |
||||
if processed, err = strconv.ParseUint(columns[0], 16, 32); err != nil { |
||||
return SoftnetEntry{}, fmt.Errorf("Unable to parse column 0: %s", err) |
||||
} |
||||
if dropped, err = strconv.ParseUint(columns[1], 16, 32); err != nil { |
||||
return SoftnetEntry{}, fmt.Errorf("Unable to parse column 1: %s", err) |
||||
} |
||||
if timeSqueezed, err = strconv.ParseUint(columns[2], 16, 32); err != nil { |
||||
return SoftnetEntry{}, fmt.Errorf("Unable to parse column 2: %s", err) |
||||
} |
||||
return SoftnetEntry{ |
||||
Processed: uint(processed), |
||||
Dropped: uint(dropped), |
||||
TimeSqueezed: uint(timeSqueezed), |
||||
}, nil |
||||
} |
||||
@ -0,0 +1,90 @@ |
||||
// Copyright 2019 The Prometheus 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.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package sysfs |
||||
|
||||
import ( |
||||
"path/filepath" |
||||
"strconv" |
||||
"strings" |
||||
|
||||
"github.com/prometheus/procfs/internal/util" |
||||
) |
||||
|
||||
// ClassCoolingDeviceStats contains info from files in /sys/class/thermal/cooling_device[0-9]*
|
||||
// for a single device.
|
||||
// https://www.kernel.org/doc/Documentation/thermal/sysfs-api.txt
|
||||
type ClassCoolingDeviceStats struct { |
||||
Name string // The name of the cooling device.
|
||||
Type string // Type of the cooling device(processor/fan/...)
|
||||
MaxState int64 // Maximum cooling state of the cooling device
|
||||
CurState int64 // Current cooling state of the cooling device
|
||||
} |
||||
|
||||
func (fs FS) ClassCoolingDeviceStats() ([]ClassCoolingDeviceStats, error) { |
||||
cds, err := filepath.Glob(fs.sys.Path("class/thermal/cooling_device[0-9]*")) |
||||
if err != nil { |
||||
return []ClassCoolingDeviceStats{}, err |
||||
} |
||||
|
||||
var coolingDeviceStats = ClassCoolingDeviceStats{} |
||||
stats := make([]ClassCoolingDeviceStats, len(cds)) |
||||
for i, cd := range cds { |
||||
cdName := strings.TrimPrefix(filepath.Base(cd), "cooling_device") |
||||
|
||||
coolingDeviceStats, err = parseCoolingDeviceStats(cd) |
||||
if err != nil { |
||||
return []ClassCoolingDeviceStats{}, err |
||||
} |
||||
|
||||
coolingDeviceStats.Name = cdName |
||||
stats[i] = coolingDeviceStats |
||||
} |
||||
return stats, nil |
||||
} |
||||
|
||||
func parseCoolingDeviceStats(cd string) (ClassCoolingDeviceStats, error) { |
||||
cdType, err := util.SysReadFile(filepath.Join(cd, "type")) |
||||
if err != nil { |
||||
return ClassCoolingDeviceStats{}, err |
||||
} |
||||
|
||||
cdMaxStateString, err := util.SysReadFile(filepath.Join(cd, "max_state")) |
||||
if err != nil { |
||||
return ClassCoolingDeviceStats{}, err |
||||
} |
||||
cdMaxStateInt, err := strconv.ParseInt(cdMaxStateString, 10, 64) |
||||
if err != nil { |
||||
return ClassCoolingDeviceStats{}, err |
||||
} |
||||
|
||||
// cur_state can be -1, eg intel powerclamp
|
||||
// https://www.kernel.org/doc/Documentation/thermal/intel_powerclamp.txt
|
||||
cdCurStateString, err := util.SysReadFile(filepath.Join(cd, "cur_state")) |
||||
if err != nil { |
||||
return ClassCoolingDeviceStats{}, err |
||||
} |
||||
|
||||
cdCurStateInt, err := strconv.ParseInt(cdCurStateString, 10, 64) |
||||
if err != nil { |
||||
return ClassCoolingDeviceStats{}, err |
||||
} |
||||
|
||||
return ClassCoolingDeviceStats{ |
||||
Type: cdType, |
||||
MaxState: cdMaxStateInt, |
||||
CurState: cdCurStateInt, |
||||
}, nil |
||||
} |
||||
@ -0,0 +1,84 @@ |
||||
// Copyright 2019 The Prometheus 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 sysfs |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io/ioutil" |
||||
"path/filepath" |
||||
"strings" |
||||
) |
||||
|
||||
const ( |
||||
notAffected = "Not Affected" |
||||
vulnerable = "Vulnerable" |
||||
mitigation = "Mitigation" |
||||
) |
||||
|
||||
// CPUVulnerabilities retrieves a map of vulnerability names to their mitigations.
|
||||
func (fs FS) CPUVulnerabilities() ([]Vulnerability, error) { |
||||
matches, err := filepath.Glob(fs.sys.Path("devices/system/cpu/vulnerabilities/*")) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
vulnerabilities := make([]Vulnerability, 0, len(matches)) |
||||
for _, match := range matches { |
||||
name := filepath.Base(match) |
||||
|
||||
value, err := ioutil.ReadFile(match) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
v, err := parseVulnerability(name, string(value)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
vulnerabilities = append(vulnerabilities, v) |
||||
} |
||||
|
||||
return vulnerabilities, nil |
||||
} |
||||
|
||||
// Vulnerability represents a single vulnerability extracted from /sys/devices/system/cpu/vulnerabilities/
|
||||
type Vulnerability struct { |
||||
CodeName string |
||||
State string |
||||
Mitigation string |
||||
} |
||||
|
||||
func parseVulnerability(name, value string) (Vulnerability, error) { |
||||
v := Vulnerability{CodeName: name} |
||||
value = strings.TrimSpace(value) |
||||
if value == notAffected { |
||||
v.State = notAffected |
||||
return v, nil |
||||
} |
||||
|
||||
if strings.HasPrefix(value, vulnerable) { |
||||
v.State = vulnerable |
||||
v.Mitigation = strings.TrimPrefix(strings.TrimPrefix(value, vulnerable), ": ") |
||||
return v, nil |
||||
} |
||||
|
||||
if strings.HasPrefix(value, mitigation) { |
||||
v.State = mitigation |
||||
v.Mitigation = strings.TrimPrefix(strings.TrimPrefix(value, mitigation), ": ") |
||||
return v, nil |
||||
} |
||||
|
||||
return v, fmt.Errorf("unknown vulnerability state for %s: %s", name, value) |
||||
} |
||||
Loading…
Reference in new issue