forked from cloudfoundry/bosh-agent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
interface_configuration_creator.go
225 lines (190 loc) · 7.36 KB
/
interface_configuration_creator.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
package net
import (
"net"
boshsettings "github.com/cloudfoundry/bosh-agent/settings"
bosherr "github.com/cloudfoundry/bosh-utils/errors"
boshlog "github.com/cloudfoundry/bosh-utils/logger"
boshsys "github.com/cloudfoundry/bosh-utils/system"
)
type StaticInterfaceConfiguration struct {
Name string
Address string
Netmask string
Network string
Broadcast string
IsDefaultForGateway bool
Mac string
Gateway string
PostUpRoutes boshsettings.Routes
}
func (c StaticInterfaceConfiguration) Version6() string {
if c.IsVersion6() {
return "6"
}
return ""
}
func (c StaticInterfaceConfiguration) IsVersion6() bool {
return len(c.Network) == 0 && len(c.Broadcast) == 0
}
func (c StaticInterfaceConfiguration) CIDR() (string, error) {
return boshsettings.NetmaskToCIDR(c.Netmask, c.IsVersion6())
}
type StaticInterfaceConfigurations []StaticInterfaceConfiguration
func (configs StaticInterfaceConfigurations) Len() int {
return len(configs)
}
func (configs StaticInterfaceConfigurations) Less(i, j int) bool {
return configs[i].Name < configs[j].Name
}
func (configs StaticInterfaceConfigurations) Swap(i, j int) {
configs[i], configs[j] = configs[j], configs[i]
}
func (configs StaticInterfaceConfigurations) HasVersion6() bool {
for _, config := range configs {
if config.IsVersion6() {
return true
}
}
return false
}
type DHCPInterfaceConfiguration struct {
Name string
PostUpRoutes boshsettings.Routes
Address string
}
func (c DHCPInterfaceConfiguration) Version6() string {
if c.IsVersion6() {
return "6"
}
return ""
}
func (c DHCPInterfaceConfiguration) IsVersion6() bool {
ip := net.ParseIP(c.Address)
if ip == nil || ip.To4() != nil {
return false
}
return true
}
type DHCPInterfaceConfigurations []DHCPInterfaceConfiguration
func (configs DHCPInterfaceConfigurations) Len() int {
return len(configs)
}
func (configs DHCPInterfaceConfigurations) Less(i, j int) bool {
return configs[i].Name < configs[j].Name
}
func (configs DHCPInterfaceConfigurations) Swap(i, j int) {
configs[i], configs[j] = configs[j], configs[i]
}
func (configs DHCPInterfaceConfigurations) HasVersion6() bool {
for _, config := range configs {
if len(config.Version6()) > 0 {
return true
}
}
return false
}
type InterfaceConfigurationCreator interface {
CreateInterfaceConfigurations(boshsettings.Networks, map[string]string) ([]StaticInterfaceConfiguration, []DHCPInterfaceConfiguration, error)
}
type interfaceConfigurationCreator struct {
logger boshlog.Logger
logTag string
}
func NewInterfaceConfigurationCreator(logger boshlog.Logger) InterfaceConfigurationCreator {
return interfaceConfigurationCreator{
logger: logger,
logTag: "interfaceConfigurationCreator",
}
}
func (creator interfaceConfigurationCreator) createInterfaceConfiguration(staticConfigs []StaticInterfaceConfiguration, dhcpConfigs []DHCPInterfaceConfiguration, ifaceName string, networkSettings boshsettings.Network) ([]StaticInterfaceConfiguration, []DHCPInterfaceConfiguration, error) {
creator.logger.Debug(creator.logTag, "Creating network configuration with settings: %s", networkSettings)
if (networkSettings.IsDHCP() || networkSettings.Mac == "") && networkSettings.Alias == "" {
creator.logger.Debug(creator.logTag, "Using dhcp networking")
dhcpConfigs = append(dhcpConfigs, DHCPInterfaceConfiguration{
Name: ifaceName,
PostUpRoutes: networkSettings.Routes,
Address: networkSettings.IP,
})
} else {
creator.logger.Debug(creator.logTag, "Using static networking")
networkAddress, broadcastAddress, _, err := boshsys.CalculateNetworkAndBroadcast(networkSettings.IP, networkSettings.Netmask)
if err != nil {
return nil, nil, bosherr.WrapError(err, "Calculating Network and Broadcast")
}
conf := StaticInterfaceConfiguration{
Name: ifaceName,
Address: networkSettings.IP,
Netmask: networkSettings.Netmask,
Network: networkAddress,
IsDefaultForGateway: networkSettings.IsDefaultFor("gateway"),
Broadcast: broadcastAddress,
Mac: networkSettings.Mac,
Gateway: networkSettings.Gateway,
PostUpRoutes: networkSettings.Routes,
}
staticConfigs = append(staticConfigs, conf)
}
return staticConfigs, dhcpConfigs, nil
}
func (creator interfaceConfigurationCreator) CreateInterfaceConfigurations(networks boshsettings.Networks, interfacesByMAC map[string]string) ([]StaticInterfaceConfiguration, []DHCPInterfaceConfiguration, error) {
// In cases where we only have one network and it has no MAC address (either because the IAAS doesn't give us one or
// it's an old CPI), if we only have one interface, we should map them
if len(networks) == 1 && len(interfacesByMAC) == 1 {
networkSettings := creator.getFirstNetwork(networks)
if networkSettings.Mac == "" {
var ifaceName string
networkSettings.Mac, ifaceName = creator.getFirstInterface(interfacesByMAC)
return creator.createInterfaceConfiguration([]StaticInterfaceConfiguration{}, []DHCPInterfaceConfiguration{}, ifaceName, networkSettings)
}
}
return creator.createMultipleInterfaceConfigurations(networks, interfacesByMAC)
}
func (creator interfaceConfigurationCreator) createMultipleInterfaceConfigurations(networks boshsettings.Networks, interfacesByMAC map[string]string) ([]StaticInterfaceConfiguration, []DHCPInterfaceConfiguration, error) {
if !networks.HasInterfaceAlias() && len(interfacesByMAC) < len(networks) {
return nil, nil, bosherr.Errorf("Number of network settings '%d' is greater than the number of network devices '%d'", len(networks), len(interfacesByMAC))
}
for name := range networks {
if mac := networks[name].Mac; mac != "" {
if _, ok := interfacesByMAC[mac]; !ok {
return nil, nil, bosherr.Errorf("No device found for network '%s' with MAC address '%s'", name, mac)
}
}
}
// Configure interfaces with network settings matching MAC address.
// If we cannot find a network setting with a matching MAC address, configure that interface as DHCP
var networkSettings boshsettings.Network
var err error
staticConfigs := []StaticInterfaceConfiguration{}
dhcpConfigs := []DHCPInterfaceConfiguration{}
for mac, ifaceName := range interfacesByMAC {
networkSettings, _ = networks.NetworkForMac(mac)
staticConfigs, dhcpConfigs, err = creator.createInterfaceConfiguration(staticConfigs, dhcpConfigs, ifaceName, networkSettings)
if err != nil {
return nil, nil, bosherr.WrapError(err, "Creating interface configuration")
}
}
for _, networkSettings = range networks {
if networkSettings.Mac != "" {
continue
}
if networkSettings.Alias != "" {
staticConfigs, dhcpConfigs, err = creator.createInterfaceConfiguration(staticConfigs, dhcpConfigs, networkSettings.Alias, networkSettings)
if err != nil {
return nil, nil, bosherr.WrapError(err, "Creating interface configuration using alias")
}
}
}
return staticConfigs, dhcpConfigs, nil
}
func (creator interfaceConfigurationCreator) getFirstNetwork(networks boshsettings.Networks) boshsettings.Network {
for networkName := range networks {
return networks[networkName]
}
return boshsettings.Network{}
}
func (creator interfaceConfigurationCreator) getFirstInterface(interfacesByMAC map[string]string) (string, string) {
for mac := range interfacesByMAC {
return mac, interfacesByMAC[mac]
}
return "", ""
}