mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-11-24 18:45:21 +00:00
Link cost-aware routing
This commit is contained in:
parent
5ea16e63a1
commit
bfdcf0762f
@ -174,7 +174,7 @@ func run() int {
|
|||||||
if err := json.Unmarshal(recv.Response, &resp); err != nil {
|
if err := json.Unmarshal(recv.Response, &resp); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
table.SetHeader([]string{"URI", "State", "Dir", "IP Address", "Uptime", "RTT", "RX", "TX", "Pr", "Last Error"})
|
table.SetHeader([]string{"URI", "State", "Dir", "IP Address", "Uptime", "RTT", "RX", "TX", "Pr", "Cost", "Last Error"})
|
||||||
for _, peer := range resp.Peers {
|
for _, peer := range resp.Peers {
|
||||||
state, lasterr, dir, rtt := "Up", "-", "Out", "-"
|
state, lasterr, dir, rtt := "Up", "-", "Out", "-"
|
||||||
if !peer.Up {
|
if !peer.Up {
|
||||||
@ -200,6 +200,7 @@ func run() int {
|
|||||||
peer.RXBytes.String(),
|
peer.RXBytes.String(),
|
||||||
peer.TXBytes.String(),
|
peer.TXBytes.String(),
|
||||||
fmt.Sprintf("%d", peer.Priority),
|
fmt.Sprintf("%d", peer.Priority),
|
||||||
|
fmt.Sprintf("%d", peer.Cost),
|
||||||
lasterr,
|
lasterr,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ type PeerEntry struct {
|
|||||||
PublicKey string `json:"key"`
|
PublicKey string `json:"key"`
|
||||||
Port uint64 `json:"port"`
|
Port uint64 `json:"port"`
|
||||||
Priority uint64 `json:"priority"`
|
Priority uint64 `json:"priority"`
|
||||||
|
Cost uint64 `json:"cost"`
|
||||||
RXBytes DataUnit `json:"bytes_recvd,omitempty"`
|
RXBytes DataUnit `json:"bytes_recvd,omitempty"`
|
||||||
TXBytes DataUnit `json:"bytes_sent,omitempty"`
|
TXBytes DataUnit `json:"bytes_sent,omitempty"`
|
||||||
Uptime float64 `json:"uptime,omitempty"`
|
Uptime float64 `json:"uptime,omitempty"`
|
||||||
@ -41,6 +42,7 @@ func (a *AdminSocket) getPeersHandler(_ *GetPeersRequest, res *GetPeersResponse)
|
|||||||
Up: p.Up,
|
Up: p.Up,
|
||||||
Inbound: p.Inbound,
|
Inbound: p.Inbound,
|
||||||
Priority: uint64(p.Priority), // can't be uint8 thanks to gobind
|
Priority: uint64(p.Priority), // can't be uint8 thanks to gobind
|
||||||
|
Cost: uint64(p.Cost), // can't be uint8 thanks to gobind
|
||||||
URI: p.URI,
|
URI: p.URI,
|
||||||
RXBytes: DataUnit(p.RXBytes),
|
RXBytes: DataUnit(p.RXBytes),
|
||||||
TXBytes: DataUnit(p.TXBytes),
|
TXBytes: DataUnit(p.TXBytes),
|
||||||
|
@ -30,6 +30,7 @@ type PeerInfo struct {
|
|||||||
Coords []uint64
|
Coords []uint64
|
||||||
Port uint64
|
Port uint64
|
||||||
Priority uint8
|
Priority uint8
|
||||||
|
Cost uint8
|
||||||
RXBytes uint64
|
RXBytes uint64
|
||||||
TXBytes uint64
|
TXBytes uint64
|
||||||
Uptime time.Duration
|
Uptime time.Duration
|
||||||
@ -94,6 +95,7 @@ func (c *Core) GetPeers() []PeerInfo {
|
|||||||
peerinfo.Port = p.Port
|
peerinfo.Port = p.Port
|
||||||
peerinfo.Priority = p.Priority
|
peerinfo.Priority = p.Priority
|
||||||
peerinfo.Latency = p.Latency
|
peerinfo.Latency = p.Latency
|
||||||
|
peerinfo.Cost = p.Cost
|
||||||
}
|
}
|
||||||
peers = append(peers, peerinfo)
|
peers = append(peers, peerinfo)
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ type link struct {
|
|||||||
type linkOptions struct {
|
type linkOptions struct {
|
||||||
pinnedEd25519Keys map[keyArray]struct{}
|
pinnedEd25519Keys map[keyArray]struct{}
|
||||||
priority uint8
|
priority uint8
|
||||||
|
cost uint8
|
||||||
tlsSNI string
|
tlsSNI string
|
||||||
password []byte
|
password []byte
|
||||||
maxBackoff time.Duration
|
maxBackoff time.Duration
|
||||||
@ -139,6 +140,7 @@ func (e linkError) Error() string { return string(e) }
|
|||||||
const ErrLinkAlreadyConfigured = linkError("peer is already configured")
|
const ErrLinkAlreadyConfigured = linkError("peer is already configured")
|
||||||
const ErrLinkNotConfigured = linkError("peer is not configured")
|
const ErrLinkNotConfigured = linkError("peer is not configured")
|
||||||
const ErrLinkPriorityInvalid = linkError("priority value is invalid")
|
const ErrLinkPriorityInvalid = linkError("priority value is invalid")
|
||||||
|
const ErrLinkCostInvalid = linkError("cost value is invalid")
|
||||||
const ErrLinkPinnedKeyInvalid = linkError("pinned public key is invalid")
|
const ErrLinkPinnedKeyInvalid = linkError("pinned public key is invalid")
|
||||||
const ErrLinkPasswordInvalid = linkError("password is invalid")
|
const ErrLinkPasswordInvalid = linkError("password is invalid")
|
||||||
const ErrLinkUnrecognisedSchema = linkError("link schema unknown")
|
const ErrLinkUnrecognisedSchema = linkError("link schema unknown")
|
||||||
@ -181,6 +183,14 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
|
|||||||
}
|
}
|
||||||
options.priority = uint8(pi)
|
options.priority = uint8(pi)
|
||||||
}
|
}
|
||||||
|
if p := u.Query().Get("cost"); p != "" {
|
||||||
|
c, err := strconv.ParseUint(p, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
retErr = ErrLinkCostInvalid
|
||||||
|
return
|
||||||
|
}
|
||||||
|
options.cost = uint8(c)
|
||||||
|
}
|
||||||
if p := u.Query().Get("password"); p != "" {
|
if p := u.Query().Get("password"); p != "" {
|
||||||
if len(p) > blake2b.Size {
|
if len(p) > blake2b.Size {
|
||||||
retErr = ErrLinkPasswordInvalid
|
retErr = ErrLinkPasswordInvalid
|
||||||
@ -448,6 +458,13 @@ func (l *links) listen(u *url.URL, sintf string) (*Listener, error) {
|
|||||||
}
|
}
|
||||||
options.priority = uint8(pi)
|
options.priority = uint8(pi)
|
||||||
}
|
}
|
||||||
|
if p := u.Query().Get("cost"); p != "" {
|
||||||
|
c, err := strconv.ParseUint(p, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrLinkCostInvalid
|
||||||
|
}
|
||||||
|
options.cost = uint8(c)
|
||||||
|
}
|
||||||
if p := u.Query().Get("password"); p != "" {
|
if p := u.Query().Get("password"); p != "" {
|
||||||
if len(p) > blake2b.Size {
|
if len(p) > blake2b.Size {
|
||||||
return nil, ErrLinkPasswordInvalid
|
return nil, ErrLinkPasswordInvalid
|
||||||
@ -567,6 +584,7 @@ func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, s
|
|||||||
meta := version_getBaseMetadata()
|
meta := version_getBaseMetadata()
|
||||||
meta.publicKey = l.core.public
|
meta.publicKey = l.core.public
|
||||||
meta.priority = options.priority
|
meta.priority = options.priority
|
||||||
|
meta.cost = options.cost
|
||||||
metaBytes, err := meta.encode(l.core.secret, options.password)
|
metaBytes, err := meta.encode(l.core.secret, options.password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to generate handshake: %w", err)
|
return fmt.Errorf("failed to generate handshake: %w", err)
|
||||||
@ -628,17 +646,20 @@ func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, s
|
|||||||
remoteAddr := net.IP(address.AddrForKey(meta.publicKey)[:]).String()
|
remoteAddr := net.IP(address.AddrForKey(meta.publicKey)[:]).String()
|
||||||
remoteStr := fmt.Sprintf("%s@%s", remoteAddr, conn.RemoteAddr())
|
remoteStr := fmt.Sprintf("%s@%s", remoteAddr, conn.RemoteAddr())
|
||||||
localStr := conn.LocalAddr()
|
localStr := conn.LocalAddr()
|
||||||
priority := options.priority
|
cost, priority := options.cost, options.priority
|
||||||
if meta.priority > priority {
|
if meta.priority > priority {
|
||||||
priority = meta.priority
|
priority = meta.priority
|
||||||
}
|
}
|
||||||
|
if meta.cost > cost {
|
||||||
|
cost = meta.cost
|
||||||
|
}
|
||||||
l.core.log.Infof("Connected %s: %s, source %s",
|
l.core.log.Infof("Connected %s: %s, source %s",
|
||||||
dir, remoteStr, localStr)
|
dir, remoteStr, localStr)
|
||||||
if success != nil {
|
if success != nil {
|
||||||
success()
|
success()
|
||||||
}
|
}
|
||||||
|
|
||||||
err = l.core.HandleConn(meta.publicKey, conn, priority)
|
err = l.core.HandleConn(meta.publicKey, conn, cost, priority)
|
||||||
switch err {
|
switch err {
|
||||||
case io.EOF, net.ErrClosed, nil:
|
case io.EOF, net.ErrClosed, nil:
|
||||||
l.core.log.Infof("Disconnected %s: %s, source %s",
|
l.core.log.Infof("Disconnected %s: %s, source %s",
|
||||||
|
@ -22,6 +22,7 @@ type version_metadata struct {
|
|||||||
minorVer uint16
|
minorVer uint16
|
||||||
publicKey ed25519.PublicKey
|
publicKey ed25519.PublicKey
|
||||||
priority uint8
|
priority uint8
|
||||||
|
cost uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -36,6 +37,7 @@ const (
|
|||||||
metaVersionMinor // uint16
|
metaVersionMinor // uint16
|
||||||
metaPublicKey // [32]byte
|
metaPublicKey // [32]byte
|
||||||
metaPriority // uint8
|
metaPriority // uint8
|
||||||
|
metaCost // uint8
|
||||||
)
|
)
|
||||||
|
|
||||||
// Gets a base metadata with no keys set, but with the correct version numbers.
|
// Gets a base metadata with no keys set, but with the correct version numbers.
|
||||||
@ -64,9 +66,17 @@ func (m *version_metadata) encode(privateKey ed25519.PrivateKey, password []byte
|
|||||||
bs = binary.BigEndian.AppendUint16(bs, ed25519.PublicKeySize)
|
bs = binary.BigEndian.AppendUint16(bs, ed25519.PublicKeySize)
|
||||||
bs = append(bs, m.publicKey[:]...)
|
bs = append(bs, m.publicKey[:]...)
|
||||||
|
|
||||||
|
if m.priority > 0 {
|
||||||
bs = binary.BigEndian.AppendUint16(bs, metaPriority)
|
bs = binary.BigEndian.AppendUint16(bs, metaPriority)
|
||||||
bs = binary.BigEndian.AppendUint16(bs, 1)
|
bs = binary.BigEndian.AppendUint16(bs, 1)
|
||||||
bs = append(bs, m.priority)
|
bs = append(bs, m.priority)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.cost > 0 {
|
||||||
|
bs = binary.BigEndian.AppendUint16(bs, metaCost)
|
||||||
|
bs = binary.BigEndian.AppendUint16(bs, 1)
|
||||||
|
bs = append(bs, m.cost)
|
||||||
|
}
|
||||||
|
|
||||||
hasher, err := blake2b.New512(password)
|
hasher, err := blake2b.New512(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -126,6 +136,9 @@ func (m *version_metadata) decode(r io.Reader, password []byte) error {
|
|||||||
|
|
||||||
case metaPriority:
|
case metaPriority:
|
||||||
m.priority = bs[0]
|
m.priority = bs[0]
|
||||||
|
|
||||||
|
case metaCost:
|
||||||
|
m.cost = bs[0]
|
||||||
}
|
}
|
||||||
bs = bs[oplen:]
|
bs = bs[oplen:]
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,9 @@ func TestVersionRoundtrip(t *testing.T) {
|
|||||||
{majorVer: 258, minorVer: 259},
|
{majorVer: 258, minorVer: 259},
|
||||||
{majorVer: 3, minorVer: 5, priority: 6},
|
{majorVer: 3, minorVer: 5, priority: 6},
|
||||||
{majorVer: 260, minorVer: 261, priority: 7},
|
{majorVer: 260, minorVer: 261, priority: 7},
|
||||||
|
{majorVer: 258, minorVer: 259, cost: 5},
|
||||||
|
{majorVer: 3, minorVer: 5, priority: 6, cost: 12},
|
||||||
|
{majorVer: 260, minorVer: 261, priority: 7, cost: 1},
|
||||||
} {
|
} {
|
||||||
// Generate a random public key for each time, since it is
|
// Generate a random public key for each time, since it is
|
||||||
// a required field.
|
// a required field.
|
||||||
|
@ -45,6 +45,7 @@ type interfaceInfo struct {
|
|||||||
listen bool
|
listen bool
|
||||||
port uint16
|
port uint16
|
||||||
priority uint8
|
priority uint8
|
||||||
|
cost uint8
|
||||||
password []byte
|
password []byte
|
||||||
hash []byte
|
hash []byte
|
||||||
}
|
}
|
||||||
@ -214,6 +215,7 @@ func (m *Multicast) _getAllowedInterfaces() map[string]*interfaceInfo {
|
|||||||
listen: ifcfg.Listen,
|
listen: ifcfg.Listen,
|
||||||
port: ifcfg.Port,
|
port: ifcfg.Port,
|
||||||
priority: ifcfg.Priority,
|
priority: ifcfg.Priority,
|
||||||
|
cost: ifcfg.Cost,
|
||||||
password: []byte(ifcfg.Password),
|
password: []byte(ifcfg.Password),
|
||||||
hash: hasher.Sum(nil),
|
hash: hasher.Sum(nil),
|
||||||
}
|
}
|
||||||
@ -314,6 +316,7 @@ func (m *Multicast) _announce() {
|
|||||||
// No listener was found - let's create one
|
// No listener was found - let's create one
|
||||||
v := &url.Values{}
|
v := &url.Values{}
|
||||||
v.Add("priority", fmt.Sprintf("%d", info.priority))
|
v.Add("priority", fmt.Sprintf("%d", info.priority))
|
||||||
|
v.Add("cost", fmt.Sprintf("%d", info.cost))
|
||||||
v.Add("password", string(info.password))
|
v.Add("password", string(info.password))
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "tls",
|
Scheme: "tls",
|
||||||
@ -428,6 +431,7 @@ func (m *Multicast) listen() {
|
|||||||
v := &url.Values{}
|
v := &url.Values{}
|
||||||
v.Add("key", hex.EncodeToString(adv.PublicKey))
|
v.Add("key", hex.EncodeToString(adv.PublicKey))
|
||||||
v.Add("priority", fmt.Sprintf("%d", info.priority))
|
v.Add("priority", fmt.Sprintf("%d", info.priority))
|
||||||
|
v.Add("cost", fmt.Sprintf("%d", info.cost))
|
||||||
v.Add("password", string(info.password))
|
v.Add("password", string(info.password))
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
Scheme: "tls",
|
Scheme: "tls",
|
||||||
|
@ -21,6 +21,7 @@ type MulticastInterface struct {
|
|||||||
Listen bool
|
Listen bool
|
||||||
Port uint16
|
Port uint16
|
||||||
Priority uint8
|
Priority uint8
|
||||||
|
Cost uint8
|
||||||
Password string
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user