github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/network/fan.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package network 5 6 import ( 7 "encoding/binary" 8 "fmt" 9 "net" 10 "strings" 11 12 "github.com/juju/errors" 13 ) 14 15 // FanConfigEntry defines a configuration for single fan. 16 type FanConfigEntry struct { 17 Underlay *net.IPNet 18 Overlay *net.IPNet 19 } 20 21 // FanConfig defines a set of fan configurations for the model. 22 type FanConfig []FanConfigEntry 23 24 // ParseFanConfig parses fan configuration from model-config in the format: 25 // "underlay1=overlay1 underlay2=overlay2" eg. "172.16.0.0/16=253.0.0.0/8 10.0.0.0/12:254.0.0.0/7" 26 func ParseFanConfig(line string) (config FanConfig, err error) { 27 if line == "" { 28 return nil, nil 29 } 30 entries := strings.Split(line, " ") 31 config = make([]FanConfigEntry, len(entries)) 32 for i, line := range entries { 33 cidrs := strings.Split(line, "=") 34 if len(cidrs) != 2 { 35 return nil, fmt.Errorf("invalid FAN config entry: %v", line) 36 } 37 if _, config[i].Underlay, err = net.ParseCIDR(strings.TrimSpace(cidrs[0])); err != nil { 38 return nil, errors.Annotatef(err, "invalid address in FAN config") 39 } 40 if _, config[i].Overlay, err = net.ParseCIDR(strings.TrimSpace(cidrs[1])); err != nil { 41 return nil, errors.Annotatef(err, "invalid address in FAN config") 42 } 43 underlaySize, _ := config[i].Underlay.Mask.Size() 44 overlaySize, _ := config[i].Overlay.Mask.Size() 45 if underlaySize <= overlaySize { 46 return nil, fmt.Errorf("invalid FAN config, underlay mask must be larger than overlay: %s", line) 47 } 48 } 49 return config, nil 50 } 51 52 func (fc *FanConfig) String() (line string) { 53 configs := make([]string, len(*fc)) 54 for i, fan := range *fc { 55 configs[i] = fmt.Sprintf("%s=%s", fan.Underlay.String(), fan.Overlay.String()) 56 } 57 return strings.Join(configs, " ") 58 } 59 60 // CalculateOverlaySegment takes underlay CIDR and FAN config entry and 61 // cuts the segment of overlay that corresponds to this underlay: 62 // eg. for FAN 172.31/16 -> 243/8 and physical subnet 172.31.64/20 63 // we get FAN subnet 243.64/12. 64 func CalculateOverlaySegment(underlayCIDR string, fan FanConfigEntry) (*net.IPNet, error) { 65 _, underlayNet, err := net.ParseCIDR(underlayCIDR) 66 if err != nil { 67 return nil, errors.Trace(err) 68 } 69 subnetSize, _ := underlayNet.Mask.Size() 70 underlaySize, _ := fan.Underlay.Mask.Size() 71 if underlaySize <= subnetSize && fan.Underlay.Contains(underlayNet.IP) { 72 overlaySize, _ := fan.Overlay.Mask.Size() 73 newOverlaySize := overlaySize + (subnetSize - underlaySize) 74 fanSize := uint(underlaySize - overlaySize) 75 newFanIP := underlayNet.IP.To4() 76 if newFanIP == nil { 77 return nil, errors.New("fan address is not an IPv4 address.") 78 } 79 for i := 0; i < 4; i++ { 80 newFanIP[i] &^= fan.Underlay.Mask[i] 81 } 82 numIp := binary.BigEndian.Uint32(newFanIP) 83 numIp <<= fanSize 84 binary.BigEndian.PutUint32(newFanIP, numIp) 85 for i := 0; i < 4; i++ { 86 newFanIP[i] += fan.Overlay.IP[i] 87 } 88 return &net.IPNet{IP: newFanIP, Mask: net.CIDRMask(newOverlaySize, 32)}, nil 89 } else { 90 return nil, nil 91 } 92 }