~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/network/network.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2014 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package network
 
5
 
 
6
import (
 
7
        "bufio"
 
8
        "fmt"
 
9
        "net"
 
10
        "os"
 
11
        "regexp"
 
12
        "sort"
 
13
        "strings"
 
14
 
 
15
        "github.com/juju/errors"
 
16
        "github.com/juju/loggo"
 
17
        "github.com/juju/utils/set"
 
18
)
 
19
 
 
20
var logger = loggo.GetLogger("juju.network")
 
21
 
 
22
// SpaceInvalidChars is a regexp for validating that space names contain no
 
23
// invalid characters.
 
24
var SpaceInvalidChars = regexp.MustCompile("[^0-9a-z-]")
 
25
 
 
26
// noAddress represents an error when an address is requested but not available.
 
27
type noAddress struct {
 
28
        errors.Err
 
29
}
 
30
 
 
31
// NoAddressError returns an error which satisfies IsNoAddressError(). The given
 
32
// addressKind specifies what kind of address is missing, usually "private" or
 
33
// "public".
 
34
func NoAddressError(addressKind string) error {
 
35
        newErr := errors.NewErr("no %s address", addressKind)
 
36
        newErr.SetLocation(1)
 
37
        return &noAddress{newErr}
 
38
}
 
39
 
 
40
// IsNoAddressError reports whether err was created with NoAddressError().
 
41
func IsNoAddressError(err error) bool {
 
42
        err = errors.Cause(err)
 
43
        _, ok := err.(*noAddress)
 
44
        return ok
 
45
}
 
46
 
 
47
// Id defines a provider-specific network id.
 
48
type Id string
 
49
 
 
50
// AnySubnet when passed as a subnet id should be interpreted by the
 
51
// providers as "the subnet id does not matter". It's up to the
 
52
// provider how to handle this case - it might return an error.
 
53
const AnySubnet Id = ""
 
54
 
 
55
// UnknownId can be used whenever an Id is needed but not known.
 
56
const UnknownId = ""
 
57
 
 
58
// DefaultLXDBridge is the bridge that gets used for LXD containers
 
59
const DefaultLXDBridge = "lxdbr0"
 
60
 
 
61
var dashPrefix = regexp.MustCompile("^-*")
 
62
var dashSuffix = regexp.MustCompile("-*$")
 
63
var multipleDashes = regexp.MustCompile("--+")
 
64
 
 
65
// ConvertSpaceName converts names between provider space names and valid juju
 
66
// space names.
 
67
// TODO(mfoord): once MAAS space name rules are in sync with juju space name
 
68
// rules this can go away.
 
69
func ConvertSpaceName(name string, existing set.Strings) string {
 
70
        // First lower case and replace spaces with dashes.
 
71
        name = strings.Replace(name, " ", "-", -1)
 
72
        name = strings.ToLower(name)
 
73
        // Replace any character that isn't in the set "-", "a-z", "0-9".
 
74
        name = SpaceInvalidChars.ReplaceAllString(name, "")
 
75
        // Get rid of any dashes at the start as that isn't valid.
 
76
        name = dashPrefix.ReplaceAllString(name, "")
 
77
        // And any at the end.
 
78
        name = dashSuffix.ReplaceAllString(name, "")
 
79
        // Repleace multiple dashes with a single dash.
 
80
        name = multipleDashes.ReplaceAllString(name, "-")
 
81
        // Special case of when the space name was only dashes or invalid
 
82
        // characters!
 
83
        if name == "" {
 
84
                name = "empty"
 
85
        }
 
86
        // If this name is in use add a numerical suffix.
 
87
        if existing.Contains(name) {
 
88
                counter := 2
 
89
                for existing.Contains(name + fmt.Sprintf("-%d", counter)) {
 
90
                        counter += 1
 
91
                }
 
92
                name = name + fmt.Sprintf("-%d", counter)
 
93
        }
 
94
        return name
 
95
}
 
96
 
 
97
// SubnetInfo describes the bare minimum information for a subnet,
 
