1
0
mirror of https://github.com/fumiama/WireGold.git synced 2026-06-04 23:40:26 +08:00
Files
WireGold/gold/link/router.go
2024-08-03 15:32:31 +08:00

114 lines
2.5 KiB
Go
Raw Permalink 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 link
import (
"encoding/binary"
"net"
"sync"
"github.com/FloatTech/ttl"
"github.com/sirupsen/logrus"
"github.com/fumiama/WireGold/config"
)
type Router struct {
mu sync.RWMutex
// map[cidr]*Link
table map[string]*Link
list []*net.IPNet
cache *ttl.Cache[string, *Link]
}
// Accept 判断是否应当接受 ip 发来的包
func (l *Link) Accept(ip net.IP) bool {
for _, cidr := range l.allowedips {
if cidr.Contains(ip) {
return true
}
}
return false
}
// IsToMe 判断是否是发给自己的包
func (l *Link) IsToMe(ip net.IP) bool {
return ip.Equal(l.me.me) || ip.Equal(net.IPv4bcast) || isSubnetBcast(ip, &l.me.subnet)
}
// SetDefault 设置默认网关
func (r *Router) SetDefault(l *Link) {
defnet := &net.IPNet{IP: net.IPv4(0, 0, 0, 0), Mask: net.IPv4Mask(0, 0, 0, 0)}
r.mu.Lock()
r.list[len(r.list)-1] = defnet
r.table[defnet.String()] = l
r.mu.Unlock()
}
// NextHop 得到前往 ip 的下一跳的 link
func (r *Router) NextHop(ip string) (l *Link) {
l = r.cache.Get(ip)
if l != nil {
if config.ShowDebugLog {
logrus.Debugln("[router] get cached nexthop to", ip, "link", l)
}
return
}
ipb := net.ParseIP(ip)
if ipb == nil {
logrus.Errorln("[router] nil ip")
return
}
// 遍历 r.table得到正确的下一跳
// 注意使用 r.mu 读写锁避免竞争
r.mu.RLock()
defer r.mu.RUnlock()
for _, c := range r.list {
if c.Contains(ipb) {
l = r.table[c.String()]
if config.ShowDebugLog {
logrus.Debugln("[router] get nexthop to", ipb, "-->", c, "link", l)
}
r.cache.Set(ip, l)
return l
}
}
logrus.Errorln("[router] cannot find nexthop for ip:", ipb)
return
}
// SetItem 添加一条表项
func (r *Router) SetItem(ip *net.IPNet, l *Link) {
r.mu.Lock()
// 从第一条表项开始匹配
for i := 0; i < len(r.list); i++ {
if r.list[i].Contains(ip.IP) {
// 是同一个网络
if ip.Mask.String() == r.list[i].Mask.String() {
logrus.Warnln("[router] change link of item", r.list[i], "from", r.table[r.list[i].String()], "to", l)
r.table[r.list[i].String()] = l
break
}
// 是新网络
r.list = append(r.list, nil)
copy(r.list[i+1:], r.list[i:len(r.list)-1])
r.list[i] = ip
r.table[ip.String()] = l
logrus.Infoln("[router] add route in link", l, ip, "-->", l.peerip)
break
}
}
r.mu.Unlock()
}
func isSubnetBcast(ip net.IP, subnet *net.IPNet) bool {
if !subnet.Contains(ip) {
return false
}
maskr := make(net.IPMask, 4)
binary.LittleEndian.PutUint32(maskr[:], ^binary.LittleEndian.Uint32(subnet.Mask))
return ip.Mask(maskr).Equal(net.IP(maskr))
}