mirror of
https://gitee.com/willfree/mlsr.git
synced 2026-06-15 18:44:53 +08:00
375 lines
10 KiB
Go
375 lines
10 KiB
Go
// Package route
|
||
// @Author: Wang Feng
|
||
// @Description:
|
||
// @Version: 0.1.0
|
||
// @Date: 2022/5/9 16:53
|
||
// @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
|
||
//
|
||
|
||
package route
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
common2 "minlib/common"
|
||
"minlib/component"
|
||
"minlib/encoding"
|
||
"mlsr/common"
|
||
"mlsr/extensions"
|
||
"mlsr/lsa"
|
||
"mlsr/lsdb"
|
||
"mlsr/utils"
|
||
"strconv"
|
||
"time"
|
||
)
|
||
|
||
type RoutingTable struct {
|
||
// lsa存储库
|
||
lsdb *lsdb.Lsdb
|
||
// 配置参数
|
||
mlsrConfig *common.MlsrConfig
|
||
// 任务调度器
|
||
scheduler *lsdb.MlsrScheduler
|
||
|
||
// 路由条目列表
|
||
rTable []*RoutingTableEntry
|
||
// 路由计算间隔时间
|
||
m_routingCalcInterval time.Duration
|
||
// 路由表是否正在计算
|
||
m_isRoutingTableCalculating bool
|
||
// 是否已经安排了路由计算
|
||
m_isRouteCalculationScheduled bool
|
||
// 当前路由器的邻接LSA是否存在
|
||
m_ownAdjLsaExist bool
|
||
|
||
// 通知路由表更改的信号
|
||
AfterRoutingChange *utils.Signal
|
||
// 监听Lsdb被修改的信号接收器
|
||
m_afterLsdbModified *utils.Connection
|
||
|
||
// 双曲坐标状态 => 暂时用不到
|
||
m_hyperbolicState uint32
|
||
}
|
||
|
||
//
|
||
// PrintSelf
|
||
// @Description: 打印状态,用于测试
|
||
// @receiver t
|
||
//
|
||
func (t *RoutingTable) PrintSelf() {
|
||
fmt.Println("----------- Routing Table begin ---------")
|
||
fmt.Println("len: " + strconv.Itoa(len(t.rTable)))
|
||
for i := 0; i < len(t.rTable); i++ {
|
||
fmt.Println(t.rTable[i].ToString())
|
||
}
|
||
fmt.Println("路由计算间隔: " + t.m_routingCalcInterval.String())
|
||
fmt.Println("是否正在计算: " + strconv.FormatBool(t.m_isRoutingTableCalculating))
|
||
fmt.Println("是否安排计算: " + strconv.FormatBool(t.m_isRouteCalculationScheduled))
|
||
fmt.Println("本机路由器邻接lsa存在状态: ", t.m_ownAdjLsaExist)
|
||
fmt.Println("----------- Routing Table end ---------")
|
||
}
|
||
|
||
//
|
||
// Init
|
||
// @Description: 初始化
|
||
// @receiver t
|
||
// @param mc
|
||
// @param ms
|
||
// @param mlsdb
|
||
//
|
||
func (t *RoutingTable) Init(mc *common.MlsrConfig,
|
||
ms *lsdb.MlsrScheduler, mlsdb *lsdb.Lsdb) {
|
||
// 初始化任务调度器
|
||
t.scheduler = ms
|
||
// 初始化配置项
|
||
t.mlsrConfig = mc
|
||
// 初始化lsdb
|
||
t.lsdb = mlsdb
|
||
|
||
// 路由计算间隔时间
|
||
t.m_routingCalcInterval = mc.GetRoutingCalcInterval()
|
||
// 路由计算状态
|
||
t.m_isRoutingTableCalculating = false
|
||
t.m_isRouteCalculationScheduled = false
|
||
|
||
// 初始化信号
|
||
t.AfterRoutingChange = utils.NewSignal()
|
||
|
||
bindFunc := func(args ...interface{}) {
|
||
// 获取四个参数
|
||
ilsa := args[0].(lsa.ILsa)
|
||
updateType := args[1].(lsdb.LsdbUpdate)
|
||
common2.LogInfo("RoutingTable.bindFunc: ",
|
||
ilsa.GetOriginRouter().ToUri(), " ", updateType)
|
||
//var namesToAdd []*component.Identifier
|
||
//var namesToRemove []*component.Identifier
|
||
//if updateType == lsdb.REMOVED {
|
||
// namesToAdd = args[2].([]*component.Identifier)
|
||
// namesToRemove = args[3].([]*component.Identifier)
|
||
//}
|
||
|
||
// 根据四个参数做进一步的信息获取
|
||
lsaType := ilsa.GetType()
|
||
updateForOwnAdjacencyLsa := false
|
||
if ilsa.GetOriginRouter().ToUri() == t.mlsrConfig.GetRouterPrefix().ToUri() &&
|
||
lsaType == lsa.LsaADJACENCYType {
|
||
updateForOwnAdjacencyLsa = true
|
||
}
|
||
|
||
// 事件监听:如果监听到了传来的删除本地邻接LSA操作
|
||
if updateType == lsdb.REMOVED && updateForOwnAdjacencyLsa {
|
||
// 如果删除了自己的邻接LSA,那么我们就没有活动邻居。
|
||
//(永远不会删除自身坐标LSA。但路由表计算在HelloProtocol中安排。HR的路由表计算器会考虑链路的非活动状态)
|
||
common2.LogDebug("No Adj LSA of router itself, routing table can not be calculated :(")
|
||
t.clearRoutingTable()
|
||
common2.LogDebug("Calling Update NPT With new Route")
|
||
// todo 触发改变 AfterRoutingChange(m_rTable);
|
||
t.AfterRoutingChange.Emit(t.rTable)
|
||
t.m_ownAdjLsaExist = false
|
||
}
|
||
|
||
// 事件监听:如果监听到了传来的安装本地邻接LSA操作
|
||
if updateType == lsdb.INSTALLED && updateForOwnAdjacencyLsa {
|
||
t.m_ownAdjLsaExist = true
|
||
}
|
||
|
||
scheduleCalculation := false
|
||
|
||
// 事件监听:如果监听到了传来的安装或更新本地邻接LSA操作
|
||
// 不要在移除时做任何事情,等待Hello协议去确认,然后做出响应
|
||
if updateType == lsdb.INSTALLED || updateType == lsdb.UPDATED {
|
||
if lsaType == lsa.LsaADJACENCYType {
|
||
scheduleCalculation = true
|
||
}
|
||
}
|
||
|
||
if scheduleCalculation {
|
||
common2.LogInfo("Is Schedule RoutingTable Calculation...")
|
||
err := t.ScheduleRoutingTableCalculation()
|
||
if err != nil {
|
||
common2.LogError("RoutingTable.Init ScheduleRoutingTableCalculation error.")
|
||
}
|
||
}
|
||
}
|
||
|
||
t.m_afterLsdbModified = t.lsdb.OnLsdbModified.Connect(bindFunc)
|
||
}
|
||
|
||
//
|
||
// Calculate
|
||
// @Description: 计算网络中每个路由器的下一个跃点列表。
|
||
// @receiver t
|
||
//
|
||
func (t *RoutingTable) Calculate() {
|
||
if !t.m_isRoutingTableCalculating {
|
||
// 先将状态改为正在做路由计算
|
||
t.m_isRoutingTableCalculating = true
|
||
|
||
// 做邻接路由计算
|
||
t.calculateLsRoutingTable()
|
||
|
||
// 恢复到可以被安排做路由计算的状态
|
||
t.m_isRouteCalculationScheduled = false
|
||
t.m_isRoutingTableCalculating = false
|
||
} else {
|
||
// 安排指定时间之后执行一个路由计算
|
||
err := t.ScheduleRoutingTableCalculation()
|
||
if err != nil {
|
||
common2.LogError("Calculate error,Schedule RoutingTableCalculation error, ", err)
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// AddNextHop
|
||
// @Description: 向路由表条目添加下一个跃点。
|
||
// @receiver t
|
||
// @param destRouter 要修改其RTE的目标路由器。
|
||
// @param hop 要添加到RTE的下一个跃点。
|
||
//
|
||
func (t *RoutingTable) AddNextHop(destRouter *component.Identifier, hop *NextHop) {
|
||
common2.LogInfo("Adding " + hop.LogicFaceUri() + " for destination " + destRouter.ToUri())
|
||
|
||
// 查找路由表项
|
||
rte := t.FindRoutingTableEntry(destRouter)
|
||
// 如果没有这条表项,则构建并加入
|
||
if rte == nil {
|
||
rte = new(RoutingTableEntry)
|
||
rte.SetDestination(destRouter)
|
||
rte.AddNextHop(hop)
|
||
t.rTable = append(t.rTable, rte)
|
||
} else {
|
||
// 如果有,则直接编辑该条目,增加一个下一跳.
|
||
rte.AddNextHop(hop)
|
||
}
|
||
}
|
||
|
||
//
|
||
// FindRoutingTableEntry
|
||
// @Description: 根据某个目的路由器,查找对应的路由表项
|
||
// @receiver t
|
||
// @param destRouter
|
||
// @return *RoutingTableEntry
|
||
//
|
||
func (t *RoutingTable) FindRoutingTableEntry(destRouter *component.Identifier) *RoutingTableEntry {
|
||
uri := destRouter.ToUri()
|
||
for i := 0; i < len(t.rTable); i++ {
|
||
if t.rTable[i].GetDestination().ToUri() == uri {
|
||
return t.rTable[i]
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
//
|
||
// ScheduleRoutingTableCalculation
|
||
// @Description: 仅当尚未计划计算事件时,才在事件计划程序中计划计算事件。
|
||
// @receiver t
|
||
//
|
||
func (t *RoutingTable) ScheduleRoutingTableCalculation() error {
|
||
if !t.m_isRouteCalculationScheduled {
|
||
common2.LogInfo("Scheduling routing table calculation in ", t.m_routingCalcInterval)
|
||
job, err := t.scheduler.ScheduleTaskAfterDuration(t.m_routingCalcInterval, 1).Do(t.Calculate)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
job.LimitRunsTo(1)
|
||
t.scheduler.StartAsync()
|
||
t.m_isRouteCalculationScheduled = true
|
||
}
|
||
return nil
|
||
}
|
||
|
||
//
|
||
// calculateLsRoutingTable
|
||
// @Description: 计算链路状态路由表。
|
||
// @receiver t
|
||
//
|
||
func (t *RoutingTable) calculateLsRoutingTable() {
|
||
if t.lsdb.GetIsBuildAdjLsaScheduled() {
|
||
common2.LogError("Adjacency build is scheduled, routing table can not be calculated :(")
|
||
return
|
||
}
|
||
|
||
// 我们只在LS中检查这一点,因为我们从不移除自己的坐标LSA。而如果没有任何邻居,则移除自己的邻接LSA
|
||
if !t.m_ownAdjLsaExist {
|
||
return
|
||
}
|
||
|
||
t.clearRoutingTable()
|
||
|
||
// 构造路由映射表
|
||
lsas, err := t.lsdb.GetLSAsByType(lsa.LsaADJACENCYType)
|
||
if err != nil {
|
||
common2.LogError("Get Lsa in calculateLsRoutingTable error, ", err)
|
||
}
|
||
rMap := new(RouterMap)
|
||
rMap.Init()
|
||
err = rMap.CreateFromAdjLsdb(lsas)
|
||
if err != nil {
|
||
common2.LogError("create RouterMap from lsdb error in calculateLsRoutingTable error, ", err)
|
||
}
|
||
|
||
nRouters := rMap.GetMapSize()
|
||
|
||
// 构造路由计算器
|
||
calculator := new(LinkStateRoutingTableCalculator)
|
||
calculator.SetRouterNum(nRouters)
|
||
// 使用计算器去计算路由
|
||
routers, nexthops, err := calculator.CalculatePath(rMap, t.mlsrConfig, t.lsdb)
|
||
if err != nil {
|
||
common2.LogError("CalculatePath in calculateLsRoutingTable error, ", err)
|
||
}
|
||
// 将路由计算结果依次加入路由表
|
||
for i := 0; i < len(routers); i++ {
|
||
t.AddNextHop(routers[i], nexthops[i])
|
||
}
|
||
|
||
// 开始根据新计算的路由去更新NPT表
|
||
common2.LogInfo("Calling Update NPT With new Route")
|
||
t.AfterRoutingChange.Emit(t.rTable)
|
||
}
|
||
|
||
//
|
||
// clearRoutingTable
|
||
// @Description: 清空路由表
|
||
// @receiver t
|
||
//
|
||
func (t *RoutingTable) clearRoutingTable() {
|
||
t.rTable = []*RoutingTableEntry{}
|
||
}
|
||
|
||
//
|
||
// WireEncode
|
||
// @Description: 线速编码
|
||
// @receiver l
|
||
// @param encoder
|
||
// @return int
|
||
// @return error
|
||
//
|
||
func (t *RoutingTable) WireEncode(encoder *encoding.Encoder) (int, error) {
|
||
// 判断列表长度,为0则抛出错误
|
||
if len(t.rTable) == 0 {
|
||
return 0, errors.New("Invalid RoutingTable, expect at least one RoutingTableEntry!")
|
||
}
|
||
totalLength := 0
|
||
// 编码 TLV-VALUE
|
||
// 反向遍历,可以保证解码的时候正向输出
|
||
for i := len(t.rTable) - 1; i >= 0; i-- {
|
||
if t.rTable[i] == nil {
|
||
continue
|
||
}
|
||
tmpLen, err := t.rTable[i].WireEncode(encoder)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
totalLength += tmpLen
|
||
}
|
||
|
||
// 编码 TLV-LENGTH
|
||
tmpLen, err := encoder.PrependVarNumber(encoding.VlInt(totalLength))
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
totalLength += tmpLen
|
||
|
||
// 编码 TLV-TYPE
|
||
tmpLen, err = encoder.PrependVarNumber(extensions.TlvMlsrRoutingTable)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
totalLength += tmpLen
|
||
|
||
return totalLength, nil
|
||
}
|
||
|
||
//
|
||
// WireDecode
|
||
// @Description: 线速解码
|
||
// @receiver l
|
||
// @param block
|
||
// @return error
|
||
//
|
||
func (t *RoutingTable) WireDecode(block *encoding.Block) error {
|
||
// 检查 TLV-TYPE 是否正确
|
||
if err := encoding.ExpectType(block.GetType(), extensions.TlvMlsrRoutingTable); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 解析子 TLV
|
||
if err := block.ParseSubElements(); err != nil {
|
||
return err
|
||
}
|
||
tableEntries := make([]*RoutingTableEntry, len(block.GetSubElements()))
|
||
for index, element := range block.GetSubElements() {
|
||
var tableEntry RoutingTableEntry
|
||
err := tableEntry.WireDecode(element)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
tableEntries[index] = &tableEntry
|
||
}
|
||
t.rTable = tableEntries
|
||
return nil
|
||
}
|