github.com/skf/moby@v1.13.1/daemon/network.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "net" 6 "runtime" 7 "sort" 8 "strings" 9 10 "github.com/Sirupsen/logrus" 11 apierrors "github.com/docker/docker/api/errors" 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/api/types/network" 14 clustertypes "github.com/docker/docker/daemon/cluster/provider" 15 "github.com/docker/docker/pkg/plugingetter" 16 "github.com/docker/docker/runconfig" 17 "github.com/docker/libnetwork" 18 "github.com/docker/libnetwork/driverapi" 19 "github.com/docker/libnetwork/ipamapi" 20 networktypes "github.com/docker/libnetwork/types" 21 "github.com/pkg/errors" 22 "golang.org/x/net/context" 23 ) 24 25 // NetworkControllerEnabled checks if the networking stack is enabled. 26 // This feature depends on OS primitives and it's disabled in systems like Windows. 27 func (daemon *Daemon) NetworkControllerEnabled() bool { 28 return daemon.netController != nil 29 } 30 31 // FindNetwork function finds a network for a given string that can represent network name or id 32 func (daemon *Daemon) FindNetwork(idName string) (libnetwork.Network, error) { 33 // Find by Name 34 n, err := daemon.GetNetworkByName(idName) 35 if err != nil && !isNoSuchNetworkError(err) { 36 return nil, err 37 } 38 39 if n != nil { 40 return n, nil 41 } 42 43 // Find by id 44 return daemon.GetNetworkByID(idName) 45 } 46 47 func isNoSuchNetworkError(err error) bool { 48 _, ok := err.(libnetwork.ErrNoSuchNetwork) 49 return ok 50 } 51 52 // GetNetworkByID function returns a network whose ID begins with the given prefix. 53 // It fails with an error if no matching, or more than one matching, networks are found. 54 func (daemon *Daemon) GetNetworkByID(partialID string) (libnetwork.Network, error) { 55 list := daemon.GetNetworksByID(partialID) 56 57 if len(list) == 0 { 58 return nil, libnetwork.ErrNoSuchNetwork(partialID) 59 } 60 if len(list) > 1 { 61 return nil, libnetwork.ErrInvalidID(partialID) 62 } 63 return list[0], nil 64 } 65 66 // GetNetworkByName function returns a network for a given network name. 67 // If no network name is given, the default network is returned. 68 func (daemon *Daemon) GetNetworkByName(name string) (libnetwork.Network, error) { 69 c := daemon.netController 70 if c == nil { 71 return nil, libnetwork.ErrNoSuchNetwork(name) 72 } 73 if name == "" { 74 name = c.Config().Daemon.DefaultNetwork 75 } 76 return c.NetworkByName(name) 77 } 78 79 // GetNetworksByID returns a list of networks whose ID partially matches zero or more networks 80 func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network { 81 c := daemon.netController 82 if c == nil { 83 return nil 84 } 85 list := []libnetwork.Network{} 86 l := func(nw libnetwork.Network) bool { 87 if strings.HasPrefix(nw.ID(), partialID) { 88 list = append(list, nw) 89 } 90 return false 91 } 92 c.WalkNetworks(l) 93 94 return list 95 } 96 97 // getAllNetworks returns a list containing all networks 98 func (daemon *Daemon) getAllNetworks() []libnetwork.Network { 99 c := daemon.netController 100 list := []libnetwork.Network{} 101 l := func(nw libnetwork.Network) bool { 102 list = append(list, nw) 103 return false 104 } 105 c.WalkNetworks(l) 106 107 return list 108 } 109 110 func isIngressNetwork(name string) bool { 111 return name == "ingress" 112 } 113 114 var ingressChan = make(chan struct{}, 1) 115 116 func ingressWait() func() { 117 ingressChan <- struct{}{} 118 return func() { <-ingressChan } 119 } 120 121 // SetupIngress setups ingress networking. 122 func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nodeIP string) error { 123 ip, _, err := net.ParseCIDR(nodeIP) 124 if err != nil { 125 return err 126 } 127 128 go func() { 129 controller := daemon.netController 130 controller.AgentInitWait() 131 132 if n, err := daemon.GetNetworkByName(create.Name); err == nil && n != nil && n.ID() != create.ID { 133 if err := controller.SandboxDestroy("ingress-sbox"); err != nil { 134 logrus.Errorf("Failed to delete stale ingress sandbox: %v", err) 135 return 136 } 137 138 // Cleanup any stale endpoints that might be left over during previous iterations 139 epList := n.Endpoints() 140 for _, ep := range epList { 141 if err := ep.Delete(true); err != nil { 142 logrus.Errorf("Failed to delete endpoint %s (%s): %v", ep.Name(), ep.ID(), err) 143 } 144 } 145 146 if err := n.Delete(); err != nil { 147 logrus.Errorf("Failed to delete stale ingress network %s: %v", n.ID(), err) 148 return 149 } 150 } 151 152 if _, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true); err != nil { 153 // If it is any other error other than already 154 // exists error log error and return. 155 if _, ok := err.(libnetwork.NetworkNameError); !ok { 156 logrus.Errorf("Failed creating ingress network: %v", err) 157 return 158 } 159 160 // Otherwise continue down the call to create or recreate sandbox. 161 } 162 163 n, err := daemon.GetNetworkByID(create.ID) 164 if err != nil { 165 logrus.Errorf("Failed getting ingress network by id after creating: %v", err) 166 return 167 } 168 169 sb, err := controller.NewSandbox("ingress-sbox", libnetwork.OptionIngress()) 170 if err != nil { 171 if _, ok := err.(networktypes.ForbiddenError); !ok { 172 logrus.Errorf("Failed creating ingress sandbox: %v", err) 173 } 174 return 175 } 176 177 ep, err := n.CreateEndpoint("ingress-endpoint", libnetwork.CreateOptionIpam(ip, nil, nil, nil)) 178 if err != nil { 179 logrus.Errorf("Failed creating ingress endpoint: %v", err) 180 return 181 } 182 183 if err := ep.Join(sb, nil); err != nil { 184 logrus.Errorf("Failed joining ingress sandbox to ingress endpoint: %v", err) 185 } 186 187 if err := sb.EnableService(); err != nil { 188 logrus.WithError(err).Error("Failed enabling service for ingress sandbox") 189 } 190 }() 191 192 return nil 193 } 194 195 // SetNetworkBootstrapKeys sets the bootstrap keys. 196 func (daemon *Daemon) SetNetworkBootstrapKeys(keys []*networktypes.EncryptionKey) error { 197 return daemon.netController.SetKeys(keys) 198 } 199 200 // UpdateAttachment notifies the attacher about the attachment config. 201 func (daemon *Daemon) UpdateAttachment(networkName, networkID, containerID string, config *network.NetworkingConfig) error { 202 if daemon.clusterProvider == nil { 203 return fmt.Errorf("cluster provider is not initialized") 204 } 205 206 if err := daemon.clusterProvider.UpdateAttachment(networkName, containerID, config); err != nil { 207 return daemon.clusterProvider.UpdateAttachment(networkID, containerID, config) 208 } 209 210 return nil 211 } 212 213 // WaitForDetachment makes the cluster manager wait for detachment of 214 // the container from the network. 215 func (daemon *Daemon) WaitForDetachment(ctx context.Context, networkName, networkID, taskID, containerID string) error { 216 if daemon.clusterProvider == nil { 217 return fmt.Errorf("cluster provider is not initialized") 218 } 219 220 return daemon.clusterProvider.WaitForDetachment(ctx, networkName, networkID, taskID, containerID) 221 } 222 223 // CreateManagedNetwork creates an agent network. 224 func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error { 225 _, err := daemon.createNetwork(create.NetworkCreateRequest, create.ID, true) 226 return err 227 } 228 229 // CreateNetwork creates a network with the given name, driver and other optional parameters 230 func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) { 231 resp, err := daemon.createNetwork(create, "", false) 232 if err != nil { 233 return nil, err 234 } 235 return resp, err 236 } 237 238 func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) { 239 // If there is a pending ingress network creation wait here 240 // since ingress network creation can happen via node download 241 // from manager or task download. 242 if isIngressNetwork(create.Name) { 243 defer ingressWait()() 244 } 245 246 if runconfig.IsPreDefinedNetwork(create.Name) && !agent { 247 err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name) 248 return nil, apierrors.NewRequestForbiddenError(err) 249 } 250 251 var warning string 252 nw, err := daemon.GetNetworkByName(create.Name) 253 if err != nil { 254 if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok { 255 return nil, err 256 } 257 } 258 if nw != nil { 259 if create.CheckDuplicate { 260 return nil, libnetwork.NetworkNameError(create.Name) 261 } 262 warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID()) 263 } 264 265 c := daemon.netController 266 driver := create.Driver 267 if driver == "" { 268 driver = c.Config().Daemon.DefaultDriver 269 } 270 271 nwOptions := []libnetwork.NetworkOption{ 272 libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6), 273 libnetwork.NetworkOptionDriverOpts(create.Options), 274 libnetwork.NetworkOptionLabels(create.Labels), 275 libnetwork.NetworkOptionAttachable(create.Attachable), 276 } 277 278 if create.IPAM != nil { 279 ipam := create.IPAM 280 v4Conf, v6Conf, err := getIpamConfig(ipam.Config) 281 if err != nil { 282 return nil, err 283 } 284 nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options)) 285 } 286 287 if create.Internal { 288 nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork()) 289 } 290 if agent { 291 nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic()) 292 nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false)) 293 } 294 295 if isIngressNetwork(create.Name) { 296 nwOptions = append(nwOptions, libnetwork.NetworkOptionIngress()) 297 } 298 299 n, err := c.NewNetwork(driver, create.Name, id, nwOptions...) 300 if err != nil { 301 return nil, err 302 } 303 304 daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.ACQUIRE) 305 if create.IPAM != nil { 306 daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.ACQUIRE) 307 } 308 daemon.LogNetworkEvent(n, "create") 309 310 return &types.NetworkCreateResponse{ 311 ID: n.ID(), 312 Warning: warning, 313 }, nil 314 } 315 316 func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) { 317 var builtinDrivers []string 318 319 if capability == driverapi.NetworkPluginEndpointType { 320 builtinDrivers = daemon.netController.BuiltinDrivers() 321 } else if capability == ipamapi.PluginEndpointType { 322 builtinDrivers = daemon.netController.BuiltinIPAMDrivers() 323 } 324 325 for _, d := range builtinDrivers { 326 if d == driver { 327 return 328 } 329 } 330 331 if daemon.PluginStore != nil { 332 _, err := daemon.PluginStore.Get(driver, capability, mode) 333 if err != nil { 334 logrus.WithError(err).WithFields(logrus.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation") 335 } 336 } 337 } 338 339 func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) { 340 ipamV4Cfg := []*libnetwork.IpamConf{} 341 ipamV6Cfg := []*libnetwork.IpamConf{} 342 for _, d := range data { 343 iCfg := libnetwork.IpamConf{} 344 iCfg.PreferredPool = d.Subnet 345 iCfg.SubPool = d.IPRange 346 iCfg.Gateway = d.Gateway 347 iCfg.AuxAddresses = d.AuxAddress 348 ip, _, err := net.ParseCIDR(d.Subnet) 349 if err != nil { 350 return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err) 351 } 352 if ip.To4() != nil { 353 ipamV4Cfg = append(ipamV4Cfg, &iCfg) 354 } else { 355 ipamV6Cfg = append(ipamV6Cfg, &iCfg) 356 } 357 } 358 return ipamV4Cfg, ipamV6Cfg, nil 359 } 360 361 // UpdateContainerServiceConfig updates a service configuration. 362 func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error { 363 container, err := daemon.GetContainer(containerName) 364 if err != nil { 365 return err 366 } 367 368 container.NetworkSettings.Service = serviceConfig 369 return nil 370 } 371 372 // ConnectContainerToNetwork connects the given container to the given 373 // network. If either cannot be found, an err is returned. If the 374 // network cannot be set up, an err is returned. 375 func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error { 376 if runtime.GOOS == "solaris" { 377 return errors.New("docker network connect is unsupported on Solaris platform") 378 } 379 container, err := daemon.GetContainer(containerName) 380 if err != nil { 381 return err 382 } 383 return daemon.ConnectToNetwork(container, networkName, endpointConfig) 384 } 385 386 // DisconnectContainerFromNetwork disconnects the given container from 387 // the given network. If either cannot be found, an err is returned. 388 func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error { 389 if runtime.GOOS == "solaris" { 390 return errors.New("docker network disconnect is unsupported on Solaris platform") 391 } 392 container, err := daemon.GetContainer(containerName) 393 if err != nil { 394 if force { 395 return daemon.ForceEndpointDelete(containerName, networkName) 396 } 397 return err 398 } 399 return daemon.DisconnectFromNetwork(container, networkName, force) 400 } 401 402 // GetNetworkDriverList returns the list of plugins drivers 403 // registered for network. 404 func (daemon *Daemon) GetNetworkDriverList() []string { 405 if !daemon.NetworkControllerEnabled() { 406 return nil 407 } 408 409 pluginList := daemon.netController.BuiltinDrivers() 410 411 managedPlugins := daemon.PluginStore.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType) 412 413 for _, plugin := range managedPlugins { 414 pluginList = append(pluginList, plugin.Name()) 415 } 416 417 pluginMap := make(map[string]bool) 418 for _, plugin := range pluginList { 419 pluginMap[plugin] = true 420 } 421 422 networks := daemon.netController.Networks() 423 424 for _, network := range networks { 425 if !pluginMap[network.Type()] { 426 pluginList = append(pluginList, network.Type()) 427 pluginMap[network.Type()] = true 428 } 429 } 430 431 sort.Strings(pluginList) 432 433 return pluginList 434 } 435 436 // DeleteManagedNetwork deletes an agent network. 437 func (daemon *Daemon) DeleteManagedNetwork(networkID string) error { 438 return daemon.deleteNetwork(networkID, true) 439 } 440 441 // DeleteNetwork destroys a network unless it's one of docker's predefined networks. 442 func (daemon *Daemon) DeleteNetwork(networkID string) error { 443 return daemon.deleteNetwork(networkID, false) 444 } 445 446 func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error { 447 nw, err := daemon.FindNetwork(networkID) 448 if err != nil { 449 return err 450 } 451 452 if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic { 453 err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name()) 454 return apierrors.NewRequestForbiddenError(err) 455 } 456 457 if err := nw.Delete(); err != nil { 458 return err 459 } 460 daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.RELEASE) 461 ipamType, _, _, _ := nw.Info().IpamConfig() 462 daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.RELEASE) 463 daemon.LogNetworkEvent(nw, "destroy") 464 return nil 465 } 466 467 // GetNetworks returns a list of all networks 468 func (daemon *Daemon) GetNetworks() []libnetwork.Network { 469 return daemon.getAllNetworks() 470 } 471 472 // clearAttachableNetworks removes the attachable networks 473 // after disconnecting any connected container 474 func (daemon *Daemon) clearAttachableNetworks() { 475 for _, n := range daemon.GetNetworks() { 476 if !n.Info().Attachable() { 477 continue 478 } 479 for _, ep := range n.Endpoints() { 480 epInfo := ep.Info() 481 if epInfo == nil { 482 continue 483 } 484 sb := epInfo.Sandbox() 485 if sb == nil { 486 continue 487 } 488 containerID := sb.ContainerID() 489 if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil { 490 logrus.Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v", 491 containerID, n.Name(), err) 492 } 493 } 494 if err := daemon.DeleteManagedNetwork(n.ID()); err != nil { 495 logrus.Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err) 496 } 497 } 498 }