1
0
mirror of https://gitee.com/willfree/mlsr.git synced 2026-06-13 15:38:36 +08:00
Files
mlsr/route/NamePrefixTable.go
2022-09-18 23:02:04 +08:00

494 lines
17 KiB
Go

// Package route
// @Author: Wang Feng
// @Description:
// @Version: 0.1.0
// @Date: 2022/6/10 11:16
// @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
//
package route
import (
"fmt"
common2 "minlib/common"
"minlib/component"
"mlsr/lsa"
"mlsr/lsdb"
"mlsr/utils"
"strconv"
)
//
// NamePrefixTable
// @Description: 名称前缀表
//
type NamePrefixTable struct {
// 路由表池:存储“目的路由器标识URI->RTPE”的映射
// 相当于存储了所有拥有前缀的路由表项,并包含每个路由表项对应的前缀列表信息,以及该前缀列表长度useCount
m_rtpool map[string]*RoutingTablePoolEntry
// 名称前缀表项列表
nptEntryList []*NamePrefixTableEntry
// 该名称前缀表所属的本机路由器标识
m_ownRouterName *component.Identifier
// 路由表。包含路由计算器计算出来的每个路由表标识及其对应的下一跳列表
m_routingTable *RoutingTable
// 信号接收器
m_afterRoutingChangeConnection *utils.SignalConnection
m_afterLsdbModified *utils.SignalConnection
// FIB FIB表交互结构体
m_fib *Fib
}
//
// PrintSelf
// @Description: 打印名称前缀表的状态。用于测试。
// @receiver t
//
func (t *NamePrefixTable) PrintSelf() {
fmt.Println("------------------- Name Prefix Table begin: " + t.m_ownRouterName.ToUri() + " -----------------")
fmt.Println("-----------------" + " 1.路由表项池 begin " + "-----------------")
fmt.Println("路由表项池大小:" + strconv.Itoa(len(t.m_rtpool)))
for _, rtpe := range t.m_rtpool {
fmt.Println(rtpe.ToString())
}
fmt.Println("-----------------" + " 1.路由表项池 end " + "-----------------")
fmt.Println("----------------" + " 2.名称前缀列表 start " + "----------------")
fmt.Println("名称前缀列表大小:" + strconv.Itoa(len(t.nptEntryList)))
for i := 0; i < len(t.nptEntryList); i++ {
fmt.Println(t.nptEntryList[i].ToString())
}
fmt.Println("----------------" + " 2.名称前缀列表 end " + "----------------")
t.m_routingTable.PrintSelf()
fmt.Println("------------------- Name Prefix Table end: " + t.m_ownRouterName.ToUri() + " -----------------")
}
//
// Init
// @Description: 名称前缀表初始化
// @receiver t
// @param ownRouterName
// @param routingTable
// @param afterRoutingChangeSignal
// @param afterLsdbModifiedSignal
//
func (t *NamePrefixTable) Init(ownRouterName *component.Identifier,
routingTable *RoutingTable, afterRoutingChangeSignal *utils.Signal,
afterLsdbModifiedSignal *utils.Signal, fib *Fib) {
// 初始化数据结构
t.m_rtpool = make(map[string]*RoutingTablePoolEntry)
// 赋值变量
t.m_ownRouterName = ownRouterName
t.m_routingTable = routingTable
t.m_fib = fib
// 监听路由表的修改,触发NPT表修改
bindRoutingChangeFunc := func(args ...interface{}) {
common2.LogInfo("NamePrefixTable bindRoutingChangeFunc.")
entrys, ok := args[0].([]*RoutingTableEntry)
if !ok || entrys == nil {
common2.LogError("NamePrefixTable Invalid Entry")
return
}
t.UpdateWithNewRoute(entrys)
}
t.m_afterRoutingChangeConnection = afterRoutingChangeSignal.Connect(bindRoutingChangeFunc)
// 监听LSDB修改,触发NPT表修改
bindLsdbModifiedFunc := func(args ...interface{}) {
common2.LogInfo("NamePrefixTable bindLsdbModifiedFunc.")
// 获取四个参数
ilsa := args[0].(lsa.ILsa)
if ilsa == nil {
common2.LogError("Invalid lsa")
return
}
updateType := args[1].(lsdb.LsdbUpdate)
common2.LogInfo("NamePrefixTable bindLsdbModifiedFunc lsa: ", ilsa.GetOriginRouter().ToUri())
common2.LogInfo("NamePrefixTable bindLsdbModifiedFunc updateType: ", updateType)
namesToAdd := []*component.Identifier{}
namesToRemove := []*component.Identifier{}
if updateType == lsdb.UPDATED {
namesToAdd, ok := args[2].([]*component.Identifier)
if !ok || namesToAdd == nil {
common2.LogError("Invalid namesToAdd")
return
}
namesToRemove, ok = args[3].([]*component.Identifier)
if !ok || namesToRemove == nil {
common2.LogError("Invalid namesToRemove")
return
}
}
// 执行更新操作
t.UpdateFromLsdb(ilsa, updateType, namesToAdd, namesToRemove)
}
t.m_afterLsdbModified = afterLsdbModifiedSignal.Connect(bindLsdbModifiedFunc)
}
//
// UpdateFromLsdb
// @Description: 根据lsdb的更新,对名称进行增加、更新或移除
// @receiver t
// @param lsa
// @param updateType
// @param namesToAdd
// @param namesToRemove
//
func (t *NamePrefixTable) UpdateFromLsdb(ilsa lsa.ILsa,
updateType lsdb.LsdbUpdate, namesToAdd []*component.Identifier,
namesToRemove []*component.Identifier) {
// 如果是本地Lsa的增删更操作,则不做响应
if ilsa.GetOriginRouter().ToUri() == t.m_ownRouterName.ToUri() {
return
}
common2.LogInfo("Got update from Lsdb for router: ", ilsa.GetOriginRouter().ToUri())
// lsa安装操作
if updateType == lsdb.INSTALLED {
// 先增加对该路由器标识的条目
t.AddEntry(ilsa.GetOriginRouter(), ilsa.GetOriginRouter())
// 只针对名称LSA进行更新
if ilsa.GetType() == lsa.LsaNAMEType {
// 获取该lsa中的名称前缀列表
nlsa := ilsa.(*lsa.NameLsa)
names := nlsa.GetNamePrefixes()
// 遍历所有名称前缀,将其添加到名称前缀表中
for i := 0; i < len(names); i++ {
if names[i].ToUri() != t.m_ownRouterName.ToUri() {
t.AddEntry(names[i], ilsa.GetOriginRouter())
}
}
}
} else if updateType == lsdb.UPDATED {
// lsa更新操作(增加、删除)
if ilsa.GetType() == lsa.LsaNAMEType {
// 增加
for i := 0; i < len(namesToAdd); i++ {
if namesToAdd[i].ToUri() != t.m_ownRouterName.ToUri() {
t.AddEntry(namesToAdd[i], ilsa.GetOriginRouter())
}
}
// 删除
for i := 0; i < len(namesToRemove); i++ {
if namesToRemove[i].ToUri() != t.m_ownRouterName.ToUri() {
t.RemoveEntry(namesToRemove[i], ilsa.GetOriginRouter())
}
}
}
} else {
// 既不是安装,又不是更新(增加或删除lsa的某些部分) => 那就是删除整个LSA
t.RemoveEntry(ilsa.GetOriginRouter(), ilsa.GetOriginRouter())
if ilsa.GetType() == lsa.LsaNAMEType {
// 获取该lsa中的名称前缀列表
nlsa := ilsa.(*lsa.NameLsa)
names := nlsa.GetNamePrefixes()
// 遍历所有名称前缀,将其添加到名称前缀表中
for i := 0; i < len(names); i++ {
if names[i].ToUri() != t.m_ownRouterName.ToUri() {
t.RemoveEntry(names[i], ilsa.GetOriginRouter())
}
}
}
}
}
//
// findNamePrefix
// @Description: 查找名称前缀
// @receiver t
// @param name
// @return int 返回-1时表示没有查找到
//
func (t *NamePrefixTable) findNamePrefix(name *component.Identifier) int {
for i := 0; i < len(t.nptEntryList); i++ {
if t.nptEntryList[i].GetNamePrefix().ToUri() == name.ToUri() {
return i
}
}
return -1
}
//
// deleteNamePrefix
// @Description: 根据名称前缀的索引坐标,删除指定名称前缀
// @receiver t
// @param nameIndex
//
func (t *NamePrefixTable) deleteNamePrefix(nameIndex int) {
var newList []*NamePrefixTableEntry
for i := 0; i < len(t.nptEntryList); i++ {
if i != nameIndex {
newList = append(newList, t.nptEntryList[i])
}
}
t.nptEntryList = newList
}
//
// AddEntry
// @Description: 此方法将路由器添加到名称前缀表条目中。如果名称前缀表条目不存在,则会创建它。
// 该方法将首先查看其缓存项的本地池,以找到destRouter的路由信息。
// 如果在那里找不到,它将构造一个,并用路由表中适当的RoutingTable条目中的信息填充它。
// 如果没有匹配项,它将实例化它,但没有下一跳。FIB也将收到NPT条目变更的通知。
// @receiver t
// @param name
// @param destRouter
//
func (t *NamePrefixTable) AddEntry(name *component.Identifier, destRouter *component.Identifier) {
// 检查播发的名称前缀是否已在表中。
nameIndex := t.findNamePrefix(name)
// 查找目的路由器标识是否在路由表项缓存池中
v, ok := t.m_rtpool[destRouter.ToUri()]
// 如果池中没有该目的路由器的路由表项,也即找不到去到name的路由路径,就加一个缓存池项
if !ok {
// 查看路由表,看是否有包含该目的路由器的条目
rte := t.m_routingTable.FindRoutingTableEntry(destRouter)
// 如果路由表里也没有,那我们在缓存里加一个新的条目(虽然没路径)
rtpe := new(RoutingTablePoolEntry)
if rte == nil {
rtpe.InitDest(destRouter, 0)
} else {
// 有的话,直接从路由器中取出该条目,放入缓存池
rtpe.InitRTE(rte, 0)
}
// 放入缓存池,并将v刷新为该缓存池项
v = t.AddRtpeToPool(rtpe)
}
// 更新npt项,并通知给fib
if nameIndex < 0 {
// 如果NPT中没有该name
common2.LogDebug("Adding origin: " + v.GetDestination().ToUri() +
" to a new name prefix: " + name.ToUri())
// 构造名称前缀表项,并添加之
npte := new(NamePrefixTableEntry)
npte.m_namePrefix = name
npte.AddRoutingTableEntry(v) // useCount在这个时候会+1
npte.GenerateNhlfromRteList()
t.nptEntryList = append(t.nptEntryList, npte)
nameIndex = t.findNamePrefix(name)
// 如果这个条目有下一跳,我们需要通知FIB
if len(npte.GetNextHops()) > 0 {
common2.LogDebug("Updating FIB with next hops for ", npte.GetNamePrefix().ToUri())
// 更新fib
// m_fib.update(name, npte->getNexthopList());
err := t.m_fib.Update(name, npte.GetNexthopList())
if err != nil {
common2.LogError(err.Error())
}
} else {
// 如果没有下一跳
// 路由表可以重新计算并添加一个没有下一跳的路由表条目,以替换现有的路由表条目。
// 在这种情况下,通过下一个跃点无法再访问名称前缀,应将其从FIB中删除。
// 但是,前缀应该保留在名称前缀表中,因为未来的路由表计算可能会添加下一跳。
common2.LogDebug(npte.GetNamePrefix().ToUri() + " has no next hops; removing from FIB")
// 更新fib
// m_fib.remove(name);
if err := t.m_fib.Remove(name); err != nil {
common2.LogError(err.Error())
}
}
} else {
// 如果NPT有这个name
common2.LogDebug("Adding origin: " + v.GetDestination().ToUri() +
" to existing prefix: " + name.ToUri())
// 更新之
t.nptEntryList[nameIndex].AddRoutingTableEntry(v) // useCount在这个时候会+1
t.nptEntryList[nameIndex].GenerateNhlfromRteList()
// FIB通知
if len(t.nptEntryList[nameIndex].GetNextHops()) > 0 {
common2.LogDebug("Updating FIB with next hops for ",
t.nptEntryList[nameIndex].GetNamePrefix().ToUri())
// 更新fib
//m_fib.update(name, npte->getNexthopList());
if err := t.m_fib.Update(name, t.nptEntryList[nameIndex].GetNexthopList()); err != nil {
common2.LogError(err.Error())
}
} else {
common2.LogDebug(t.nptEntryList[nameIndex].GetNamePrefix().ToUri() +
" has no next hops; removing from FIB")
// 更新fib
//m_fib.remove(name);
if err := t.m_fib.Remove(name); err != nil {
common2.LogError(err.Error())
}
}
}
// 将此NPT的引用添加到RTPE中。
v.NamePrefixTableEntries[t.nptEntryList[nameIndex].GetNamePrefix().ToUri()] = t.nptEntryList[nameIndex]
}
//
// RemoveEntry
// @Description: 此方法从条目中删除目标。如果传递了无效的“名称-目标”对,也不会失败。
// 删除后,如果RoutingTablePoolEntry的使用计数为0,则会将其从表中删除。
// 此外,如果名称前缀没有与之关联的路由表条目,则会将其从NPT中删除。
// 在任何情况下,FIB都会被告知这些变化。
// @receiver t
// @param name
// @param destRouter
//
func (t *NamePrefixTable) RemoveEntry(name *component.Identifier, destRouter *component.Identifier) {
common2.LogDebug("Removing origin: " + destRouter.ToUri() + " from " + name.ToUri())
// 根据目的路由器标识,获取其在路由条目缓存池中的条目
rtpe, ok := t.m_rtpool[destRouter.ToUri()]
if !ok {
// 如果没有找到,则不进行后续处理
common2.LogDebug("No entry for origin: " + destRouter.ToUri() +
" found, so it cannot be removed from prefix: " + name.ToUri())
return
}
// 查找名称前缀
nameIndex := t.findNamePrefix(name)
if nameIndex >= 0 {
common2.LogDebug("Removing origin: " + rtpe.GetDestination().ToUri() +
" from prefix: " + name.ToUri())
// 判断该缓存表项在被删除一个与某前缀的关联之后,其使用数是否为零,如果是,则删除该引用。
useCount := t.nptEntryList[nameIndex].RemoveRoutingTableEntry(rtpe)
if useCount == 0 {
t.DeleteRtpeFromPool(rtpe)
}
// 1 如果前缀是路由器前缀,并且没有任何其他路由表条目,则已从LSDB中删除与该原始路由器关联的邻接/坐标LSA,
// 因此应从名称前缀表中删除路由器前缀。
// 2 如果前缀是播发的名称前缀:如果另一个路由器播发此名称前缀,
// 则RteList应具有该路由器的另一个条目;下一个跃点应重新计算并安装在FIB中。
// 3 如果没有其他路由器播发此名称前缀,则RteList应为空,并且可以从名称前缀表中删除前缀。
// 一旦新名称LSA播发此前缀,将创建前缀的新条目。
if t.nptEntryList[nameIndex].GetRteListSize() == 0 {
common2.LogDebug(name.ToUri() + " has no routing table entries;" +
" removing from table and FIB")
t.deleteNamePrefix(nameIndex)
// 删除fib中的该name
//m_fib.remove(name);
if err := t.m_fib.Remove(name); err != nil {
common2.LogError(err.Error())
}
} else {
common2.LogDebug(name.ToUri() + " has other routing table entries;" +
" updating FIB with next hops")
t.nptEntryList[nameIndex].GenerateNhlfromRteList()
// 更新fib
//m_fib.update(name, (*nameItr)->getNexthopList());
if err := t.m_fib.Update(name, t.nptEntryList[nameIndex].GetNexthopList()); err != nil {
common2.LogError(err.Error())
}
}
} else {
common2.LogDebug("Attempted to remove origin: " + rtpe.GetDestination().ToUri() +
" from non-existent prefix: " + name.ToUri())
}
}
//
// isNextHopsEqual
// @Description: 遍历查看两个下一跳列表是否完全一致
// @param hops1
// @param hops2
// @return bool
//
func isNextHopsEqual(hops1 []*NextHop, hops2 []*NextHop) bool {
// 长度不等,则false
if len(hops1) != len(hops2) {
return false
}
// 遍历,如果有一个不相等,则false
for i := 0; i < len(hops1); i++ {
if hops1[i].LogicFaceUri() != hops2[i].LogicFaceUri() ||
hops1[i].RouteCost.Cost() != hops2[i].RouteCost.Cost() {
return false
}
}
return true
}
//
// UpdateWithNewRoute
// @Description: 接收假定为详尽的条目列表,并使用条目中相应条目中包含的下一跳信息更新每个池条目。
// 如果找不到条目,则假定该池条目的目标不可访问,其下一跳信息将被删除。
// @receiver t
// @param entries
//
func (t *NamePrefixTable) UpdateWithNewRoute(entries []*RoutingTableEntry) {
common2.LogDebug("Updating table with newly calculated routes")
// 遍历名称前缀表中的路由表缓存池
for _, rtpe := range t.m_rtpool {
// 查看当前缓存表项的目的路由器,是否在传入的真路由表项里可以找到对应的
sameIndex := -1 // 默认没找到
for i := 0; i < len(entries); i++ {
if entries[i].GetDestination().ToUri() == rtpe.GetDestination().ToUri() {
sameIndex = i
}
}
// 根据缓存池与原路由表项的差异,将缓存池更新
if sameIndex >= 0 && !isNextHopsEqual(rtpe.GetNextHops(), entries[sameIndex].GetNextHops()) {
// 如果找到了对应条目,且两个路由表条目的下一跳列表不一致
common2.LogDebug("Routing entry: " + rtpe.GetDestination().ToUri() + " has changed next-hops.")
// 更新rtpe的下一跳列表
rtpe.SetNexthopList(entries[sameIndex].NextHopList)
// 更新rtpe的每个名称前缀表项
for _, nameEntry := range rtpe.NamePrefixTableEntries {
t.AddEntry(nameEntry.GetNamePrefix(), rtpe.GetDestination())
}
} else if sameIndex < 0 {
// 没有找到对应条目,说明到该路由器的路径已经无了无了无了~
common2.LogDebug("Routing entry: " + rtpe.GetDestination().ToUri() + " now has no next-hops.")
// 更新rtpe的下一跳列表:清空
rtpe.Clear()
// 更新rtpe的每个名称前缀表项
for _, nameEntry := range rtpe.NamePrefixTableEntries {
t.AddEntry(nameEntry.GetNamePrefix(), rtpe.GetDestination())
}
} else {
// 有找到对应条目,但是两个条目的下一跳列表完全一致
common2.LogDebug("No change in routing entry:" + rtpe.GetDestination().ToUri() +
", no action necessary.")
}
}
}
//
// AddRtpeToPool
// @Description: 将RoutingTablePoolEntry添加到NPT的本地池。
// 在C++版实现中,返回值将使用共享指针,因为它消除了处理生命周期问题的复杂hacks,并简化了内存管理。
// @receiver t
// @param rtpe
// @return *RoutingTablePoolEntry
//
func (t *NamePrefixTable) AddRtpeToPool(rtpe *RoutingTablePoolEntry) *RoutingTablePoolEntry {
t.m_rtpool[rtpe.GetDestination().ToUri()] = rtpe
return rtpe
}
//
// DeleteRtpeFromPool
// @Description: 从池中删除池项。
// @receiver t
// @param rtpe
//
func (t *NamePrefixTable) DeleteRtpeFromPool(rtpe *RoutingTablePoolEntry) {
// 查看是否有该条目
_, ok := t.m_rtpool[rtpe.GetDestination().ToUri()]
if !ok {
common2.LogDebug("Attempted to delete non-existent origin: " +
rtpe.GetDestination().ToUri() + " from NPT routing table entry storage pool.")
}
delete(t.m_rtpool, rtpe.GetDestination().ToUri())
}