Skip to content

Commit ffa2375

Browse files
Zoning check for Fibre Channel
1 parent fcaeb45 commit ffa2375

File tree

5 files changed

+160
-5
lines changed

5 files changed

+160
-5
lines changed

mocks/mock_utils/mock_fcp/mock_reconcile_utils.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

utils/fcp/fcp.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ func (client *Client) AttachVolume(
350350
return mpathSize, err
351351
}
352352

353+
// Check if zoning exists for the target
354+
if isZoned, err := client.fcpUtils.CheckZoningExistsWithTarget(ctx, publishInfo.FCTargetWWNN); !isZoned {
355+
return mpathSize, err
356+
}
357+
353358
// First attempt to fix invalid serials by rescanning them
354359
err = client.handleInvalidSerials(ctx, lunID, publishInfo.FCTargetWWNN, publishInfo.FCPLunSerial, rescanOneLun)
355360
if err != nil {

utils/fcp/reconcile_utils.go

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type FcpReconcileUtils interface {
2121
GetSysfsBlockDirsForLUN(int, []map[string]int) []string
2222
GetDevicesForLUN(paths []string) ([]string, error)
2323
ReconcileFCPVolumeInfo(ctx context.Context, trackingInfo *models.VolumeTrackingInfo) (bool, error)
24+
CheckZoningExistsWithTarget(context.Context, string) (bool, error)
2425
}
2526

2627
type FcpReconcileHelper struct {
@@ -103,11 +104,7 @@ func (h *FcpReconcileHelper) GetFCPHostSessionMapForTarget(
103104
continue
104105
}
105106

106-
tgName := strings.TrimPrefix(string(targetName), "0x")
107-
tgName = strings.TrimSuffix(tgName, "\n")
108-
nname := strings.ReplaceAll(fcpNodeName, ":", "")
109-
110-
if tgName == nname {
107+
if MatchWorldWideNames(string(targetName), fcpNodeName, false) {
111108
fcHostPath := h.chrootPathPrefix + "/sys/class/fc_host/"
112109

113110
var hostNumber string
@@ -201,3 +198,56 @@ func (h *FcpReconcileHelper) GetDevicesForLUN(paths []string) ([]string, error)
201198
}
202199
return devices, nil
203200
}
201+
202+
// CheckZoningExistsWithTarget checks if the target is zoned with the initiator.
203+
func (h *FcpReconcileHelper) CheckZoningExistsWithTarget(ctx context.Context, targetNodeName string) (bool, error) {
204+
fields := LogFields{"targetNodeName": targetNodeName}
205+
Logc(ctx).WithFields(fields).Debug(">>>> fcp.CheckZoningExistsWithTarget")
206+
defer Logc(ctx).WithFields(fields).Debug("<<<< fcp.CheckZoningExistsWithTarget")
207+
208+
sysPath := h.chrootPathPrefix + "/sys/class/fc_remote_ports/"
209+
rportDirs, err := os.ReadDir(sysPath)
210+
if err != nil {
211+
Logc(ctx).WithField("error", err).Errorf("Could not read %s", sysPath)
212+
return false, err
213+
}
214+
215+
for _, rportDir := range rportDirs {
216+
rportDirName := rportDir.Name()
217+
if !strings.HasPrefix(rportDirName, "rport") {
218+
continue
219+
}
220+
221+
devicePath := sysPath + rportDirName
222+
nodeNamePath := devicePath + "/node_name"
223+
nodeName, err := os.ReadFile(nodeNamePath)
224+
if err != nil {
225+
Logc(ctx).WithFields(LogFields{
226+
"path": nodeNamePath,
227+
"error": err,
228+
}).Error("Could not read target name file")
229+
continue
230+
}
231+
232+
if !MatchWorldWideNames(string(nodeName), targetNodeName, false) {
233+
// Skip the check for non-relevant target
234+
continue
235+
}
236+
237+
portStatus, err := os.ReadFile(devicePath + "/port_state")
238+
if err != nil {
239+
Logc(ctx).WithFields(LogFields{
240+
"path": devicePath + "/port_state",
241+
"error": err,
242+
}).Error("Could not read port state file")
243+
continue
244+
}
245+
246+
portStatusStr := strings.TrimSpace(string(portStatus))
247+
if portStatusStr == "Online" {
248+
return true, nil
249+
}
250+
}
251+
252+
return false, fmt.Errorf("no zoned ports found")
253+
}

utils/fcp/utils.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,21 @@ func ConvertStrToWWNFormat(wwnStr string) string {
151151
}
152152
return wwn
153153
}
154+
155+
// MatchWorldWideNames compares two WWNs and returns true if they match.
156+
func MatchWorldWideNames(wwn1, wwn2 string, identicalSearch bool) bool {
157+
if identicalSearch {
158+
return wwn1 == wwn2
159+
}
160+
161+
// Sanitize the WWN strings
162+
wwn1Str := strings.TrimPrefix(wwn1, "0x")
163+
wwn1Str = strings.TrimSpace(wwn1Str)
164+
wwn1Str = strings.ReplaceAll(wwn1Str, ":", "")
165+
166+
wwn2Str := strings.TrimPrefix(wwn2, "0x")
167+
wwn2Str = strings.TrimSpace(wwn2Str)
168+
wwn2Str = strings.ReplaceAll(wwn2Str, ":", "")
169+
170+
return wwn1Str == wwn2Str
171+
}

utils/fcp/utils_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package fcp
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestMatchWorldWideNames(t *testing.T) {
8+
tests := []struct {
9+
name string
10+
wwn1 string
11+
wwn2 string
12+
identicalSearch bool
13+
expected bool
14+
}{
15+
{
16+
name: "Identical WWNs with identicalSearch true",
17+
wwn1: "0x5005076801401b3f",
18+
wwn2: "0x5005076801401b3f",
19+
identicalSearch: true,
20+
expected: true,
21+
},
22+
{
23+
name: "Different WWNs with identicalSearch true",
24+
wwn1: "0x5005076801401b3f",
25+
wwn2: "0x5005076801401b40",
26+
identicalSearch: true,
27+
expected: false,
28+
},
29+
{
30+
name: "Identical WWNs with identicalSearch false",
31+
wwn1: "0x5005076801401b3f",
32+
wwn2: "5005076801401b3f",
33+
identicalSearch: false,
34+
expected: true,
35+
},
36+
{
37+
name: "Different WWNs with identicalSearch false",
38+
wwn1: "0x5005076801401b3f",
39+
wwn2: "5005076801401b40",
40+
identicalSearch: false,
41+
expected: false,
42+
},
43+
{
44+
name: "WWNs with colons and identicalSearch false",
45+
wwn1: "0x50:05:07:68:01:40:1b:3f",
46+
wwn2: "5005076801401b3f",
47+
identicalSearch: false,
48+
expected: true,
49+
},
50+
{
51+
name: "WWNs with colons and identicalSearch false",
52+
wwn1: "0x5005076801401b3f",
53+
wwn2: "50:05:07:68:01:40:1b:3f",
54+
identicalSearch: false,
55+
expected: true,
56+
},
57+
}
58+
59+
for _, tt := range tests {
60+
t.Run(tt.name, func(t *testing.T) {
61+
result := MatchWorldWideNames(tt.wwn1, tt.wwn2, tt.identicalSearch)
62+
if result != tt.expected {
63+
t.Errorf("MatchWorldWideNames(%s, %s, %v) = %v; want %v", tt.wwn1, tt.wwn2, tt.identicalSearch, result, tt.expected)
64+
}
65+
})
66+
}
67+
}

0 commit comments

Comments
 (0)