1
0
mirror of https://gitee.com/willfree/mlsr.git synced 2026-06-09 19:09:35 +08:00
Files
mlsr/route/RoutingTable.go
T

264 lines
6.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package route
// @Author: Wang Feng
// @Description:
// @Version: 0.1.0
// @Date: 2022/5/9 16:53
// @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
//
package route
import (
"errors"
common2 "minlib/common"
"minlib/component"
"minlib/encoding"
"mlsr/common"
"mlsr/extensions"
"mlsr/lsa"
"mlsr/lsdb"
"mlsr/route/Calculator"
"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
// 双曲坐标状态 => 暂时用不到
m_hyperbolicState uint32
}
func (t *RoutingTable) Init() {
// 初始化任务调度器
t.scheduler = new(lsdb.MlsrScheduler)
t.scheduler.Init()
}
//
// 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.LogFatal("Calculate errorSchedule 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.AddNextHop(hop)
t.rTable = append(t.rTable, rte)
} else {
// 如果有,则直接编辑该条目,增加一个下一跳.
// todo: 这块需要测试,是否在go中可以直接根据引用进行表项的修改
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)
err := t.scheduler.ScheduleTaskAfterDuration(t.m_routingCalcInterval, t.Calculate)
if err != nil {
return err
}
t.m_isRouteCalculationScheduled = true
}
return nil
}
//
// calculateLsRoutingTable
// @Description: 计算链路状态路由表。
// @receiver t
//
func (t *RoutingTable) calculateLsRoutingTable() {
if t.lsdb.GetIsBuildAdjLsaScheduled() {
common2.LogFatal("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.LogFatal("Get Lsa in calculateLsRoutingTable error, ", err)
}
rMap := new(Calculator.RouterMap)
rMap.Init()
err = rMap.CreateFromAdjLsdb(lsas)
if err != nil {
common2.LogFatal("create RouterMap from lsdb error in calculateLsRoutingTable error, ", err)
}
nRouters := rMap.GetMapSize()
// 构造路由计算器
calculator := new(Calculator.LinkStateRoutingTableCalculator)
calculator.SetRouterNum(nRouters)
// 使用计算器去计算路由
err = calculator.CalculatePath(rMap, t, t.mlsrConfig, t.lsdb)
if err != nil {
common2.LogFatal("CalculatePath in calculateLsRoutingTable error, ", err)
}
// todo: 开始根据新计算的路由去更新NPT表
common2.LogInfo("Calling Update NPT With new Route")
//todo
}
//
// 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
}