login negotiation and session/conn reinstatment

This commit is contained in:
Le Zhang
2016-11-30 00:42:18 +08:00
parent fd52b81c51
commit bb67ec66c7
7 changed files with 623 additions and 229 deletions

View File

@@ -22,19 +22,26 @@ import (
"net"
"os"
"strconv"
"sync"
log "github.com/Sirupsen/logrus"
"github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/config"
"github.com/gostor/gotgt/pkg/scsi"
"github.com/gostor/gotgt/pkg/util"
"github.com/satori/go.uuid"
)
const (
ISCSI_MAX_TSIH = uint16(0xffff)
ISCSI_UNSPEC_TSIH = uint16(0)
)
type ISCSITargetDriver struct {
SCSI *scsi.SCSITargetService
Name string
iSCSITargets map[string]*ISCSITarget
SCSI *scsi.SCSITargetService
Name string
iSCSITargets map[string]*ISCSITarget
TSIHPool map[uint16]bool
TSIHPoolMutex sync.Mutex
}
func init() {
@@ -46,9 +53,31 @@ func NewISCSITargetDriver(base *scsi.SCSITargetService) (scsi.SCSITargetDriver,
Name: "iscsi",
iSCSITargets: map[string]*ISCSITarget{},
SCSI: base,
TSIHPool: map[uint16]bool{0: true, 65535: true},
}, nil
}
func (s *ISCSITargetDriver) AllocTSIH() uint16 {
var i uint16
s.TSIHPoolMutex.Lock()
for i = uint16(0); i < ISCSI_MAX_TSIH; i++ {
exist := s.TSIHPool[i]
if !exist {
s.TSIHPool[i] = true
s.TSIHPoolMutex.Unlock()
return i
}
}
s.TSIHPoolMutex.Unlock()
return ISCSI_UNSPEC_TSIH
}
func (s *ISCSITargetDriver) ReleaseTSIH(tsih uint16) {
s.TSIHPoolMutex.Lock()
delete(s.TSIHPool, tsih)
s.TSIHPoolMutex.Unlock()
}
func (s *ISCSITargetDriver) NewTarget(tgtName string, configInfo *config.Config) error {
if _, ok := s.iSCSITargets[tgtName]; ok {
return fmt.Errorf("target name has been existed")
@@ -138,7 +167,10 @@ func (s *ISCSITargetDriver) Run() error {
}
log.Info(conn.LocalAddr().String())
log.Info("Accepting ...")
iscsiConn := &iscsiConnection{conn: conn}
iscsiConn := &iscsiConnection{conn: conn,
loginParam: &iscsiLoginParam{}}
iscsiConn.init()
iscsiConn.rxIOState = IOSTATE_RX_BHS
@@ -160,7 +192,7 @@ func (s *ISCSITargetDriver) handler(events byte, conn *iscsiConnection) {
s.txHandler(conn)
}
if conn.state == CONN_STATE_CLOSE {
log.Warningf("iscsi connection[%d] closed", conn.CID)
log.Warningf("iscsi connection[%d] closed", conn.cid)
conn.close()
}
}
@@ -175,8 +207,8 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
conn.readLock.Lock()
defer conn.readLock.Unlock()
if conn.state == CONN_STATE_SCSI {
hdigest = conn.sessionParam[ISCSI_PARAM_HDRDGST_EN].Value & DIGEST_CRC32C
ddigest = conn.sessionParam[ISCSI_PARAM_DATADGST_EN].Value & DIGEST_CRC32C
hdigest = conn.loginParam.sessionParam[ISCSI_PARAM_HDRDGST_EN].Value & DIGEST_CRC32C
ddigest = conn.loginParam.sessionParam[ISCSI_PARAM_DATADGST_EN].Value & DIGEST_CRC32C
}
for {
switch conn.rxIOState {
@@ -289,101 +321,62 @@ func (s *ISCSITargetDriver) rxHandler(conn *iscsiConnection) {
func (s *ISCSITargetDriver) iscsiExecLogin(conn *iscsiConnection) error {
var (
target *ISCSITarget
cmd = conn.req
TPGT uint16
err error
cmd = conn.req
err error
negoKeys []util.KeyValue
)
conn.resp = &ISCSICommand{
OpCode: OpLoginResp,
Transit: true,
CSG: cmd.CSG,
NSG: FullFeaturePhase,
StatSN: cmd.ExpStatSN,
TaskTag: cmd.TaskTag,
ExpCmdSN: cmd.CmdSN,
MaxCmdSN: cmd.CmdSN,
RawData: util.MarshalKVText([]util.KeyValue{
{"HeaderDigest", "None"},
{"DataDigest", "None"},
{"ImmediateData", "Yes"},
{"InitialR2T", "Yes"},
{"MaxBurstLength", "262144"},
{"FirstBurstLength", "65536"},
{"DefaultTime2Wait", "2"},
{"DefaultTime2Retain", "0"},
{"MaxOutstandingR2T", "1"},
{"IFMarker", "No"},
{"OFMarker", "No"},
{"DataPDUInOrder", "Yes"},
{"DataSequenceInOrder", "Yes"},
}),
}
conn.CID = cmd.ConnID
pairs := util.ParseKVText(cmd.RawData)
if initiatorName, ok := pairs["InitiatorName"]; ok {
conn.initiator = initiatorName
}
if alias, ok := pairs["InitiatorAlias"]; ok {
conn.initiatorAlias = alias
}
targetName := pairs["TargetName"]
if sessType, ok := pairs["SessionType"]; ok {
if sessType == "Normal" {
conn.sessionType = SESSION_NORMAL
} else {
conn.sessionType = SESSION_DISCOVERY
}
}
if conn.sessionType == SESSION_DISCOVERY {
conn.tid = 0xffff
} else {
for _, t := range s.iSCSITargets {
if t.SCSITarget.Name == targetName {
target = t
break
}
}
if target == nil {
conn.state = CONN_STATE_EXIT
return fmt.Errorf("No target found with name(%s)", targetName)
}
TPGT, err = target.FindTPG(conn.conn.LocalAddr().String())
conn.cid = cmd.ConnID
conn.loginParam.iniCSG = cmd.CSG
conn.loginParam.iniNSG = cmd.NSG
conn.loginParam.iniCont = cmd.Cont
conn.loginParam.iniTrans = cmd.Transit
conn.loginParam.isid = cmd.ISID
conn.loginParam.tsih = cmd.TSIH
conn.expCmdSN = cmd.CmdSN
conn.statSN += 1
if conn.loginParam.iniCSG == SecurityNegotiation {
conn.state = CONN_STATE_EXIT
return fmt.Errorf("Doesn't support Auth")
}
pairs := util.ParseKVText(cmd.RawData)
negoKeys, err = loginKVProcess(conn, pairs)
if err != nil {
return err
}
if !conn.loginParam.keyDeclared {
negoKeys = loginKVDeclare(conn, negoKeys)
conn.loginParam.keyDeclared = true
}
if !conn.loginParam.paramInit {
err = s.BindISCSISession(conn)
if err != nil {
conn.state = CONN_STATE_EXIT
return err
}
conn.tpgt = TPGT
conn.tid = target.TID
conn.loginParam.paramInit = true
}
switch conn.state {
case CONN_STATE_FREE:
conn.state = CONN_STATE_SECURITY
case CONN_STATE_SECURITY:
if conn.loginParam.tgtNSG == FullFeaturePhase &&
conn.loginParam.tgtTrans {
conn.state = CONN_STATE_LOGIN_FULL
} else {
conn.state = CONN_STATE_LOGIN
}
conn.state = CONN_STATE_LOGIN_FULL
conn.expCmdSN = cmd.CmdSN
conn.statSN += 1
switch conn.sessionType {
case SESSION_NORMAL:
if conn.session == nil {
// create a new session
sess, err := s.NewISCSISession(conn, cmd.ISID)
if err != nil {
log.Error(err)
return err
}
itnexus := &api.ITNexus{uuid.NewV1(), GeniSCSIITNexusID(sess)}
scsi.AddITNexus(&sess.Target.SCSITarget, itnexus)
sess.ITNexusID = itnexus.ID
conn.session = sess
}
case SESSION_DISCOVERY:
conn.resp = &ISCSICommand{
OpCode: OpLoginResp,
Transit: conn.loginParam.tgtTrans,
CSG: cmd.CSG,
NSG: conn.loginParam.tgtNSG,
StatSN: cmd.ExpStatSN,
TaskTag: cmd.TaskTag,
ExpCmdSN: cmd.CmdSN,
MaxCmdSN: cmd.CmdSN,
RawData: util.MarshalKVText(negoKeys),
}
return nil
@@ -476,14 +469,13 @@ func iscsiExecReject(conn *iscsiConnection) error {
}
func iscsiExecR2T(conn *iscsiConnection) error {
var val uint
conn.txTask = &iscsiTask{conn: conn, cmd: conn.req, tag: conn.req.TaskTag, scmd: &api.SCSICommand{}}
conn.txIOState = IOSTATE_TX_BHS
conn.statSN += 1
task := conn.rxTask
resp := &ISCSICommand{
OpCode: OpReady,
Immediate: true,
Final: true,
StatSN: conn.req.ExpStatSN,
TaskTag: conn.req.TaskTag,
ExpCmdSN: conn.session.ExpCmdSN,
@@ -492,7 +484,8 @@ func iscsiExecR2T(conn *iscsiConnection) error {
BufferOffset: uint32(task.offset),
DesiredLength: uint32(task.r2tCount),
}
if val := sessionKeys[ISCSI_PARAM_MAX_BURST].def; task.r2tCount > int(val) {
if val = conn.loginParam.sessionParam[ISCSI_PARAM_MAX_BURST].Value; task.r2tCount > int(val) {
resp.DesiredLength = uint32(val)
}
conn.resp = resp
@@ -506,8 +499,8 @@ func (s *ISCSITargetDriver) txHandler(conn *iscsiConnection) {
final bool = false
)
if conn.state == CONN_STATE_SCSI {
hdigest = conn.sessionParam[ISCSI_PARAM_HDRDGST_EN].Value & DIGEST_CRC32C
ddigest = conn.sessionParam[ISCSI_PARAM_DATADGST_EN].Value & DIGEST_CRC32C
hdigest = conn.loginParam.sessionParam[ISCSI_PARAM_HDRDGST_EN].Value & DIGEST_CRC32C
ddigest = conn.loginParam.sessionParam[ISCSI_PARAM_DATADGST_EN].Value & DIGEST_CRC32C
}
if conn.state == CONN_STATE_SCSI && conn.txTask == nil {
err := s.scsiCommandHandler(conn)
@@ -564,10 +557,14 @@ func (s *ISCSITargetDriver) txHandler(conn *iscsiConnection) {
case CONN_STATE_SECURITY_LOGIN:
conn.state = CONN_STATE_LOGIN
log.Debugf("CONN_STATE_LOGIN")
case CONN_STATE_LOGIN:
log.Debugf("CONN_STATE_LOGIN")
conn.rxIOState = IOSTATE_RX_BHS
s.handler(DATAIN, conn)
case CONN_STATE_SECURITY_FULL, CONN_STATE_LOGIN_FULL:
if conn.sessionType == SESSION_NORMAL {
if conn.session.SessionType == SESSION_NORMAL {
conn.state = CONN_STATE_KERNEL
log.Infof("CONN_STATE_KERNEL")
log.Debugf("CONN_STATE_KERNEL")
conn.state = CONN_STATE_SCSI
log.Debugf("CONN_STATE_SCSI")
} else {
@@ -583,7 +580,6 @@ func (s *ISCSITargetDriver) txHandler(conn *iscsiConnection) {
conn.rxIOState = IOSTATE_RX_BHS
s.handler(DATAIN, conn)
}
log.Infof("%d", conn.state)
}
func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error) {
@@ -604,15 +600,24 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
if task.scmd.OutSDBBuffer.Buffer == nil {
task.scmd.OutSDBBuffer.Buffer = bytes.NewBuffer([]byte{})
}
task.scmd.OutSDBBuffer.Buffer.Write(conn.req.RawData)
if conn.session.SessionParam[ISCSI_PARAM_IMM_DATA_EN].Value == 1 {
task.scmd.OutSDBBuffer.Buffer.Write(conn.req.RawData)
}
if task.r2tCount > 0 {
// prepare to receive more data
conn.session.ExpCmdSN += 1
task.state = taskPending
conn.session.PendingTasks.Push(task)
conn.rxTask = task
iscsiExecR2T(conn)
break
if conn.session.SessionParam[ISCSI_PARAM_INITIAL_R2T_EN].Value == 1 {
iscsiExecR2T(conn)
break
} else {
log.Debugf("Not ready to exec the task")
conn.rxIOState = IOSTATE_RX_BHS
s.handler(DATAIN, conn)
return nil
}
}
}
task.offset = 0
@@ -691,7 +696,12 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
return nil
} else if task.r2tCount > 0 {
// prepare to receive more data
task.r2tSN += 1
if task.unsolCount == 0 {
task.r2tSN += 1
} else {
task.r2tSN = 0
task.unsolCount = 0
}
conn.rxTask = task
iscsiExecR2T(conn)
break
@@ -803,12 +813,12 @@ func (s *ISCSITargetDriver) iscsiExecTask(task *iscsiTask) error {
task.scmd.Direction = api.SCSIDataWrite
}
}
task.scmd.ITNexusID = task.conn.session.ITNexusID
task.scmd.ITNexusID = task.conn.session.ITNexus.ID
task.scmd.SCB = bytes.NewBuffer(cmd.CDB)
task.scmd.SCBLength = len(cmd.CDB)
task.scmd.Lun = cmd.LUN
task.scmd.Tag = uint64(cmd.TaskTag)
task.scmd.RelTargetPortID = task.conn.tpgt
task.scmd.RelTargetPortID = task.conn.session.TPGT
task.state = taskSCSI
if task.scmd.OutSDBBuffer.Buffer == nil {
task.scmd.OutSDBBuffer.Buffer = bytes.NewBuffer(cmd.RawData)