github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/hypervisor/manager/subnets.go (about) 1 package manager 2 3 import ( 4 "flag" 5 "fmt" 6 "net" 7 "os" 8 "path" 9 "sort" 10 11 "github.com/Cloud-Foundations/Dominator/lib/json" 12 "github.com/Cloud-Foundations/Dominator/lib/net/util" 13 "github.com/Cloud-Foundations/Dominator/lib/srpc" 14 proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 15 ) 16 17 var ( 18 addHypervisorSubnet = flag.Bool("addHypervisorSubnet", false, 19 "If true, automatically add the subnet for the default gateway (deprecated)") 20 ) 21 22 func checkSubnetAccess(subnet proto.Subnet, 23 authInfo *srpc.AuthInformation) bool { 24 if authInfo.HaveMethodAccess { 25 return true 26 } 27 if len(subnet.AllowedUsers) < 1 && len(subnet.AllowedGroups) < 1 { 28 return true 29 } 30 for _, allowedUser := range subnet.AllowedUsers { 31 if authInfo.Username == allowedUser { 32 return true 33 } 34 } 35 for _, allowedGroup := range subnet.AllowedGroups { 36 if _, ok := authInfo.GroupList[allowedGroup]; ok { 37 return true 38 } 39 } 40 return false 41 } 42 43 func getHypervisorSubnet() (proto.Subnet, error) { 44 defaultRoute, err := util.GetDefaultRoute() 45 if err != nil { 46 return proto.Subnet{}, err 47 } 48 resolverConfig, err := util.GetResolverConfiguration() 49 if err != nil { 50 return proto.Subnet{}, err 51 } 52 myIP, err := util.GetMyIP() 53 if err != nil { 54 return proto.Subnet{}, err 55 } 56 nameservers := make([]net.IP, 0, len(resolverConfig.Nameservers)) 57 for _, nameserver := range resolverConfig.Nameservers { 58 if nameserver[0] == 127 { 59 nameservers = append(nameservers, myIP) 60 } else { 61 nameservers = append(nameservers, nameserver) 62 } 63 } 64 return proto.Subnet{ 65 Id: "hypervisor", 66 IpGateway: defaultRoute.Address, 67 IpMask: net.IP(defaultRoute.Mask), 68 DomainNameServers: nameservers, 69 }, nil 70 } 71 72 func (m *Manager) getBridgeForSubnet(subnet proto.Subnet) ( 73 string, string, error) { 74 mapName := fmt.Sprintf("br@%s", subnet.Id) 75 if _, ok := m.BridgeMap[mapName]; ok { 76 return mapName, "", nil 77 } else if bridge, ok := m.VlanIdToBridge[subnet.VlanId]; ok { 78 return bridge, "", nil 79 } else if bridge, ok = m.VlanIdToBridge[0]; ok { 80 return bridge, fmt.Sprintf(",vlan=%d", subnet.VlanId), nil 81 } else { 82 return "", "", fmt.Errorf("no usable bridge") 83 } 84 } 85 86 // This must be called with the lock held. 87 func (m *Manager) getMatchingSubnet(ipAddr net.IP) string { 88 if len(ipAddr) > 0 { 89 for id, subnet := range m.subnets { 90 subnetMask := net.IPMask(subnet.IpMask) 91 subnetAddr := subnet.IpGateway.Mask(subnetMask) 92 if ipAddr.Mask(subnetMask).Equal(subnetAddr) { 93 return id 94 } 95 } 96 } 97 return "" 98 } 99 100 // This must be called with the lock held. 101 func (m *Manager) getSubnetAndAuth(subnetId string, 102 authInfo *srpc.AuthInformation) (proto.Subnet, error) { 103 if len(m.subnets) < 1 { 104 return proto.Subnet{}, fmt.Errorf("no subnets exist") 105 } 106 if subnetId != "" { 107 if subnet, ok := m.subnets[subnetId]; !ok { 108 return proto.Subnet{}, fmt.Errorf("subnet: %s does not exist", 109 subnetId) 110 } else if !checkSubnetAccess(subnet, authInfo) { 111 return proto.Subnet{}, fmt.Errorf("no access to subnet: %s", 112 subnetId) 113 } else { 114 return subnet, nil 115 } 116 } 117 // Unspecified subnet: try to find one. 118 if len(m.subnets) == 1 { 119 if subnet, ok := m.subnets["hypervisor"]; !ok { 120 return proto.Subnet{}, fmt.Errorf( 121 "hypervisor subnet does not exist") 122 } else { 123 return subnet, nil 124 } 125 } 126 subnetsPermitted := make([]string, 0, 1) 127 for _, subnet := range m.subnets { 128 if subnet.Id == "hypervisor" { 129 continue 130 } 131 if !checkSubnetAccess(subnet, authInfo) { 132 continue 133 } 134 if len(subnetsPermitted) > 0 { 135 return proto.Subnet{}, fmt.Errorf( 136 "multiple available subnets: pick one") 137 } 138 subnetsPermitted = append(subnetsPermitted, subnet.Id) 139 } 140 if len(subnetsPermitted) < 1 { 141 return proto.Subnet{}, fmt.Errorf("no subnets permitted") 142 } 143 return m.subnets[subnetsPermitted[0]], nil 144 } 145 146 func (m *Manager) listSubnets(doSort bool) []proto.Subnet { 147 m.mutex.Lock() 148 defer m.mutex.Unlock() 149 subnets := make([]proto.Subnet, 0, len(m.subnets)) 150 if !doSort { 151 for _, subnet := range m.subnets { 152 subnets = append(subnets, subnet) 153 } 154 return subnets 155 } 156 subnetIDs := make([]string, 0, len(m.subnets)) 157 for subnetID := range m.subnets { 158 subnetIDs = append(subnetIDs, subnetID) 159 } 160 sort.Strings(subnetIDs) 161 for _, subnetID := range subnetIDs { 162 subnets = append(subnets, m.subnets[subnetID]) 163 } 164 return subnets 165 } 166 167 // This returns with the Manager locked, waiting for existing subnets to be 168 // drained from the channel by the caller before unlocking. 169 func (m *Manager) makeSubnetChannel() <-chan proto.Subnet { 170 ch := make(chan proto.Subnet, 1) 171 m.mutex.Lock() 172 m.subnetChannels = append(m.subnetChannels, ch) 173 go func() { 174 defer m.mutex.Unlock() 175 for _, subnet := range m.subnets { 176 ch <- subnet 177 } 178 }() 179 return ch 180 } 181 182 func (m *Manager) loadSubnets() error { 183 var subnets []proto.Subnet 184 err := json.ReadFromFile(path.Join(m.StateDir, "subnets.json"), &subnets) 185 if err != nil && !os.IsNotExist(err) { 186 return err 187 } 188 for index := range subnets { 189 subnets[index].Shrink() 190 } 191 m.subnets = make(map[string]proto.Subnet, len(subnets)+1) 192 for _, subnet := range subnets { 193 m.subnets[subnet.Id] = subnet 194 } 195 if *addHypervisorSubnet { 196 if subnet, err := getHypervisorSubnet(); err != nil { 197 return err 198 } else { 199 m.subnets["hypervisor"] = subnet 200 } 201 } 202 for _, subnet := range m.subnets { 203 m.DhcpServer.AddSubnet(subnet) 204 } 205 return nil 206 } 207 208 func (m *Manager) updateSubnets(request proto.UpdateSubnetsRequest) error { 209 for index, subnet := range request.Add { 210 if subnet.Id == "hypervisor" { 211 return fmt.Errorf("cannot add hypervisor subnet") 212 } 213 request.Add[index].Shrink() 214 } 215 for index, subnet := range request.Change { 216 if subnet.Id == "hypervisor" { 217 return fmt.Errorf("cannot change hypervisor subnet") 218 } 219 request.Change[index].Shrink() 220 } 221 for _, subnetId := range request.Delete { 222 if subnetId == "hypervisor" { 223 return fmt.Errorf("cannot delete hypervisor subnet") 224 } 225 } 226 if err := m.updateSubnetsLocked(request); err != nil { 227 return err 228 } 229 for _, subnet := range request.Add { 230 m.DhcpServer.AddSubnet(subnet) 231 for _, ch := range m.subnetChannels { 232 ch <- subnet 233 } 234 } 235 for _, subnet := range request.Change { 236 m.DhcpServer.RemoveSubnet(subnet.Id) 237 m.DhcpServer.AddSubnet(subnet) 238 // TOOO(rgooch): Design a clean way to send updates to the channels. 239 } 240 for _, subnetId := range request.Delete { 241 m.DhcpServer.RemoveSubnet(subnetId) 242 // TOOO(rgooch): Design a clean way to send deletes to the channels. 243 } 244 return nil 245 } 246 247 func (m *Manager) updateSubnetsLocked( 248 request proto.UpdateSubnetsRequest) error { 249 m.mutex.Lock() 250 defer m.mutex.Unlock() 251 for _, subnet := range request.Add { 252 if _, ok := m.subnets[subnet.Id]; ok { 253 return fmt.Errorf("subnet: %s already exists", subnet.Id) 254 } 255 } 256 for _, subnet := range request.Change { 257 if _, ok := m.subnets[subnet.Id]; !ok { 258 return fmt.Errorf("subnet: %s does not exist", subnet.Id) 259 } 260 } 261 for _, subnetId := range request.Delete { 262 if _, ok := m.subnets[subnetId]; !ok { 263 return fmt.Errorf("subnet: %s does not exist", subnetId) 264 } 265 } 266 for _, subnet := range request.Add { 267 m.subnets[subnet.Id] = subnet 268 } 269 for _, subnet := range request.Change { 270 m.subnets[subnet.Id] = subnet 271 } 272 for _, subnetId := range request.Delete { 273 delete(m.subnets, subnetId) 274 } 275 subnetsToWrite := make([]proto.Subnet, 0, len(m.subnets)-1) 276 for _, subnet := range m.subnets { 277 if subnet.Id != "hypervisor" { 278 subnetsToWrite = append(subnetsToWrite, subnet) 279 } 280 } 281 // TODO(rgooch): Should precompute the numFreeAddresses map. 282 numFreeAddresses, err := m.computeNumFreeAddressesMap(m.addressPool) 283 if err != nil { 284 return err 285 } 286 err = json.WriteToFile(path.Join(m.StateDir, "subnets.json"), 287 publicFilePerms, " ", subnetsToWrite) 288 if err != nil { 289 return err 290 } 291 m.sendUpdateWithLock( 292 proto.Update{ 293 HaveAddressPool: true, 294 AddressPool: m.addressPool.Registered, 295 NumFreeAddresses: numFreeAddresses, 296 HaveSubnets: true, 297 Subnets: subnetsToWrite, 298 }) 299 return nil 300 }