1
0
mirror of https://gitee.com/willfree/mlsr.git synced 2026-06-03 15:56:13 +08:00
Files
mlsr/lsdb/Lsdb.go
T
2022-06-06 16:50:41 +08:00

534 lines
16 KiB
Go

// 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/<network>/nlsr/LSA/<site>/<router>/<lsaType>/<seqNo>
//* 2) 已经包含segment number的兴趣包:
//* /localhop/<network>/nlsr/LSA/<site>/<router>/<lsaType>/<seqNo>/<version>/<segmentNo>
// @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的基础兴趣包格式为:
// /<network>/NLSR/LSA/<site>/%C1.Router/<router>/<lsa-type>/<seqNo>
// @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))
}