github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/network/network.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package network
     5  
     6  import (
     7  	"fmt"
     8  	"math/rand"
     9  	"net"
    10  	"sort"
    11  
    12  	"github.com/juju/loggo"
    13  )
    14  
    15  var logger = loggo.GetLogger("juju.core.network")
    16  
    17  // macAddressTemplate is suitable for generating virtual MAC addresses,
    18  // particularly for use by container devices.
    19  // The last 3 segments are randomised.
    20  // TODO (manadart 2018-06-21) Depending on where this is utilised,
    21  // ensuring MAC address uniqueness within a model might be prudent.
    22  const macAddressTemplate = "00:16:3e:%02x:%02x:%02x"
    23  
    24  // GenerateVirtualMACAddress creates a random MAC address within the address
    25  // space implied by macAddressTemplate above.
    26  var GenerateVirtualMACAddress = func() string {
    27  	digits := make([]interface{}, 3)
    28  	for i := range digits {
    29  		digits[i] = rand.Intn(256)
    30  	}
    31  	return fmt.Sprintf(macAddressTemplate, digits...)
    32  }
    33  
    34  // Id defines a provider-specific network ID.
    35  type Id string
    36  
    37  // String returns the underlying string representation of the Id.
    38  // This method helps with formatting and type inference.
    39  func (id Id) String() string {
    40  	return string(id)
    41  }
    42  
    43  // IDSet represents the classic "set" data structure, and contains Id.
    44  // IDSet is used as a typed version to prevent string -> Id -> string
    45  // conversion when using set.Strings
    46  type IDSet map[Id]struct{}
    47  
    48  // MakeIDSet creates and initializes a IDSet and populates it with
    49  // initial values as specified in the parameters.
    50  func MakeIDSet(values ...Id) IDSet {
    51  	set := make(map[Id]struct{}, len(values))
    52  	for _, id := range values {
    53  		set[id] = struct{}{}
    54  	}
    55  	return set
    56  }
    57  
    58  // Add puts a value into the set.
    59  func (s IDSet) Add(value Id) {
    60  	s[value] = struct{}{}
    61  }
    62  
    63  // Size returns the number of elements in the set.
    64  func (s IDSet) Size() int {
    65  	return len(s)
    66  }
    67  
    68  // IsEmpty is true for empty or uninitialized sets.
    69  func (s IDSet) IsEmpty() bool {
    70  	return len(s) == 0
    71  }
    72  
    73  // Contains returns true if the value is in the set, and false otherwise.
    74  func (s IDSet) Contains(id Id) bool {
    75  	_, exists := s[id]
    76  	return exists
    77  }
    78  
    79  // Difference returns a new IDSet representing all the values in the
    80  // target that are not in the parameter.
    81  func (s IDSet) Difference(other IDSet) IDSet {
    82  	result := make(IDSet)
    83  	// Use the internal map rather than going through the friendlier functions
    84  	// to avoid extra allocation of slices.
    85  	for value := range s {
    86  		if !other.Contains(value) {
    87  			result[value] = struct{}{}
    88  		}
    89  	}
    90  	return result
    91  }
    92  
    93  // Values returns an unordered slice containing all the values in the set.
    94  func (s IDSet) Values() []Id {
    95  	result := make([]Id, len(s))
    96  	i := 0
    97  	for key := range s {
    98  		result[i] = key
    99  		i++
   100  	}
   101  	return result
   102  }
   103  
   104  // SortedValues returns an ordered slice containing all the values in the set.
   105  func (s IDSet) SortedValues() []Id {
   106  	values := s.Values()
   107  	sort.Slice(values, func(i, j int) bool {
   108  		return values[i] < values[j]
   109  	})
   110  	return values
   111  }
   112  
   113  // SubnetsForAddresses returns subnets corresponding to the addresses
   114  // in the input address list.
   115  // There can be situations (observed for CAAS) where the addresses can
   116  // contain a FQDN.
   117  // For these cases we log a warning and eschew subnet determination.
   118  func SubnetsForAddresses(addrs []string) []string {
   119  	var subs []string
   120  	for _, a := range addrs {
   121  		// We don't expect this to be the case, but guard conservatively.
   122  		if _, _, err := net.ParseCIDR(a); err == nil {
   123  			subs = append(subs, a)
   124  			continue
   125  		}
   126  
   127  		if addr := net.ParseIP(a); addr != nil {
   128  			if addr.To4() != nil {
   129  				subs = append(subs, addr.String()+"/32")
   130  			} else {
   131  				subs = append(subs, addr.String()+"/128")
   132  			}
   133  			continue
   134  		}
   135  
   136  		logger.Warningf("unable to determine egress subnet for %q", a)
   137  	}
   138  	return subs
   139  }