Repository: akvorado/akvorado

Issue:
After Upgrade 2.0.4 : crash akvorado-akvorado-conntrack-fixer-1
### Disclaimer

- [x] I have read and understood the disclaimer.
- [ ] I am a new user.

### Akvorado version

2.0.4

### Bug description

Crash loop for component : 

{"level":"info","listen":"@akvorado","time":"2025-12-08T09:02:48Z","caller":"akvorado/common/httpserver/root.go:147","module":"akvorado/common/httpserver","message":"starting HTTP server"}
{"level":"info","listen":"@akvorado/conntrack-fixer","time":"2025-12-08T09:02:48Z","caller":"akvorado/common/httpserver/root.go:147","module":"akvorado/common/httpserver","message":"starting HTTP server"}
{"level":"info","time":"2025-12-08T09:02:48Z","caller":"akvorado/conntrackfixer/root.go:103","module":"akvorado/conntrackfixer","message":"starting conntrack-fixer component"}
{"level":"info","time":"2025-12-08T09:02:48Z","caller":"akvorado/conntrackfixer/root.go:212","module":"akvorado/conntrackfixer","message":"conntrack fixer running"}
{"level":"info","version":"v2.0.4","time":"2025-12-08T09:02:48Z","caller":"akvorado/cmd/components.go:38","module":"akvorado/cmd","message":"akvorado has started"}
{"level":"error","error":"Error response from daemon: client version 1.52 is too new. Maximum supported API version is 1.41","time":"2025-12-08T09:02:48Z","caller":"akvorado/conntrackfixer/root.go:168","module":"akvorado/conntrackfixer","message":"cannot list containers"}
{"level":"error","error":"error while watching for Docker events: Error response from daemon: client version 1.52 is too new. Maximum supported API version is 1.41","component":"conntrack-fixer","time":"2025-12-08T09:02:48Z","caller":"akvorado/common/daemon/root.go:68","module":"akvorado/common/daemon","message":"component error, quitting"}
{"level":"info","time":"2025-12-08T09:02:48Z","caller":"akvorado/cmd/components.go:41","module":"akvorado/cmd","message":"stopping all components"}
{"level":"info","time":"2025-12-08T09:02:48Z","caller":"akvorado/conntrackfixer/root.go:221","module":"akvorado/conntrackfixer","message":"stopping conntrack-fixer component"}
{"level":"info","time":"2025-12-08T09:02:48Z","caller":"akvorado/conntrackfixer/root.go:226","module":"akvorado/conntrackfixer","message":"conntrack-fixer component stopped"}
{"level":"error","error":"error while watching for Docker events: Error response from daemon: client version 1.52 is too new. Maximum supported API version is 1.41","time":"2025-12-08T09:02:48Z","caller":"akvorado/cmd/components.go:22","module":"akvorado/cmd","message":"unable to stop component, ignoring"}
{"level":"info","time":"2025-12-08T09:02:48Z","caller":"akvorado/common/httpserver/root.go:193","module":"akvorado/common/httpserver","message":"stopping HTTP component"}

Hints from issue comments:
@vincentbernat: Can you provide the output of `docker version`? Thanks. In the meantime, you can disable the conntrack fixer. It should not be needed anymore. In `docker/docker-compose-local.yml`:

```yaml
services:
  akvorado-conntrack-fixer:
    profiles: [ disabled ]
```@vincentbernat: It seems the minimum supported Docker Version is now 25.0: https://github.com/moby/moby/pull/51119. You would need to upgrade your Docker Engine package. The alternative would include using an older version of the Docker client embedded in Akvorado, but then we would run into the reverse issue in the future (client too old for recent Docker Engines).@vincentbernat: We may just remove the conntrack fixer. It is not needed since Docker Engine v23:
- https://github.com/moby/moby/pull/44752 (v23)
- https://github.com/moby/moby/pull/44742 (v24+)@remyd74: Ok, that's perfect with the latest docker version. 


{"level":"info","binding":"2055/udp -> 2055","time":"2025-12-08T11:30:03Z","caller":"akvorado/conntrackfixer/root.go:195","module":"akvorado/conntrackfixer","message":"clear conntrack for UDP port"}
{"level":"info","binding":"4739/udp -> 4739","time":"2025-12-08T11:30:03Z","caller":"akvorado/conntrackfixer/root.go:195","module":"akvorado/conntrackfixer","message":"clear conntrack for UDP port"}
{"level":"info","binding":"6343/udp -> 6343","time":"2025-12-08T11:30:03Z","caller":"akvorado/conntrackfixer/root.go:195","module":"akvorado/conntrackfixer","message":"clear conntrack for UDP port"}

Many thanks for fast and great help !

Solution patch:
diff --git a/.github/e2e.sh b/.github/e2e.sh
index ca7c6913..1c2d7d9d 100755
--- a/.github/e2e.sh
+++ b/.github/e2e.sh
@@ -16,7 +16,7 @@ EOF
         # For each service, collect coverage files
         [ -n "$AKVORADO_COVERAGE_DIRECTORY" ]
         mkdir -p ${AKVORADO_COVERAGE_DIRECTORY}
-        for service in orchestrator inlet outlet console exporter-1 conntrack-fixer; do
+        for service in orchestrator inlet outlet console exporter-1; do
             cat >> docker/docker-compose-local.yml <<EOF
   akvorado-${service}:
     volumes:
