forked from scionproto/scion
-
Notifications
You must be signed in to change notification settings - Fork 0
/
router.go
124 lines (110 loc) · 3.43 KB
/
router.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2018 ETH Zurich
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package router implements an IPv4/IPv6 router. The routes map destination
// addresses to ring buffers.
package router
import (
"net"
"sync"
"github.com/scionproto/scion/go/lib/addr"
"github.com/scionproto/scion/go/lib/common"
"github.com/scionproto/scion/go/lib/ringbuf"
)
var NetMap NetMapI = &Networks{}
type NetMapI interface {
Add(*net.IPNet, addr.IA, *ringbuf.Ring) error
Delete(*net.IPNet) error
Lookup(net.IP) (addr.IA, *ringbuf.Ring)
}
// Networks is an unordered mapping of non-overlapping IP allocations to ASes. It is
// concurrency safe. It is intended to be a stand-in until we have a a proper
// mapping type, as the lookup is O(n) for the number of networks it contains.
type Networks struct {
m sync.RWMutex
nets []*network
}
func (ns *Networks) Add(ipnet *net.IPNet, ia addr.IA, ring *ringbuf.Ring) error {
if ia.I == 0 || ia.A == 0 {
return common.NewBasicError("Networks.Add(): Illegal wildcard remote AS", nil, "ia", ia)
}
if ring == nil {
return common.NewBasicError("Networks.Add(): ringBuf.Ring must not be nil", nil, "ia", ia)
}
cnet := newCanonNet(ipnet)
ns.m.Lock()
defer ns.m.Unlock()
newNet := &network{cnet, ia, ring}
for _, exnet := range ns.nets {
if exnet.net.Contains(cnet.IP) || cnet.Contains(exnet.net.IP) {
return common.NewBasicError("Networks.Add(): Networks overlap", nil,
"new", newNet, "existing", exnet)
}
}
ns.nets = append(ns.nets, newNet)
return nil
}
func (ns *Networks) Delete(ipnet *net.IPNet) error {
cnet := newCanonNet(ipnet)
ns.m.Lock()
defer ns.m.Unlock()
idx := ns.getIdxL(cnet)
if idx < 0 {
return common.NewBasicError("Networks.Delete(): IPNet entry not present", nil, "net", ipnet)
}
// Fast delete, as it doesn't preserve order.
// https://github.com/golang/go/wiki/SliceTricks#delete-without-preserving-order
l := len(ns.nets)
ns.nets[idx] = ns.nets[l-1] // Copy last element to index i
ns.nets[l-1] = nil // Zero last element, to allow it to be garbage collected.
ns.nets = ns.nets[:l-1]
return nil
}
func (ns *Networks) Lookup(ip net.IP) (addr.IA, *ringbuf.Ring) {
ns.m.RLock()
defer ns.m.RUnlock()
for _, n := range ns.nets {
if n.net.Contains(ip) {
return n.ia, n.ring
}
}
return addr.IA{}, nil
}
func (ns *Networks) getIdxL(cnet *canonNet) int {
for i, n := range ns.nets {
if n.net.Equal(cnet) {
return i
}
}
return -1
}
type network struct {
net *canonNet
ia addr.IA
ring *ringbuf.Ring
}
// canonNet contains a canonicalized version of net.IPNet, which allows it to
// be tested for equality.
type canonNet struct {
*net.IPNet
}
func newCanonNet(ipnet *net.IPNet) *canonNet {
cn := &canonNet{&net.IPNet{}}
// Canonicalize the IP
cn.IP = ipnet.IP.Mask(ipnet.Mask)
cn.Mask = append([]byte(nil), ipnet.Mask...)
return cn
}
func (cn *canonNet) Equal(other *canonNet) bool {
return cn.Mask.String() == other.Mask.String() && cn.IP.Equal(other.IP)
}