1
0
mirror of https://gitee.com/willfree/mlsr.git synced 2026-06-15 18:44:53 +08:00
Files
mlsr/route/RoutingTable.go
T
2022-07-07 15:49:47 +08:00

375 lines
10 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"
"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 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.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
}