diff --git a/Makefile b/Makefile
index 4cb0d51b..7acbf6fe 100644
--- a/Makefile
+++ b/Makefile
@@ -39,8 +39,7 @@ GENERATED_GO = \
 	console/homepagetopwidget_enumer.go \
 	common/kafka/saslmechanism_enumer.go
 GENERATED_TEST_GO = \
-	common/clickhousedb/mocks/mock_driver.go \
-	conntrackfixer/mocks/mock_conntrackfixer.go
+	common/clickhousedb/mocks/mock_driver.go
 GENERATED = \
 	$(GENERATED_GO) \
 	$(GENERATED_JS) \
@@ -97,12 +96,6 @@ common/clickhousedb/mocks/mock_driver.go: ; $(info $(M) generate mocks for Click
 	$Q $(MOCKGEN) -package mocks -build_constraint "!release" -destination $@ \
 		github.com/ClickHouse/clickhouse-go/v2/lib/driver Conn,Row,Rows,ColumnType
 	$Q touch $@
-conntrackfixer/mocks/mock_conntrackfixer.go: ; $(info $(M) generate mocks for conntrack-fixer…)
-	$Q if [ `$(GO) env GOOS` = "linux" ]; then \
-	   $(MOCKGEN) -package mocks -build_constraint "!release" -destination $@ \
-		akvorado/conntrackfixer ConntrackConn,DockerClient ; \
-		touch $@ ; \
-	fi
 
 inlet/flow/input/udp/reuseport_%.o: inlet/flow/input/udp/reuseport_kern.c inlet/flow/input/udp/vmlinux.h ; $(info $(M) generate eBPF program for input/udp ($*)…)
 	$Q ! $(CLANG) -print-targets 2> /dev/null | grep -qF $* || \
diff --git a/cmd/conntrack-fixer.go b/cmd/conntrack-fixer.go
deleted file mode 100644
index b83eb4fb..00000000
--- a/cmd/conntrack-fixer.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// SPDX-FileCopyrightText: 2022 Free Mobile
-// SPDX-License-Identifier: AGPL-3.0-only
-
-//go:build linux
-
-package cmd
-
-import (
-	"fmt"
-
-	"github.com/spf13/cobra"
-
-	"akvorado/common/daemon"
-	"akvorado/common/httpserver"
-	"akvorado/common/reporter"
-	"akvorado/conntrackfixer"
-)
-
-var conntrackFixerCmd = &cobra.Command{
-	Use:   "conntrack-fixer",
-	Short: "Clean conntrack for UDP ports",
-	Long: `This helper cleans the conntrack entries for the UDP ports exposed by
-containers started with the label "akvorado.conntrack.fix=1".`,
-	Args: cobra.NoArgs,
-	RunE: func(_ *cobra.Command, _ []string) error {
-		// This is a simplified service which is not configurable.
-		r, err := reporter.New(reporter.DefaultConfiguration())
-		if err != nil {
-			return fmt.Errorf("unable to initialize reporter: %w", err)
-		}
-		daemonComponent, err := daemon.New(r)
-		if err != nil {
-			return fmt.Errorf("unable to initialize daemon component: %w", err)
-		}
-		httpConfiguration := httpserver.DefaultConfiguration()
-		httpConfiguration.Listen = ""
-		httpComponent, err := httpserver.New(r, "conntrack-fixer", httpConfiguration, httpserver.Dependencies{
-			Daemon: daemonComponent,
-		})
-		if err != nil {
-			return fmt.Errorf("unable to initialize HTTP component: %w", err)
-		}
-		conntrackFixerComponent, err := conntrackfixer.New(r,
-			conntrackfixer.Dependencies{
-				Daemon: daemonComponent,
-				HTTP:   httpComponent,
-			})
-		if err != nil {
-			return fmt.Errorf("unable to initialize conntrack fixer component: %w", err)
-		}
-		addCommonHTTPHandlers(r, "conntrack-fixer", httpComponent)
-		moreMetrics(r)
-
-		components := []any{
-			httpComponent,
-			conntrackFixerComponent,
-		}
-		return StartStopComponents(r, daemonComponent, components)
-	},
-}
-
-func init() {
-	RootCmd.AddCommand(conntrackFixerCmd)
-}
diff --git a/conntrackfixer/interfaces.go b/conntrackfixer/interfaces.go
deleted file mode 100644
index 17edce9f..00000000
--- a/conntrackfixer/interfaces.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-FileCopyrightText: 2022 Free Mobile
-// SPDX-License-Identifier: AGPL-3.0-only
-
-//go:build linux
-
-package conntrackfixer
-
-import (
-	"context"
-
-	"github.com/moby/moby/client"
-	"github.com/ti-mo/conntrack"
-)
-
-// ConntrackConn is the part of conntrack.Conn we use
-type ConntrackConn interface {
-	Close() error
-	Dump(opts *conntrack.DumpOptions) ([]conntrack.Flow, error)
-	Delete(f conntrack.Flow) error
-}
-
-// DockerClient is the part of docker.Client we use
-type DockerClient interface {
-	client.ContainerAPIClient
-	client.SystemAPIClient
-	ServerVersion(ctx context.Context, options client.ServerVersionOptions) (client.ServerVersionResult, error)
-	Close() error
-}
diff --git a/conntrackfixer/mocks/empty.go b/conntrackfixer/mocks/empty.go
deleted file mode 100644
index 0f74ad99..00000000
--- a/conntrackfixer/mocks/empty.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// SPDX-FileCopyrightText: 2022 Free Mobile
-// SPDX-License-Identifier: AGPL-3.0-only
-
-// Package mocks contains mocks for conntrackfixer package.
-package mocks
-
-import (
-	_ "go.uber.org/mock/mockgen/model" // for mockgen in vendor mode
-)
diff --git a/conntrackfixer/root.go b/conntrackfixer/root.go
deleted file mode 100644
index 0965708e..00000000
--- a/conntrackfixer/root.go
+++ /dev/null
@@ -1,256 +0,0 @@
-// SPDX-FileCopyrightText: 2022 Free Mobile
-// SPDX-License-Identifier: AGPL-3.0-only
-
-//go:build linux
-
-// Package conntrackfixer remove conntrack entries from selected containers
-package conntrackfixer
-
-import (
-	"context"
-	"fmt"
-	"strconv"
-	"strings"
-	"time"
-
-	"akvorado/common/daemon"
-	"akvorado/common/httpserver"
-	"akvorado/common/reporter"
-
-	"github.com/moby/moby/client"
-	"github.com/ti-mo/conntrack"
-	"gopkg.in/tomb.v2"
-)
-
-// Component represents the broker.
-type Component struct {
-	r *reporter.Reporter
-	d *Dependencies
-	t tomb.Tomb
-
-	dockerClient  DockerClient
-	conntrackConn ConntrackConn
-
-	changes chan bool
-	healthy chan reporter.ChannelHealthcheckFunc
-
-	metrics struct {
-		conntrackDeleted *reporter.CounterVec
-		runs             *reporter.CounterVec
-		errors           *reporter.CounterVec
-	}
-}
-
-// Dependencies define the dependencies of the broker.
-type Dependencies struct {
-	HTTP   *httpserver.Component
-	Daemon daemon.Component
-}
-
-// New creates a new component
-func New(r *reporter.Reporter, dependencies Dependencies) (*Component, error) {
-	cli, err := client.New(
-		client.FromEnv,
-	)
-	if err != nil {
-		return nil, fmt.Errorf("unable to initialize Docker client: %w", err)
-	}
-	chl, err := conntrack.Dial(nil)
-	if err != nil {
-		cli.Close()
-		return nil, fmt.Errorf("cannot initialize conntrack support: %w", err)
-	}
-
-	c := Component{
-		r: r,
-		d: &dependencies,
-
-		dockerClient:  cli,
-		conntrackConn: chl,
-
-		changes: make(chan bool),
-		healthy: make(chan reporter.ChannelHealthcheckFunc),
-	}
-
-	c.metrics.conntrackDeleted = c.r.CounterVec(
-		reporter.CounterOpts{
-			Name: "conntrack_deleted_total",
-			Help: "Number of conntrack entries deleted.",
-		},
-		[]string{"container", "port"},
-	)
-	c.metrics.runs = c.r.CounterVec(
-		reporter.CounterOpts{
-			Name: "runs_total",
-			Help: "Number of conntrack cleaning runs triggered.",
-		},
-		[]string{"reason"},
-	)
-	c.metrics.errors = c.r.CounterVec(
-		reporter.CounterOpts{
-			Name: "errors_total",
-			Help: "Number of non-fatal errors.",
-		},
-		[]string{"error"},
-	)
-
-	c.d.Daemon.Track(&c.t, "conntrack-fixer")
-	return &c, nil
-}
-
-// Start the conntrack fixer component
-func (c *Component) Start() error {
-	c.r.Info().Msg("starting conntrack-fixer component")
-	c.r.RegisterHealthcheck("conntrack-fixer", c.channelHealthcheck())
-
-	// Trigger an update
-	trigger := func() {
-		select {
-		case c.changes <- true:
-		case <-c.t.Dying():
-		}
-	}
-
-	// Goroutine to watch for changes
-	ready := make(chan bool)
-	c.t.Go(func() error {
-		filter := client.Filters{}
-		filter.Add("event", "start")
-		filter.Add("label", "akvorado.conntrack.fix=true")
-		events := c.dockerClient.Events(c.t.Context(nil), client.EventsListOptions{Filters: filter})
-		close(ready)
-		for {
-			t := time.NewTimer(5 * time.Minute)
-			select {
-			case <-c.t.Dying():
-				return nil
-			case err := <-events.Err:
-				return fmt.Errorf("error while watching for Docker events: %w", err)
-			case msg := <-events.Messages:
-				c.r.Info().
-					Str("id", msg.Actor.ID).
-					Str("from", msg.Actor.Attributes["image"]).
-					Msg("new container started")
-				c.metrics.runs.WithLabelValues("new container").Inc()
-				trigger()
-			case <-t.C:
-				c.metrics.runs.WithLabelValues("schedule").Inc()
-				trigger()
-			}
-			t.Stop()
-		}
-	})
-
-	// Goroutine to react to changes
-	c.t.Go(func() error {
-		filter := client.Filters{}
-		filter.Add("label", "akvorado.conntrack.fix=true")
-		for {
-			select {
-			case <-c.t.Dying():
-				return nil
-			case cb, ok := <-c.healthy:
-				if ok {
-					ctx, cancel := context.WithTimeout(c.t.Context(nil), time.Second)
-					if _, err := c.dockerClient.ServerVersion(ctx, client.ServerVersionOptions{}); err == nil {
-						cb(reporter.HealthcheckOK, "docker client alive")
-					} else {
-						cb(reporter.HealthcheckWarning, "docker client unavailable")
-					}
-					cancel()
-				}
-			case <-c.changes:
-				containers, err := c.dockerClient.ContainerList(c.t.Context(nil),
-					client.ContainerListOptions{
-						Filters: filter,
-					})
-				if err != nil {
-					c.r.Err(err).Msg("cannot list containers")
-					c.metrics.errors.WithLabelValues("cannot list containers").Inc()
-					continue
-				}
-				for _, container := range containers.Items {
-					details, err := c.dockerClient.ContainerInspect(c.t.Context(nil), container.ID,
-						client.ContainerInspectOptions{})
-					if err != nil {
-						c.r.Err(err).Msg("cannot get details on container")
-						c.metrics.errors.WithLabelValues("cannot get details on container").Inc()
-						continue
-					}
-					for rport, bindings := range details.Container.NetworkSettings.Ports {
-						if !strings.HasSuffix(rport.String(), "/udp") {
-							continue
-						}
-						ports := map[string]struct{}{}
-						for _, binding := range bindings {
-							ports[binding.HostPort] = struct{}{}
-						}
-						for hportStr := range ports {
-							hport, err := strconv.ParseUint(hportStr, 10, 16)
-							if err != nil {
-								panic(err)
-							}
-							l := c.r.With().Str("binding",
-								fmt.Sprintf("%s -> %d", rport, hport)).Logger()
-							l.Info().Msg("clear conntrack for UDP port")
-							if count := c.purgeConntrack(uint16(hport)); count > 0 {
-								c.metrics.conntrackDeleted.
-									WithLabelValues(container.ID, hportStr).
-									Add(float64(count))
-								l.Info().Msgf("%d entries deleted", count)
-							}
-						}
-					}
-				}
-
-			}
-		}
-	})
-
-	// Trigger now
-	<-ready
-	c.r.Info().Msg("conntrack fixer running")
-	c.metrics.runs.WithLabelValues("start").Inc()
-	trigger()
-
-	return nil
-}
-
-// Stop stops the conntrack-fixer component
-func (c *Component) Stop() error {
-	c.r.Info().Msg("stopping conntrack-fixer component")
-	defer func() {
-		close(c.changes)
-		c.conntrackConn.Close()
-		c.dockerClient.Close()
-		c.r.Info().Msg("conntrack-fixer component stopped")
-	}()
-	c.t.Kill(nil)
-	return c.t.Wait()
-}
-
-func (c *Component) channelHealthcheck() reporter.HealthcheckFunc {
-	return reporter.ChannelHealthcheck(c.t.Context(nil), c.healthy)
-}
-
-// purgeConntrack purge the conntrack for the given port.
-func (c *Component) purgeConntrack(port uint16) int {
-	flows, err := c.conntrackConn.Dump(nil)
-	if err != nil {
-		c.r.Err(err).Msg("cannot list conntrack entries")
-		c.metrics.errors.WithLabelValues("cannot list conntrack entries").Inc()
-		return 0
-	}
-	count := 0
-	for _, flow := range flows {
-		if flow.TupleOrig.Proto.Protocol == 17 && flow.TupleOrig.Proto.DestinationPort == port {
-			if err := c.conntrackConn.Delete(flow); err != nil {
-				c.r.Err(err).Msg("cannot delete conntrack entry")
-				c.metrics.errors.WithLabelValues("cannot delete conntrack entries").Inc()
-			} else {
-				count++
-			}
-		}
-	}
-	return count
-}
diff --git a/console/data/docs/01-install.md b/console/data/docs/01-install.md
index 067d5e6c..afad15fd 100644
--- a/console/data/docs/01-install.md
+++ b/console/data/docs/01-install.md
@@ -19,7 +19,7 @@ Check the `docker/docker-compose.yml` file for an example of how to deploy
 the [quick start procedure](00-intro.md#quick-start). This documentation assumes
 you are using the `docker compose` setup.
 
-The minimum supported version for Docker Engine is v25 (Docker API 1.44).
+The minimum supported version for Docker Engine is v23.
 
 If you want to compile the Docker image yourself, use `make docker`.
 
diff --git a/console/data/docs/05-troubleshooting.md b/console/data/docs/05-troubleshooting.md
index f4a894e4..aad5e6d4 100644
--- a/console/data/docs/05-troubleshooting.md
+++ b/console/data/docs/05-troubleshooting.md
@@ -45,7 +45,6 @@ Check that all components are running and healthy:
 ```console
 $ docker compose ps --format "table {{.Service}}\t{{.Status}}"
 SERVICE                    STATUS
-akvorado-conntrack-fixer   Up 28 minutes
 akvorado-console           Up 27 minutes (healthy)
 akvorado-inlet             Up 27 minutes (healthy)
 akvorado-orchestrator      Up 27 minutes (healthy)
@@ -118,6 +117,19 @@ address of the exporter and the port with the correct port (2055 for NetFlow,
 0 packets dropped by kernel
 ```
 
+If you receive flows but they do not reach Akvorado, check you are running
+Docker Engine v23 or more recent:
+
+```console
+$ docker version
+[...]
+Server:
+ Engine:
+  Version:          27.5.1+dfsg4
+  API version:      1.47 (minimum version 1.24)
+[...]
+```
+
 Next, check if flows are sent to Kafka correctly:
 
 ```console
diff --git a/console/data/docs/99-changelog.md b/console/data/docs/99-changelog.md
index aea9cff2..0fb97694 100644
--- a/console/data/docs/99-changelog.md
+++ b/console/data/docs/99-changelog.md
@@ -10,12 +10,15 @@ identified with a specific icon:
 - 🩹: bug fix
 - 🌱: miscellaneous change
 
+## Unreleased
+
+- 💥 *docker*: remove conntrack-fixer service (this requires Docker Engine v23 or more recent)
+
 ## 2.0.4 - 2025-12-04
 
 The previous release introduced a performance regression for users with many
 flows from a single exporter. This is fixed in this release.
 
-- 💥 *docker*: bump minimum Docker API version supported to 1.44 (Docker Engine v25)
 - 🩹 *docker*: restart geoip container on boot
 - 🌱 *inlet*: make load-balancing algorithm for Kafka partitions configurable
   (`random` or `by-exporter`) and revert back to `random` by default (like before 2.0.3)
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index e6111015..ccc0477d 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -167,7 +167,6 @@ services:
       - traefik.http.routers.akvorado-inlet.entrypoints=private
       - traefik.http.routers.akvorado-inlet.rule=PathPrefix(`/api/v0/inlet`)
       - traefik.http.services.akvorado-inlet.loadbalancer.server.port=8080
-      - akvorado.conntrack.fix=true
       - metrics.port=8080
       - metrics.path=/api/v0/metrics
   akvorado-outlet:
@@ -203,19 +202,6 @@ services:
       - traefik.http.services.akvorado-outlet.loadbalancer.server.port=8080
       - metrics.port=8080
       - metrics.path=/api/v0/metrics
-  akvorado-conntrack-fixer:
-    extends:
-      file: versions.yml
-      service: akvorado
-    cap_add:
-      - NET_ADMIN
-    command: conntrack-fixer
-    restart: unless-stopped
-    network_mode: host
-    healthcheck:
-      test: ["CMD", "/usr/local/bin/akvorado", "healthcheck", "--service", "conntrack-fixer"]
-    volumes:
-      - /var/run/docker.sock:/var/run/docker.sock:ro
 
   clickhouse:
     extends:
diff --git a/go.mod b/go.mod
index 37f6a52a..f5a2d049 100644
--- a/go.mod
+++ b/go.mod
@@ -31,20 +31,17 @@ require (
 	github.com/hashicorp/go-version v1.8.0
 	github.com/itchyny/gojq v0.12.18
 	github.com/mattn/go-isatty v0.0.20
-	github.com/moby/moby/api v1.52.0
-	github.com/moby/moby/client v0.2.1
 	github.com/netsampler/goflow2/v2 v2.2.3
 	github.com/openconfig/gnmi v0.14.0
 	github.com/openconfig/gnmic/pkg/api v0.1.9
-	github.com/opencontainers/image-spec v1.1.1
 	github.com/oschwald/maxminddb-golang/v2 v2.1.1
 	github.com/osrg/gobgp/v4 v4.1.0
+	github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
 	github.com/prometheus/client_golang v1.23.2
 	github.com/rs/zerolog v1.34.0
 	github.com/scrapli/scrapligo v1.3.3
 	github.com/slayercat/GoSNMPServer v0.5.2
 	github.com/spf13/cobra v1.10.1
-	github.com/ti-mo/conntrack v0.6.0
 	github.com/twmb/franz-go v1.20.5
 	github.com/twmb/franz-go/pkg/kadm v1.17.1
 	github.com/twmb/franz-go/pkg/kfake v0.0.0-20250711145744-a849b8be17b7
@@ -72,7 +69,6 @@ require (
 	filippo.io/edwards25519 v1.1.0 // indirect
 	github.com/AlekSi/pointer v1.2.0 // indirect
 	github.com/BurntSushi/toml v1.5.0 // indirect
-	github.com/Microsoft/go-winio v0.6.2 // indirect
 	github.com/andybalholm/brotli v1.2.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bio-routing/tflow2 v0.0.0-20181230153523-2e308a4a3c3a // indirect
@@ -84,25 +80,19 @@ require (
 	github.com/clipperhouse/stringish v0.1.1 // indirect
 	github.com/clipperhouse/uax29/v2 v2.3.0 // indirect
 	github.com/cloudwego/base64x v0.1.6 // indirect
-	github.com/containerd/errdefs v1.0.0 // indirect
-	github.com/containerd/errdefs/pkg v0.3.0 // indirect
 	github.com/cosiner/argv v0.1.0 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
 	github.com/creack/pty v1.1.24 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/derekparker/trie v0.0.0-20230829180723-39f4de51ef7d // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
-	github.com/distribution/reference v0.6.0 // indirect
 	github.com/dlclark/regexp2 v1.11.5 // indirect
 	github.com/dmarkham/enumer v1.6.1 // indirect
 	github.com/dnephin/pflag v1.0.7 // indirect
-	github.com/docker/go-connections v0.6.0 // indirect
-	github.com/docker/go-units v0.5.0 // indirect
 	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/emicklei/dot v0.15.0 // indirect
 	github.com/fatih/color v1.18.0 // indirect
 	github.com/fatih/structtag v1.2.0 // indirect
-	github.com/felixge/httpsnoop v1.0.4 // indirect
 	github.com/frapposelli/wwhrd v0.4.0 // indirect
 	github.com/gabriel-vasile/mimetype v1.4.8 // indirect
 	github.com/gin-contrib/sse v1.1.0 // indirect
@@ -138,7 +128,6 @@ require (
 	github.com/jhump/protoreflect v1.17.0 // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
-	github.com/josharian/native v1.1.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/klauspost/compress v1.18.1 // indirect
 	github.com/klauspost/cpuid/v2 v2.3.0 // indirect
@@ -146,23 +135,19 @@ require (
 	github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
 	github.com/mattn/go-colorable v0.1.14 // indirect
 	github.com/mattn/go-runewidth v0.0.19 // indirect
-	github.com/mdlayher/netlink v1.7.2 // indirect
 	github.com/mdlayher/socket v0.5.1 // indirect
 	github.com/mgechev/dots v1.0.0 // indirect
 	github.com/mgechev/revive v1.12.0 // indirect
 	github.com/mna/pigeon v1.3.0 // indirect
-	github.com/moby/docker-image-spec v1.3.1 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/openconfig/grpctunnel v0.1.0 // indirect
-	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/pascaldekloe/name v1.0.1 // indirect
 	github.com/paulmach/orb v0.11.1 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.4 // indirect
 	github.com/pierrec/lz4/v4 v4.1.22 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
-	github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
 	github.com/prometheus/client_model v0.6.2 // indirect
@@ -181,14 +166,12 @@ require (
 	github.com/sirupsen/logrus v1.9.3 // indirect
 	github.com/spf13/afero v1.14.0 // indirect
 	github.com/spf13/pflag v1.0.9 // indirect
-	github.com/ti-mo/netfilter v0.5.3 // indirect
 	github.com/tklauser/go-sysconf v0.3.12 // indirect
 	github.com/tklauser/numcpus v0.6.1 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.3.0 // indirect
 	github.com/yusufpapurcu/wmi v1.2.4 // indirect
 	go.opentelemetry.io/auto/sdk v1.2.1 // indirect
-	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
 	go.opentelemetry.io/otel v1.38.0 // indirect
 	go.opentelemetry.io/otel/metric v1.38.0 // indirect
 	go.opentelemetry.io/otel/trace v1.38.0 // indirect
diff --git a/go.sum b/go.sum
index f222f6d0..1f1dc702 100644
--- a/go.sum
+++ b/go.sum
@@ -13,8 +13,6 @@ github.com/ClickHouse/ch-go v0.69.0 h1:nO0OJkpxOlN/eaXFj0KzjTz5p7vwP1/y3GN4qc5z/
 github.com/ClickHouse/ch-go v0.69.0/go.mod h1:9XeZpSAT4S0kVjOpaJ5186b7PY/NH/hhF8R6u0WIjwg=
 github.com/ClickHouse/clickhouse-go/v2 v2.40.3 h1:46jB4kKwVDUOnECpStKMVXxvR0Cg9zeV9vdbPjtn6po=
 github.com/ClickHouse/clickhouse-go/v2 v2.40.3/go.mod h1:qO0HwvjCnTB4BPL/k6EE3l4d9f/uF+aoimAhJX70eKA=
-github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
-github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
 github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
 github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
 github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
@@ -61,10 +59,6 @@ github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuh
 github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
 github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
 github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
-github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
-github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
-github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
-github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/cosiner/argv v0.1.0 h1:BVDiEL32lwHukgJKP87btEPenzrrHUjajs/8yzaqcXg=
 github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8=
@@ -82,8 +76,6 @@ github.com/derekparker/trie v0.0.0-20230829180723-39f4de51ef7d h1:hUWoLdw5kvo2xC
 github.com/derekparker/trie v0.0.0-20230829180723-39f4de51ef7d/go.mod h1:C7Es+DLenIpPc9J6IYw4jrK0h7S9bKj4DNl8+KxGEXU=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
-github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
 github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
@@ -92,10 +84,6 @@ github.com/dmarkham/enumer v1.6.1 h1:aSc9awYtZL07TUueWs40QcHtxTvHTAwG0EqrNsK45w4
 github.com/dmarkham/enumer v1.6.1/go.mod h1:yixql+kDDQRYqcuBM2n9Vlt7NoT9ixgXhaXry8vmRg8=
 github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk=
 github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE=
-github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
-github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
-github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
-github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
 github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA=
@@ -108,8 +96,6 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
 github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
 github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
 github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
-github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
-github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
 github.com/frapposelli/wwhrd v0.4.0 h1:Vn4hjT/tHNeOnTxFBO0ys1NBH8/Inxqqi1Q0eJmCImo=
 github.com/frapposelli/wwhrd v0.4.0/go.mod h1:Bzwvr3hY1yoBsBbIMkckeHUI6jf1cLRueaaMxZ3N9FY=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -304,12 +290,6 @@ github.com/mgechev/revive v1.12.0 h1:Q+/kkbbwerrVYPv9d9efaPGmAO/NsxwW/nE6ahpQaCU
 github.com/mgechev/revive v1.12.0/go.mod h1:VXsY2LsTigk8XU9BpZauVLjVrhICMOV3k1lpB3CXrp8=
 github.com/mna/pigeon v1.3.0 h1:/3fzVrl1C2RK3x04tyL+ribn+3S3VSEFFbCFLmRPAoc=
 github.com/mna/pigeon v1.3.0/go.mod h1:SKQNHonx2q9U2QSSoPtMigExj+vQ1mOpL7UVFQF/IA0=
-github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
-github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
-github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg=
-github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
-github.com/moby/moby/client v0.2.1 h1:1Grh1552mvv6i+sYOdY+xKKVTvzJegcVMhuXocyDz/k=
-github.com/moby/moby/client v0.2.1/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -342,10 +322,6 @@ github.com/openconfig/gnmic/pkg/api v0.1.9 h1:XPln4mDgC2Bjh9VqE+BY1LLvQrk1tGHZLi
 github.com/openconfig/gnmic/pkg/api v0.1.9/go.mod h1:Sbjj4ITlGT1w2cXt1qEMU6jBYpRm6aoR6Spe4Do86ec=
 github.com/openconfig/grpctunnel v0.1.0 h1:EN99qtlExZczgQgp5ANnHRC/Rs62cAG+Tz2BQ5m/maM=
 github.com/openconfig/grpctunnel v0.1.0/go.mod h1:G04Pdu0pml98tdvXrvLaU+EBo3PxYfI9MYqpvdaEHLo=
-github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
-github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
-github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
 github.com/oschwald/maxminddb-golang/v2 v2.1.1 h1:lA8FH0oOrM4u7mLvowq8IT6a3Q/qEnqRzLQn9eH5ojc=
 github.com/oschwald/maxminddb-golang/v2 v2.1.1/go.mod h1:PLdx6PR+siSIoXqqy7C7r3SB3KZnhxWr1Dp6g0Hacl8=
 github.com/osrg/gobgp/v4 v4.1.0 h1:f9wjTna4puPy80USuvoM4yquv29SzPra5u+bQtWfris=
@@ -437,10 +413,6 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
 github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
-github.com/ti-mo/conntrack v0.6.0 h1:laiW2+dzKyS2u0aVr6FeRQs+v7cj4t7q+twolL/ZkjQ=
-github.com/ti-mo/conntrack v0.6.0/go.mod h1:4HZrFQQLOSuBzgQNid3H/wYyyp1kfGXUYxueXjIGibo=
-github.com/ti-mo/netfilter v0.5.3 h1:ikzduvnaUMwre5bhbNwWOd6bjqLMVb33vv0XXbK0xGQ=
-github.com/ti-mo/netfilter v0.5.3/go.mod h1:08SyBCg6hu1qyQk4s3DjjJKNrm3RTb32nm6AzyT972E=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
 github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
@@ -463,8 +435,6 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
 github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
 github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
 github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
-github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
-github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
 github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
@@ -486,8 +456,6 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
 go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
 go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
 go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
 go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
 go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
 go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
@@ -695,5 +663,3 @@ modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
 modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
 modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
 modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
-pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
-pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=



Test patch:
diff --git a/conntrackfixer/root_test.go b/conntrackfixer/root_test.go
deleted file mode 100644
index daf17d2b..00000000
--- a/conntrackfixer/root_test.go
+++ /dev/null
@@ -1,242 +0,0 @@
-// SPDX-FileCopyrightText: 2022 Free Mobile
-// SPDX-License-Identifier: AGPL-3.0-only
-
-//go:build linux
-
-package conntrackfixer
-
-import (
-	"context"
-	"errors"
-	"net/netip"
-	"testing"
-	"time"
-
-	"github.com/moby/moby/api/types/container"
-	"github.com/moby/moby/api/types/events"
-	"github.com/moby/moby/api/types/network"
-	"github.com/moby/moby/client"
-	_ "github.com/opencontainers/image-spec/specs-go/v1" // used by mock
-	"github.com/ti-mo/conntrack"
-	"go.uber.org/mock/gomock"
-
-	"akvorado/common/daemon"
-	"akvorado/common/helpers"
-	"akvorado/common/httpserver"
-	"akvorado/common/reporter"
-	"akvorado/conntrackfixer/mocks"
-)
-
-func TestRoot(t *testing.T) {
-	r := reporter.NewMock(t)
-	h := httpserver.NewMock(t, r)
-	c, err := New(r, Dependencies{
-		HTTP:   h,
-		Daemon: daemon.NewMock(t),
-	})
-	if err != nil {
-		t.Fatalf("New() error:\n%+v", err)
-	}
-
-	// Replace docker client and conntrack connection with mocks
-	ctrl := gomock.NewController(t)
-	dockerClientMock := mocks.NewMockDockerClient(ctrl)
-	c.dockerClient = dockerClientMock
-	conntrackConnMock := mocks.NewMockConntrackConn(ctrl)
-	c.conntrackConn = conntrackConnMock
-
-	dockerClientMock.EXPECT().
-		Close().
-		Return(nil)
-	conntrackConnMock.EXPECT().
-		Close().
-		Return(nil)
-
-	dockerEventMessages := make(chan events.Message)
-	dockerEvents := client.EventsResult{
-		Messages: dockerEventMessages,
-		Err:      nil,
-	}
-	dockerClientMock.EXPECT().
-		Events(gomock.Any(), gomock.Any()).
-		Return(dockerEvents)
-
-	// Initial trigger
-	networkSettings := &container.NetworkSettings{}
-	networkSettings.Ports = network.PortMap{
-		network.MustParsePort("2055/udp"): {
-			network.PortBinding{
-				HostIP:   netip.MustParseAddr("127.0.0.1"),
-				HostPort: "6776",
-			},
-		},
-	}
-	dockerClientMock.EXPECT().
-		ContainerList(gomock.Any(), gomock.Any()).
-		Return(client.ContainerListResult{
-			Items: []container.Summary{{ID: "initial"}},
-		}, nil)
-	dockerClientMock.EXPECT().
-		ContainerInspect(gomock.Any(), "initial", gomock.Any()).
-		Return(client.ContainerInspectResult{
-			Container: container.InspectResponse{
-				NetworkSettings: networkSettings,
-			},
-		}, nil)
-	conntrackConnMock.EXPECT().
-		Dump(nil).
-		Return([]conntrack.Flow{
-			{
-				ID: 1,
-				TupleOrig: conntrack.Tuple{
-					Proto: conntrack.ProtoTuple{
-						Protocol:        17,
-						DestinationPort: 6777,
-					},
-				},
-			}, {
-				ID: 2,
-				TupleOrig: conntrack.Tuple{
-					Proto: conntrack.ProtoTuple{
-						Protocol:        17,
-						DestinationPort: 6776,
-					},
-				},
-			},
-		}, nil)
-	conntrackConnMock.EXPECT().
-		Delete(conntrack.Flow{
-			ID: 2,
-			TupleOrig: conntrack.Tuple{
-				Proto: conntrack.ProtoTuple{
-					Protocol:        17,
-					DestinationPort: 6776,
-				},
-			},
-		}).
-		Return(nil)
-	helpers.StartStop(t, c)
-
-	// Healthcheck test
-	t.Run("healthcheck", func(t *testing.T) {
-		dockerClientMock.EXPECT().ServerVersion(gomock.Any(), gomock.Any()).
-			Return(client.ServerVersionResult{}, nil)
-		got := r.RunHealthchecks(context.Background())
-		if diff := helpers.Diff(got.Details["conntrack-fixer"], reporter.HealthcheckResult{
-			Status: reporter.HealthcheckOK,
-			Reason: "docker client alive",
-		}); diff != "" {
-			t.Fatalf("runHealthcheck() (-got, +want):\n%s", diff)
-		}
-		dockerClientMock.EXPECT().ServerVersion(gomock.Any(), gomock.Any()).
-			Return(client.ServerVersionResult{}, errors.New("unexpected"))
-		got = r.RunHealthchecks(context.Background())
-		if diff := helpers.Diff(got.Details["conntrack-fixer"], reporter.HealthcheckResult{
-			Status: reporter.HealthcheckWarning,
-			Reason: "docker client unavailable",
-		}); diff != "" {
-			t.Fatalf("runHealthcheck() (-got, +want):\n%s", diff)
-		}
-	})
-
-	// New container
-	t.Run("new container", func(_ *testing.T) {
-		networkSettings := &container.NetworkSettings{}
-		networkSettings.Ports = network.PortMap{
-			network.MustParsePort("2055/udp"): {
-				network.PortBinding{
-					HostIP:   netip.MustParseAddr("127.0.0.1"),
-					HostPort: "6777",
-				},
-			},
-		}
-		dockerClientMock.EXPECT().
-			ContainerList(gomock.Any(), gomock.Any()).
-			Return(client.ContainerListResult{
-				Items: []container.Summary{{ID: "new one"}},
-			}, nil)
-		dockerClientMock.EXPECT().
-			ContainerInspect(gomock.Any(), "new one", gomock.Any()).
-			Return(client.ContainerInspectResult{
-				Container: container.InspectResponse{
-					NetworkSettings: networkSettings,
-				},
-			}, nil)
-		conntrackConnMock.EXPECT().
-			Dump(nil).
-			Return([]conntrack.Flow{
-				{
-					ID: 3,
-					TupleOrig: conntrack.Tuple{
-						Proto: conntrack.ProtoTuple{
-							Protocol:        6, // TCP!
-							DestinationPort: 6777,
-						},
-					},
-				}, {
-					ID: 4,
-					TupleOrig: conntrack.Tuple{
-						Proto: conntrack.ProtoTuple{
-							Protocol:        17,
-							DestinationPort: 6777,
-						},
-					},
-				}, {
-					ID: 5,
-					TupleOrig: conntrack.Tuple{
-						Proto: conntrack.ProtoTuple{
-							Protocol:        17,
-							DestinationPort: 6777,
-						},
-					},
-				},
-			}, nil)
-		conntrackConnMock.EXPECT().
-			Delete(conntrack.Flow{
-				ID: 4,
-				TupleOrig: conntrack.Tuple{
-					Proto: conntrack.ProtoTuple{
-						Protocol:        17,
-						DestinationPort: 6777,
-					},
-				},
-			}).
-			Return(errors.New("already deleted"))
-		conntrackConnMock.EXPECT().
-			Delete(conntrack.Flow{
-				ID: 5,
-				TupleOrig: conntrack.Tuple{
-					Proto: conntrack.ProtoTuple{
-						Protocol:        17,
-						DestinationPort: 6777,
-					},
-				},
-			}).
-			Return(nil)
-		dockerEventMessages <- events.Message{
-			Type:   events.ContainerEventType,
-			Action: events.ActionCreate,
-			Actor: events.Actor{
-				ID: "something",
-				Attributes: map[string]string{
-					"image": "some/image:v17",
-				},
-			},
-		}
-		time.Sleep(20 * time.Millisecond)
-	})
-
-	t.Run("metrics", func(t *testing.T) {
-		gotMetrics := r.GetMetrics("akvorado_conntrackfixer_")
-		expectedMetrics := map[string]string{
-			`conntrack_deleted_total{container="initial",port="6776"}`: "1",
-			`conntrack_deleted_total{container="new one",port="6777"}`: "1",
-			`errors_total{error="cannot delete conntrack entries"}`:    "1",
-			`runs_total{reason="new container"}`:                       "1",
-			`runs_total{reason="start"}`:                               "1",
-		}
-		if diff := helpers.Diff(gotMetrics, expectedMetrics); diff != "" {
-			t.Fatalf("Metrics after template (-got, +want):\n%s", diff)
-		}
-	})
-}