diff --git a/cmd/daemon.go b/cmd/daemon.go index e9d0e9c..ca87535 100644 --- a/cmd/daemon.go +++ b/cmd/daemon.go @@ -37,22 +37,24 @@ func newDaemonCommand(cli *client.Client) *cobra.Command { var host string var driver string var logLevel string + var blockMultipleHosts bool var cmd = &cobra.Command{ Use: "daemon", Short: "Setup a daemon", Long: `Setup the Gotgt's daemon`, RunE: func(cmd *cobra.Command, args []string) error { - return createDaemon(host, driver, logLevel) + return createDaemon(host, driver, logLevel, blockMultipleHosts) }, } flags := cmd.Flags() flags.StringVar(&logLevel, "log", "info", "Log level of SCSI target daemon") flags.StringVar(&host, "host", "tcp://127.0.0.1:23457", "Host for SCSI target daemon") flags.StringVar(&driver, "driver", "iscsi", "SCSI low level driver") + flags.BoolVar(&blockMultipleHosts, "block-multiple-hosts", false, "Disable login from multiple hosts") return cmd } -func createDaemon(host, driver, level string) error { +func createDaemon(host, driver, level string, blockMultipleHosts bool) error { switch level { case "info": log.SetLevel(log.InfoLevel) @@ -88,6 +90,10 @@ func createDaemon(host, driver, level string) error { targetDriver.NewTarget(tgtname, config) } + if blockMultipleHosts { + targetDriver.EnableBlockMultipleHostLogin() + } + // comment this to avoid concurrent issue // runtime.GOMAXPROCS(runtime.NumCPU()) // run a service diff --git a/pkg/port/iscsit/iscsid.go b/pkg/port/iscsit/iscsid.go index 1f37aeb..4d18a87 100644 --- a/pkg/port/iscsit/iscsid.go +++ b/pkg/port/iscsit/iscsid.go @@ -21,6 +21,7 @@ import ( "net" "os" "strconv" + "strings" "sync" "time" @@ -44,23 +45,25 @@ const ( ) var ( - EnableStats bool + EnableStats bool + CurrentHostIP string ) type ISCSITargetDriver struct { - SCSI *scsi.SCSITargetService - Name string - iSCSITargets map[string]*ISCSITarget - TSIHPool map[uint16]bool - TSIHPoolMutex sync.Mutex - isClientConnected bool - enableStats bool - mu *sync.RWMutex - l net.Listener - state uint8 - OpCode int - TargetStats scsi.Stats - clusterIP string + SCSI *scsi.SCSITargetService + Name string + iSCSITargets map[string]*ISCSITarget + TSIHPool map[uint16]bool + TSIHPoolMutex sync.Mutex + isClientConnected bool + enableStats bool + mu *sync.RWMutex + l net.Listener + state uint8 + OpCode int + TargetStats scsi.Stats + clusterIP string + blockMultipleHostLogin bool } func init() { @@ -133,6 +136,10 @@ func (s *ISCSITargetDriver) SetClusterIP(ip string) { s.clusterIP = ip } +func (s *ISCSITargetDriver) EnableBlockMultipleHostLogin() { + s.blockMultipleHostLogin = true +} + func (s *ISCSITargetDriver) RereadTargetLUNMap() { s.SCSI.RereadTargetLUNMap() } @@ -210,6 +217,19 @@ func (s *ISCSITargetDriver) Run() error { continue } + remoteIP := strings.Split(conn.RemoteAddr().String(), ":")[0] + + if CurrentHostIP == "" { + CurrentHostIP = remoteIP + } + + if s.blockMultipleHostLogin && remoteIP != CurrentHostIP { + conn.Close() + log.Infof("rejecting connection: %s target already connected at %s", + remoteIP, CurrentHostIP) + continue + } + log.Info(conn.LocalAddr().String()) s.setClientStatus(true) @@ -273,6 +293,7 @@ func (s *ISCSITargetDriver) handler(events byte, conn *iscsiConnection) { if conn.state == CONN_STATE_CLOSE { log.Warningf("iscsi connection[%d] closed", conn.cid) conn.close() + CurrentHostIP = "" } } @@ -457,6 +478,7 @@ func iscsiExecLogout(conn *iscsiConnection) error { conn.resp.ExpCmdSN = conn.session.ExpCmdSN conn.resp.MaxCmdSN = conn.session.ExpCmdSN + conn.session.MaxQueueCommand } + CurrentHostIP = "" return nil } diff --git a/pkg/scsi/drivers.go b/pkg/scsi/drivers.go index 4a3c2e1..2018019 100644 --- a/pkg/scsi/drivers.go +++ b/pkg/scsi/drivers.go @@ -31,6 +31,7 @@ type SCSITargetDriver interface { Resize(uint64) error Stats() Stats SetClusterIP(string) + EnableBlockMultipleHostLogin() } type Stats struct {