Repository: moby/moby
Pull request #49740: builder-next: add buildkit executor for wcow
Author: login: profnandaa
Labels: name: area/builder
description: Build
name: status/2-code-review
name: kind/feature
description: Functionality or other elements that the project doesn't currently have. Features are new and shiny
name: impact/changelog
name: area/builder/buildkit
description: Build
Created: 2025-04-03T18:40:17Z | Merged: 2025-05-22T11:42:28Z

WCOW support on Buildkit is now coming to maturity. As part of making this generally available, integrating it in
Docker Engine is critical for it's adoption.

This commit adds the buildkit execuitor for WCOW as the next-builder (backend) for building Windows containers.

This will be an opt-in feature, with the end users setting DOCKER_BUILDKIT=1 environment variable to use it.

The integration tests bit has also been handled.  Since https://github.com/moby/buildkit/pull/5956 has been merged,
BUILDKIT_REF has been set to properly.

### How I did it

I update the code for `newExecutor()` from the `_nolinux.go` to a Windows-specific one in `executor_windows.go` and split it into two depending on where it is called from:

* `newSnapshotterController()` --> `newExecutor()`
* `newGraphdriverController()` --> `newExecutorGD()`, just the previous stub, renamed.

For the networking bit, I re-used the same `bridgeProvider` logic used for Linux, with some minor modification, e.g. `networkName = "nat"` and critically, the `Set()` method for `lnInteface` to set the right networking endpoint details in the run-spec. That piece of logic, I adapted it from [`daemon/oci_windows.go`](https://github.com/moby/moby/blob/453c165be709d294ab744f2efbd2552b338bb1a0/daemon/oci_windows.go#L148-L210)

### How to verify it

* See the demo notes below.
* I have also updated the buildkit CI pipeline that is now using the `dockerd-containerd` worker in the integration tests.

**- A picture of a cute animal (not mandatory but encouraged)**
```
<*))))><
```

---
### Demo

I have this prototype currently working. Opening this PR to seek some direction on approach.
A few notes to run this:

On my case, I'm running on Windows 11, ymmv.

1) Basic build script:
```powershell
# cat .\build-binaries.ps1
docker rm $(docker ps -a -q)

docker build -t nativebuildimage -f Dockerfile.windows -m 2GB .

$DOCKER_GITCOMMIT=(git rev-parse --short HEAD)
docker run --name binaries -e DOCKER_GITCOMMIT=$DOCKER_GITCOMMIT -m 2GB nativebuildimage hack\make.ps1 -Binary

docker cp binaries:C:\gopath\src\github.com\docker\docker\bundles\dockerd.exe dockerd.exe
```

2) Need this config for your daemon:
```jsonc
// cat  C:\ProgramData\Docker\config\daemon.json
{
  "hosts": [
    "npipe:////./pipe/docker_engine_windows"
  ],
  "default-runtime": "io.containerd.runhcs.v1",
  "features": {
    "containerd-snapshotter": true
  }
}
```

3) Place the `containerd.exe` and `containerd-shim-runhcs-v1.exe` binaries in the same directory where your `dockerd.exe` is; then run the built `.\dockerd.exe`. Can see my daemon logs here - https://paste.opensuse.org/pastes/c234cb981201

