github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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 func (ep *endpoint) Info() EndpointInfo { 191 if ep.sandboxID != "" { 192 return ep 193 } 194 n, err := ep.getNetworkFromStore() 195 if err != nil { 196 return nil 197 } 198 199 ep, err = n.getEndpointFromStore(ep.ID()) 200 if err != nil { 201 return nil 202 } 203 204 sb, ok := ep.getSandbox() 205 if !ok { 206 // endpoint hasn't joined any sandbox. 207 // Just return the endpoint 208 return ep 209 } 210 211 return sb.getEndpoint(ep.ID()) 212 } 213 214 func (ep *endpoint) Iface() InterfaceInfo { 215 ep.Lock() 216 defer ep.Unlock() 217 218 if ep.iface != nil { 219 return ep.iface 220 } 221 222 return nil 223 } 224 225 func (ep *endpoint) Interface() driverapi.InterfaceInfo { 226 ep.Lock() 227 defer ep.Unlock() 228 229 if ep.iface != nil { 230 return ep.iface 231 } 232 233 return nil 234 } 235 236 func (epi *endpointInterface) SetMacAddress(mac net.HardwareAddr) error { 237 if epi.mac != nil { 238 return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac) 239 } 240 if mac == nil { 241 return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface") 242 } 243 epi.mac = types.GetMacCopy(mac) 244 return nil 245 } 246 247 func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error { 248 if address.IP == nil { 249 return types.BadRequestErrorf("tried to set nil IP address to endpoint interface") 250 } 251 if address.IP.To4() == nil { 252 return setAddress(&epi.addrv6, address) 253 } 254 return setAddress(&epi.addr, address) 255 } 256 257 func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error { 258 if *ifaceAddr != nil { 259 return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address) 260 } 261 *ifaceAddr = types.GetIPNetCopy(address) 262 return nil 263 } 264 265 func (epi *endpointInterface) MacAddress() net.HardwareAddr { 266 return types.GetMacCopy(epi.mac) 267 } 268 269 func (epi *endpointInterface) Address() *net.IPNet { 270 return types.GetIPNetCopy(epi.addr) 271 } 272 273 func (epi *endpointInterface) AddressIPv6() *net.IPNet { 274 return types.GetIPNetCopy(epi.addrv6) 275 } 276 277 func (epi *endpointInterface) LinkLocalAddresses() []*net.IPNet { 278 return epi.llAddrs 279 } 280 281 func (epi *endpointInterface) SrcName() string { 282 return epi.srcName 283 } 284 285 func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error { 286 epi.srcName = srcName 287 epi.dstPrefix = dstPrefix 288 return nil 289 } 290 291 func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo { 292 ep.Lock() 293 defer ep.Unlock() 294 295 if ep.iface != nil { 296 return ep.iface 297 } 298 299 return nil 300 } 301 302 func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error { 303 ep.Lock() 304 defer ep.Unlock() 305 306 r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop} 307 308 if routeType == types.NEXTHOP { 309 // If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface). 310 ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &r) 311 } else { 312 // If the route doesn't specify a next-hop, it must be a connected route, bound to an interface. 313 ep.iface.routes = append(ep.iface.routes, r.Destination) 314 } 315 return nil 316 } 317 318 func (ep *endpoint) AddTableEntry(tableName, key string, value []byte) error { 319 ep.Lock() 320 defer ep.Unlock() 321 322 ep.joinInfo.driverTableEntries = append(ep.joinInfo.driverTableEntries, &tableEntry{ 323 tableName: tableName, 324 key: key, 325 value: value, 326 }) 327 328 return nil 329 } 330 331 func (ep *endpoint) Sandbox() Sandbox { 332 cnt, ok := ep.getSandbox() 333 if !ok { 334 return nil 335 } 336 return cnt 337 } 338 339 func (ep *endpoint) LoadBalancer() bool { 340 ep.Lock() 341 defer ep.Unlock() 342 return ep.loadBalancer 343 } 344 345 func (ep *endpoint) StaticRoutes() []*types.StaticRoute { 346 ep.Lock() 347 defer ep.Unlock() 348 349 if ep.joinInfo == nil { 350 return nil 351 } 352 353 return ep.joinInfo.StaticRoutes 354 } 355 356 func (ep *endpoint) Gateway() net.IP { 357 ep.Lock() 358 defer ep.Unlock() 359 360 if ep.joinInfo == nil { 361 return net.IP{} 362 } 363 364 return types.GetIPCopy(ep.joinInfo.gw) 365 } 366 367 func (ep *endpoint) GatewayIPv6() net.IP { 368 ep.Lock() 369 defer ep.Unlock() 370 371 if ep.joinInfo == nil { 372 return net.IP{} 373 } 374 375 return types.GetIPCopy(ep.joinInfo.gw6) 376 } 377 378 func (ep *endpoint) SetGateway(gw net.IP) error { 379 ep.Lock() 380 defer ep.Unlock() 381 382 ep.joinInfo.gw = types.GetIPCopy(gw) 383 return nil 384 } 385 386 func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error { 387 ep.Lock() 388 defer ep.Unlock() 389 390 ep.joinInfo.gw6 = types.GetIPCopy(gw6) 391 return nil 392 } 393 394 func (ep *endpoint) retrieveFromStore() (*endpoint, error) { 395 n, err := ep.getNetworkFromStore() 396 if err != nil { 397 return nil, fmt.Errorf("could not find network in store to get latest endpoint %s: %v", ep.Name(), err) 398 } 399 return n.getEndpointFromStore(ep.ID()) 400 } 401 402 func (ep *endpoint) DisableGatewayService() { 403 ep.Lock() 404 defer ep.Unlock() 405 406 ep.joinInfo.disableGatewayService = true 407 } 408 409 func (epj *endpointJoinInfo) MarshalJSON() ([]byte, error) { 410 epMap := make(map[string]interface{}) 411 if epj.gw != nil { 412 epMap["gw"] = epj.gw.String() 413 } 414 if epj.gw6 != nil { 415 epMap["gw6"] = epj.gw6.String() 416 } 417 epMap["disableGatewayService"] = epj.disableGatewayService 418 epMap["StaticRoutes"] = epj.StaticRoutes 419 return json.Marshal(epMap) 420 } 421 422 func (epj *endpointJoinInfo) UnmarshalJSON(b []byte) error { 423 var ( 424 err error 425 epMap map[string]interface{} 426 ) 427 if err = json.Unmarshal(b, &epMap); err != nil { 428 return err 429 } 430 if v, ok := epMap["gw"]; ok { 431 epj.gw = net.ParseIP(v.(string)) 432 } 433 if v, ok := epMap["gw6"]; ok { 434 epj.gw6 = net.ParseIP(v.(string)) 435 } 436 epj.disableGatewayService = epMap["disableGatewayService"].(bool) 437 438 var tStaticRoute []types.StaticRoute 439 if v, ok := epMap["StaticRoutes"]; ok { 440 tb, _ := json.Marshal(v) 441 var tStaticRoute []types.StaticRoute 442 // TODO(cpuguy83): Linter caught that we aren't checking errors here 443 // I don't know why we aren't other than potentially the data is not always expected to be right? 444 // This is why I'm not adding the error check. 445 // 446 // In any case for posterity please if you figure this out document it or check the error 447 json.Unmarshal(tb, &tStaticRoute) //nolint:errcheck 448 } 449 var StaticRoutes []*types.StaticRoute 450 for _, r := range tStaticRoute { 451 r := r 452 StaticRoutes = append(StaticRoutes, &r) 453 } 454 epj.StaticRoutes = StaticRoutes 455 456 return nil 457 } 458 459 func (epj *endpointJoinInfo) CopyTo(dstEpj *endpointJoinInfo) error { 460 dstEpj.disableGatewayService = epj.disableGatewayService 461 dstEpj.StaticRoutes = make([]*types.StaticRoute, len(epj.StaticRoutes)) 462 copy(dstEpj.StaticRoutes, epj.StaticRoutes) 463 dstEpj.driverTableEntries = make([]*tableEntry, len(epj.driverTableEntries)) 464 copy(dstEpj.driverTableEntries, epj.driverTableEntries) 465 dstEpj.gw = types.GetIPCopy(epj.gw) 466 dstEpj.gw6 = types.GetIPCopy(epj.gw6) 467 return nil 468 }