Skip to content

Commit

Permalink
Zoning check for Fibre Channel
Browse files Browse the repository at this point in the history
  • Loading branch information
VinayKumarHavanur authored Jan 8, 2025
1 parent fcaeb45 commit ffa2375
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 5 deletions.
15 changes: 15 additions & 0 deletions mocks/mock_utils/mock_fcp/mock_reconcile_utils.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions utils/fcp/fcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,11 @@ func (client *Client) AttachVolume(
return mpathSize, err
}

// Check if zoning exists for the target
if isZoned, err := client.fcpUtils.CheckZoningExistsWithTarget(ctx, publishInfo.FCTargetWWNN); !isZoned {
return mpathSize, err
}

// First attempt to fix invalid serials by rescanning them
err = client.handleInvalidSerials(ctx, lunID, publishInfo.FCTargetWWNN, publishInfo.FCPLunSerial, rescanOneLun)
if err != nil {
Expand Down
60 changes: 55 additions & 5 deletions utils/fcp/reconcile_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type FcpReconcileUtils interface {
GetSysfsBlockDirsForLUN(int, []map[string]int) []string
GetDevicesForLUN(paths []string) ([]string, error)
ReconcileFCPVolumeInfo(ctx context.Context, trackingInfo *models.VolumeTrackingInfo) (bool, error)
CheckZoningExistsWithTarget(context.Context, string) (bool, error)
}

type FcpReconcileHelper struct {
Expand Down Expand Up @@ -103,11 +104,7 @@ func (h *FcpReconcileHelper) GetFCPHostSessionMapForTarget(
continue
}

tgName := strings.TrimPrefix(string(targetName), "0x")
tgName = strings.TrimSuffix(tgName, "\n")
nname := strings.ReplaceAll(fcpNodeName, ":", "")

if tgName == nname {
if MatchWorldWideNames(string(targetName), fcpNodeName, false) {
fcHostPath := h.chrootPathPrefix + "/sys/class/fc_host/"

var hostNumber string
Expand Down Expand Up @@ -201,3 +198,56 @@ func (h *FcpReconcileHelper) GetDevicesForLUN(paths []string) ([]string, error)
}
return devices, nil
}

// CheckZoningExistsWithTarget checks if the target is zoned with the initiator.
func (h *FcpReconcileHelper) CheckZoningExistsWithTarget(ctx context.Context, targetNodeName string) (bool, error) {
fields := LogFields{"targetNodeName": targetNodeName}
Logc(ctx).WithFields(fields).Debug(">>>> fcp.CheckZoningExistsWithTarget")
defer Logc(ctx).WithFields(fields).Debug("<<<< fcp.CheckZoningExistsWithTarget")

sysPath := h.chrootPathPrefix + "/sys/class/fc_remote_ports/"
rportDirs, err := os.ReadDir(sysPath)
if err != nil {
Logc(ctx).WithField("error", err).Errorf("Could not read %s", sysPath)
return false, err
}

for _, rportDir := range rportDirs {
rportDirName := rportDir.Name()
if !strings.HasPrefix(rportDirName, "rport") {
continue
}

devicePath := sysPath + rportDirName
nodeNamePath := devicePath + "/node_name"
nodeName, err := os.ReadFile(nodeNamePath)
if err != nil {
Logc(ctx).WithFields(LogFields{
"path": nodeNamePath,
"error": err,
}).Error("Could not read target name file")
continue
}

if !MatchWorldWideNames(string(nodeName), targetNodeName, false) {
// Skip the check for non-relevant target
continue
}

portStatus, err := os.ReadFile(devicePath + "/port_state")
if err != nil {
Logc(ctx).WithFields(LogFields{
"path": devicePath + "/port_state",
"error": err,
}).Error("Could not read port state file")
continue
}

portStatusStr := strings.TrimSpace(string(portStatus))
if portStatusStr == "Online" {
return true, nil
}
}

return false, fmt.Errorf("no zoned ports found")
}
18 changes: 18 additions & 0 deletions utils/fcp/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,21 @@ func ConvertStrToWWNFormat(wwnStr string) string {
}
return wwn
}

// MatchWorldWideNames compares two WWNs and returns true if they match.
func MatchWorldWideNames(wwn1, wwn2 string, identicalSearch bool) bool {
if identicalSearch {
return wwn1 == wwn2
}

// Sanitize the WWN strings
wwn1Str := strings.TrimPrefix(wwn1, "0x")
wwn1Str = strings.TrimSpace(wwn1Str)
wwn1Str = strings.ReplaceAll(wwn1Str, ":", "")

wwn2Str := strings.TrimPrefix(wwn2, "0x")
wwn2Str = strings.TrimSpace(wwn2Str)
wwn2Str = strings.ReplaceAll(wwn2Str, ":", "")

return wwn1Str == wwn2Str
}
67 changes: 67 additions & 0 deletions utils/fcp/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package fcp

import (
"testing"
)

func TestMatchWorldWideNames(t *testing.T) {
tests := []struct {
name string
wwn1 string
wwn2 string
identicalSearch bool
expected bool
}{
{
name: "Identical WWNs with identicalSearch true",
wwn1: "0x5005076801401b3f",
wwn2: "0x5005076801401b3f",
identicalSearch: true,
expected: true,
},
{
name: "Different WWNs with identicalSearch true",
wwn1: "0x5005076801401b3f",
wwn2: "0x5005076801401b40",
identicalSearch: true,
expected: false,
},
{
name: "Identical WWNs with identicalSearch false",
wwn1: "0x5005076801401b3f",
wwn2: "5005076801401b3f",
identicalSearch: false,
expected: true,
},
{
name: "Different WWNs with identicalSearch false",
wwn1: "0x5005076801401b3f",
wwn2: "5005076801401b40",
identicalSearch: false,
expected: false,
},
{
name: "WWNs with colons and identicalSearch false",
wwn1: "0x50:05:07:68:01:40:1b:3f",
wwn2: "5005076801401b3f",
identicalSearch: false,
expected: true,
},
{
name: "WWNs with colons and identicalSearch false",
wwn1: "0x5005076801401b3f",
wwn2: "50:05:07:68:01:40:1b:3f",
identicalSearch: false,
expected: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := MatchWorldWideNames(tt.wwn1, tt.wwn2, tt.identicalSearch)
if result != tt.expected {
t.Errorf("MatchWorldWideNames(%s, %s, %v) = %v; want %v", tt.wwn1, tt.wwn2, tt.identicalSearch, result, tt.expected)
}
})
}
}

0 comments on commit ffa2375

Please sign in to comment.