98
// which the provider knows about but juju might not yet.
 
99
type SubnetInfo struct {
 
100
        // CIDR of the network, in 123.45.67.89/24 format. Can be empty if
 
101
        // unknown.
 
102
        CIDR string
 
103
 
 
104
        // ProviderId is a provider-specific network id. This the only
 
105
        // required field.
 
106
        ProviderId Id
 
107
 
 
108
        // VLANTag needs to be between 1 and 4094 for VLANs and 0 for
 
109
        // normal networks. It's defined by IEEE 802.1Q standard, and used
 
110
        // to define a VLAN network. For more information, see:
 
111
        // http://en.wikipedia.org/wiki/IEEE_802.1Q.
 
112
        VLANTag int
 
113
 
 
114
        // AvailabilityZones describes which availability zone(s) this
 
115
        // subnet is in. It can be empty if the provider does not support
 
116
        // availability zones.
 
117
        AvailabilityZones []string
 
118
 
 
119
        // SpaceProviderId holds the provider Id of the space associated with
 
120
        // this subnet. Can be empty if not supported.
 
121
        SpaceProviderId Id
 
122
}
 
123
 
 
124
type SpaceInfo struct {
 
125
        Name       string
 
126
        ProviderId Id
 
127
        Subnets    []SubnetInfo
 
128
}
 
129
type BySpaceName []SpaceInfo
 
130
 
 
131
func (s BySpaceName) Len() int      { return len(s) }
 
