Files
mlsr/communication/SyncLogicHandler.go
T

269 lines
8.9 KiB
Go

// Package communication
// @Author: Wang Feng / zhengqi Wu
// @Description:
// @Version: 0.1.0
// @Date: 2022/4/1 16:07
// @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
//
package communication
import (
"errors"
common2 "minlib/common"
"minlib/component"
"minlib/logicface"
mutil "minlib/utils"
"mlsr/common"
"mlsr/lsa"
"mlsr/utils"
"strconv"
)
// IsLsaNew 用于判断新的LSA是否到来
//
// 参数说明:
//
// identifier LSA的标识
//
// lsaType LSA的类型
//
// seq LSA的序列号
//
// incomingLogicFaceId LSA到来的LogicFaceId
//
type IsLsaNew = func(identifier *component.Identifier, lsaType lsa.LsaType, seq uint64, incomingLogicFaceId uint64) bool
// SyncLogicHandler MLSR-to-MINSync 中间层
//
// 本结构体为MLSR提供MINSync同步协议的一种抽象
//
// MLSR与MINSync之间并不存在强关联关系,只是因为当前只实现了MINSync这一版本的同步协议,因此后续有其余的同步协议也可以通过该中间层向
// MLSR提供同步协议的抽象
//
type SyncLogicHandler struct {
/////////////// 私有属性 /////////////
// syncFace 用于同步数据的LogicFace
syncFace *logicface.DummyClientLogicFace
// isLsaNew 用于判断LSA是否更新的自定义函数
isLsaNew IsLsaNew
// confParam MLSR配置参数
confParam *common.MlsrConfigParameters
// nlsrComponent NLSR字符串
mlsrComponent string
// lsaComponent LSA字符串
lsaComponent string
/////////////// 公有属性 /////////////
// OnNewLsa 当新LSA到来时的所触发的信号
OnNewLsa *mutil.Signal
// NameLsaUserPrefix NameLsa前缀
NameLsaUserPrefix *component.Identifier
// AdjLsaUserPrefix AdjLsa前缀
AdjLsaUserPrefix *component.Identifier
// CoorLsa 双曲路由Lsa前缀
CoorLsaUserPrefix *component.Identifier
// SyncLogic 同步数据逻辑(目前仅支持MINSync)
SyncLogic *SyncProtocolAdapter
}
// ProcessUpdate 处理到达该路由节点的新同步数据
//
// 参数说明:
//
// updateName: 更新的数据前缀
//
// highSeq: 更新的数据版本
//
// incomingFaceId: 该同步数据到达的LogicFaceId
//
func (s *SyncLogicHandler) ProcessUpdate(updateName *component.Identifier, highSeq, incomingFaceId uint64) {
common2.LogInfo("Update Name: ", updateName.ToUri(), " Seq no: ", highSeq)
// nlsrPosition 从同步数据的标识中获取子字符串'nlsr'的位置
mlsrPosition := utils.GetNameComponentPosition(updateName, s.mlsrComponent)
// lsaPosition 从同步数据的标识中获取子字符串'lsa'的位置
lsaPosition := utils.GetNameComponentPosition(updateName, s.lsaComponent)
if mlsrPosition < 0 || lsaPosition < 0 {
common2.LogWarn("收到了不合法的同步更新数据")
return
}
// networkName 用于表示源MLSR节点网络标识
networkName, err := updateName.GetSubIdentifier(1, mlsrPosition-1)
if err != nil {
common2.LogError("解析源MLSR节点网络标识出错", err.Error())
return
}
networkNameBlock, err := networkName.SelfWireEncode(networkName)
// routerName 用于表示源MLSR节点路由器标识
// NLSR源代码:updateName.getSubName(lsaPosition + 1).getPrefix(-1);
// 意味着取updateName的第[lsaPosition+1, updateName.Size()-2]个组件组成标识
// 等价于从第lsaPosition+1开始取updateName.Size()-lsaPosition-2个
routerName, err := updateName.GetSubIdentifier(lsaPosition+1, updateName.Size()-lsaPosition-2)
if err != nil {
common2.LogError("解析源MLSR节点路由器标识出错", err.Error())
return
}
routerNameBlock, err := routerName.SelfWireEncode(routerName)
if err != nil {
common2.LogError(err.Error())
return
}
routerNameCopy, err := component.NewIdentifierByBlock(routerNameBlock)
if err != nil {
common2.LogError(err.Error())
return
}
// 将networkName和routerName组合成originRouterName
originRouterName, err := component.NewIdentifierByBlock(networkNameBlock)
if err != nil {
common2.LogError(err.Error())
return
}
for _, comp := range routerNameCopy.GetComponents() {
originRouterName.Append(comp)
}
s.ProcessUpdateFromSync(originRouterName, updateName, highSeq, incomingFaceId)
}
// ProcessUpdateFromSync 处理更新的回调函数
//
// 主要用来确定更新的LSA类型并拉取它的载荷
//
// 首先检查收到的更新是否是我们自身发布的,这是可能发生的,
// 原因可以查看MINSync全同步逻辑中的TestMultipleNodesSimultaneousPublish测试用例
//
// 随后检查更新的类型,确定该更新信息用于更新哪类LSA
//
// 最后转发兴趣包拉取该LSA对应的载荷
//
func (s *SyncLogicHandler) ProcessUpdateFromSync(originRouter, updateName *component.Identifier, seqNo, incomingFaceId uint64) {
common2.LogDebug("Origin Router of update: ", originRouter.ToUri())
// 先校验该LSA更新是否由本地路由器发布,一个路由器不应该拉取自己发布的LSA
if originRouter.ToUri() != s.confParam.GetRouterPrefix().ToUri() {
// 校验LSA类型
var lsaType lsa.LsaType
lsaTypeComp, err := updateName.Get(-1)
if err != nil {
common2.LogError(err.Error())
return
}
// 将lsaTypeComp字符串转换为LSAType
// 先转为int,再转为LSAType
lsaTypeInt, err := strconv.Atoi(lsaTypeComp.ToUri())
if err != nil {
common2.LogError(err.Error())
return
}
lsaType = lsa.LsaType(lsaTypeInt)
// 判断是否Lsa更新
if s.isLsaNew(originRouter, lsaType, seqNo, incomingFaceId) {
// 双曲路由特性未实现,这里先不判断
//if lsaType == lsa.LsaADJACENCYType && seqNo != 0 {
// common2.LogError()
// return
//}
//if (lsaType == Lsa::Type::COORDINATE && seqNo != 0 &&
// m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_OFF) {
// NLSR_LOG_ERROR("Got an update for coordinate LSA when link-state " <<
// "is enabled. Not going to fetch.");
// return;
//}
// 触发OnNewLsa信号,通知MLSR新的LSA到来
s.OnNewLsa.Emit(updateName, seqNo, originRouter, incomingFaceId)
}
}
}
// PublishRoutingUpdate 通知MINSync向其它节点发布更新
//
// 序列号seqNo取决于调用该方法时sequencing manager的状态
//
// 发布更新时会这样做可以满足其他路由器的Sync兴趣包,让它们知道有同步更新可用
//
func (s *SyncLogicHandler) PublishRoutingUpdate(t lsa.LsaType, seqNo uint64) {
switch t {
case lsa.LsaADJACENCYType:
s.SyncLogic.PublishUpdate(s.AdjLsaUserPrefix, seqNo)
case lsa.LsaCOORDINATEType:
s.SyncLogic.PublishUpdate(s.CoorLsaUserPrefix, seqNo)
case lsa.LsaNAMEType:
s.SyncLogic.PublishUpdate(s.NameLsaUserPrefix, seqNo)
}
}
// NewSyncLogicHandler SyncLogicHandler的工厂方法
//
func NewSyncLogicHandler(face *logicface.DummyClientLogicFace, isLsaNew IsLsaNew, conf *common.MlsrConfigParameters) (*SyncLogicHandler, error) {
if face == nil || isLsaNew == nil || conf == nil {
return nil, errors.New("无效的输入参数")
}
// 基础参数
syncLogicHandler := new(SyncLogicHandler)
syncLogicHandler.OnNewLsa = mutil.NewSignal()
syncLogicHandler.syncFace = face
syncLogicHandler.isLsaNew = isLsaNew
syncLogicHandler.confParam = conf
// 标识组件构造
syncLogicHandler.mlsrComponent = "mlsr"
syncLogicHandler.lsaComponent = "LSA"
// NLSR的源码中使用了字符串类型的标识组件, 而不是非负数类型
nameComponent := component.CreateIdentifierComponentByString(strconv.Itoa(int(lsa.LsaNAMEType)))
adjComponent := component.CreateIdentifierComponentByString(strconv.Itoa(int(lsa.LsaADJACENCYType)))
coorComponent := component.CreateIdentifierComponentByString(strconv.Itoa(int(lsa.LsaCOORDINATEType)))
// Bug: 复制标识SyncPrefix
// Fix: 复制标识SyncUserPrefix
syncUserPrefix := conf.GetSyncUserPrefix()
if syncUserPrefix == nil {
return nil, errors.New("无效同步标识")
}
syncUserPrefixBlock, err := syncUserPrefix.SelfWireEncode(syncUserPrefix)
if err != nil {
return nil, err
}
// NameLsaUserPrefix 构建
syncLogicHandler.NameLsaUserPrefix, err = component.NewIdentifierByBlock(syncUserPrefixBlock)
if err != nil {
return nil, err
}
syncLogicHandler.NameLsaUserPrefix.Append(nameComponent)
// AdjLsaUserPrefix 构建
syncLogicHandler.AdjLsaUserPrefix, err = component.NewIdentifierByBlock(syncUserPrefixBlock)
if err != nil {
return nil, err
}
syncLogicHandler.AdjLsaUserPrefix.Append(adjComponent)
// CoorLsaUserPrefix 构建
syncLogicHandler.CoorLsaUserPrefix, err = component.NewIdentifierByBlock(syncUserPrefixBlock)
if err != nil {
return nil, err
}
syncLogicHandler.CoorLsaUserPrefix.Append(coorComponent)
// 双曲路由特性暂未支持
// if conf.GetHyperbolicState()
// 同步逻辑实例
syncLogicHandler.SyncLogic, err = NewSyncProtocolAdapter(face,
// 公共的SyncPrefix
conf.GetSyncPrefix(),
// userPrefix
syncLogicHandler.NameLsaUserPrefix,
// syncInterestLifetime
conf.GetSyncInterestLifetime(),
// 处理更新同步数据的回调函数
syncLogicHandler.ProcessUpdate)
return syncLogicHandler, nil
}