forked from scionproto/scion
/
map.go
148 lines (130 loc) · 3.82 KB
/
map.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2017 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 base contains the tables for remote SIGs, ASes and their prefixes
package base
import (
"sync"
log "github.com/inconshreveable/log15"
"github.com/scionproto/scion/go/lib/addr"
"github.com/scionproto/scion/go/lib/common"
"github.com/scionproto/scion/go/sig/config"
)
var Map = newASMap()
// ASMap is not concurrency safe against multiple writers.
type ASMap sync.Map
func newASMap() *ASMap {
return &ASMap{}
}
func (am *ASMap) Delete(key addr.IAInt) {
(*sync.Map)(am).Delete(key)
}
func (am *ASMap) Load(key addr.IAInt) (*ASEntry, bool) {
value, ok := (*sync.Map)(am).Load(key)
if value == nil {
return nil, ok
}
return value.(*ASEntry), ok
}
func (am *ASMap) LoadOrStore(key addr.IAInt, value *ASEntry) (*ASEntry, bool) {
actual, ok := (*sync.Map)(am).LoadOrStore(key, value)
if actual == nil {
return nil, ok
}
return actual.(*ASEntry), ok
}
func (am *ASMap) Store(key addr.IAInt, value *ASEntry) {
(*sync.Map)(am).Store(key, value)
}
func (am *ASMap) Range(f func(key addr.IAInt, value *ASEntry) bool) {
(*sync.Map)(am).Range(func(key, value interface{}) bool {
return f(key.(addr.IAInt), value.(*ASEntry))
})
}
func (am *ASMap) ReloadConfig(cfg *config.Cfg) bool {
// Method calls first to prevent skips due to logical short-circuit
s := am.addNewIAs(cfg)
return am.delOldIAs(cfg) && s
}
// addNewIAs adds the ASes in cfg that are not currently configured.
func (am *ASMap) addNewIAs(cfg *config.Cfg) bool {
s := true
for iaVal, cfgEntry := range cfg.ASes {
ia := iaVal.Copy()
log.Info("ReloadConfig: Adding AS...", "ia", ia)
ae, err := am.AddIA(ia)
if err != nil {
log.Error("ReloadConfig: Adding AS failed", "err", err)
s = false
continue
}
s = ae.ReloadConfig(cfgEntry) && s
log.Info("ReloadConfig: Added AS", "ia", ia)
}
return s
}
func (am *ASMap) delOldIAs(cfg *config.Cfg) bool {
s := true
// Delete all ASes that currently exist but are not in cfg
am.Range(func(iaInt addr.IAInt, as *ASEntry) bool {
ia := iaInt.IA()
if _, ok := cfg.ASes[*ia]; !ok {
log.Info("ReloadConfig: Deleting AS...", "ia", ia)
// Deletion also handles session/tun device cleanup
err := am.DelIA(ia)
if err != nil {
log.Error("ReloadConfig: Deleting AS failed", "err", err)
s = false
return true
}
log.Info("ReloadConfig: Deleted AS", "ia", ia)
}
return true
})
return s
}
// AddIA idempotently adds an entry for a remote IA.
func (am *ASMap) AddIA(ia *addr.ISD_AS) (*ASEntry, error) {
if ia.I == 0 || ia.A == 0 {
// A 0 for either ISD or AS indicates a wildcard, and not a specific ISD-AS.
return nil, common.NewBasicError("AddIA: ISD and AS must not be 0", nil, "ia", ia)
}
key := ia.IAInt()
ae, ok := am.Load(key)
if ok {
return ae, nil
}
ae, err := newASEntry(ia)
if err != nil {
return nil, err
}
am.Store(key, ae)
return ae, nil
}
// DelIA removes an entry for a remote IA.
func (am *ASMap) DelIA(ia *addr.ISD_AS) error {
key := ia.IAInt()
ae, ok := am.Load(key)
if !ok {
return common.NewBasicError("DelIA: No entry found", nil, "ia", ia)
}
am.Delete(key)
return ae.Cleanup()
}
// ASEntry returns the entry for the specified remote IA, or nil if not present.
func (am *ASMap) ASEntry(ia *addr.ISD_AS) *ASEntry {
if as, ok := am.Load(ia.IAInt()); ok {
return as
}
return nil
}