github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/libnetwork/sandbox_linux.go (about) 1 package libnetwork 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "time" 8 9 "github.com/containerd/log" 10 "github.com/docker/docker/libnetwork/netutils" 11 "github.com/docker/docker/libnetwork/osl" 12 "github.com/docker/docker/libnetwork/types" 13 ) 14 15 func releaseOSSboxResources(ns *osl.Namespace, ep *Endpoint) { 16 for _, i := range ns.Interfaces() { 17 // Only remove the interfaces owned by this endpoint from the sandbox. 18 if ep.hasInterface(i.SrcName()) { 19 if err := i.Remove(); err != nil { 20 log.G(context.TODO()).Debugf("Remove interface %s failed: %v", i.SrcName(), err) 21 } 22 } 23 } 24 25 ep.mu.Lock() 26 joinInfo := ep.joinInfo 27 vip := ep.virtualIP 28 lbModeIsDSR := ep.network.loadBalancerMode == loadBalancerModeDSR 29 ep.mu.Unlock() 30 31 if len(vip) > 0 && lbModeIsDSR { 32 ipNet := &net.IPNet{IP: vip, Mask: net.CIDRMask(32, 32)} 33 if err := ns.RemoveAliasIP(ns.GetLoopbackIfaceName(), ipNet); err != nil { 34 log.G(context.TODO()).WithError(err).Debugf("failed to remove virtual ip %v to loopback", ipNet) 35 } 36 } 37 38 if joinInfo == nil { 39 return 40 } 41 42 // Remove non-interface routes. 43 for _, r := range joinInfo.StaticRoutes { 44 if err := ns.RemoveStaticRoute(r); err != nil { 45 log.G(context.TODO()).Debugf("Remove route failed: %v", err) 46 } 47 } 48 } 49 50 // Statistics retrieves the interfaces' statistics for the sandbox. 51 func (sb *Sandbox) Statistics() (map[string]*types.InterfaceStatistics, error) { 52 m := make(map[string]*types.InterfaceStatistics) 53 54 sb.mu.Lock() 55 osb := sb.osSbox 56 sb.mu.Unlock() 57 if osb == nil { 58 return m, nil 59 } 60 61 var err error 62 for _, i := range osb.Interfaces() { 63 if m[i.DstName()], err = i.Statistics(); err != nil { 64 return m, err 65 } 66 } 67 68 return m, nil 69 } 70 71 func (sb *Sandbox) updateGateway(ep *Endpoint) error { 72 sb.mu.Lock() 73 osSbox := sb.osSbox 74 sb.mu.Unlock() 75 if osSbox == nil { 76 return nil 77 } 78 osSbox.UnsetGateway() //nolint:errcheck 79 osSbox.UnsetGatewayIPv6() //nolint:errcheck 80 81 if ep == nil { 82 return nil 83 } 84 85 ep.mu.Lock() 86 joinInfo := ep.joinInfo 87 ep.mu.Unlock() 88 89 if err := osSbox.SetGateway(joinInfo.gw); err != nil { 90 return fmt.Errorf("failed to set gateway while updating gateway: %v", err) 91 } 92 93 if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil { 94 return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err) 95 } 96 97 return nil 98 } 99 100 func (sb *Sandbox) ExecFunc(f func()) error { 101 sb.mu.Lock() 102 osSbox := sb.osSbox 103 sb.mu.Unlock() 104 if osSbox != nil { 105 return osSbox.InvokeFunc(f) 106 } 107 return fmt.Errorf("osl sandbox unavailable in ExecFunc for %v", sb.ContainerID()) 108 } 109 110 // SetKey updates the Sandbox Key. 111 func (sb *Sandbox) SetKey(basePath string) error { 112 start := time.Now() 113 defer func() { 114 log.G(context.TODO()).Debugf("sandbox set key processing took %s for container %s", time.Since(start), sb.ContainerID()) 115 }() 116 117 if basePath == "" { 118 return types.InvalidParameterErrorf("invalid sandbox key") 119 } 120 121 sb.mu.Lock() 122 if sb.inDelete { 123 sb.mu.Unlock() 124 return types.ForbiddenErrorf("failed to SetKey: sandbox %q delete in progress", sb.id) 125 } 126 oldosSbox := sb.osSbox 127 sb.mu.Unlock() 128 129 if oldosSbox != nil { 130 // If we already have an OS sandbox, release the network resources from that 131 // and destroy the OS snab. We are moving into a new home further down. Note that none 132 // of the network resources gets destroyed during the move. 133 if err := sb.releaseOSSbox(); err != nil { 134 log.G(context.TODO()).WithError(err).Error("Error destroying os sandbox") 135 } 136 } 137 138 osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key()) 139 if err != nil { 140 return err 141 } 142 143 sb.mu.Lock() 144 sb.osSbox = osSbox 145 sb.mu.Unlock() 146 147 // If the resolver was setup before stop it and set it up in the 148 // new osl sandbox. 149 if oldosSbox != nil && sb.resolver != nil { 150 sb.resolver.Stop() 151 152 if err := sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err == nil { 153 if err := sb.resolver.Start(); err != nil { 154 log.G(context.TODO()).Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err) 155 } 156 } else { 157 log.G(context.TODO()).Errorf("Resolver Setup Function failed for container %s, %q", sb.ContainerID(), err) 158 } 159 } 160 161 if err := sb.finishInitDNS(); err != nil { 162 return err 163 } 164 165 for _, ep := range sb.Endpoints() { 166 if err = sb.populateNetworkResources(ep); err != nil { 167 return err 168 } 169 } 170 171 return nil 172 } 173 174 // IPv6 support can always be determined for host networking. For other network 175 // types it can only be determined once there's a container namespace to probe, 176 // return ok=false in that case. 177 func (sb *Sandbox) ipv6Enabled() (enabled, ok bool) { 178 // For host networking, IPv6 support depends on the host. 179 if sb.config.useDefaultSandBox { 180 return netutils.IsV6Listenable(), true 181 } 182 183 // For other network types, look at whether the container's loopback interface has an IPv6 address. 184 sb.mu.Lock() 185 osSbox := sb.osSbox 186 sb.mu.Unlock() 187 188 if osSbox == nil { 189 return false, false 190 } 191 return osSbox.IPv6LoEnabled(), true 192 } 193 194 func (sb *Sandbox) releaseOSSbox() error { 195 sb.mu.Lock() 196 osSbox := sb.osSbox 197 sb.osSbox = nil 198 sb.mu.Unlock() 199 200 if osSbox == nil { 201 return nil 202 } 203 204 for _, ep := range sb.Endpoints() { 205 releaseOSSboxResources(osSbox, ep) 206 } 207 208 return osSbox.Destroy() 209 } 210 211 func (sb *Sandbox) restoreOslSandbox() error { 212 var routes []*types.StaticRoute 213 214 // restore osl sandbox 215 interfaces := make(map[osl.Iface][]osl.IfaceOption) 216 for _, ep := range sb.endpoints { 217 ep.mu.Lock() 218 joinInfo := ep.joinInfo 219 i := ep.iface 220 ep.mu.Unlock() 221 222 if i == nil { 223 log.G(context.TODO()).Errorf("error restoring endpoint %s for container %s", ep.Name(), sb.ContainerID()) 224 continue 225 } 226 227 ifaceOptions := []osl.IfaceOption{ 228 osl.WithIPv4Address(i.addr), 229 osl.WithRoutes(i.routes), 230 } 231 if i.addrv6 != nil && i.addrv6.IP.To16() != nil { 232 ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6)) 233 } 234 if i.mac != nil { 235 ifaceOptions = append(ifaceOptions, osl.WithMACAddress(i.mac)) 236 } 237 if len(i.llAddrs) != 0 { 238 ifaceOptions = append(ifaceOptions, osl.WithLinkLocalAddresses(i.llAddrs)) 239 } 240 interfaces[osl.Iface{SrcName: i.srcName, DstPrefix: i.dstPrefix}] = ifaceOptions 241 if joinInfo != nil { 242 routes = append(routes, joinInfo.StaticRoutes...) 243 } 244 if ep.needResolver() { 245 sb.startResolver(true) 246 } 247 } 248 249 gwep := sb.getGatewayEndpoint() 250 if gwep == nil { 251 return nil 252 } 253 254 // restore osl sandbox 255 return sb.osSbox.Restore(interfaces, routes, gwep.joinInfo.gw, gwep.joinInfo.gw6) 256 } 257 258 func (sb *Sandbox) populateNetworkResources(ep *Endpoint) error { 259 sb.mu.Lock() 260 if sb.osSbox == nil { 261 sb.mu.Unlock() 262 return nil 263 } 264 inDelete := sb.inDelete 265 sb.mu.Unlock() 266 267 ep.mu.Lock() 268 joinInfo := ep.joinInfo 269 i := ep.iface 270 lbModeIsDSR := ep.network.loadBalancerMode == loadBalancerModeDSR 271 ep.mu.Unlock() 272 273 if ep.needResolver() { 274 sb.startResolver(false) 275 } 276 277 if i != nil && i.srcName != "" { 278 var ifaceOptions []osl.IfaceOption 279 280 ifaceOptions = append(ifaceOptions, osl.WithIPv4Address(i.addr), osl.WithRoutes(i.routes)) 281 if i.addrv6 != nil && i.addrv6.IP.To16() != nil { 282 ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6)) 283 } 284 if len(i.llAddrs) != 0 { 285 ifaceOptions = append(ifaceOptions, osl.WithLinkLocalAddresses(i.llAddrs)) 286 } 287 if i.mac != nil { 288 ifaceOptions = append(ifaceOptions, osl.WithMACAddress(i.mac)) 289 } 290 291 if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil { 292 return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err) 293 } 294 295 if len(ep.virtualIP) > 0 && lbModeIsDSR { 296 if sb.loadBalancerNID == "" { 297 if err := sb.osSbox.DisableARPForVIP(i.srcName); err != nil { 298 return fmt.Errorf("failed disable ARP for VIP: %v", err) 299 } 300 } 301 ipNet := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)} 302 if err := sb.osSbox.AddAliasIP(sb.osSbox.GetLoopbackIfaceName(), ipNet); err != nil { 303 return fmt.Errorf("failed to add virtual ip %v to loopback: %v", ipNet, err) 304 } 305 } 306 } 307 308 if joinInfo != nil { 309 // Set up non-interface routes. 310 for _, r := range joinInfo.StaticRoutes { 311 if err := sb.osSbox.AddStaticRoute(r); err != nil { 312 return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err) 313 } 314 } 315 } 316 317 if ep == sb.getGatewayEndpoint() { 318 if err := sb.updateGateway(ep); err != nil { 319 return err 320 } 321 } 322 323 // Make sure to add the endpoint to the populated endpoint set 324 // before populating loadbalancers. 325 sb.mu.Lock() 326 sb.populatedEndpoints[ep.ID()] = struct{}{} 327 sb.mu.Unlock() 328 329 // Populate load balancer only after updating all the other 330 // information including gateway and other routes so that 331 // loadbalancers are populated all the network state is in 332 // place in the sandbox. 333 sb.populateLoadBalancers(ep) 334 335 // Only update the store if we did not come here as part of 336 // sandbox delete. If we came here as part of delete then do 337 // not bother updating the store. The sandbox object will be 338 // deleted anyway 339 if !inDelete { 340 return sb.storeUpdate() 341 } 342 343 return nil 344 }