1
0
mirror of https://gitee.com/willfree/mlsr.git synced 2026-06-05 19:59:27 +08:00
Files
mlsr/lsdb/Lsdb.go
T

430 lines
12 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()
// 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
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通知路由更新
// 安装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: 处理兴趣包。类似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) 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.GetSeqNo() >= seqNo {
return false
}
return true
}
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 lsa == 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("Removing LSA: ", lsa.ToString())
}
func (l *Lsdb) RemoveLsaByContainerIndex(index int) {
}
//
// BuildAdjLsa
// @Description: 构建一个邻接LSA
// 只有当路由器的所有邻居状态是已知的时,才可以构建它的邻接LSA。
// @receiver l
//
func (l *Lsdb) BuildAdjLsa() {
}
//
// BuildAndInstallOwnAdjLsa
// @Description: 为当前路由器构建并安装一个邻接LSA
// @receiver l
//
func (l *Lsdb) BuildAndInstallOwnAdjLsa() {
}
//
// ScheduleLsaExpiration
// @Description: 在调度器中安排一个刷新或过期事件
// @receiver l
//
func (l *Lsdb) ScheduleLsaExpiration(lsa lsa.ILsa, duration time.Duration) {
// 安排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)
}
}
}
}
func (l *Lsdb) ProcessInterestForLsa(interest *packet.Interest,
originRouterIdentifier *component.Identifier, lsaType lsa.LsaType, seqNo uint64) {
}
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))
}