Skip to content

Commit 7481a8e

Browse files
authored
Merge release v0.1.10
Release v0.1.10
2 parents a1ab01a + 4b4ce0d commit 7481a8e

16 files changed

Lines changed: 416 additions & 65 deletions

File tree

internal/switchtec/cmd/fabric/perf.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020, 2021, 2022 Hewlett Packard Enterprise Development LP
2+
* Copyright 2020-2025 Hewlett Packard Enterprise Development LP
33
* Other additional copyright holders may be indicated within.
44
*
55
* The entirety of this work is licensed under the Apache License,
@@ -51,7 +51,7 @@ func (cmd *BandwidthCmd) Run() error {
5151
return err
5252
}
5353

54-
// Resetting the bandwidht counter takes about 1s
54+
// Resetting the bandwidth counter takes about 1s
5555
time.Sleep(time.Second)
5656

5757
// Record the bandwidth counters

internal/switchtec/pkg/nvme/nvme.go

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020, 2021, 2022 Hewlett Packard Enterprise Development LP
2+
* Copyright 2020-2025 Hewlett Packard Enterprise Development LP
33
* Other additional copyright holders may be indicated within.
44
*
55
* The entirety of this work is licensed under the Apache License,
@@ -22,6 +22,7 @@ package nvme
2222
import (
2323
"encoding/binary"
2424
"fmt"
25+
"math/rand"
2526
"path"
2627
"regexp"
2728
"strconv"
@@ -33,6 +34,8 @@ import (
3334
"github.com/google/uuid"
3435

3536
"github.com/NearNodeFlash/nnf-ec/internal/switchtec/pkg/switchtec"
37+
"github.com/NearNodeFlash/nnf-ec/pkg/ec"
38+
sf "github.com/NearNodeFlash/nnf-ec/pkg/rfsf/pkg/models"
3639
)
3740

3841
// Device describes the NVMe Device and its attributes
@@ -532,7 +535,7 @@ type id_ctrl struct {
532535
NVMSetIdentifierMaximum uint16 // NSETIDMAX
533536
EnduraceGroupIdentifierMaximum uint16 // ENDGIDMAX
534537
ANATranstitionTime uint8 // ANATT
535-
AsymentricNamespaceAccessCapabilities uint8 // ANACAP
538+
AsymmetricNamespaceAccessCapabilities uint8 // ANACAP
536539
ANAGroupIdenfierMaximum uint32 // ANAGRPMAX
537540
NumberOfANAGroupIdentifiers uint32 // NANAGRPID
538541
PersistentEventLogSize uint32 // PELS
@@ -1101,7 +1104,7 @@ type SmartLog struct {
11011104
DataUnitsWrittenLo uint64
11021105
DataUnitsWrittenHi uint64
11031106
HostReadsLo uint64
1104-
HistReadsHi uint64
1107+
HostReadsHi uint64
11051108
HostWritesLo uint64
11061109
HostWritesHi uint64
11071110
ControllerBusyTimeLo uint64
@@ -1126,6 +1129,7 @@ type SmartLog struct {
11261129
Reserved232 [280]uint8
11271130
}
11281131

1132+
// GetSmartLog - retrieve the smartlog information
11291133
func (dev *Device) GetSmartLog() (*SmartLog, error) {
11301134

11311135
log := new(SmartLog)
@@ -1146,6 +1150,53 @@ func (dev *Device) GetSmartLog() (*SmartLog, error) {
11461150
return log, nil
11471151
}
11481152

1153+
// InterpretSmartLog - calculate the drive's swordfish status
1154+
func InterpretSmartLog(log *SmartLog) sf.ResourceState {
1155+
// Check critical warnings first - check individual bitfield members
1156+
if log.CriticalWarning.SpareCapacity != 0 { // Spare capacity
1157+
return sf.DISABLED_RST
1158+
}
1159+
if log.CriticalWarning.ReadOnly != 0 { // Read-only mode
1160+
return sf.DISABLED_RST
1161+
}
1162+
1163+
// Check other critical warnings for degraded state
1164+
if log.CriticalWarning.Temperature != 0 ||
1165+
log.CriticalWarning.Degraded != 0 ||
1166+
log.CriticalWarning.BackupFailed != 0 ||
1167+
log.CriticalWarning.PersistentMemoryRegionReadOnly != 0 {
1168+
return sf.STANDBY_OFFLINE_RST
1169+
}
1170+
1171+
return sf.ENABLED_RST // Healthy
1172+
}
1173+
1174+
func MangleSmartLog(log *SmartLog) {
1175+
1176+
// Occaionally managle the smart log data
1177+
if rand.Intn(100) < 10 { // 10% chance of simulating critical condition
1178+
warningType := rand.Intn(6)
1179+
switch warningType {
1180+
case 0:
1181+
log.CriticalWarning.SpareCapacity = 1
1182+
log.AvailableSpare = 5 // Below threshold
1183+
case 1:
1184+
log.CriticalWarning.Temperature = 1
1185+
log.CompositeTemperature = 358 // ~85°C
1186+
case 2:
1187+
log.CriticalWarning.Degraded = 1
1188+
case 3:
1189+
log.CriticalWarning.ReadOnly = 1
1190+
case 4:
1191+
log.CriticalWarning.BackupFailed = 1
1192+
case 5:
1193+
log.CriticalWarning.PersistentMemoryRegionReadOnly = 1
1194+
}
1195+
}
1196+
1197+
}
1198+
1199+
// Log contstants
11491200
const (
11501201
LogCdw10LogPageIdentiferMask = 0xFF
11511202
LogCdw10LogPageIdentiferShift = 0
@@ -1166,7 +1217,7 @@ const (
11661217
)
11671218

11681219
func (dev *Device) getNsidLog(logPageIdentifier uint8, retainAsynchronousEvent uint8, nsid uint32, buf []byte) error {
1169-
return dev.getLog(logPageIdentifier, 0, 0, nsid, 0, buf)
1220+
return dev.getLog(logPageIdentifier, 0, retainAsynchronousEvent, nsid, 0, buf)
11701221
}
11711222

11721223
func (dev *Device) getLog(logPageIdentifier uint8, logSpecificField uint8, retainAsynchronousEvent uint8, nsid uint32, logPageOffset uint64, buf []byte) error {
@@ -1200,3 +1251,26 @@ func (dev *Device) getLog(logPageIdentifier uint8, logSpecificField uint8, retai
12001251
return dev.ops.submitAdminPassthru(dev, &cmd, buf)
12011252

12021253
}
1254+
1255+
// LogSmartLog outputs the SMART log data in a structured way for logging.
1256+
func LogSmartLog(log ec.Logger, smartLog *SmartLog, context ...interface{}) {
1257+
if smartLog == nil {
1258+
log.Error(nil, "SMART log is nil", context...)
1259+
return
1260+
}
1261+
log.Info("SMART log data",
1262+
append(context,
1263+
"criticalWarning.spareCapacity", smartLog.CriticalWarning.SpareCapacity,
1264+
"criticalWarning.temperature", smartLog.CriticalWarning.Temperature,
1265+
"criticalWarning.degraded", smartLog.CriticalWarning.Degraded,
1266+
"criticalWarning.readOnly", smartLog.CriticalWarning.ReadOnly,
1267+
"criticalWarning.backupFailed", smartLog.CriticalWarning.BackupFailed,
1268+
"criticalWarning.persistentMemoryRegionReadOnly", smartLog.CriticalWarning.PersistentMemoryRegionReadOnly,
1269+
"availableSpare", smartLog.AvailableSpare,
1270+
"availableSpareThreshold", smartLog.AvailableSpareThreshold,
1271+
"percentageUsed", smartLog.PercentageUsed,
1272+
"compositeTemperature", smartLog.CompositeTemperature,
1273+
"mediaErrorsLo", smartLog.MediaErrorsLo,
1274+
"numberErrorLogEntriesLo", smartLog.NumberErrorLogEntriesLo,
1275+
)...)
1276+
}

pkg/manager-fabric/manager.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,11 @@ func (p *Port) bind() error {
782782
if endpoint.boundPaxId != uint8(s.paxId) ||
783783
endpoint.boundHvdPhyId != uint8(initiatorPort.config.Port) ||
784784
endpoint.boundHvdLogId != uint8(logicalPortId) {
785-
panic(fmt.Sprintf("Already Bound: Misconfigured Port: PAX: %d, Physical Port: %d, Logical Port: %d, PDFID: %#04x", endpoint.boundPaxId, endpoint.boundHvdPhyId, endpoint.boundHvdLogId, endpoint.pdfid))
785+
panic(fmt.Sprintf("Already Bound: Misconfigured Port: PAX: %d(%d), Physical Port: %d(%d), Logical Port: %d(%d), PDFID: %#04x",
786+
endpoint.boundPaxId, uint8(s.paxId),
787+
endpoint.boundHvdPhyId, uint8(initiatorPort.config.Port),
788+
endpoint.boundHvdLogId, uint8(logicalPortId),
789+
endpoint.pdfid))
786790
}
787791

788792
break
@@ -1121,7 +1125,7 @@ func Start() error {
11211125
event.EventManager.Publish(msgreg.FabricReadyNnf(m.id))
11221126

11231127
// Run the Fabric Monitor in a background thread.
1124-
go NewFabricMonitor(m).Run()
1128+
StartFabricMonitor(m)
11251129

11261130
return nil
11271131
}

pkg/manager-fabric/monitor.go

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020, 2021, 2022 Hewlett Packard Enterprise Development LP
2+
* Copyright 2020-2025 Hewlett Packard Enterprise Development LP
33
* Other additional copyright holders may be indicated within.
44
*
55
* The entirety of this work is licensed under the Apache License,
@@ -27,23 +27,53 @@ import (
2727
"github.com/NearNodeFlash/nnf-ec/internal/switchtec/pkg/switchtec"
2828
)
2929

30-
// The Fabric Monitor is responsible for ensuring that the fabriic and related sub-resource
30+
// NewFabricMonitor - The Fabric Monitor is responsible for ensuring that the fabriic and related sub-resource
3131
// are updated with the latest information from the switch. This runs as a background
3232
// thread, and periodically queries the fabric.
33-
func NewFabricMonitor(f *Fabric) *monitor {
34-
return &monitor{fabric: f}
33+
func NewMonitor(f *Fabric, i time.Duration) *monitor {
34+
return &monitor{fabric: f, interval: i}
3535
}
3636

3737
type monitor struct {
38-
fabric *Fabric
38+
fabric *Fabric
39+
interval time.Duration
40+
}
41+
42+
// StartFabricMonitor starts the fabric monitor in a background goroutine if the period is non-zero.
43+
func StartFabricMonitor(fabric *Fabric) {
44+
defaultFabricMonitorPeriod := 60 * time.Second
45+
fabricMonitorPeriod := defaultFabricMonitorPeriod
46+
if periodStr := os.Getenv("NNF_FABRIC_MONITOR_PERIOD"); periodStr != "" {
47+
if d, err := time.ParseDuration(periodStr); err == nil {
48+
fabricMonitorPeriod = d
49+
} else {
50+
if fabric != nil && !fabric.log.IsZero() {
51+
fabric.log.Info("Invalid NNF_FABRIC_MONITOR_PERIOD, using default", "value", fabricMonitorPeriod, "error", err)
52+
}
53+
}
54+
}
55+
56+
// A period of 0 means don't start the monitor.
57+
if fabricMonitorPeriod == 0 {
58+
if fabric != nil && !fabric.log.IsZero() {
59+
fabric.log.Info("Not starting fabric monitor", "monitorPeriod", fabricMonitorPeriod)
60+
}
61+
return
62+
}
63+
64+
mon := NewMonitor(fabric, fabricMonitorPeriod)
65+
go mon.Run()
66+
if fabric != nil && !fabric.log.IsZero() {
67+
fabric.log.Info("Started fabric monitor", "monitorPeriod", fabricMonitorPeriod)
68+
}
69+
3970
}
4071

4172
// Run Fabric Monitor forever
4273
func (m *monitor) Run() {
4374

4475
for {
45-
46-
time.Sleep(time.Second * 60)
76+
time.Sleep(m.interval)
4777

4878
for idx := range m.fabric.switches {
4979
s := &m.fabric.switches[idx]
@@ -62,13 +92,13 @@ func (m *monitor) Run() {
6292
}
6393

6494
for _, event := range events {
65-
physPortId, isDown := m.getEventInfo(event)
95+
physPortID, isDown := m.getEventInfo(event)
6696

67-
if physPortId == invalidPhysicalPortId {
97+
if physPortID == invalidPhysicalPortId {
6898
continue
6999
}
70100

71-
if p := s.findPortByPhysicalPortId(physPortId); p != nil {
101+
if p := s.findPortByPhysicalPortId(physPortID); p != nil {
72102
p.notify(isDown)
73103
}
74104
}

pkg/manager-message-registry/registries/Nnf.1.0.0.go

Lines changed: 14 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/manager-message-registry/registries/Nnf.1.0.0.json

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"Message": "The storage pool '%1' patched, SerialNumber '%2', Namespace '%3' replaced with SerialNumber '%4', Namespace '%5'",
5555
"Severity": "OK",
5656
"MessageSeverity": "OK",
57-
"NumberOfArgs": 1,
57+
"NumberOfArgs": 5,
5858
"ParamTypes": [
5959
"string",
6060
"string",
@@ -77,6 +77,30 @@
7777
"This argument shall contain the namespace id on the new storage device."
7878
],
7979
"Resolution": "None"
80+
},
81+
"NvmeStateChange": {
82+
"Description": "Indicates that an NVMe device has changed state",
83+
"LongDescription": "This message shall be used to indicate that an NVMe device has changed state",
84+
"Message": "The Nvme State changed slot '%1', model '%2', serial '%3'",
85+
"Severity": "Warning",
86+
"MessageSeverity": "Warning",
87+
"NumberOfArgs": 3,
88+
"ParamTypes": [
89+
"number",
90+
"string",
91+
"string"
92+
],
93+
"ArgDescriptions": [
94+
"The slot identifier.",
95+
"The model number.",
96+
"The serial number."
97+
],
98+
"ArgLongDescriptions": [
99+
"This argument shall contain the NVMe slot number.",
100+
"This argument shall contain the NVMe model number.",
101+
"This argument shall contain the NVMe serial number."
102+
],
103+
"Resolution": "None"
80104
}
81105
}
82106
}

pkg/manager-nnf/allocation_policy.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ func NewAllocationPolicy(config AllocationConfig, oem map[string]interface{}) Al
112112

113113
/* ------------------------------ Spare Allocation Policy --------------------- */
114114

115-
// Required number of drives for the Spare Allocation Policy
116-
const SpareAllocationPolicyRequiredDriveCount = 16
115+
const SpareAllocationPolicyExpectedDriveCount = 16
116+
const SpareAllocationPolicyMinimumDriveCount = 14
117117

118118
type SpareAllocationPolicy struct {
119119
compliance AllocationComplianceType
@@ -137,7 +137,7 @@ func (p *SpareAllocationPolicy) Initialize(capacityBytes uint64) error {
137137
return !!!(storage[i].UnallocatedBytes() < storage[j].UnallocatedBytes())
138138
})
139139

140-
count := SpareAllocationPolicyRequiredDriveCount
140+
count := SpareAllocationPolicyExpectedDriveCount
141141
if len(storage) < count {
142142
count = len(storage)
143143
}
@@ -161,17 +161,17 @@ func (p *SpareAllocationPolicy) CheckAndAdjustCapacity() error {
161161

162162
if p.compliance != RelaxedAllocationComplianceType {
163163

164-
if len(p.storage) != SpareAllocationPolicyRequiredDriveCount {
165-
return fmt.Errorf("Insufficient drive count. Required: %d Available: %d", SpareAllocationPolicyRequiredDriveCount, len(p.storage))
164+
if len(p.storage) < SpareAllocationPolicyMinimumDriveCount {
165+
return fmt.Errorf("Insufficient drive count. Required: %d Available: %d", SpareAllocationPolicyMinimumDriveCount, len(p.storage))
166166
}
167167

168168
roundUpToMultiple := func(n, m uint64) uint64 { // Round 'n' up to a multiple of 'm'
169169
return ((n + m - 1) / m) * m
170170
}
171171

172172
// Validate each drive can contribute sufficient capacity towards the entire pool.
173-
poolCapacityBytes := roundUpToMultiple(p.capacityBytes, SpareAllocationPolicyRequiredDriveCount)
174-
driveCapacityBytes := roundUpToMultiple(poolCapacityBytes/SpareAllocationPolicyRequiredDriveCount, 4096)
173+
poolCapacityBytes := roundUpToMultiple(p.capacityBytes, SpareAllocationPolicyMinimumDriveCount)
174+
driveCapacityBytes := roundUpToMultiple(poolCapacityBytes/SpareAllocationPolicyMinimumDriveCount, 4096)
175175

176176
for _, s := range p.storage {
177177
if driveCapacityBytes > s.UnallocatedBytes() {

pkg/manager-nnf/manager.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,8 @@ func (s *StorageService) EventHandler(e event.Event) error {
625625
}
626626

627627
log.Info("Storage Service Enabled", "health", s.health)
628+
629+
nvme.StartNVMeMonitor(s.log)
628630
}
629631

630632
// Check for storage pool events

0 commit comments

Comments
 (0)