github.com/rawahars/moby@v24.0.4+incompatible/libnetwork/endpoint_info.go (about) 1 package libnetwork 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net" 7 8 "github.com/docker/docker/libnetwork/driverapi" 9 "github.com/docker/docker/libnetwork/types" 10 ) 11 12 // EndpointInfo provides an interface to retrieve network resources bound to the endpoint. 13 type EndpointInfo interface { 14 // Iface returns InterfaceInfo, go interface that can be used 15 // to get more information on the interface which was assigned to 16 // the endpoint by the driver. This can be used after the 17 // endpoint has been created. 18 Iface() InterfaceInfo 19 20 // Gateway returns the IPv4 gateway assigned by the driver. 21 // This will only return a valid value if a container has joined the endpoint. 22 Gateway() net.IP 23 24 // GatewayIPv6 returns the IPv6 gateway assigned by the driver. 25 // This will only return a valid value if a container has joined the endpoint. 26 GatewayIPv6() net.IP 27 28 // StaticRoutes returns the list of static routes configured by the network 29 // driver when the container joins a network 30 StaticRoutes() []*types.StaticRoute 31 32 // Sandbox returns the attached sandbox if there, nil otherwise. 33 Sandbox() *Sandbox 34 35 // LoadBalancer returns whether the endpoint is the load balancer endpoint for the network. 36 LoadBalancer() bool 37 } 38 39 // InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint. 40 type InterfaceInfo interface { 41 // MacAddress returns the MAC address assigned to the endpoint. 42 MacAddress() net.HardwareAddr 43 44 // Address returns the IPv4 address assigned to the endpoint. 45 Address() *net.IPNet 46 47 // AddressIPv6 returns the IPv6 address assigned to the endpoint. 48 AddressIPv6() *net.IPNet 49 50 // LinkLocalAddresses returns the list of link-local (IPv4/IPv6) addresses assigned to the endpoint. 51 LinkLocalAddresses() []*net.IPNet 52 53 // SrcName returns the name of the interface w/in the container 54 SrcName() string 55 } 56 57 type endpointInterface struct { 58 mac net.HardwareAddr 59 addr *net.IPNet 60 addrv6 *net.IPNet 61 llAddrs []*net.IPNet 62 srcName string 63 dstPrefix string 64 routes []*net.IPNet 65 v4PoolID string 66 v6PoolID string 67 } 68 69 func (epi *endpointInterface) MarshalJSON() ([]byte, error) { 70 epMap := make(map[string]interface{}) 71 if epi.mac != nil { 72 epMap["mac"] = epi.mac.String() 73 } 74 if epi.addr != nil { 75 epMap["addr"] = epi.addr.String() 76 } 77 if epi.addrv6 != nil { 78 epMap["addrv6"] = epi.addrv6.String() 79 } 80 if len(epi.llAddrs) != 0 { 81 list := make([]string, 0, len(epi.llAddrs)) 82 for _, ll := range epi.llAddrs { 83 list = append(list, ll.String()) 84 } 85 epMap["llAddrs"] = list 86 } 87 epMap["srcName"] = epi.srcName 88 epMap["dstPrefix"] = epi.dstPrefix 89 var routes []string 90 for _, route := range epi.routes { 91 routes = append(routes, route.String()) 92 } 93 epMap["routes"] = routes 94 epMap["v4PoolID"] = epi.v4PoolID 95 epMap["v6PoolID"] = epi.v6PoolID 96 return json.Marshal(epMap) 97 } 98 99 func (epi *endpointInterface) UnmarshalJSON(b []byte) error { 100 var ( 101 err error 102 epMap map[string]interface{} 103 ) 104 if err = json.Unmarshal(b, &epMap); err != nil { 105 return err 106 } 107 if v, ok := epMap["mac"]; ok { 108 if epi.mac, err = net.ParseMAC(v.(string)); err != nil { 109 return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string)) 110 } 111 } 112 if v, ok := epMap["addr"]; ok { 113 if epi.addr, err = types.ParseCIDR(v.(string)); err != nil { 114 return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err) 115 } 116 } 117 if v, ok := epMap["addrv6"]; ok { 118 if epi.addrv6, err = types.ParseCIDR(v.(string)); err != nil { 119 return types.InternalErrorf("failed to decode endpoint interface ipv6 address after json unmarshal: %v", err) 120 } 121 } 122 if v, ok := epMap["llAddrs"]; ok { 123 list := v.([]interface{}) 124 epi.llAddrs = make([]*net.IPNet, 0, len(list)) 125 for _, llS := range list { 126 ll, err := types.ParseCIDR(llS.(string)) 127 if err != nil { 128 return types.InternalErrorf("failed to decode endpoint interface link-local address (%v) after json unmarshal: %v", llS, err) 129 } 130 epi.llAddrs = append(epi.llAddrs, ll) 131 } 132 } 133 epi.srcName = epMap["srcName"].(string) 134 epi.dstPrefix = epMap["dstPrefix"].(string) 135 136 rb, _ := json.Marshal(epMap["routes"]) 137 var routes []string 138 139 // TODO(cpuguy83): linter noticed we don't check the error here... no idea why but it seems like it could introduce problems if we start checking 140 json.Unmarshal(rb, &routes) //nolint:errcheck 141 142 epi.routes = make([]*net.IPNet, 0) 143 for _, route := range routes { 144 ip, ipr, err := net.ParseCIDR(route) 145 if err == nil { 146 ipr.IP = ip 147 epi.routes = append(epi.routes, ipr) 148 } 149 } 150 epi.v4PoolID = epMap["v4PoolID"].(string) 151 epi.v6PoolID = epMap["v6PoolID"].(string) 152 153 return nil 154 } 155 156 func (epi *endpointInterface) CopyTo(dstEpi *endpointInterface) error { 157 dstEpi.mac = types.GetMacCopy(epi.mac) 158 dstEpi.addr = types.GetIPNetCopy(epi.addr) 159 dstEpi.addrv6 = types.GetIPNetCopy(epi.addrv6) 160 dstEpi.srcName = epi.srcName 161 dstEpi.dstPrefix = epi.dstPrefix 162 dstEpi.v4PoolID = epi.v4PoolID 163 dstEpi.v6PoolID = epi.v6PoolID 164 if len(epi.llAddrs) != 0 { 165 dstEpi.llAddrs = make([]*net.IPNet, 0, len(epi.llAddrs)) 166 dstEpi.llAddrs = append(dstEpi.llAddrs, epi.llAddrs...) 167 } 168 169 for _, route := range epi.routes { 170 dstEpi.routes = append(dstEpi.routes, types.GetIPNetCopy(route)) 171 } 172 173 return nil 174 } 175 176 type endpointJoinInfo struct { 177 gw net.IP 178 gw6 net.IP 179 StaticRoutes []*types.StaticRoute 180 driverTableEntries []*tableEntry 181 disableGatewayService bool 182 } 183 184 type tableEntry struct { 185 tableName string 186 key string 187 value []byte 188 } 189 190 // Info returns certain operational data belonging to this endpoint. 191 func (ep *Endpoint) Info() EndpointInfo { 192 if ep.sandboxID != "" { 193 return ep 194 } 195 n, err := ep.getNetworkFromStore() 196 if err != nil { 197 return nil 198 } 199 200 ep, err = n.getEndpointFromStore(ep.ID()) 201 if err != nil { 202 return nil 203 } 204 205 sb, ok := ep.getSandbox() 206 if !ok { 207 // endpoint hasn't joined any sandbox. 208 // Just return the endpoint 209 return ep 210 } 211 212 return sb.getEndpoint(ep.ID()) 213 } 214 215 func (ep *Endpoint) Iface() InterfaceInfo { 216 ep.mu.Lock() 217 defer ep.mu.Unlock() 218 219 if ep.iface != nil { 220 return ep.iface 221 } 222 223 return nil 224 } 225 226 func (ep *Endpoint) Interface() driverapi.InterfaceInfo { 227 ep.mu.Lock() 228 defer ep.mu.Unlock() 229 230 if ep.iface != nil { 231 return ep.iface 232 } 233 234 return nil 235 } 236 237 func (epi *endpointInterface) SetMacAddress(mac net.HardwareAddr) error { 238 if epi.mac != nil { 239 return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac) 240 } 241 if mac == nil { 242 return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface") 243 } 244 epi.mac = types.GetMacCopy(mac) 245 return nil 246 } 247 248 func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error { 249 if address.IP == nil { 250 return types.BadRequestErrorf("tried to set nil IP address to endpoint interface") 251 } 252 if address.IP.To4() == nil { 253 return setAddress(&epi.addrv6, address) 254 } 255 return setAddress(&epi.addr, address) 256 } 257 258 func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error { 259 if *ifaceAddr != nil { 260 return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address) 261 } 262 *ifaceAddr = types.GetIPNetCopy(address) 263 return nil 264 } 265 266 func (epi *endpointInterface) MacAddress() net.HardwareAddr { 267 return types.GetMacCopy(epi.mac) 268 } 269 270 func (epi *endpointInterface) Address() *net.IPNet { 271 return types.GetIPNetCopy(epi.addr) 272 } 273 274 func (epi *endpointInterface) AddressIPv6() *net.IPNet { 275 return types.GetIPNetCopy(epi.addrv6) 276 } 277 278 func (epi *endpointInterface) LinkLocalAddresses() []*net.IPNet { 279 return epi.llAddrs 280 } 281 282 func (epi *endpointInterface) SrcName() string { 283 return epi.srcName 284 } 285 286 func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error { 287 epi.srcName = srcName 288 epi.dstPrefix = dstPrefix 289 return nil 290 } 291 292 func (ep *Endpoint) InterfaceName() driverapi.InterfaceNameInfo { 293 ep.mu.Lock() 294 defer ep.mu.Unlock() 295 296 if ep.iface != nil { 297 return ep.iface 298 } 299 300 return nil 301 } 302 303 func (ep *Endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error { 304 ep.mu.Lock() 305 defer ep.mu.Unlock() 306 307 r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop} 308 309 if routeType == types.NEXTHOP { 310 // If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface). 311 ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &r) 312 } else { 313 // If the route doesn't specify a next-hop, it must be a connected route, bound to an interface. 314 ep.iface.routes = append(ep.iface.routes, r.Destination) 315 } 316 return nil 317 } 318 319 func (ep *Endpoint) AddTableEntry(tableName, key string, value []byte) error { 320 ep.mu.Lock() 321 defer ep.mu.Unlock() 322 323 ep.joinInfo.driverTableEntries = append(ep.joinInfo.driverTableEntries, &tableEntry{ 324 tableName: tableName, 325 key: key, 326 value: value, 327 }) 328 329 return nil 330 } 331 332 func (ep *Endpoint) Sandbox() *Sandbox { 333 cnt, ok := ep.getSandbox() 334 if !ok { 335 return nil 336 } 337 return cnt 338 } 339 340 func (ep *Endpoint) LoadBalancer() bool { 341 ep.mu.Lock() 342 defer ep.mu.Unlock() 343 return ep.loadBalancer 344 } 345 346 func (ep *Endpoint) StaticRoutes() []*types.StaticRoute { 347 ep.mu.Lock() 348 defer ep.mu.Unlock() 349 350 if ep.joinInfo == nil { 351 return nil 352 } 353 354 return ep.joinInfo.StaticRoutes 355 } 356 357 func (ep *Endpoint) Gateway() net.IP { 358 ep.mu.Lock() 359 defer ep.mu.Unlock() 360 361 if ep.joinInfo == nil { 362 return net.IP{} 363 } 364 365 return types.GetIPCopy(ep.joinInfo.gw) 366 } 367 368 func (ep *Endpoint) GatewayIPv6() net.IP { 369 ep.mu.Lock() 370 defer ep.mu.Unlock() 371 372 if ep.joinInfo == nil { 373 return net.IP{} 374 } 375 376 return types.GetIPCopy(ep.joinInfo.gw6) 377 } 378 379 func (ep *Endpoint) SetGateway(gw net.IP) error { 380 ep.mu.Lock() 381 defer ep.mu.Unlock() 382 383 ep.joinInfo.gw = types.GetIPCopy(gw) 384 return nil 385 } 386 387 func (ep *Endpoint) SetGatewayIPv6(gw6 net.IP) error { 388 ep.mu.Lock() 389 defer ep.mu.Unlock() 390 391 ep.joinInfo.gw6 = types.GetIPCopy(gw6) 392 return nil 393 } 394 395 func (ep *Endpoint) retrieveFromStore() (*Endpoint, error) { 396 n, err := ep.getNetworkFromStore() 397 if err != nil { 398 return nil, fmt.Errorf("could not find network in store to get latest endpoint %s: %v", ep.Name(), err) 399 } 400 return n.getEndpointFromStore(ep.ID()) 401 } 402 403 func (ep *Endpoint) DisableGatewayService() { 404 ep.mu.Lock() 405 defer ep.mu.Unlock() 406 407 ep.joinInfo.disableGatewayService = true 408 } 409 410 func (epj *endpointJoinInfo) MarshalJSON() ([]byte, error) { 411 epMap := make(map[string]interface{}) 412 if epj.gw != nil { 413 epMap["gw"] = epj.gw.String() 414 } 415 if epj.gw6 != nil { 416 epMap["gw6"] = epj.gw6.String() 417 } 418 epMap["disableGatewayService"] = epj.disableGatewayService 419 epMap["StaticRoutes"] = epj.StaticRoutes 420 return json.Marshal(epMap) 421 } 422 423 func (epj *endpointJoinInfo) UnmarshalJSON(b []byte) error { 424 var ( 425 err error 426 epMap map[string]interface{} 427 ) 428 if err = json.Unmarshal(b, &epMap); err != nil { 429 return err 430 } 431 if v, ok := epMap["gw"]; ok { 432 epj.gw = net.ParseIP(v.(string)) 433 } 434 if v, ok := epMap["gw6"]; ok { 435 epj.gw6 = net.ParseIP(v.(string)) 436 } 437 epj.disableGatewayService = epMap["disableGatewayService"].(bool) 438 439 var tStaticRoute []types.StaticRoute 440 if v, ok := epMap["StaticRoutes"]; ok { 441 tb, _ := json.Marshal(v) 442 var tStaticRoute []types.StaticRoute 443 // TODO(cpuguy83): Linter caught that we aren't checking errors here 444 // I don't know why we aren't other than potentially the data is not always expected to be right? 445 // This is why I'm not adding the error check. 446 // 447 // In any case for posterity please if you figure this out document it or check the error 448 json.Unmarshal(tb, &tStaticRoute) //nolint:errcheck 449 } 450 var StaticRoutes []*types.StaticRoute 451 for _, r := range tStaticRoute { 452 r := r 453 StaticRoutes = append(StaticRoutes, &r) 454 } 455 epj.StaticRoutes = StaticRoutes 456 457 return nil 458 } 459 460 func (epj *endpointJoinInfo) CopyTo(dstEpj *endpointJoinInfo) error { 461 dstEpj.disableGatewayService = epj.disableGatewayService 462 dstEpj.StaticRoutes = make([]*types.StaticRoute, len(epj.StaticRoutes)) 463 copy(dstEpj.StaticRoutes, epj.StaticRoutes) 464 dstEpj.driverTableEntries = make([]*tableEntry, len(epj.driverTableEntries)) 465 copy(dstEpj.driverTableEntries, epj.driverTableEntries) 466 dstEpj.gw = types.GetIPCopy(epj.gw) 467 dstEpj.gw6 = types.GetIPCopy(epj.gw6) 468 return nil 469 }