4) You have to use the docker CLI that ships with docker desktop to run this, providing the named pipe for the custom dockerd.
(the one that ships with the daemon calls into the classic builder even with `$env:DOCKER_BUILDKIT=1`)
```powershell
$env:DOCKER_BUILDKIT=1

docker -H "npipe:////./pipe/docker_engine_windows" build -t hello-next . --no-cache
```
This is for a basic dockerfile:
```dockerfile
FROM mcr.microsoft.com/windows/nanoserver:ltsc2022

RUN echo "hello world!"
```
![image](https://github.com/user-attachments/assets/3c6ddb7f-bfdc-47b8-a0bf-09bf4a2af648)


```markdown changelog
containerd image store: Initial BuildKit support for building Windows container images on Windows (requires an opt-in with `DOCKER_BUILDKIT=1`).
```



Diff:
diff --git a/.github/workflows/buildkit.yml b/.github/workflows/buildkit.yml
index 97ee2cb15fe47..89f646a05881c 100644
--- a/.github/workflows/buildkit.yml
+++ b/.github/workflows/buildkit.yml
@@ -32,7 +32,7 @@ jobs:
   validate-dco:
     uses: ./.github/workflows/.dco.yml
 
-  build:
+  build-linux:
     runs-on: ubuntu-24.04
     timeout-minutes: 120 # guardrails timeout for the whole job
     needs:
@@ -59,11 +59,11 @@ jobs:
           if-no-files-found: error
           retention-days: 1
 
-  test:
+  test-linux:
     runs-on: ubuntu-24.04
     timeout-minutes: 120 # guardrails timeout for the whole job
     needs:
-      - build
+      - build-linux
     env:
       TEST_IMAGE_BUILD: "0"
       TEST_IMAGE_ID: "buildkit-tests"
@@ -162,3 +162,213 @@ jobs:
           TESTPKGS: "./${{ matrix.pkg }}"
           TESTFLAGS: "-v --parallel=1 --timeout=30m --run=//worker=${{ matrix.worker }}$"
         working-directory: buildkit
+
+  build-windows:
+    runs-on: windows-2022
+    timeout-minutes: 120
+    needs:
+      - validate-dco
+    env:
+      GOPATH: ${{ github.workspace }}\go
+      GOBIN: ${{ github.workspace }}\go\bin
+      BIN_OUT: ${{ github.workspace }}\out
+      WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
+      WINDOWS_BASE_TAG_2022: ltsc2022
+      TEST_IMAGE_NAME: moby:test
+      TEST_CTN_NAME: moby
+    defaults:
+      run:
+        working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+        with:
+          path: ${{ env.GOPATH }}/src/github.com/docker/docker
+
+      - name: Env
+        run: |
+          Get-ChildItem Env: | Out-String
+      - name: Moby - Init
+        run: |
+          New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
+          New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
+          echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
+
+      - name: Set up Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: ${{ env.GO_VERSION }}
+          cache-dependency-path: vendor.sum
+      - name: Cache
+        uses: actions/cache@v4
+        with:
+          path: |
+            ~\AppData\Local\go-build
+            ~\go\pkg\mod
+            ${{ github.workspace }}\go-build
+            ${{ env.GOPATH }}\pkg\mod
+          key: ${{ inputs.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
+          restore-keys: |
+            ${{ inputs.os }}-${{ github.job }}-
+
+      - name: Docker info
+        run: |
+          docker info
+
+      - name: Build base image
+        run: |
+          & docker build `
+            --build-arg WINDOWS_BASE_IMAGE `
+            --build-arg WINDOWS_BASE_IMAGE_TAG `
+            --build-arg GO_VERSION `
+            -t ${{ env.TEST_IMAGE_NAME }} `
+            -f Dockerfile.windows .
+
+      - name: Build binaries
+        run: |
+          & docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" `
+              -v "${{ github.workspace }}\go-build:C:\Users\ContainerAdministrator\AppData\Local\go-build" `
+              -v "${{ github.workspace }}\go\pkg\mod:C:\gopath\pkg\mod" `
+              ${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -Daemon -Client
+          go install github.com/distribution/distribution/v3/cmd/registry@latest
+
+      - name: Checkout BuildKit
+        uses: actions/checkout@v4
+        with:
+          repository: moby/buildkit
+          ref: master
+          path: buildkit
+
+      - name: Add buildctl to binaries
+        run: |
+          go install ./cmd/buildctl
+        working-directory: buildkit
+
+      - name: Copy artifacts
+        run: |
+          New-Item -ItemType "directory" -Path "${{ env.BIN_OUT }}"
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\docker.exe" ${{ env.BIN_OUT }}\
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\dockerd.exe" ${{ env.BIN_OUT }}\
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\bin\gotestsum.exe" ${{ env.BIN_OUT }}\
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd.exe" ${{ env.BIN_OUT }}\
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd-shim-runhcs-v1.exe" ${{ env.BIN_OUT }}\
+          cp ${{ env.GOPATH }}\bin\registry.exe ${{ env.BIN_OUT }}
+          cp ${{ env.GOPATH }}\bin\buildctl.exe ${{ env.BIN_OUT }}
+
+      - name: Upload artifacts
+        uses: actions/upload-artifact@v4
+        with:
+          name: build-windows
+          path: ${{ env.BIN_OUT }}/*
+          if-no-files-found: error
+          retention-days: 2
+
+  test-windows:
+    runs-on: windows-2022
+    timeout-minutes: 120 # guardrails timeout for the whole job
+    needs:
+      - build-windows
+    env:
+      TEST_IMAGE_BUILD: "0"
+      TEST_IMAGE_ID: "buildkit-tests"
+      GOPATH: ${{ github.workspace }}\go
+      GOBIN: ${{ github.workspace }}\go\bin
+      BIN_OUT: ${{ github.workspace }}\out
+      TESTFLAGS: "-v --timeout=90m"
+      TEST_DOCKERD: "1"
+    strategy:
+      fail-fast: false
+      matrix:
+        worker:
+          - dockerd-containerd
+        pkg:
+          - ./client#1-4
+          - ./client#2-4
+          - ./client#3-4
+          - ./client#4-4
+          - ./cmd/buildctl
+          - ./frontend
+          - ./frontend/dockerfile#1-12
+          - ./frontend/dockerfile#2-12
+          - ./frontend/dockerfile#3-12
+          - ./frontend/dockerfile#4-12
+          - ./frontend/dockerfile#5-12
+          - ./frontend/dockerfile#6-12
+          - ./frontend/dockerfile#7-12
+          - ./frontend/dockerfile#8-12
+          - ./frontend/dockerfile#9-12
+          - ./frontend/dockerfile#10-12
+          - ./frontend/dockerfile#11-12
+          - ./frontend/dockerfile#12-12
+    steps:
+      - name: Prepare
+        shell: bash
+        run: |
+          disabledFeatures="cache_backend_azblob,cache_backend_s3"
+          if [ "${{ matrix.worker }}" = "dockerd" ]; then
+            disabledFeatures="${disabledFeatures},merge_diff"
+          fi
+          echo "BUILDKIT_TEST_DISABLE_FEATURES=${disabledFeatures}" >> $GITHUB_ENV
+      - name: Expose GitHub Runtime
+        uses: crazy-max/ghaction-github-runtime@v3
+      - name: Checkout
+        uses: actions/checkout@v4
+        with:
+          path: moby
+      - name: Set up Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: ${{ env.GO_VERSION }}
+          cache-dependency-path: vendor.sum
+      - name: BuildKit ref
+        shell: bash
+        run: |
+          echo "$(./hack/buildkit-ref)" >> $GITHUB_ENV
+        working-directory: moby
+      - name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
+        uses: actions/checkout@v4
+        with:
+          repository: ${{ env.BUILDKIT_REPO }}
+          ref: ${{ env.BUILDKIT_REF }}
+          path: buildkit
+
+      - name: Download Moby artifacts
+        uses: actions/download-artifact@v4
+        with:
+          name: build-windows
+          path: ${{ env.BIN_OUT }}
+
+      - name: Add binaries to PATH
+        run: |
+          ls ${{ env.BIN_OUT }}
+          Write-Output "${{ env.BIN_OUT }}" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+
+      - name: Test Prep
+        shell: bash
+        run: |
+          TESTPKG=$(echo "${{ matrix.pkg }}" | awk '-F#' '{print $1}')
+          echo "TESTPKG=$TESTPKG" >> $GITHUB_ENV
+          echo "TEST_REPORT_NAME=${{ github.job }}-$(echo "${{ matrix.pkg }}-${{ matrix.worker }}" | tr -dc '[:alnum:]-\n\r' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
+          testFlags="${{ env.TESTFLAGS }}"
+          testSlice=$(echo "${{ matrix.pkg }}" | awk '-F#' '{print $2}')
+          testSliceOffset=""
+          if [ -n "$testSlice" ]; then
+           testSliceOffset="slice=$testSlice/"
+          fi
+          if [ -n "${{ matrix.worker }}" ]; then
+           testFlags="${testFlags} --run=TestIntegration/$testSliceOffset.*/worker=${{ matrix.worker }}"
+          fi
+          echo "TESTFLAGS=${testFlags}" >> $GITHUB_ENV
+      - name: Test
+        shell: bash
+        run: |
+          mkdir -p ./bin/testreports
+          gotestsum \
+            --jsonfile="./bin/testreports/go-test-report-${{ env.TEST_REPORT_NAME }}.json" \
+            --junitfile="./bin/testreports/junit-report-${{ env.TEST_REPORT_NAME }}.xml" \
+            --packages="${{ env.TESTPKG }}" \
+            -- \
+              "-mod=vendor" \
+              "-coverprofile" "./bin/testreports/coverage-${{ env.TEST_REPORT_NAME }}.txt" \
+              "-covermode" "atomic" ${{ env.TESTFLAGS }}
+        working-directory: buildkit
diff --git a/builder/builder-next/controller.go b/builder/builder-next/controller.go
index 650b2b807e8a9..63db3098aa2b0 100644
--- a/builder/builder-next/controller.go
+++ b/builder/builder-next/controller.go
@@ -152,7 +152,18 @@ func newSnapshotterController(ctx context.Context, rt http.RoundTripper, opt Opt
 	wo.RegistryHosts = opt.RegistryHosts
 	wo.Labels = getLabels(opt, wo.Labels)
 
-	exec, err := newExecutor(opt.Root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile, cdiManager)
+	exec, err := newExecutor(
+		opt.Root,
+		opt.DefaultCgroupParent,
+		opt.NetworkController,
+		dns,
+		opt.Rootless,
+		opt.IdentityMapping,
+		opt.ApparmorProfile,
+		cdiManager,
+		opt.ContainerdAddress,
+		opt.ContainerdNamespace,
+	)
 	if err != nil {
 		return nil, err
 	}
@@ -335,7 +346,18 @@ func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt
 		return nil, err
 	}
 
-	exec, err := newExecutor(root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile, cdiManager)
+	exec, err := newExecutorGD(
+		root,
+		opt.DefaultCgroupParent,
+		opt.NetworkController,
+		dns,
+		opt.Rootless,
+		opt.IdentityMapping,
+		opt.ApparmorProfile,
+		cdiManager,
+		opt.ContainerdAddress,
+		opt.ContainerdNamespace,
+	)
 	if err != nil {
 		return nil, err
 	}
diff --git a/builder/builder-next/executor.go b/builder/builder-next/executor.go
new file mode 100644
index 0000000000000..dadbdabb9bad0
--- /dev/null
+++ b/builder/builder-next/executor.go
@@ -0,0 +1,119 @@
+package buildkit
+
+import (
+	"context"
+	"net"
+	"os"
+	"path/filepath"
+	"sync"
+
+	"github.com/containerd/log"
+	"github.com/docker/docker/daemon/config"
+	"github.com/docker/docker/libnetwork"
+	"github.com/moby/buildkit/executor/oci"
+	resourcestypes "github.com/moby/buildkit/executor/resources/types"
+	"github.com/moby/buildkit/identity"
+	"github.com/moby/buildkit/util/network"
+)
+
+type bridgeProvider struct {
+	*libnetwork.Controller
+	Root string
+}
+
+type lnInterface struct {
+	ep  *libnetwork.Endpoint
+	sbx *libnetwork.Sandbox
+	sync.Once
+	err      error
+	ready    chan struct{}
+	provider *bridgeProvider
+}
+
+func (p *bridgeProvider) New(_ context.Context, _ string) (network.Namespace, error) {
+	n, err := p.NetworkByName(networkName)
+	if err != nil {
+		return nil, err
+	}
+
+	iface := &lnInterface{ready: make(chan struct{}), provider: p}
+	iface.Once.Do(func() {
+		go iface.init(p.Controller, n)
+	})
+
+	return iface, nil
+}
+
+func (p *bridgeProvider) Close() error {
+	return nil
+}
+
+func (iface *lnInterface) init(c *libnetwork.Controller, n *libnetwork.Network) {
+	defer close(iface.ready)
+	id := identity.NewID()
+
+	ep, err := n.CreateEndpoint(context.TODO(), id, libnetwork.CreateOptionDisableResolution())
+	if err != nil {
+		iface.err = err
+		return
+	}
+
+	sbx, err := c.NewSandbox(
+		context.TODO(),
+		id,
+		libnetwork.OptionUseExternalKey(),
+		libnetwork.OptionHostsPath(filepath.Join(iface.provider.Root, id, "hosts")),
+		libnetwork.OptionResolvConfPath(filepath.Join(iface.provider.Root, id, "resolv.conf")),
+	)
+	if err != nil {
+		iface.err = err
+		return
+	}
+
+	if err := ep.Join(context.TODO(), sbx); err != nil {
+		iface.err = err
+		return
+	}
+
+	iface.sbx = sbx
+	iface.ep = ep
+}
+
+// TODO(neersighted): Unstub Sample(), and collect data from the libnetwork Endpoint.
+func (iface *lnInterface) Sample() (*resourcestypes.NetworkSample, error) {
+	return &resourcestypes.NetworkSample{}, nil
+}
+
+func (iface *lnInterface) Close() error {
+	<-iface.ready
+	if iface.sbx != nil {
+		go func() {
+			if err := iface.sbx.Delete(context.TODO()); err != nil {
+				log.G(context.TODO()).WithError(err).Errorf("failed to delete builder network sandbox")
+			}
+			if err := os.RemoveAll(filepath.Join(iface.provider.Root, iface.sbx.ContainerID())); err != nil {
+				log.G(context.TODO()).WithError(err).Errorf("failed to delete builder sandbox directory")
+			}
+		}()
+	}
+	return iface.err
+}
+
+func getDNSConfig(cfg config.DNSConfig) *oci.DNSConfig {
+	if cfg.DNS != nil || cfg.DNSSearch != nil || cfg.DNSOptions != nil {
+		return &oci.DNSConfig{
+			Nameservers:   ipAddresses(cfg.DNS),
+			SearchDomains: cfg.DNSSearch,
+			Options:       cfg.DNSOptions,
+		}
+	}
+	return nil
+}
+
+func ipAddresses(ips []net.IP) []string {
+	var addrs []string
+	for _, ip := range ips {
+		addrs = append(addrs, ip.String())
+	}
+	return addrs
+}
diff --git a/builder/builder-next/executor_linux.go b/builder/builder-next/executor_linux.go
index af25b2be08529..822dc0dbcb4f6 100644
--- a/builder/builder-next/executor_linux.go
+++ b/builder/builder-next/executor_linux.go
@@ -2,22 +2,17 @@ package buildkit
 
 import (
 	"context"
-	"net"
 	"os"
 	"path/filepath"
 	"strconv"
-	"sync"
 
 	"github.com/containerd/log"
-	"github.com/docker/docker/daemon/config"
 	"github.com/docker/docker/libnetwork"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/executor/oci"
 	"github.com/moby/buildkit/executor/resources"
-	resourcestypes "github.com/moby/buildkit/executor/resources/types"
 	"github.com/moby/buildkit/executor/runcexecutor"
-	"github.com/moby/buildkit/identity"
 	"github.com/moby/buildkit/solver/llbsolver/cdidevices"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/util/network"
@@ -27,7 +22,7 @@ import (
 
 const networkName = "bridge"
 
-func newExecutor(root, cgroupParent string, net *libnetwork.Controller, dnsConfig *oci.DNSConfig, rootless bool, idmap user.IdentityMapping, apparmorProfile string, cdiManager *cdidevices.Manager) (executor.Executor, error) {
+func newExecutor(root, cgroupParent string, net *libnetwork.Controller, dnsConfig *oci.DNSConfig, rootless bool, idmap user.IdentityMapping, apparmorProfile string, cdiManager *cdidevices.Manager, _, _ string) (executor.Executor, error) {
 	netRoot := filepath.Join(root, "net")
 	networkProviders := map[pb.NetMode]network.Provider{
 		pb.NetMode_UNSET: &bridgeProvider{Controller: net, Root: netRoot},
@@ -79,67 +74,21 @@ func newExecutor(root, cgroupParent string, net *libnetwork.Controller, dnsConfi
 	}, networkProviders)
 }
 
-type bridgeProvider struct {
-	*libnetwork.Controller
-	Root string
-}
-
-func (p *bridgeProvider) New(ctx context.Context, hostname string) (network.Namespace, error) {
-	n, err := p.NetworkByName(networkName)
-	if err != nil {
-		return nil, err
-	}
-
-	iface := &lnInterface{ready: make(chan struct{}), provider: p}
-	iface.Once.Do(func() {
-		go iface.init(p.Controller, n)
-	})
-
-	return iface, nil
-}
-
-func (p *bridgeProvider) Close() error {
-	return nil
-}
-
-type lnInterface struct {
-	ep  *libnetwork.Endpoint
-	sbx *libnetwork.Sandbox
-	sync.Once
-	err      error
-	ready    chan struct{}
-	provider *bridgeProvider
-}
-
-func (iface *lnInterface) init(c *libnetwork.Controller, n *libnetwork.Network) {
-	defer close(iface.ready)
-	id := identity.NewID()
-
-	ep, err := n.CreateEndpoint(context.TODO(), id, libnetwork.CreateOptionDisableResolution())
-	if err != nil {
-		iface.err = err
-		return
-	}
-
-	sbx, err := c.NewSandbox(context.TODO(), id, libnetwork.OptionUseExternalKey(), libnetwork.OptionHostsPath(filepath.Join(iface.provider.Root, id, "hosts")),
-		libnetwork.OptionResolvConfPath(filepath.Join(iface.provider.Root, id, "resolv.conf")))
-	if err != nil {
-		iface.err = err
-		return
-	}
-
-	if err := ep.Join(context.TODO(), sbx); err != nil {
-		iface.err = err
-		return
-	}
-
-	iface.sbx = sbx
-	iface.ep = ep
-}
-
-// TODO(neersighted): Unstub Sample(), and collect data from the libnetwork Endpoint.
-func (iface *lnInterface) Sample() (*resourcestypes.NetworkSample, error) {
-	return &resourcestypes.NetworkSample{}, nil
+// newExecutorGD calls newExecutor() on Linux.
+// Created for symmetry with the non-linux platforms, esp. Windows.
+func newExecutorGD(root, cgroupParent string, net *libnetwork.Controller, dnsConfig *oci.DNSConfig, rootless bool, idmap user.IdentityMapping, apparmorProfile string, cdiManager *cdidevices.Manager, _, _ string) (executor.Executor, error) {
+	return newExecutor(
+		root,
+		cgroupParent,
+		net,
+		dnsConfig,
+		rootless,
+		idmap,
+		apparmorProfile,
+		cdiManager,
+		"",
+		"",
+	)
 }
 
 func (iface *lnInterface) Set(s *specs.Spec) error {
@@ -158,37 +107,3 @@ func (iface *lnInterface) Set(s *specs.Spec) error {
 	}
 	return nil
 }
-
-func (iface *lnInterface) Close() error {
-	<-iface.ready
-	if iface.sbx != nil {
-		go func() {
-			if err := iface.sbx.Delete(context.TODO()); err != nil {
-				log.G(context.TODO()).WithError(err).Errorf("failed to delete builder network sandbox")
-			}
-			if err := os.RemoveAll(filepath.Join(iface.provider.Root, iface.sbx.ContainerID())); err != nil {
-				log.G(context.TODO()).WithError(err).Errorf("failed to delete builder sandbox directory")
-			}
-		}()
-	}
-	return iface.err
-}
-
-func getDNSConfig(cfg config.DNSConfig) *oci.DNSConfig {
-	if cfg.DNS != nil || cfg.DNSSearch != nil || cfg.DNSOptions != nil {
-		return &oci.DNSConfig{
-			Nameservers:   ipAddresses(cfg.DNS),
-			SearchDomains: cfg.DNSSearch,
-			Options:       cfg.DNSOptions,
-		}
-	}
-	return nil
-}
-
-func ipAddresses(ips []net.IP) []string {
-	var addrs []string
-	for _, ip := range ips {
-		addrs = append(addrs, ip.String())
-	}
-	return addrs
-}
diff --git a/builder/builder-next/executor_nolinux.go b/builder/builder-next/executor_nolinux.go
index 6150ecd64184d..09d2d3669388c 100644
--- a/builder/builder-next/executor_nolinux.go
+++ b/builder/builder-next/executor_nolinux.go
@@ -7,7 +7,6 @@ import (
 	"errors"
 	"runtime"
 
-	"github.com/docker/docker/daemon/config"
 	"github.com/docker/docker/libnetwork"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/executor/oci"
@@ -16,10 +15,6 @@ import (
 	"github.com/moby/sys/user"
 )
 
-func newExecutor(_, _ string, _ *libnetwork.Controller, _ *oci.DNSConfig, _ bool, _ user.IdentityMapping, _ string, _ *cdidevices.Manager) (executor.Executor, error) {
-	return &stubExecutor{}, nil
-}
-
 type stubExecutor struct{}
 
 func (w *stubExecutor) Run(ctx context.Context, id string, root executor.Mount, mounts []executor.Mount, process executor.ProcessInfo, started chan<- struct{}) (resourcetypes.Recorder, error) {
@@ -30,6 +25,7 @@ func (w *stubExecutor) Exec(ctx context.Context, id string, process executor.Pro
 	return errors.New("buildkit executor not implemented for " + runtime.GOOS)
 }
 
-func getDNSConfig(config.DNSConfig) *oci.DNSConfig {
-	return nil
+// function stub created for GraphDriver
+func newExecutorGD(_, _ string, _ *libnetwork.Controller, _ *oci.DNSConfig, _ bool, _ user.IdentityMapping, _ string, _ *cdidevices.Manager, _, _ string) (executor.Executor, error) {
+	return &stubExecutor{}, nil
 }
diff --git a/builder/builder-next/executor_others.go b/builder/builder-next/executor_others.go
new file mode 100644
index 0000000000000..5e4f2a921ab5d
--- /dev/null
+++ b/builder/builder-next/executor_others.go
@@ -0,0 +1,7 @@
+//go:build !linux && !windows
+
+package buildkit
+
+func newExecutor(_, _ string, _ *libnetwork.Controller, _ *oci.DNSConfig, _ bool, _ user.IdentityMapping, _ string, _ *cdidevices.Manager, _, _ string) (executor.Executor, error) {
+	return &stubExecutor{}, nil
+}
diff --git a/builder/builder-next/executor_windows.go b/builder/builder-next/executor_windows.go
new file mode 100644
index 0000000000000..a6d8d538a63cc
--- /dev/null
+++ b/builder/builder-next/executor_windows.go
@@ -0,0 +1,94 @@
+package buildkit
+
+import (
+	"context"
+	"encoding/json"
+	"path/filepath"
+
+	ctd "github.com/containerd/containerd/v2/client"
+	"github.com/containerd/log"
+	"github.com/docker/docker/libnetwork"
+	"github.com/moby/buildkit/executor"
+	"github.com/moby/buildkit/executor/containerdexecutor"
+	"github.com/moby/buildkit/executor/oci"
+	"github.com/moby/buildkit/solver/llbsolver/cdidevices"
+	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/buildkit/util/network"
+	"github.com/moby/sys/user"
+	"github.com/opencontainers/runtime-spec/specs-go"
+)
+
+const networkName = "nat"
+
+func newExecutor(
+	root string,
+	_ string,
+	net *libnetwork.Controller,
+	dns *oci.DNSConfig,
+	_ bool,
+	_ user.IdentityMapping,
+	_ string,
+	cdiManager *cdidevices.Manager,
+	containerdAddr string,
+	containerdNamespace string,
+) (executor.Executor, error) {
+	netRoot := filepath.Join(root, "net")
+	np := map[pb.NetMode]network.Provider{
+		pb.NetMode_UNSET: &bridgeProvider{Controller: net, Root: netRoot},
+		pb.NetMode_NONE:  network.NewNoneProvider(),
+	}
+
+	opt := ctd.WithDefaultNamespace(containerdNamespace)
+	client, err := ctd.New(containerdAddr, opt)
+	if err != nil {
+		return nil, err
+	}
+
+	executorOpts := containerdexecutor.ExecutorOptions{
+		Client:           client,
+		Root:             root,
+		DNSConfig:        dns,
+		CDIManager:       cdiManager,
+		NetworkProviders: np,
+	}
+	return containerdexecutor.New(executorOpts), nil
+}
+
+func (iface *lnInterface) Set(s *specs.Spec) error {
+	<-iface.ready
+	if iface.err != nil {
+		log.G(context.TODO()).WithError(iface.err).Error("failed to set networking spec")
+		return iface.err
+	}
+
+	allowUnqualifiedDNSQuery := false
+	var epList []string
+	for _, ep := range iface.sbx.Endpoints() {
+		data, err := ep.DriverInfo()
+		if err != nil {
+			continue
+		}
+
+		if data["hnsid"] != nil {
+			epList = append(epList, data["hnsid"].(string))
+		}
+
+		if data["AllowUnqualifiedDNSQuery"] != nil {
+			allowUnqualifiedDNSQuery = true
+		}
+	}
+	if s.Windows == nil {
+		s.Windows = &specs.Windows{}
+	}
+	if s.Windows.Network == nil {
+		s.Windows.Network = &specs.WindowsNetwork{}
+	}
+	s.Windows.Network.EndpointList = epList
+	s.Windows.Network.AllowUnqualifiedDNSQuery = allowUnqualifiedDNSQuery
+
+	if b, err := json.Marshal(s); err == nil {
+		log.G(context.TODO()).Debugf("Generated spec: %s", string(b))
+	}
+
+	return nil
+}


Reviews:
user: login: vvoland
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T09:55:41Z
user: login: profnandaa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T13:46:21Z
user: login: profnandaa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T13:48:18Z
user: login: vvoland
body: Apart from some minor complaints it seems good to me.

Would also appreciate a review from @tonistiigi 
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T15:15:08Z
user: login: profnandaa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-19T16:39:23Z
user: login: cpuguy83
body: Also generally LGTM, especially since its an entirely new implementation.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T20:43:19Z
user: login: vvoland
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T10:00:18Z
user: login: thaJeztah
body: LGTM


let's bring this one in so that users can start testing this feature (and shouldn't impact normal uses). Thanks!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-22T11:40:32Z

Review comments:
diff_hunk: @@ -332,7 +343,18 @@ func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt
 		return nil, err
 	}
 
-	exec, err := newExecutor(root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile, cdiManager)
+	exec, err := newExecutor(
path: builder/builder-next/controller.go
user: login: vvoland
body: Considering that this is for containerd-integration only - I think we should still keep the stub/noop executor for the graphdriver controller?
created_at: 2025-04-17T09:55:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -332,7 +343,18 @@ func newGraphDriverController(ctx context.Context, rt http.RoundTripper, opt Opt
 		return nil, err
 	}
 
-	exec, err := newExecutor(root, opt.DefaultCgroupParent, opt.NetworkController, dns, opt.Rootless, opt.IdentityMapping, opt.ApparmorProfile, cdiManager)
+	exec, err := newExecutor(
path: builder/builder-next/controller.go
user: login: profnandaa
body: Updated. That seems to clear the CI errors I was getting with the graphdriver integration tests. Thanks!
created_at: 2025-04-17T13:46:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -79,67 +74,19 @@ func newExecutor(root, cgroupParent string, net *libnetwork.Controller, dnsConfi
 	}, networkProviders)
 }
 
-type bridgeProvider struct {
path: builder/builder-next/executor_linux.go
user: login: profnandaa
body: moved these to `executor.go`, to be commonly used between Windows and Linux.
created_at: 2025-04-17T13:48:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,95 @@
+package buildkit
+
+import (
+	"context"
+	"encoding/json"
+	"path/filepath"
+
+	ctd "github.com/containerd/containerd/v2/client"
+	"github.com/containerd/log"
+	"github.com/docker/docker/libnetwork"
+	"github.com/moby/buildkit/executor"
+	"github.com/moby/buildkit/executor/containerdexecutor"
+	"github.com/moby/buildkit/executor/oci"
+	"github.com/moby/buildkit/solver/llbsolver/cdidevices"
+	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/buildkit/util/network"
+	"github.com/moby/sys/user"
+	"github.com/opencontainers/runtime-spec/specs-go"
+)
+
+const networkName = "nat"
+
+func newExecutor(
+	root string,
+	_ string,
+	net *libnetwork.Controller,
+	dns *oci.DNSConfig,
+	_ bool,
+	_ user.IdentityMapping,
+	_ string,
+	cdiManager *cdidevices.Manager,
+	containerdAddr string,
+	containerdNamespace string,
+) (executor.Executor, error) {
+	netRoot := filepath.Join(root, "net")
+	np := map[pb.NetMode]network.Provider{
+		pb.NetMode_UNSET: &bridgeProvider{Controller: net, Root: netRoot},
+		pb.NetMode_NONE:  network.NewNoneProvider(),
+	}
+
+	opt := ctd.WithDefaultNamespace(containerdNamespace)
+	client, err := ctd.New(containerdAddr, opt)
+	if err != nil {
+		return nil, err
+	}
+
+	executorOpts := containerdexecutor.ExecutorOptions{
+		Client:           client,
+		Root:             root,
+		DNSConfig:        dns,
+		CDIManager:       cdiManager,
+		NetworkProviders: np,
+	}
+	return containerdexecutor.New(executorOpts), nil
+}
+
+func (iface *lnInterface) Set(s *specs.Spec) error {
+	<-iface.ready
+	if iface.err != nil {
+		log.G(context.TODO()).WithError(iface.err).Error("failed to set networking spec")
+		return iface.err
+	}
+
+	AllowUnqualifiedDNSQuery := false
+	var epList []string
+	for _, ep := range iface.sbx.Endpoints() {
+		data, err := ep.DriverInfo()
+		if err != nil {
+			continue
+		}
+
+		if data["hnsid"] != nil {
+			epList = append(epList, data["hnsid"].(string))
+		}
+
+		if data["AllowUnqualifiedDNSQuery"] != nil {
+			AllowUnqualifiedDNSQuery = true
+		}
+	}
+	if s.Windows == nil {
+		s.Windows = &specs.Windows{}
+	}
+	if s.Windows.Network == nil {
+		s.Windows.Network = &specs.WindowsNetwork{}
+	}
+	s.Windows.Network.EndpointList = epList
+	s.Windows.Network.AllowUnqualifiedDNSQuery = AllowUnqualifiedDNSQuery
+
+	b, err := json.Marshal(s)
+	if err != nil {
+		log.G(context.TODO()).Debugf("Generated spec: %s", string(b))
+	}
path: builder/builder-next/executor_windows.go
user: login: vvoland
body: `b` will be nil for `err != nil`. Looks like a debugging left-over?
created_at: 2025-05-19T15:07:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,95 @@
+package buildkit
+
+import (
+	"context"
+	"encoding/json"
+	"path/filepath"
+
+	ctd "github.com/containerd/containerd/v2/client"
+	"github.com/containerd/log"
+	"github.com/docker/docker/libnetwork"
+	"github.com/moby/buildkit/executor"
+	"github.com/moby/buildkit/executor/containerdexecutor"
+	"github.com/moby/buildkit/executor/oci"
+	"github.com/moby/buildkit/solver/llbsolver/cdidevices"
+	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/buildkit/util/network"
+	"github.com/moby/sys/user"
+	"github.com/opencontainers/runtime-spec/specs-go"
+)
+
+const networkName = "nat"
+
+func newExecutor(
+	root string,
+	_ string,
+	net *libnetwork.Controller,
+	dns *oci.DNSConfig,
+	_ bool,
+	_ user.IdentityMapping,
+	_ string,
+	cdiManager *cdidevices.Manager,
+	containerdAddr string,
+	containerdNamespace string,
+) (executor.Executor, error) {
+	netRoot := filepath.Join(root, "net")
+	np := map[pb.NetMode]network.Provider{
+		pb.NetMode_UNSET: &bridgeProvider{Controller: net, Root: netRoot},
+		pb.NetMode_NONE:  network.NewNoneProvider(),
+	}
+
+	opt := ctd.WithDefaultNamespace(containerdNamespace)
+	client, err := ctd.New(containerdAddr, opt)
+	if err != nil {
+		return nil, err
+	}
+
+	executorOpts := containerdexecutor.ExecutorOptions{
+		Client:           client,
+		Root:             root,
+		DNSConfig:        dns,
+		CDIManager:       cdiManager,
+		NetworkProviders: np,
+	}
+	return containerdexecutor.New(executorOpts), nil
+}
+
+func (iface *lnInterface) Set(s *specs.Spec) error {
+	<-iface.ready
+	if iface.err != nil {
+		log.G(context.TODO()).WithError(iface.err).Error("failed to set networking spec")
+		return iface.err
+	}
+
+	AllowUnqualifiedDNSQuery := false
path: builder/builder-next/executor_windows.go
user: login: vvoland
body: It's a local variable so should be lowercase
```suggestion
	allowUnqualifiedDNSQuery := false
```
created_at: 2025-05-19T15:08:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -162,3 +162,219 @@ jobs:
           TESTPKGS: "./${{ matrix.pkg }}"
           TESTFLAGS: "-v --parallel=1 --timeout=30m --run=//worker=${{ matrix.worker }}$"
         working-directory: buildkit
+
+  build-windows:
+    runs-on: windows-2022
+    timeout-minutes: 120
+    needs:
+      - validate-dco
+    env:
+      GOPATH: ${{ github.workspace }}\go
+      GOBIN: ${{ github.workspace }}\go\bin
+      BIN_OUT: ${{ github.workspace }}\out
+      WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
+      WINDOWS_BASE_TAG_2022: ltsc2022
+      TEST_IMAGE_NAME: moby:test
+      TEST_CTN_NAME: moby
+    defaults:
+      run:
+        working-directory: ${{ env.GOPATH }}/src/github.com/docker/docker
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+        with:
+          path: ${{ env.GOPATH }}/src/github.com/docker/docker
+
+      - name: Env
+        run: |
+          Get-ChildItem Env: | Out-String
+      - name: Moby - Init
+        run: |
+          New-Item -ItemType "directory" -Path "${{ github.workspace }}\go-build"
+          New-Item -ItemType "directory" -Path "${{ github.workspace }}\go\pkg\mod"
+          echo "WINDOWS_BASE_IMAGE_TAG=${{ env.WINDOWS_BASE_TAG_2022 }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
+
+      - name: Set up Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: ${{ env.GO_VERSION }}
+          cache-dependency-path: vendor.sum
+      - name: Cache
+        uses: actions/cache@v4
+        with:
+          path: |
+            ~\AppData\Local\go-build
+            ~\go\pkg\mod
+            ${{ github.workspace }}\go-build
+            ${{ env.GOPATH }}\pkg\mod
+          key: ${{ inputs.os }}-${{ github.job }}-${{ hashFiles('**/vendor.sum') }}
+          restore-keys: |
+            ${{ inputs.os }}-${{ github.job }}-
+
+      - name: Docker info
+        run: |
+          docker info
+
+      - name: Build base image
+        run: |
+          & docker build `
+            --build-arg WINDOWS_BASE_IMAGE `
+            --build-arg WINDOWS_BASE_IMAGE_TAG `
+            --build-arg GO_VERSION `
+            -t ${{ env.TEST_IMAGE_NAME }} `
+            -f Dockerfile.windows .
+
+      - name: Build binaries
+        run: |
+          & docker run --name ${{ env.TEST_CTN_NAME }} -e "DOCKER_GITCOMMIT=${{ github.sha }}" `
+              -v "${{ github.workspace }}\go-build:C:\Users\ContainerAdministrator\AppData\Local\go-build" `
+              -v "${{ github.workspace }}\go\pkg\mod:C:\gopath\pkg\mod" `
+              ${{ env.TEST_IMAGE_NAME }} hack\make.ps1 -Daemon -Client
+          go install github.com/distribution/distribution/v3/cmd/registry@latest
+
+      - name: Checkout BuildKit
+        uses: actions/checkout@v4
+        with:
+          repository: moby/buildkit
+          ref: master
+          path: buildkit
+
+      - name: Add buildctl to binaries
+        run: |
+          go install ./cmd/buildctl
+        working-directory: buildkit
+
+      - name: Copy artifacts
+        run: |
+          New-Item -ItemType "directory" -Path "${{ env.BIN_OUT }}"
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\docker.exe" ${{ env.BIN_OUT }}\
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\src\github.com\docker\docker\bundles\dockerd.exe" ${{ env.BIN_OUT }}\
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\gopath\bin\gotestsum.exe" ${{ env.BIN_OUT }}\
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd.exe" ${{ env.BIN_OUT }}\
+          docker cp "${{ env.TEST_CTN_NAME }}`:c`:\containerd\bin\containerd-shim-runhcs-v1.exe" ${{ env.BIN_OUT }}\
+          cp ${{ env.GOPATH }}\bin\registry.exe ${{ env.BIN_OUT }}
+          cp ${{ env.GOPATH }}\bin\buildctl.exe ${{ env.BIN_OUT }}
+
+      - name: Upload artifacts
+        uses: actions/upload-artifact@v4
+        with:
+          name: build-windows
+          path: ${{ env.BIN_OUT }}/*
+          if-no-files-found: error
+          retention-days: 2
+
+  test-windows:
+    runs-on: windows-2022
+    timeout-minutes: 120 # guardrails timeout for the whole job
+    needs:
+      - build-windows
+    env:
+      TEST_IMAGE_BUILD: "0"
+      TEST_IMAGE_ID: "buildkit-tests"
+      GOPATH: ${{ github.workspace }}\go
+      GOBIN: ${{ github.workspace }}\go\bin
+      BIN_OUT: ${{ github.workspace }}\out
+      WINDOWS_BASE_IMAGE: mcr.microsoft.com/windows/servercore
+      WINDOWS_BASE_TAG_2022: ltsc2022
+      TESTFLAGS: "-v --timeout=60m"
+      TEST_DOCKERD: "1"
+    strategy:
+      fail-fast: false
+      matrix:
+        worker:
+          - dockerd-containerd
+        pkg:
+          - ./client#1-4
+          - ./client#2-4
+          - ./client#3-4
+          - ./client#4-4
+          - ./cmd/buildctl
+          - ./frontend
+          - ./frontend/dockerfile#1-12
+          - ./frontend/dockerfile#2-12
+          - ./frontend/dockerfile#3-12
+          - ./frontend/dockerfile#4-12
+          - ./frontend/dockerfile#5-12
+          - ./frontend/dockerfile#6-12
+          - ./frontend/dockerfile#7-12
+          - ./frontend/dockerfile#8-12
+          - ./frontend/dockerfile#9-12
+          - ./frontend/dockerfile#10-12
+          - ./frontend/dockerfile#11-12
+          - ./frontend/dockerfile#12-12
+    steps:
+      - name: Prepare
+        shell: bash
+        run: |
+          disabledFeatures="cache_backend_azblob,cache_backend_s3"
+          if [ "${{ matrix.worker }}" = "dockerd" ]; then
+            disabledFeatures="${disabledFeatures},merge_diff"
+          fi
+          echo "BUILDKIT_TEST_DISABLE_FEATURES=${disabledFeatures}" >> $GITHUB_ENV
+      - name: Expose GitHub Runtime
+        uses: crazy-max/ghaction-github-runtime@v3
+      - name: Checkout
+        uses: actions/checkout@v4
+        with:
+          path: moby
+      - name: Set up Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: ${{ env.GO_VERSION }}
+          cache-dependency-path: vendor.sum
+      - name: BuildKit ref
+        shell: bash
+        run: |
+          echo "$(./hack/buildkit-ref)" >> $GITHUB_ENV
+        working-directory: moby
+      - name: Checkout BuildKit ${{ env.BUILDKIT_REF }}
+        uses: actions/checkout@v4
+        with:
+          repository: ${{ env.BUILDKIT_REPO }}
+          ref: ${{ env.BUILDKIT_REF }}
+          path: buildkit
+        env:
+          # to be removed on the next buildkit release
+          # Buildkit PR has now merged.
+          BUILDKIT_REF: master
path: .github/workflows/buildkit.yml
user: login: vvoland
body: Please also include links to the required PRs in the comment
created_at: 2025-05-19T15:12:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,95 @@
+package buildkit
+
+import (
+	"context"
+	"encoding/json"
+	"path/filepath"
+
+	ctd "github.com/containerd/containerd/v2/client"
+	"github.com/containerd/log"
+	"github.com/docker/docker/libnetwork"
+	"github.com/moby/buildkit/executor"
+	"github.com/moby/buildkit/executor/containerdexecutor"
+	"github.com/moby/buildkit/executor/oci"
+	"github.com/moby/buildkit/solver/llbsolver/cdidevices"
+	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/buildkit/util/network"
+	"github.com/moby/sys/user"
+	"github.com/opencontainers/runtime-spec/specs-go"
+)
+
+const networkName = "nat"
+
+func newExecutor(
+	root string,
+	_ string,
+	net *libnetwork.Controller,
+	dns *oci.DNSConfig,
+	_ bool,
+	_ user.IdentityMapping,
+	_ string,
+	cdiManager *cdidevices.Manager,
+	containerdAddr string,
+	containerdNamespace string,
+) (executor.Executor, error) {
+	netRoot := filepath.Join(root, "net")
+	np := map[pb.NetMode]network.Provider{
+		pb.NetMode_UNSET: &bridgeProvider{Controller: net, Root: netRoot},
+		pb.NetMode_NONE:  network.NewNoneProvider(),
+	}
+
+	opt := ctd.WithDefaultNamespace(containerdNamespace)
+	client, err := ctd.New(containerdAddr, opt)
+	if err != nil {
+		return nil, err
+	}
+
+	executorOpts := containerdexecutor.ExecutorOptions{
+		Client:           client,
+		Root:             root,
+		DNSConfig:        dns,
+		CDIManager:       cdiManager,
+		NetworkProviders: np,
+	}
+	return containerdexecutor.New(executorOpts), nil
+}
+
+func (iface *lnInterface) Set(s *specs.Spec) error {
+	<-iface.ready
+	if iface.err != nil {
+		log.G(context.TODO()).WithError(iface.err).Error("failed to set networking spec")
+		return iface.err
+	}
+
+	AllowUnqualifiedDNSQuery := false
+	var epList []string
+	for _, ep := range iface.sbx.Endpoints() {
+		data, err := ep.DriverInfo()
+		if err != nil {
+			continue
+		}
+
+		if data["hnsid"] != nil {
+			epList = append(epList, data["hnsid"].(string))
+		}
+
+		if data["AllowUnqualifiedDNSQuery"] != nil {
+			AllowUnqualifiedDNSQuery = true
+		}
+	}
+	if s.Windows == nil {
+		s.Windows = &specs.Windows{}
+	}
+	if s.Windows.Network == nil {
+		s.Windows.Network = &specs.WindowsNetwork{}
+	}
+	s.Windows.Network.EndpointList = epList
+	s.Windows.Network.AllowUnqualifiedDNSQuery = AllowUnqualifiedDNSQuery
+
+	b, err := json.Marshal(s)
+	if err != nil {
+		log.G(context.TODO()).Debugf("Generated spec: %s", string(b))
+	}
path: builder/builder-next/executor_windows.go
user: login: profnandaa
body: my bad, good catch.
created_at: 2025-05-19T16:39:23Z
author_association: CONTRIBUTOR

PR comments:
user: login: profnandaa
created_at: 2025-04-10T20:51:14Z
body: I've managed to crack the networking bit, albeit still hacky but good progress:
```
#6 [3/3] RUN curl.exe -I bing.com
#6 4.994   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
#6 4.994                                  Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
#6 5.019 HTTP/1.1 301 Moved Permanently
#6 5.019 Content-Length: 0
#6 5.019 Date: Thu, 10 Apr 2025 20:47:47 GMT
#6 5.019 Location: http://www.bing.com/
#6 5.019 X-Msedge-Ref: Ref A: ECCAB5D563A2483F8FA6174B7FFF702B Ref B: BL2AA2011006042 Ref C: 2025-04-10T20:47:47Z
#6 5.019
#6 DONE 5.5s
```

===
**Daemon Logs:**
```
<snip>
time="2025-04-10T23:47:00.542142400+03:00" level=info msg="Initializing buildkit"
time="2025-04-10T23:47:00.561561500+03:00" level=debug msg="creating new network namespace 6wxrpcj29ayrqmd5o2x9hek31"
time="2025-04-10T23:47:00.562074500+03:00" level=debug msg="hcn::HostComputeNamespace::Create id="
time="2025-04-10T23:47:00.562074500+03:00" level=debug msg="hcn::HostComputeNamespace::Create JSON: {\"Type\":\"Guest\",\"SchemaVersion\":{\"Major\":2,\"Minor\":0}}"
time="2025-04-10T23:47:00.564342100+03:00" level=debug msg="finished creating network namespace 6wxrpcj29ayrqmd5o2x9hek31"
time="2025-04-10T23:47:00.718005000+03:00" level=debug msg="finished setting up network namespace 6wxrpcj29ayrqmd5o2x9hek31"
time="2025-04-10T23:47:00.718005000+03:00" level=debug msg="remote introspection plugin filters" filters="[type==io.containerd.runtime.v1 type==io.containerd.runtime.v2]"
time="2025-04-10T23:47:00.720985700+03:00" level=debug msg="creating new network namespace e2znw5e556whdhdeklc277go0"
time="2025-04-10T23:47:00.720985700+03:00" level=debug msg="hcn::HostComputeNamespace::Create id="
time="2025-04-10T23:47:00.720985700+03:00" level=debug msg="hcn::HostComputeNamespace::Create JSON: {\"Type\":\"Guest\",\"SchemaVersion\":{\"Major\":2,\"Minor\":0}}"
time="2025-04-10T23:47:00.721579200+03:00" level=debug msg="finished creating network namespace e2znw5e556whdhdeklc277go0"
time="2025-04-10T23:47:00.798236700+03:00" level=debug msg="finished setting up network namespace e2znw5e556whdhdeklc277go0"
time="2025-04-10T23:47:00.972923100+03:00" level=info msg="Completed buildkit initialization"
<snip>
```
author_association: CONTRIBUTOR
user: login: profnandaa
created_at: 2025-04-15T07:33:53Z
body: UPDATE: Redone the networking bit to use docker/moby networking model instead of CNI as previously done.

````
#6 [3/4] RUN curl.exe -I bing.com
#6 5.092   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
#6 5.092                                  Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0HTTP/1.1 301 Moved Permanently
#6 5.139 Content-Length: 0
#6 5.139 Date: Tue, 15 Apr 2025 07:45:54 GMT
#6 5.139 Location: http://www.bing.com/
#6 5.139 X-Msedge-Ref: Ref A: 73F7F62AA34B4200A93BA4B9141B1AD9 Ref B: BL2AA2011004025 Ref C: 2025-04-15T07:45:55Z
#6 5.139
#6 5.139   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
#6 5.139
#6 DONE 5.6s
````
author_association: CONTRIBUTOR
user: login: profnandaa
created_at: 2025-04-16T10:05:15Z
body: ~I think the graph-driver tests are supposed to be skipped, can add `containerd-integration` tag for me?~ @thaJeztah 
ref https://github.com/moby/moby/pull/47955
/cc. @charitykathure
author_association: CONTRIBUTOR
user: login: profnandaa
created_at: 2025-05-05T05:40:28Z
body: UPDATE: enabled buildkit integration tests CI - [diff](https://github.com/moby/moby/compare/9257fe60ae028f1a9a58dcdcd5afbc0d4fac2450..66bcaf181418ff6b5503630f000a56cb071477d4).
author_association: CONTRIBUTOR
user: login: cpuguy83
created_at: 2025-05-19T20:44:16Z
body: Looks like dockerfile tests are timing out, though.
author_association: MEMBER
user: login: thaJeztah
created_at: 2025-05-19T21:15:17Z
body: I guess I should dust-off https://github.com/moby/moby/pull/48038 as well if this one gets in
author_association: MEMBER
user: login: profnandaa
created_at: 2025-05-19T21:17:30Z
body: > Looks like dockerfile tests are timing out, though.

Thanks for taking a look. Increased the timeout to `90m` for now. Will consider splitting the test suite further if this persists.
author_association: CONTRIBUTOR
user: login: thaJeztah
created_at: 2025-05-20T08:43:12Z
body: Looks like we're hitting GitHub rate limits as part of the builds 😞 

```
INFO: Downloading go...
INFO: Downloading compiler 1 of 3...
INFO: Downloading compiler 2 of 3...
Exception calling "DownloadFile" with "2" argument(s): "The remote server 
returned an error: (429) Too Many Requests."
At line:1 char:1385
+ ... stem.Net.WebClient; $webClient.DownloadFile($source, $target); } } se ...
+                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordE 
   xception
    + FullyQualifiedErrorId : WebException
```
author_association: MEMBER
user: login: profnandaa
created_at: 2025-05-20T17:30:37Z
body: > Looks like we're hitting GitHub rate limits as part of the builds 😞
> 
> ```
> INFO: Downloading go...
> INFO: Downloading compiler 1 of 3...
> INFO: Downloading compiler 2 of 3...
> Exception calling "DownloadFile" with "2" argument(s): "The remote server 
> returned an error: (429) Too Many Requests."
> At line:1 char:1385
> + ... stem.Net.WebClient; $webClient.DownloadFile($source, $target); } } se ...
> +                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>     + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordE 
>    xception
>     + FullyQualifiedErrorId : WebException
> ```

sure, this was rate-limiting. Someone can re-run those for me?
author_association: CONTRIBUTOR
user: login: thaJeztah
created_at: 2025-05-22T10:31:20Z
body: - did a quick rebase of https://github.com/moby/moby/pull/48038
author_association: MEMBER
user: login: profnandaa
created_at: 2025-05-22T11:49:52Z
body: Thank you all! ❤️ 
author_association: CONTRIBUTOR