github.com/khulnasoft-lab/khulnasoft@v26.0.1-0.20240328202558-330a6f959fe0+incompatible/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 // Set up hosts and resolv.conf files. IPv6 support in the container can't be 162 // determined yet, as sysctls haven't been applied by the runtime. Calling 163 // FinishInit after the container task has been created, when sysctls have been 164 // applied will regenerate these files. 165 if err := sb.finishInitDNS(); err != nil { 166 return err 167 } 168 169 for _, ep := range sb.Endpoints() { 170 if err = sb.populateNetworkResources(ep); err != nil { 171 return err 172 } 173 } 174 175 return nil 176 } 177 178 // FinishConfig completes Sandbox configuration. If called after the container task has been 179 // created, and sysctl settings applied, the configuration will be based on the container's 180 // IPv6 support. 181 func (sb *Sandbox) FinishConfig() error { 182 if sb.config.useDefaultSandBox { 183 return nil 184 } 185 186 sb.mu.Lock() 187 osSbox := sb.osSbox 188 sb.mu.Unlock() 189 if osSbox == nil { 190 return nil 191 } 192 193 // If sysctl changes have been made, IPv6 may have been enabled/disabled since last checked. 194 osSbox.RefreshIPv6LoEnabled() 195 196 return sb.finishInitDNS() 197 } 198 199 // IPv6 support can always be determined for host networking. For other network 200 // types it can only be determined once there's a container namespace to probe, 201 // return ok=false in that case. 202 func (sb *Sandbox) ipv6Enabled() (enabled, ok bool) { 203 // For host networking, IPv6 support depends on the host. 204 if sb.config.useDefaultSandBox { 205 return netutils.IsV6Listenable(), true 206 } 207 208 // For other network types, look at whether the container's loopback interface has an IPv6 address. 209 sb.mu.Lock() 210 osSbox := sb.osSbox 211 sb.mu.Unlock() 212 213 if osSbox == nil { 214 return false, false 215 } 216 return osSbox.IPv6LoEnabled(), true 217 } 218 219 func (sb *Sandbox) releaseOSSbox() error { 220 sb.mu.Lock() 221 osSbox := sb.osSbox 222 sb.osSbox = nil 223 sb.mu.Unlock() 224 225 if osSbox == nil { 226 return nil 227 } 228 229 for _, ep := range sb.Endpoints() { 230 releaseOSSboxResources(osSbox, ep) 231 } 232 233 return osSbox.Destroy() 234 } 235 236 func (sb *Sandbox) restoreOslSandbox() error { 237 var routes []*types.StaticRoute 238 239 // restore osl sandbox 240 interfaces := make(map[osl.Iface][]osl.IfaceOption) 241 for _, ep := range sb.endpoints { 242 ep.mu.Lock() 243 joinInfo := ep.joinInfo 244 i := ep.iface 245 ep.mu.Unlock() 246 247 if i == nil { 248 log.G(context.TODO()).Errorf("error restoring endpoint %s for container %s", ep.Name(), sb.ContainerID()) 249 continue 250 } 251 252 ifaceOptions := []osl.IfaceOption{ 253 osl.WithIPv4Address(i.addr), 254 osl.WithRoutes(i.routes), 255 } 256 if i.addrv6 != nil && i.addrv6.IP.To16() != nil { 257 ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6)) 258 } 259 if i.mac != nil { 260 ifaceOptions = append(ifaceOptions, osl.WithMACAddress(i.mac)) 261 } 262 if len(i.llAddrs) != 0 { 263 ifaceOptions = append(ifaceOptions, osl.WithLinkLocalAddresses(i.llAddrs)) 264 } 265 interfaces[osl.Iface{SrcName: i.srcName, DstPrefix: i.dstPrefix}] = ifaceOptions 266 if joinInfo != nil { 267 routes = append(routes, joinInfo.StaticRoutes...) 268 } 269 if ep.needResolver() { 270 sb.startResolver(true) 271 } 272 } 273 274 gwep := sb.getGatewayEndpoint() 275 if gwep == nil { 276 return nil 277 } 278 279 // restore osl sandbox 280 return sb.osSbox.Restore(interfaces, routes, gwep.joinInfo.gw, gwep.joinInfo.gw6) 281 } 282 283 func (sb *Sandbox) populateNetworkResources(ep *Endpoint) error { 284 sb.mu.Lock() 285 if sb.osSbox == nil { 286 sb.mu.Unlock() 287 return nil 288 } 289 inDelete := sb.inDelete 290 sb.mu.Unlock() 291 292 ep.mu.Lock() 293 joinInfo := ep.joinInfo 294 i := ep.iface 295 lbModeIsDSR := ep.network.loadBalancerMode == loadBalancerModeDSR 296 ep.mu.Unlock() 297 298 if ep.needResolver() { 299 sb.startResolver(false) 300 } 301 302 if i != nil && i.srcName != "" { 303 var ifaceOptions []osl.IfaceOption 304 305 ifaceOptions = append(ifaceOptions, osl.WithIPv4Address(i.addr), osl.WithRoutes(i.routes)) 306 if i.addrv6 != nil && i.addrv6.IP.To16() != nil { 307 ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6)) 308 } 309 if len(i.llAddrs) != 0 { 310 ifaceOptions = append(ifaceOptions, osl.WithLinkLocalAddresses(i.llAddrs)) 311 } 312 if i.mac != nil { 313 ifaceOptions = append(ifaceOptions, osl.WithMACAddress(i.mac)) 314 } 315 316 if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil { 317 return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err) 318 } 319 320 if len(ep.virtualIP) > 0 && lbModeIsDSR { 321 if sb.loadBalancerNID == "" { 322 if err := sb.osSbox.DisableARPForVIP(i.srcName); err != nil { 323 return fmt.Errorf("failed disable ARP for VIP: %v", err) 324 } 325 } 326 ipNet := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)} 327 if err := sb.osSbox.AddAliasIP(sb.osSbox.GetLoopbackIfaceName(), ipNet); err != nil { 328 return fmt.Errorf("failed to add virtual ip %v to loopback: %v", ipNet, err) 329 } 330 } 331 } 332 333 if joinInfo != nil { 334 // Set up non-interface routes. 335 for _, r := range joinInfo.StaticRoutes { 336 if err := sb.osSbox.AddStaticRoute(r); err != nil { 337 return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err) 338 } 339 } 340 } 341 342 if ep == sb.getGatewayEndpoint() { 343 if err := sb.updateGateway(ep); err != nil { 344 return err 345 } 346 } 347 348 // Make sure to add the endpoint to the populated endpoint set 349 // before populating loadbalancers. 350 sb.mu.Lock() 351 sb.populatedEndpoints[ep.ID()] = struct{}{} 352 sb.mu.Unlock() 353 354 // Populate load balancer only after updating all the other 355 // information including gateway and other routes so that 356 // loadbalancers are populated all the network state is in 357 // place in the sandbox. 358 sb.populateLoadBalancers(ep) 359 360 // Only update the store if we did not come here as part of 361 // sandbox delete. If we came here as part of delete then do 362 // not bother updating the store. The sandbox object will be 363 // deleted anyway 364 if !inDelete { 365 return sb.storeUpdate() 366 } 367 368 return nil 369 }