mirror of
https://gitee.com/willfree/mlsr.git
synced 2026-06-15 19:24:47 +08:00
309 lines
11 KiB
Go
309 lines
11 KiB
Go
// Package route
|
|
// @Author: Wang Feng
|
|
// @Description:
|
|
// @Version: 0.1.0
|
|
// @Date: 2022/6/10 11:16
|
|
// @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
|
|
//
|
|
|
|
package route
|
|
|
|
import (
|
|
common2 "minlib/common"
|
|
"minlib/component"
|
|
"mlsr/lsa"
|
|
"mlsr/lsdb"
|
|
)
|
|
|
|
//
|
|
// NamePrefixTable
|
|
// @Description: 名称前缀表
|
|
//
|
|
type NamePrefixTable struct {
|
|
// 路由表池:存储“目的路由器标识URI->RTPE”的映射
|
|
// 相当于存储了所有拥有前缀的路由表项,并包含每个路由表项对应的前缀列表信息,以及该前缀列表长度useCount
|
|
m_rtpool map[string]*RoutingTablePoolEntry
|
|
// 名称前缀表项列表
|
|
nptEntryList []*NamePrefixTableEntry
|
|
// 该名称前缀表所属的本机路由器标识
|
|
m_ownRouterName *component.Identifier
|
|
// 路由表。包含路由计算器计算出来的每个路由表标识及其对应的下一跳列表
|
|
m_routingTable *RoutingTable
|
|
// todo fib
|
|
}
|
|
|
|
//
|
|
// 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())
|
|
// todo 更新fib m_fib.update(name, npte->getNexthopList());
|
|
} else {
|
|
// 如果没有下一跳
|
|
// 路由表可以重新计算并添加一个没有下一跳的路由表条目,以替换现有的路由表条目。
|
|
// 在这种情况下,通过下一个跃点无法再访问名称前缀,应将其从FIB中删除。
|
|
// 但是,前缀应该保留在名称前缀表中,因为未来的路由表计算可能会添加下一跳。
|
|
common2.LogDebug(npte.GetNamePrefix().ToUri() + " has no next hops; removing from FIB")
|
|
// todo 更新fib m_fib.remove(name);
|
|
}
|
|
} 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())
|
|
// todo 更新fib m_fib.update(name, npte->getNexthopList());
|
|
} else {
|
|
common2.LogDebug(t.nptEntryList[nameIndex].GetNamePrefix().ToUri() +
|
|
" has no next hops; removing from FIB")
|
|
// todo 更新fib m_fib.remove(name);
|
|
}
|
|
}
|
|
|
|
// 将此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)
|
|
// todo 删除fib中的该name m_fib.remove(name);
|
|
} else {
|
|
common2.LogDebug(name.ToUri() + " has other routing table entries;" +
|
|
" updating FIB with next hops")
|
|
t.nptEntryList[nameIndex].GenerateNhlfromRteList()
|
|
// todo 更新fib m_fib.update(name, (*nameItr)->getNexthopList());
|
|
}
|
|
} else {
|
|
common2.LogDebug("Attempted to remove origin: " + rtpe.GetDestination().ToUri() +
|
|
" from non-existent prefix: " + name.ToUri())
|
|
}
|
|
}
|
|
|
|
//
|
|
// UpdateWithNewRoute
|
|
// @Description: 接收假定为详尽的条目列表,并使用条目中相应条目中包含的下一跳信息更新每个池条目。
|
|
// 如果找不到条目,则假定该池条目的目标不可访问,其下一跳信息将被删除。
|
|
// @receiver t
|
|
// @param entries
|
|
//
|
|
func (t *NamePrefixTable) UpdateWithNewRoute(entries []*RoutingTableEntry) {
|
|
|
|
}
|
|
|
|
//
|
|
// AddRtpeToPool
|
|
// @Description: 将RoutingTablePoolEntry添加到NPT的本地池。
|
|
// 在C++版实现中,返回值将使用共享指针,因为它消除了处理生命周期问题的复杂hacks,并简化了内存管理。
|
|
// @receiver t
|
|
// @param rtpe
|
|
// @return *RoutingTablePoolEntry
|
|
//
|
|
func (t *NamePrefixTable) AddRtpeToPool(rtpe *RoutingTablePoolEntry) *RoutingTablePoolEntry {
|
|
|
|
}
|
|
|
|
//
|
|
// DeleteRtpeFromPool
|
|
// @Description: 从池中删除池项。
|
|
// @receiver t
|
|
// @param rtpe
|
|
//
|
|
func (t *NamePrefixTable) DeleteRtpeFromPool(rtpe *RoutingTablePoolEntry) {
|
|
|
|
}
|