github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/lib/net/configurator/compute.go (about) 1 package configurator 2 3 import ( 4 "fmt" 5 "net" 6 "sort" 7 "strings" 8 9 "github.com/Cloud-Foundations/Dominator/lib/log" 10 fm_proto "github.com/Cloud-Foundations/Dominator/proto/fleetmanager" 11 hyper_proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 12 ) 13 14 func findMatchingSubnet(subnets []*hyper_proto.Subnet, 15 ipAddr net.IP) *hyper_proto.Subnet { 16 for _, subnet := range subnets { 17 subnetMask := net.IPMask(subnet.IpMask) 18 subnetAddr := subnet.IpGateway.Mask(subnetMask) 19 if ipAddr.Mask(subnetMask).Equal(subnetAddr) { 20 return subnet 21 } 22 } 23 return nil 24 } 25 26 func findSubnet(subnets []*hyper_proto.Subnet, 27 subnetId string) *hyper_proto.Subnet { 28 for _, subnet := range subnets { 29 if subnet.Id == subnetId { 30 return subnet 31 } 32 } 33 return nil 34 } 35 36 func getNetworkEntries( 37 info fm_proto.GetMachineInfoResponse) []fm_proto.NetworkEntry { 38 networkEntries := make([]fm_proto.NetworkEntry, 1, 39 len(info.Machine.SecondaryNetworkEntries)+1) 40 networkEntries[0] = info.Machine.NetworkEntry 41 for _, networkEntry := range info.Machine.SecondaryNetworkEntries { 42 networkEntries = append(networkEntries, networkEntry) 43 } 44 return networkEntries 45 } 46 47 func (netconf *NetworkConfig) addBondedInterface(name string, ipAddr net.IP, 48 subnet *hyper_proto.Subnet) { 49 netconf.bondedInterfaces = append(netconf.bondedInterfaces, 50 bondedInterfaceType{ 51 name: name, 52 ipAddr: ipAddr, 53 subnet: subnet, 54 }) 55 } 56 57 func (netconf *NetworkConfig) addBridgeOnlyInterface(iface net.Interface, 58 subnetId string) { 59 netconf.bridgeOnlyInterfaces = append(netconf.bridgeOnlyInterfaces, 60 bridgeOnlyInterfaceType{ 61 netInterface: iface, 62 subnetId: subnetId, 63 }) 64 } 65 66 func (netconf *NetworkConfig) addNormalInterface(iface net.Interface, 67 ipAddr net.IP, subnet *hyper_proto.Subnet) { 68 netconf.normalInterfaces = append(netconf.normalInterfaces, 69 normalInterfaceType{ 70 netInterface: iface, 71 ipAddr: ipAddr, 72 subnet: subnet, 73 }) 74 } 75 76 func compute(machineInfo fm_proto.GetMachineInfoResponse, 77 _interfaces map[string]net.Interface, 78 logger log.DebugLogger) (*NetworkConfig, error) { 79 netconf := &NetworkConfig{} 80 networkEntries := getNetworkEntries(machineInfo) 81 interfaces := make(map[string]net.Interface, len(_interfaces)) 82 var vlanInterfaceNames []string 83 for name, iface := range _interfaces { 84 interfaces[name] = iface 85 } 86 hwAddrToInterface := make(map[string]net.Interface, len(interfaces)) 87 for _, iface := range interfaces { 88 hwAddrToInterface[iface.HardwareAddr.String()] = iface 89 } 90 preferredSubnet := findMatchingSubnet(machineInfo.Subnets, 91 machineInfo.Machine.HostIpAddress) 92 if machineInfo.Machine.GatewaySubnetId != "" { 93 preferredSubnet = findSubnet(machineInfo.Subnets, 94 machineInfo.Machine.GatewaySubnetId) 95 } 96 // First process network entries with normal interfaces. 97 var bondedNetworkEntries []fm_proto.NetworkEntry 98 normalInterfaceIndex := 0 99 usedSubnets := make(map[*hyper_proto.Subnet]struct{}) 100 for _, networkEntry := range networkEntries { 101 if len(networkEntry.HostIpAddress) < 1 { 102 if len(networkEntry.HostMacAddress) < 1 || 103 networkEntry.SubnetId == "" { 104 continue 105 } 106 iface, ok := hwAddrToInterface[networkEntry.HostMacAddress.String()] 107 if !ok { 108 return nil, fmt.Errorf("MAC address: %s not found", 109 networkEntry.HostMacAddress) 110 } 111 subnet := findSubnet(machineInfo.Subnets, networkEntry.SubnetId) 112 if subnet == nil { 113 return nil, 114 fmt.Errorf("subnetId: %s not found", networkEntry.SubnetId) 115 } 116 if !subnet.Manage { 117 return nil, 118 fmt.Errorf("subnetId: %s is not managed", subnet.Id) 119 } 120 if len(subnet.Id) >= 10 { 121 return nil, 122 fmt.Errorf("subnetId: %s is over 9 characters", subnet.Id) 123 } 124 if strings.ContainsAny(subnet.Id, "/.") { 125 return nil, 126 fmt.Errorf("subnetId: %s contains '/' or '.'", subnet.Id) 127 } 128 usedSubnets[subnet] = struct{}{} 129 netconf.addBridgeOnlyInterface(iface, networkEntry.SubnetId) 130 delete(interfaces, iface.Name) 131 continue 132 } 133 if len(networkEntry.HostMacAddress) < 1 { 134 bondedNetworkEntries = append(bondedNetworkEntries, networkEntry) 135 continue 136 } 137 iface, ok := hwAddrToInterface[networkEntry.HostMacAddress.String()] 138 if !ok { 139 logger.Printf("MAC address: %s not found\n", 140 networkEntry.HostMacAddress) 141 continue 142 } 143 subnet := findMatchingSubnet(machineInfo.Subnets, 144 networkEntry.HostIpAddress) 145 if subnet == nil { 146 logger.Printf("no matching subnet for ip=%s\n", 147 networkEntry.HostIpAddress) 148 continue 149 } 150 usedSubnets[subnet] = struct{}{} 151 normalInterfaceIndex++ 152 netconf.addNormalInterface(iface, networkEntry.HostIpAddress, subnet) 153 delete(interfaces, iface.Name) 154 if subnet == preferredSubnet { 155 netconf.DefaultSubnet = subnet 156 } else if netconf.DefaultSubnet == nil { 157 netconf.DefaultSubnet = subnet 158 } 159 if networkEntry.VlanTrunk { 160 vlanInterfaceNames = append(vlanInterfaceNames, iface.Name) 161 netconf.vlanRawDevice = iface.Name 162 } 163 } 164 // All remaining interfaces which are marked as up will be used for VLAN 165 // trunk. If there multiple interfaces, they will be bonded. 166 for name, iface := range interfaces { 167 if iface.Flags&net.FlagUp == 0 { 168 delete(interfaces, name) 169 } else { 170 netconf.bondSlaves = append(netconf.bondSlaves, name) 171 netconf.vlanRawDevice = name 172 vlanInterfaceNames = append(vlanInterfaceNames, name) 173 } 174 } 175 if len(vlanInterfaceNames) > 1 { 176 netconf.vlanRawDevice = "bond0" 177 } 178 sort.Strings(netconf.bondSlaves) 179 if len(vlanInterfaceNames) > 0 { 180 for _, networkEntry := range bondedNetworkEntries { 181 subnet := findMatchingSubnet(machineInfo.Subnets, 182 networkEntry.HostIpAddress) 183 if subnet == nil { 184 logger.Printf("no matching subnet for ip=%s\n", 185 networkEntry.HostIpAddress) 186 continue 187 } 188 usedSubnets[subnet] = struct{}{} 189 entryName := fmt.Sprintf("%s.%d", 190 netconf.vlanRawDevice, subnet.VlanId) 191 netconf.addBondedInterface(entryName, networkEntry.HostIpAddress, 192 subnet) 193 if subnet == preferredSubnet { 194 netconf.DefaultSubnet = subnet 195 } else if netconf.DefaultSubnet == nil { 196 netconf.DefaultSubnet = subnet 197 } 198 } 199 for _, subnet := range machineInfo.Subnets { 200 if _, ok := usedSubnets[subnet]; ok { 201 continue 202 } 203 if subnet.VlanId > 0 && subnet.Manage { 204 netconf.bridges = append(netconf.bridges, subnet.VlanId) 205 } 206 } 207 } 208 return netconf, nil 209 }