// Package lsdb // @Author: Wang Feng // @Description: // @Version: 0.1.0 // @Date: 2022/3/24 11:41 // @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室 // package lsdb import ( "bytes" common2 "minlib/common" "minlib/component" "minlib/logicface" "minlib/packet" "mlsr/common" "mlsr/communication" "mlsr/lsa" "mlsr/lsdb/LsaContainer" "time" ) // Lsdb更新状态 const ( INSTALLED = 0 // 已安装 UPDATED = 1 // 已更新 REMOVED = -1 // 已移除 ) const GRACE_PERIOD = 10 * time.Second // 超期宽限期。LSA比设定时间晚几秒钟被删除,以避免信息过早失效。 type Lsdb struct { // 配置参数 mlsrConfig *common.MlsrConfig // 同步协议配置项 sync *communication.SyncLogicHandler // LSA容器 LsaContainer.LsaContainer lsaRefreshTime time.Duration // lsa刷新时间 adjLsaBuildInterval time.Duration // 邻接LSA构建间隔 thisRouterPrefix *component.Identifier // 当前路由器的标识 // 任务调度器 scheduler *MlsrScheduler // LogicFace接口 face *logicface.LogicFace // 将LSA的名称从sync映射到其已知的最高序列号; // 用于阻止MLSR尝试获取过时的LSA highestSeqNo map[*component.Identifier]uint64 // 不同类型lsa的序列号管理器 sequencingManager *SequencingManager isBuildAdjLsaScheduled bool // 是否安排构建邻接LSA adjBuildCount uint64 // 邻接LSA的构建的统计数目 } func (l *Lsdb) Init(mc *common.MlsrConfig, ms *MlsrScheduler, _face *logicface.LogicFace) { // 配置项 l.mlsrConfig = mc // 调度器 l.scheduler = ms // 逻辑face l.face = _face // 序列号管理器 l.sequencingManager = GetInstance() // 存储器 err := l.LsaContainer.Init() if err != nil { common2.LogFatal("lsdb.LsaContainer init error, ", err.Error()) } // todo 构造sync // lsa刷新时间 l.lsaRefreshTime = l.mlsrConfig.GetLsaRefreshTime() // 邻接lsa构建间隔 l.adjLsaBuildInterval = l.mlsrConfig.GetAdjLsaBuildInterval() // 本机路由前缀 l.thisRouterPrefix = l.mlsrConfig.GetRouterPrefix() // 是否已经安排邻接LSA的构建 l.isBuildAdjLsaScheduled = false // 邻接LSA构建次数统计 l.adjBuildCount = 0 // 在LSDB初始化之前,对配置文件中的本机路由器进行拉式前缀注册(即监听该前缀) // todo: 为了在Windows上单独测试,暂时注释掉face注册前缀这一步骤 //lsaPrefix := l.mlsrConfig.GetLsaPrefix() //err := l.face.RegisterPullIdentifier(lsaPrefix, 2000) //if err != nil { // common2.LogFatal("Lsdb Init error, because of face register, ", err.Error()) //} // 构建并安装自己的名称LSA // todo 先测试其它项 //l.BuildAndInstallOwnNameLsa() } // // DoesLsaExist // @Description: 返回LSDB是否存在某个LSA的查询结果 // @receiver l // @param routerIdentifier // @param lsaType // @return bool // func (l *Lsdb) DoesLsaNameExist(routerIdentifier *component.Identifier, lsaType lsa.LsaType) bool { return l.ExistsRouterNameAndType(routerIdentifier, lsaType) } // // DoesLsaExist // @Description: 返回LSDB是否存在某个LSA的查询结果 // @receiver l // @param lsa // @return bool // func (l *Lsdb) DoesLsaExist(lsa lsa.ILsa) bool { return l.Exists(lsa) } // // BuildAndInstallOwnNameLsa // @Description: 构建一个属于本路由器的名称LSA,并安装它到LSDB。 // @receiver l // func (l *Lsdb) BuildAndInstallOwnNameLsa() { // 根据配置文件,构造本机的名称LSA nlsa := new(lsa.NameLsa) nlsa.SetOriginRouter(l.thisRouterPrefix) // 源路由 nlsa.SetSeqNo(l.sequencingManager.GetNameLsaSeq() + 1) // 序列号 nlsa.SetLsaExpirationTime(l.getLsaExpirationTimePoint()) // 超期时间 nlsa.NameLsaNamePrefixList.InsertNamePrefixList(l.mlsrConfig.GetNamePrefixList()) // 名称前缀列表 // 刷新序列号管理器中的名称LSA序列号 l.sequencingManager.IncreaseNameLsaSeq() // todo: 使用sync通知路由更新 // m_sync.publishRoutingUpdate(Lsa::Type::NAME, m_sequencingManager.getNameLsaSeq()); // 安装lsa到LSDB l.InstallLsa(nlsa) } // // BuildAndInstallOwnCoordinateLsa // @Description: 构建一个属于本路由器的坐标LSA,并安装它到LSDB // @receiver l // func (l *Lsdb) BuildAndInstallOwnCoordinateLsa() { // todo:坐标计算预留接口 } // // ScheduleAdjLsaBuild // @Description: 安排LSA的构建 // @receiver l // func (l *Lsdb) ScheduleAdjLsaBuild() { // 计数 l.adjBuildCount++ // 日志记录 if l.isBuildAdjLsaScheduled { common2.LogInfo("Rescheduling Adjacency LSA build in ", l.adjLsaBuildInterval) } else { common2.LogInfo("Scheduling Adjacency LSA build in ", l.adjLsaBuildInterval) l.isBuildAdjLsaScheduled = true } // 安排构造邻接LSA job, err := l.scheduler.ScheduleTaskAfterDuration(l.adjLsaBuildInterval, 1).Do(l.BuildAdjLsa) job.LimitRunsTo(1) l.scheduler.StartAsync() if err != nil { common2.LogError("Scheduling Adjacency LSA build error, ", err.Error()) } } // // ProcessInterest // @Description:收到一个兴趣包,根据兴趣包名称,查找LSA并返回。 // 处理兴趣包。类似NDN的拉式传输。 // 在NLSR的设计中,由于对兴趣包进行了进一步的分段,因此有以下两种兴趣包: //* 1) 需要从segment fetcher中查找的兴趣包: //* /localhop//nlsr/LSA//// //* 2) 已经包含segment number的兴趣包: //* /localhop//nlsr/LSA////// // @receiver l // @param interest // func (l *Lsdb) ProcessInterest(interest *packet.Interest) { } func (l *Lsdb) processInterestForLsa(interest *packet.Interest, originRouterIdentifier *component.Identifier, lsaType lsa.LsaType, seqNo uint64) { } func (l *Lsdb) ProcessGPPkt(pkt *packet.GPPkt) { } // // GetIsBuildAdjLsaScheduled // @Description: 判断是否已经安排了邻接LSA的构建 // @receiver l // @return bool // func (l *Lsdb) GetIsBuildAdjLsaScheduled() bool { return l.isBuildAdjLsaScheduled } // // GetSync // @Description: 获取Sync协议逻辑处理器 // @receiver l // @return communication.SyncLogicHandler // func (l *Lsdb) GetSync() *communication.SyncLogicHandler { return l.sync } // // FindLsa // @Description: 根据LSA类型及所属路由器,获取LSA // @receiver l* // @param routerIdentifier // @param lsaType // @return lsa.ILsa // func (l *Lsdb) FindLsa(routerIdentifier *component.Identifier, lsaType lsa.LsaType) lsa.ILsa { lsaGet, err := l.GetLSAByNameAndType(routerIdentifier, lsaType) if err != nil { lsaGet = nil } return lsaGet } // // isLsaNew // @Description: 返回来自某个路由器的seq是否表示新的LSA。 // @receiver l // @param routerIdentifier // @param lsaType // @param seqNo // @return bool // func (l *Lsdb) isLsaNew(routerIdentifier *component.Identifier, lsaType lsa.LsaType, seqNo uint64) bool { iLsa := l.FindLsa(routerIdentifier, lsaType) // 没找到,说明是最新的 if iLsa == nil { return true } // 找到了,且LSDB中的该lsa序列号小于要查的lsa,说明是最新的 if iLsa.GetSeqNo() < seqNo { return true } return false } // // IsLsaNew // @Description: 返回来自某个路由器的seq是否表示新的LSA。 // @receiver l // @param fLsa // @return bool // func (l *Lsdb) IsLsaNew(fLsa lsa.ILsa) bool { return l.isLsaNew(fLsa.GetOriginRouter(), fLsa.GetType(), fLsa.GetSeqNo()) } // // InstallLsa // @Description: 将LSA安装到lsdb中 // @receiver l // @param lsa // func (l *Lsdb) InstallLsa(lsa lsa.ILsa) { timeToExpire := l.lsaRefreshTime // 判断不是本机LSA时,调整超期时间 if lsa.GetOriginRouter().ToUri() != l.thisRouterPrefix.ToUri() { // 如果该其他路由器发来的LSA还没超时,则将超时时间间隔设置为该LSA剩余存活时间 if l.uintToTime(lsa.GetExpirationTime()).After(time.Now()) { timeToExpire = l.uintToTime(lsa.GetExpirationTime()).Sub(time.Now()) } } // 查看数据库中是否已有该LSA源路由器所发出的LSA lsaInDb := l.FindLsa(lsa.GetOriginRouter(), lsa.GetType()) if lsaInDb == nil { // 如果没有: common2.LogDebug("Adding Lsa ", lsa.ToString()) // 1. 就插入该LSA err := l.Emplace(lsa) if err != nil { common2.LogError("Add Lsa error", lsa.ToString()) return } // 2. 触发LSDB安装LSA的动作信号 // todo: onLsdbModified(lsa, LsdbUpdate::INSTALLED, {}, {}); // 3. 设置LSA超期时间事件 l.ScheduleLsaExpiration(lsa, timeToExpire) } else if lsaInDb.GetSeqNo() < lsa.GetSeqNo() { // 如果查到了,而且传入的这个LSA比数据库中的更新,我们将更新数据库 common2.LogDebug("Updating Lsa ", lsaInDb.ToString()) // 1. 就插入该LSA err := l.Emplace(lsa) if err != nil { common2.LogError("Add Lsa error", lsa.ToString()) return } // 2. 触发LSDB更新LSA的动作信号 // todo: onLsdbModified(lsa, LsdbUpdate::UPDATED, namesToAdd, namesToRemove); // 3. 设置LSA超期时间事件 l.ScheduleLsaExpiration(lsa, timeToExpire) common2.LogDebug("Updated Lsa ", lsa.ToString()) } } // // RemoveLsa // @Description: 从LSDB中删除LSA // @receiver l // @param lsa // func (l *Lsdb) RemoveLsa(lsa lsa.ILsa) { err := l.LsaContainer.EraseLsa(lsa) if err != nil { common2.LogError("") return } common2.LogDebug("Removed LSA: ", lsa.ToString()) } // // RemoveLsaByNameAndType // @Description: 删除lsa // @receiver l // @param routerIdentifier // @param lsaType // func (l *Lsdb) RemoveLsaByNameAndType(routerIdentifier *component.Identifier, lsaType lsa.LsaType) { err := l.LsaContainer.EraseLsaByNameAndType(routerIdentifier, lsaType) if err != nil { common2.LogError("") return } common2.LogDebug("Removed LSA: ", routerIdentifier.ToUri()) } // // BuildAdjLsa // @Description: 构建一个邻接LSA // 只有当路由器的所有邻居状态是已知的时,才可以构建它的邻接LSA。 // @receiver l // func (l *Lsdb) BuildAdjLsa() { common2.LogDebug("buildAdjLsa called") // 构建邻接lsa的任务启动,那么安排构建就变为false l.isBuildAdjLsaScheduled = false // 根据配置文件中邻接表的状态,执行不同的动作 if l.mlsrConfig.GetAdjacencys().IsAdjLsaBuildable(uint32(l.mlsrConfig.GetHelloRetries())) { // 只有在有计划的情况下才执行adjLsa构建 adjBuildCountCache := l.adjBuildCount if adjBuildCountCache > 0 { // 只有有安排时,构建邻接lsa if l.mlsrConfig.GetAdjacencys().GetNumOfActiveNeighbor() > 0 { // 有激活状态的邻居,则安装邻接LSA common2.LogDebug("Building and installing own Adj LSA") l.BuildAndInstallOwnAdjLsa() } else { // 我们没有活跃的邻居,这意味着没有人可以穿过我们。 // 因此,请删除LSDB中的条目。这会阻止此路由器刷新LSA,最终导致其他路由器也将其删除。 common2.LogDebug("Removing own Adj LSA; no ACTIVE neighbors") l.RemoveLsaByNameAndType(l.thisRouterPrefix, lsa.LsaADJACENCYType) } // 如果在构建adj LSA的过程中,FIB必须等待兴趣响应, // 那么计划的adj LSA构建的数量可能会发生变化,因此我们不应该只将其设置为0。 l.adjBuildCount = l.adjBuildCount - adjBuildCountCache } } else { // 我们仍在等待了解某个邻居的邻接状态,因此请安排稍后的构建(当有望完成时) l.isBuildAdjLsaScheduled = true scheTime := l.mlsrConfig.GetHelloTimeout() * time.Duration(l.mlsrConfig.GetHelloRetries()) job, err := l.scheduler.ScheduleTaskAfterDuration(scheTime, 1).Do(l.BuildAdjLsa) job.LimitRunsTo(1) l.scheduler.StartAsync() if err != nil { common2.LogError("Scheduling BuildAdjLsa error, ", err.Error()) } } } // // BuildAndInstallOwnAdjLsa // @Description: 为当前路由器构建并安装一个邻接LSA // @receiver l // func (l *Lsdb) BuildAndInstallOwnAdjLsa() { // 根据配置文件,构造本机的名称LSA adjLsa := new(lsa.AdjLsa) adjLsa.SetOriginRouter(l.thisRouterPrefix) adjLsa.SetSeqNo(l.sequencingManager.GetAdjLsaSeq() + 1) // 序列号 adjLsa.SetLsaExpirationTime(l.getLsaExpirationTimePoint()) // 超期时间 adjLsa.AdjLsaAdjacenctList.InsertAdjacenctList(l.mlsrConfig.GetAdjacencyList()) // 名称前缀列表 // 刷新序列号管理器中的名称LSA序列号 l.sequencingManager.IncreaseAdjLsaSeq() // todo: 使用sync通知路由更新 // m_sync.publishRoutingUpdate(Lsa::Type::ADJACENCY, m_sequencingManager.getAdjLsaSeq()); // 安装lsa到LSDB l.InstallLsa(adjLsa) } // // ScheduleLsaExpiration // @Description: 在调度器中安排一个刷新或过期事件 // @receiver l // func (l *Lsdb) ScheduleLsaExpiration(lsa lsa.ILsa, duration time.Duration) { // 在指定间隔的几秒后触发刷新或过期事件 duration = duration + GRACE_PERIOD // 安排LSA在指定时间间隔后进行删除 job, err := l.scheduler.ScheduleTaskAfterDuration(duration, 1).Do(l.ExpireOrRefreshLsa, lsa) job.LimitRunsTo(1) l.scheduler.StartAsync() if err != nil { common2.LogError("Scheduling Lsa Expiration error, ", err.Error()) } } // // ExpireOrRefreshLsa // @Description: LSA过期时间触发后,执行该函数 // @receiver l // @param lsa // func (l *Lsdb) ExpireOrRefreshLsa(lsa lsa.ILsa) { common2.LogDebug("ExpireOrRefreshLsa called for ", lsa.ToString()) lsaInDb := l.FindLsa(lsa.GetOriginRouter(), lsa.GetType()) if lsaInDb != nil { common2.LogDebug("LSA Exists with seq no: ", lsaInDb.GetSeqNo()) // 只有DB中LSA序列号依然是传入调度器的LSA序列号时,才执行删除或更新动作。否则,该LSA已是新的,则不应修改它。 if lsaInDb.GetSeqNo() == lsa.GetSeqNo() { if lsaInDb.GetOriginRouter().ToUri() == l.thisRouterPrefix.ToUri() { // 如果是本机LSA,由于它不能被删除,因此我们只继续更新它 // 1. 更新 common2.LogDebug("Own lsa refreshing, ", lsaInDb.ToString()) lsaInDb.SetSeqNo(lsaInDb.GetSeqNo() + 1) l.sequencingManager.SetLsaSeq(lsaInDb.GetSeqNo()+1, lsaInDb.GetType()) lsaInDb.SetExpirationTime(l.getLsaExpirationTimePoint()) err := l.Emplace(lsaInDb) if err != nil { common2.LogError("Own lsa refresh error, ", err.Error()) return } common2.LogDebug("Own lsa refreshed, ", lsaInDb.ToString()) // 2. 安排新的超期事件 l.ScheduleLsaExpiration(lsaInDb, l.lsaRefreshTime) // 3. todo: 将lsa更新通知给sync // m_sync.publishRoutingUpdate(lsaPtr->getType(), m_sequencingManager.getLsaSeq(lsaPtr->getType())); } else { // 如果是其他路由器的LSA,我们将删除它。 // 更新其他路由器的LSA是通过min-sync实现的,而不是超期触发。 common2.LogDebug("Other's LSA, so removing from LSDB, lsa is ", lsa.ToString()) l.RemoveLsa(lsaInDb) } } } } // // ExpressInterest // @Description: 发送请求其它路由器LSA的兴趣包 // @receiver l // @param interestName // @param timeOut // @param deadline // func (l *Lsdb) ExpressInterest(interestName *component.Identifier, timeOut uint32, deadline *time.Time) { } // // OnFetchLsaError // @Description: 在发生所有错误的情况下,将尝试重新获取LSA,直到deadline到达。 // @receiver l // @param errorCode // @param msg // @param interestName // @param retransmitNo // @param deadline // @param lsaName // @param seqNo // func (l *Lsdb) onFetchLsaError(errorCode uint32, msg string, interestName *component.Identifier, retransmitNo uint32, deadline *time.Time, lsaName *component.Identifier, seqNo uint64) { } // // AfterFetchLsa // @Description: 当SegmentFetcher返回一个有效LSA之后的成功回调 // 在NLSR的设计中,一个获取LSA的基础兴趣包格式为: // //NLSR/LSA//%C1.Router/// // @receiver l // @param buffer // @param interestName // func (l *Lsdb) afterFetchLsa(buffer bytes.Buffer, interestName *component.Identifier) { } func (l *Lsdb) getLsaExpirationTimePoint() uint64 { timeExpire := time.Now() timeExpire = timeExpire.Add(l.mlsrConfig.GetRouterDeadInterval()) return uint64(timeExpire.UnixMilli()) } func (l *Lsdb) uintToTime(uintTime uint64) time.Time { return time.UnixMilli(int64(uintTime)) }