155
type byMACThenCIDRThenIndexThenName []params.NetworkConfig
157
func (c byMACThenCIDRThenIndexThenName) Len() int {
161
func (c byMACThenCIDRThenIndexThenName) Swap(i, j int) {
162
orgI, orgJ := c[i], c[j]
163
c[j], c[i] = orgI, orgJ
166
func (c byMACThenCIDRThenIndexThenName) Less(i, j int) bool {
167
if c[i].MACAddress == c[j].MACAddress {
168
// Same MACAddress means related interfaces.
169
if c[i].CIDR == "" || c[j].CIDR == "" {
170
// Empty CIDRs go at the bottom, otherwise order by InterfaceName.
171
return c[i].CIDR != "" || c[i].InterfaceName < c[j].InterfaceName
173
if c[i].DeviceIndex == c[j].DeviceIndex {
174
if c[i].InterfaceName == c[j].InterfaceName {
175
// Sort addresses of the same interface.
176
return c[i].CIDR < c[j].CIDR || c[i].Address < c[j].Address
178
// Prefer shorter names (e.g. parents) with equal DeviceIndex.
179
return c[i].InterfaceName < c[j].InterfaceName
181
// When both CIDR and DeviceIndex are non-empty, order by DeviceIndex
182
return c[i].DeviceIndex < c[j].DeviceIndex
184
// Group by MACAddress.
185
return c[i].MACAddress < c[j].MACAddress
188
// SortNetworkConfigsByParents returns the given input sorted, such that any
189
// child interfaces appear after their parents.
190
func SortNetworkConfigsByParents(input []params.NetworkConfig) []params.NetworkConfig {
191
sortedInputCopy := CopyNetworkConfigs(input)
192
sort.Stable(byMACThenCIDRThenIndexThenName(sortedInputCopy))
193
return sortedInputCopy
196
type byInterfaceName []params.NetworkConfig
198
func (c byInterfaceName) Len() int {
202
func (c byInterfaceName) Swap(i, j int) {
203
orgI, orgJ := c[i], c[j]
204
c[j], c[i] = orgI, orgJ
207
func (c byInterfaceName) Less(i, j int) bool {
208
return c[i].InterfaceName < c[j].InterfaceName
211
// SortNetworkConfigsByInterfaceName returns the given input sorted by
213
func SortNetworkConfigsByInterfaceName(input []params.NetworkConfig) []params.NetworkConfig {
214
sortedInputCopy := CopyNetworkConfigs(input)
215
sort.Stable(byInterfaceName(sortedInputCopy))
216
return sortedInputCopy
219
// NetworkConfigsToIndentedJSON returns the given input as an indented JSON
221
func NetworkConfigsToIndentedJSON(input []params.NetworkConfig) (string, error) {
222
jsonBytes, err := json.MarshalIndent(input, "", " ")
226
return string(jsonBytes), nil
229
// CopyNetworkConfigs returns a copy of the given input
230
func CopyNetworkConfigs(input []params.NetworkConfig) []params.NetworkConfig {
231
return append([]params.NetworkConfig(nil), input...)
234
151
// NetworkConfigFromInterfaceInfo converts a slice of network.InterfaceInfo into
235
152
// the equivalent params.NetworkConfig slice.
236
153
func NetworkConfigFromInterfaceInfo(interfaceInfos []network.InterfaceInfo) []params.NetworkConfig {
583
500
return config, nil
586
// MergeProviderAndObservedNetworkConfigs returns the effective, sorted, network
587
// configs after merging providerConfig with observedConfig.
588
func MergeProviderAndObservedNetworkConfigs(providerConfigs, observedConfigs []params.NetworkConfig) ([]params.NetworkConfig, error) {
589
providerConfigsByName := make(map[string][]params.NetworkConfig)
590
sortedProviderConfigs := SortNetworkConfigsByParents(providerConfigs)
591
for _, config := range sortedProviderConfigs {
592
name := config.InterfaceName
593
providerConfigsByName[name] = append(providerConfigsByName[name], config)
596
jsonProviderConfig, err := NetworkConfigsToIndentedJSON(sortedProviderConfigs)
598
return nil, errors.Annotatef(err, "cannot serialize provider config %#v as JSON", sortedProviderConfigs)
600
logger.Debugf("provider network config of machine:\n%s", jsonProviderConfig)
602
sortedObservedConfigs := SortNetworkConfigsByParents(observedConfigs)
603
jsonObservedConfig, err := NetworkConfigsToIndentedJSON(sortedObservedConfigs)
605
return nil, errors.Annotatef(err, "cannot serialize observed config %#v as JSON", sortedObservedConfigs)
607
logger.Debugf("observed network config of machine:\n%s", jsonObservedConfig)
609
var mergedConfigs []params.NetworkConfig
610
for _, config := range sortedObservedConfigs {
611
name := config.InterfaceName
612
logger.Tracef("merging observed config for device %q: %+v", name, config)
613
if strings.HasPrefix(name, instancecfg.DefaultBridgePrefix) {
614
logger.Tracef("found potential juju bridge %q in observed config", name)
615
unprefixedName := strings.TrimPrefix(name, instancecfg.DefaultBridgePrefix)
616
underlyingConfigs, underlyingKnownByProvider := providerConfigsByName[unprefixedName]
617
logger.Tracef("device %q underlying %q has provider config: %+v", name, unprefixedName, underlyingConfigs)
618
if underlyingKnownByProvider {
619
// This config is for a bridge created by Juju and not known by
620
// the provider. The bridge is configured to adopt the address
621
// allocated to the underlying interface, which is known by the
622
// provider. However, since the same underlying interface can
623
// have multiple addresses, we need to match the adopted
624
// bridgeConfig to the correct address.
626
var underlyingConfig params.NetworkConfig
627
for i, underlying := range underlyingConfigs {
628
if underlying.Address == config.Address {
629
logger.Tracef("replacing undelying config %+v", underlying)
630
// Remove what we found before changing it below.
631
underlyingConfig = underlying
632
underlyingConfigs = append(underlyingConfigs[:i], underlyingConfigs[i+1:]...)
636
logger.Tracef("underlying provider config after update: %+v", underlyingConfigs)
638
bridgeConfig := config
639
bridgeConfig.InterfaceType = string(network.BridgeInterface)
640
bridgeConfig.ConfigType = underlyingConfig.ConfigType
641
bridgeConfig.VLANTag = underlyingConfig.VLANTag
642
bridgeConfig.ProviderId = "" // Juju-created bridges never have a ProviderID
643
bridgeConfig.ProviderSpaceId = underlyingConfig.ProviderSpaceId
644
bridgeConfig.ProviderVLANId = underlyingConfig.ProviderVLANId
645
bridgeConfig.ProviderSubnetId = underlyingConfig.ProviderSubnetId
646
bridgeConfig.ProviderAddressId = underlyingConfig.ProviderAddressId
647
if underlyingParent := underlyingConfig.ParentInterfaceName; underlyingParent != "" {
648
bridgeConfig.ParentInterfaceName = instancecfg.DefaultBridgePrefix + underlyingParent
651
underlyingConfig.ConfigType = string(network.ConfigManual)
652
underlyingConfig.ParentInterfaceName = name
653
underlyingConfig.ProviderAddressId = ""
654
underlyingConfig.CIDR = ""
655
underlyingConfig.Address = ""
657
underlyingConfigs = append(underlyingConfigs, underlyingConfig)
658
providerConfigsByName[unprefixedName] = underlyingConfigs
659
logger.Tracef("updated provider network config by name: %+v", providerConfigsByName)
661
mergedConfigs = append(mergedConfigs, bridgeConfig)
666
knownProviderConfigs, knownByProvider := providerConfigsByName[name]
667
if !knownByProvider {
668
// Not known by the provider and not a Juju-created bridge, so just
669
// use the observed config for it.
670
logger.Tracef("device %q not known to provider - adding only observed config: %+v", name, config)
671
mergedConfigs = append(mergedConfigs, config)
674
logger.Tracef("device %q has known provider network config: %+v", name, knownProviderConfigs)
676
for _, providerConfig := range knownProviderConfigs {
677
if providerConfig.Address == config.Address {
679
"device %q has observed address %q, index %d, and MTU %q; overriding index %d and MTU %d from provider config",
680
name, config.Address, config.DeviceIndex, config.MTU, providerConfig.DeviceIndex, providerConfig.MTU,
682
// Prefer observed device indices and MTU values as more up-to-date.
683
providerConfig.DeviceIndex = config.DeviceIndex
684
providerConfig.MTU = config.MTU
686
mergedConfigs = append(mergedConfigs, providerConfig)
692
sortedMergedConfigs := SortNetworkConfigsByParents(mergedConfigs)
694
jsonMergedConfig, err := NetworkConfigsToIndentedJSON(sortedMergedConfigs)
696
errors.Annotatef(err, "cannot serialize merged config %#v as JSON", sortedMergedConfigs)
698
logger.Debugf("combined machine network config:\n%s", jsonMergedConfig)
700
return mergedConfigs, nil
503
// MergeProviderAndObservedNetworkConfigs returns the effective network configs,
504
// using observedConfigs as a base and selectively updating it using the
505
// matching providerConfigs for each interface.
506
func MergeProviderAndObservedNetworkConfigs(providerConfigs, observedConfigs []params.NetworkConfig) []params.NetworkConfig {
508
providerConfigByName := networkConfigsByName(providerConfigs)
509
logger.Tracef("known provider config by name: %+v", providerConfigByName)
511
providerConfigByAddress := networkConfigsByAddress(providerConfigs)
512
logger.Tracef("known provider config by address: %+v", providerConfigByAddress)
514
var results []params.NetworkConfig
515
for _, observed := range observedConfigs {
517
name, ipAddress := observed.InterfaceName, observed.Address
518
finalConfig := observed
520
providerConfig, known := providerConfigByName[name]
522
finalConfig = mergeObservedAndProviderInterfaceConfig(finalConfig, providerConfig)
523
logger.Debugf("updated observed interface config for %q with: %+v", name, providerConfig)
526
providerConfig, known = providerConfigByAddress[ipAddress]
528
finalConfig = mergeObservedAndProviderAddressConfig(finalConfig, providerConfig)
529
logger.Debugf("updated observed address config for %q with: %+v", name, providerConfig)
532
results = append(results, finalConfig)
533
logger.Debugf("merged config for %q: %+v", name, finalConfig)
539
func networkConfigsByName(input []params.NetworkConfig) map[string]params.NetworkConfig {
540
configsByName := make(map[string]params.NetworkConfig, len(input))
541
for _, config := range input {
542
configsByName[config.InterfaceName] = config
547
func networkConfigsByAddress(input []params.NetworkConfig) map[string]params.NetworkConfig {
548
configsByAddress := make(map[string]params.NetworkConfig, len(input))
549
for _, config := range input {
550
configsByAddress[config.Address] = config
552
return configsByAddress
555
func mergeObservedAndProviderInterfaceConfig(observedConfig, providerConfig params.NetworkConfig) params.NetworkConfig {
556
finalConfig := observedConfig
558
// The following fields cannot be observed and are only known by the
560
finalConfig.ProviderId = providerConfig.ProviderId
561
finalConfig.ProviderVLANId = providerConfig.ProviderVLANId
562
finalConfig.ProviderSubnetId = providerConfig.ProviderSubnetId
564
// The following few fields are only updated if their observed values are
567
if observedConfig.InterfaceType == "" {
568
finalConfig.InterfaceType = providerConfig.InterfaceType
571
if observedConfig.VLANTag == 0 {
572
finalConfig.VLANTag = providerConfig.VLANTag
575
if observedConfig.ParentInterfaceName == "" {
576
finalConfig.ParentInterfaceName = providerConfig.ParentInterfaceName
582
func mergeObservedAndProviderAddressConfig(observedConfig, providerConfig params.NetworkConfig) params.NetworkConfig {
583
finalConfig := observedConfig
585
// The following fields cannot be observed and are only known by the
587
finalConfig.ProviderAddressId = providerConfig.ProviderAddressId
588
finalConfig.ProviderSubnetId = providerConfig.ProviderSubnetId
589
finalConfig.ProviderSpaceId = providerConfig.ProviderSpaceId
591
// The following few fields are only updated if their observed values are
594
if observedConfig.ProviderVLANId == "" {
595
finalConfig.ProviderVLANId = providerConfig.ProviderVLANId
598
if observedConfig.VLANTag == 0 {
599
finalConfig.VLANTag = providerConfig.VLANTag
602
if observedConfig.ConfigType == "" {
603
finalConfig.ConfigType = providerConfig.ConfigType
606
if observedConfig.CIDR == "" {
607
finalConfig.CIDR = providerConfig.CIDR
610
if observedConfig.GatewayAddress == "" {
611
finalConfig.GatewayAddress = providerConfig.GatewayAddress
614
if len(observedConfig.DNSServers) == 0 {
615
finalConfig.DNSServers = providerConfig.DNSServers
618
if len(observedConfig.DNSSearchDomains) == 0 {
619
finalConfig.DNSSearchDomains = providerConfig.DNSSearchDomains