132
func (s BySpaceName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 
133
func (s BySpaceName) Less(i, j int) bool {
 
134
        return s[i].Name < s[j].Name
 
135
}
 
136
 
 
137
// InterfaceConfigType defines valid network interface configuration
 
138
// types. See interfaces(5) for details
 
139
type InterfaceConfigType string
 
140
 
 
141
const (
 
142
        ConfigUnknown  InterfaceConfigType = ""
 
143
        ConfigDHCP     InterfaceConfigType = "dhcp"
 
144
        ConfigStatic   InterfaceConfigType = "static"
 
145
        ConfigManual   InterfaceConfigType = "manual"
 
146
        ConfigLoopback InterfaceConfigType = "loopback"
 
147
)
 
148
 
 
149
// InterfaceType defines valid network interface types.
 
150
type InterfaceType string
 
151
 
 
152
const (
 
153
        UnknownInterface    InterfaceType = ""
 
154
        LoopbackInterface   InterfaceType = "loopback"
 
155
        EthernetInterface   InterfaceType = "ethernet"
 
156
        VLAN_8021QInterface InterfaceType = "802.1q"
 
157
        BondInterface       InterfaceType = "bond"
 
158
        BridgeInterface     InterfaceType = "bridge"
 
159
)
 
160
 
 
161
// InterfaceInfo describes a single network interface available on an
 
162
// instance. For providers that support networks, this will be
 
163
// available at StartInstance() time.
 
164
// TODO(mue): Rename to InterfaceConfig due to consistency later.
 
165
type InterfaceInfo struct {
 
166
        // DeviceIndex specifies the order in which the network interface
 
167
        // appears on the host. The primary interface has an index of 0.
 
168
        DeviceIndex int
 
169
 
 
170
        // MACAddress is the network interface's hardware MAC address
 
171
        // (e.g. "aa:bb:cc:dd:ee:ff").
 
172
        MACAddress string
 
173
 
 
174
        // CIDR of the network, in 123.45.67.89/24 format.
 
175
        CIDR string
 
176
 
 
177
        // ProviderId is a provider-specific NIC id.
 
178
        ProviderId Id
 
179
 
 
180
        // ProviderSubnetId is the provider-specific id for the associated
 
181
        // subnet.
 
182
        ProviderSubnetId Id
 
183
 
 
184
        // ProviderSpaceId is the provider-specific id for the associated space, if
 
185
        // known and supported.
 
186
        ProviderSpaceId Id
 
187
 
 
188
        // ProviderVLANId is the provider-specific id of the VLAN for this
 
189
        // interface.
 
190
        ProviderVLANId Id
 
191
 
 
192
        // ProviderAddressId is the provider-specific id of the assigned address.
 
193
        ProviderAddressId Id
 
194
 
 
195
        // AvailabilityZones describes the availability zones the associated
 
196
        // subnet is in.
 
197
        AvailabilityZones []string
 
198
 
 
199
        // VLANTag needs to be between 1 and 4094 for VLANs and 0 for
 
200
        // normal networks. It's defined by IEEE 802.1Q standard.
 
201
        VLANTag int
 
202
 
 
203
        // InterfaceName is the raw OS-specific network device name (e.g.
 
204
        // "eth1", even for a VLAN eth1.42 virtual interface).
 
205
        InterfaceName string
 
206
 
 
207
        // ParentInterfaceName is the name of the parent interface to use, if known.
 
208
        ParentInterfaceName string
 
209
 
 
210
        // InterfaceType is the type of the interface.
 
211
        InterfaceType InterfaceType
 
212
 
 
213
        // Disabled is true when the interface needs to be disabled on the
 
214
        // machine, e.g. not to configure it.
 
215
        Disabled bool
 
216
 
 
217
        // NoAutoStart is true when the interface should not be configured
 
218
        // to start automatically on boot. By default and for
 
219
        // backwards-compatibility, interfaces are configured to
 
220
        // auto-start.
 
221
        NoAutoStart bool
 
222
 
 
223
        // ConfigType determines whether the interface should be
 
224
        // configured via DHCP, statically, manually, etc. See
 
225
        // interfaces(5) for more information.
 
226
        ConfigType InterfaceConfigType
 
227
 
 
228
        // Address contains an optional static IP address to configure for
 
229
        // this network interface. The subnet mask to set will be inferred
 
230
        // from the CIDR value.
 
231
        Address Address
 
232
 
 
233
        // DNSServers contains an optional list of IP addresses and/or
 
234
        // hostnames to configure as DNS servers for this network
 
235
        // interface.
 
236
        DNSServers []Address
 
237
 
 
238
        // MTU is the Maximum Transmission Unit controlling the maximum size of the
 
239
        // protocol packats that the interface can pass through. It is only used
 
240
        // when > 0.
 
241
        MTU int
 
242
 
 
243
        // DNSSearchDomains contains the default DNS domain to use for non-FQDN
 
244
        // lookups.
 
245
        DNSSearchDomains []string
 
246
 
 
247
        // Gateway address, if set, defines the default gateway to
 
248
        // configure for this network interface. For containers this
 
249
        // usually is (one of) the host address(es).
 
250
        GatewayAddress Address
 
251
}
 
252
 
 
253
type interfaceInfoSlice []InterfaceInfo
 
254
 
 
255
func (s interfaceInfoSlice) Len() int      { return len(s) }
 
256
func (s interfaceInfoSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 
257
func (s interfaceInfoSlice) Less(i, j int) bool {
 
258
        iface1 := s[i]
 
259
        iface2 := s[j]
 
260
        return iface1.DeviceIndex < iface2.DeviceIndex
 
261
}
 
262
 
 
263
// SortInterfaceInfo sorts a slice of InterfaceInfo on DeviceIndex in ascending
 
264
// order.
 
265
func SortInterfaceInfo(interfaces []InterfaceInfo) {
 
266
        sort.Sort(interfaceInfoSlice(interfaces))
 
267
}
 
268
 
 
269
// ActualInterfaceName returns raw interface name for raw interface (e.g. "eth0") and
 
270
// virtual interface name for virtual interface (e.g. "eth0.42")
 
271
func (i *InterfaceInfo) ActualInterfaceName() string {
 
272
        if i.VLANTag > 0 {
 
273
                return fmt.Sprintf("%s.%d", i.InterfaceName, i.VLANTag)
 
274
        }
 
275
        return i.InterfaceName
 
276
}
 
277
 
 
278
// IsVirtual returns true when the interface is a virtual device, as
 
279
// opposed to a physical device (e.g. a VLAN or a network alias)
 
280
func (i *InterfaceInfo) IsVirtual() bool {
 
281
        return i.VLANTag > 0
 
282
}
 
283
 
 
284
// IsVLAN returns true when the interface is a VLAN interface.
 
285
func (i *InterfaceInfo) IsVLAN() bool {
 
286
        return i.VLANTag > 0
 
287
}
 
288
 
 
289
// CIDRAddress returns Address.Value combined with CIDR mask.
 
290
func (i *InterfaceInfo) CIDRAddress() string {
 
291
        if i.CIDR == "" || i.Address.Value == "" {
 
292
                return ""
 
293
        }
 
294
        _, ipNet, err := net.ParseCIDR(i.CIDR)
 
295
        if err != nil {
 
296
                return errors.Trace(err).Error()
 
297
        }
 
298
        ip := net.ParseIP(i.Address.Value)
 
299
        if ip == nil {
 
300
                return errors.Errorf("cannot parse IP address %q", i.Address.Value).Error()
 
301
        }
 
302
        ipNet.IP = ip
 
303
        return ipNet.String()
 
304
}
 
305
 
 
306
// LXCNetDefaultConfig is the location of the default network config
 
307
// of the lxc package. It's exported to allow cross-package testing.
 
308
var LXCNetDefaultConfig = "/etc/default/lxc-net"
 
309
 
 
310
// InterfaceByNameAddrs returns the addresses for the given interface
 
311
// name. It's exported to facilitate cross-package testing.
 
312
var InterfaceByNameAddrs = func(name string) ([]net.Addr, error) {
 
313
        iface, err := net.InterfaceByName(name)
 
314
        if err != nil {
 
315
                return nil, err
 
316
        }
 
317
        return iface.Addrs()
 
318
}
 
319
 
 
320
// filterAddrs looks at all of the addresses in allAddresses and removes ones
 
321
// that line up with removeAddresses. Note that net.Addr may be just an IP or
 
322
// may be a CIDR.
 
323
func filterAddrs(bridgeName string, allAddresses []Address, removeAddresses []net.Addr) []Address {
 
324
        filtered := make([]Address, 0, len(allAddresses))
 
325
        // TODO(jam) ips could be turned into a map[string]bool rather than
 
326
        // iterating over all of them, as we only compare against ip.String()
 
327
        ips := make([]net.IP, 0, len(removeAddresses))
 
328
        ipNets := make([]*net.IPNet, 0, len(removeAddresses))
 
329
        for _, ifaceAddr := range removeAddresses {
 
330
                // First check if this is a CIDR, as
 
331
                // net.InterfaceAddrs might return this instead of
 
332
                // a plain IP.
 
333
                ip, ipNet, err := net.ParseCIDR(ifaceAddr.String())
 
334
                if err != nil {
 
335
                        // It's not a CIDR, try parsing as IP.
 
336
                        ip = net.ParseIP(ifaceAddr.String())
 
337
                }
 
338
                if ip == nil {
 
339
                        logger.Debugf("cannot parse %q as IP, ignoring", ifaceAddr)
 
340
                        continue
 
341
                }
 
342
                ips = append(ips, ip)
 
343
                if ipNet != nil {
 
344
                        ipNets = append(ipNets, ipNet)
 
345
                }
 
346
        }
 
347
        for _, addr := range allAddresses {
 
348
                found := false
 
349
                // Filter all known IPs
 
350
                for _, ip := range ips {
 
351
                        if ip.String() == addr.Value {
 
352
                                found = true
 
353
                                break
 
354
                        }
 
355
                }
 
356
                if !found {
 
357
                        // Then check if it is in one of the CIDRs
 
358
                        for _, ipNet := range ipNets {
 
359
                                if ipNet.Contains(net.ParseIP(addr.Value)) {
 
360
                                        found = true
 
361
                                        break
 
362
                                }
 
363
                        }
 
364
                }
 
365
                if found {
 
366
                        logger.Debugf("filtering %q address %s for machine", bridgeName, addr.String())
 
367
                } else {
 
368
                        logger.Debugf("not filtering address %s for machine", addr)
 
369
                        filtered = append(filtered, addr)
 
370
                }
 
371
        }
 
372
        logger.Debugf("addresses after filtering: %v", filtered)
 
373
        return filtered
 
374
}
 
375
 
 
376
// filterLXCAddresses tries to discover the default lxc bridge name
 
377
// and all of its addresses, then filters those addresses out of the
 
378
// given ones and returns the result. Any errors encountered during
 
379
// this process are logged, but not considered fatal. See LP bug
 
380
// #1416928.
 
381
func filterLXCAddresses(addresses []Address) []Address {
 
382
        file, err := os.Open(LXCNetDefaultConfig)
 
383
        if os.IsNotExist(err) {
 
384
                // No lxc-net config found, nothing to do.
 
385
                logger.Debugf("no lxc bridge addresses to filter for machine")
 
386
                return addresses
 
387
        } else if err != nil {
 
388
                // Just log it, as it's not fatal.
 
389
                logger.Errorf("cannot open %q: %v", LXCNetDefaultConfig, err)
 
390
                return addresses
 
391
        }
 
392
        defer file.Close()
 
393
 
 
394
        scanner := bufio.NewScanner(file)
 
395
        for scanner.Scan() {
 
396
                line := strings.TrimSpace(scanner.Text())
 
397
                switch {
 
398
                case strings.HasPrefix(line, "#"):
 
399
                        // Skip comments.
 
400
                case strings.HasPrefix(line, "LXC_BRIDGE"):
 
401
                        // Extract <name> from LXC_BRIDGE="<name>".
 
402
                        parts := strings.Split(line, `"`)
 
403
                        if len(parts) < 2 {
 
404
                                logger.Debugf("ignoring invalid line '%s' in %q", line, LXCNetDefaultConfig)
 
405
                                continue
 
406
                        }
 
407
                        bridgeName := strings.TrimSpace(parts[1])
 
408
                        // Discover all addresses of bridgeName interface.
 
409
                        addrs, err := InterfaceByNameAddrs(bridgeName)
 
410
                        if err != nil {
 
411
                                logger.Debugf("cannot get %q addresses: %v (ignoring)", bridgeName, err)
 
412
                                continue
 
413
                        }
 
414
                        logger.Debugf("%q has addresses %v", bridgeName, addrs)
 
415
                        return filterAddrs(bridgeName, addresses, addrs)
 
416
                }
 
417
        }
 
418
        if err := scanner.Err(); err != nil {
 
419
                logger.Debugf("failed to read %q: %v (ignoring)", LXCNetDefaultConfig, err)
 
420
        }
 
421
        return addresses
 
422
}
 
423
 
 
424
// filterLXDAddresses removes addresses on the LXD bridge from the list to be
 
425
// considered.
 
426
func filterLXDAddresses(addresses []Address) []Address {
 
427
        // Should we be getting this from LXD instead?
 
428
        addrs, err := InterfaceByNameAddrs(DefaultLXDBridge)
 
429
        if err != nil {
 
430
                logger.Warningf("cannot get %q addresses: %v (ignoring)", DefaultLXDBridge, err)
 
431
                return addresses
 
432
        }
 
433
        logger.Debugf("%q has addresses %v", DefaultLXDBridge, addrs)
 
434
        return filterAddrs(DefaultLXDBridge, addresses, addrs)
 
435
 
 
436
}
 
437
 
 
438
// FilterBridgeAddresses removes addresses seen as a Bridge address (the IP
 
439
// address used only to connect to local containers), rather than a remote
 
440
// accessible address.
 
441
func FilterBridgeAddresses(addresses []Address) []Address {
 
442
        addresses = filterLXCAddresses(addresses)
 
443
        addresses = filterLXDAddresses(addresses)
 
444
        return addresses
 
445
}