Repository: submariner-io/submariner
Pull request #3350: Packetfilter API: add support for IPv6
Author: login: tpantelis
Labels: name: ready-to-test
description: When a PR is ready for full E2E testing
Created: 2025-03-13T12:27:48Z | Merged: 2025-03-17T15:44:00Z

Modified the `DriverFn` and `packetfilter.New` functions to take the IP family.




Diff:
diff --git a/pkg/globalnet/controllers/gateway_monitor.go b/pkg/globalnet/controllers/gateway_monitor.go
index 4b9120335..567fddbc2 100644
--- a/pkg/globalnet/controllers/gateway_monitor.go
+++ b/pkg/globalnet/controllers/gateway_monitor.go
@@ -92,7 +92,7 @@ func NewGatewayMonitor(ctx context.Context, config *GatewayMonitorConfig) (Inter
 
 	var err error
 
-	gatewayMonitor.pFilter, err = packetfilter.New()
+	gatewayMonitor.pFilter, err = packetfilter.New(k8snet.IPv4)
 	if err != nil {
 		return nil, errors.Wrap(err, "error creating packetfilter")
 	}
diff --git a/pkg/globalnet/controllers/gateway_monitor_test.go b/pkg/globalnet/controllers/gateway_monitor_test.go
index 6cfc94e76..febb9d62c 100644
--- a/pkg/globalnet/controllers/gateway_monitor_test.go
+++ b/pkg/globalnet/controllers/gateway_monitor_test.go
@@ -43,6 +43,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/dynamic"
 	fakek8s "k8s.io/client-go/kubernetes/fake"
+	k8snet "k8s.io/utils/net"
 )
 
 const (
@@ -270,11 +271,11 @@ var _ = Describe("Uninstall", func() {
 
 		Expect(t.pFilter.NewNamedSet(&packetfilter.SetInfo{
 			Name: ipSetName,
-		}).Create(true)).To(Succeed())
+		}, k8snet.IPv4).Create(true)).To(Succeed())
 
 		Expect(t.pFilter.NewNamedSet(&packetfilter.SetInfo{
 			Name: "other",
-		}).Create(true)).To(Succeed())
+		}, k8snet.IPv4).Create(true)).To(Succeed())
 	})
 
 	Specify("UninstallDataPath should remove the IP table chains and sets", func() {
diff --git a/pkg/globalnet/controllers/packetfilter/iface.go b/pkg/globalnet/controllers/packetfilter/iface.go
index 834861c1e..9677e6009 100644
--- a/pkg/globalnet/controllers/packetfilter/iface.go
+++ b/pkg/globalnet/controllers/packetfilter/iface.go
@@ -25,6 +25,7 @@ import (
 	"github.com/submariner-io/admiral/pkg/log"
 	"github.com/submariner-io/submariner/pkg/globalnet/constants"
 	"github.com/submariner-io/submariner/pkg/packetfilter"
+	k8snet "k8s.io/utils/net"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 )
 
@@ -63,7 +64,7 @@ const (
 var logger = log.Logger{Logger: logf.Log.WithName("PacketFilter")}
 
 func New() (Interface, error) {
-	pFilterHandler, err := packetfilter.New()
+	pFilterHandler, err := packetfilter.New(k8snet.IPv4)
 	if err != nil {
 		return nil, err //nolint:wrapcheck  // Let the caller wrap it
 	}
@@ -77,8 +78,7 @@ func New() (Interface, error) {
 
 func (i *pfilter) NewNamedSet(key string) NamedSet {
 	return i.pFilter.NewNamedSet(&packetfilter.SetInfo{
-		Name:   key,
-		Family: packetfilter.SetFamilyV4,
+		Name: key,
 	})
 }
 
diff --git a/pkg/globalnet/controllers/uninstall.go b/pkg/globalnet/controllers/uninstall.go
index 28bae7725..d853218bc 100644
--- a/pkg/globalnet/controllers/uninstall.go
+++ b/pkg/globalnet/controllers/uninstall.go
@@ -39,13 +39,14 @@ import (
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/client-go/dynamic"
 	"k8s.io/client-go/kubernetes/scheme"
+	k8snet "k8s.io/utils/net"
 )
 
 func UninstallDataPath() {
 	gnpFilter, err := pfiface.New()
 	logger.FatalOnError(err, "Error initializing GN PacketFilter")
 
-	pFilter, err := packetfilter.New()
+	pFilter, err := packetfilter.New(k8snet.IPv4)
 	logger.FatalOnError(err, "Error initializing PacketFilter")
 
 	natTableChains := []string{
diff --git a/pkg/packetfilter/adapter_test.go b/pkg/packetfilter/adapter_test.go
index e304626d1..f7b131711 100644
--- a/pkg/packetfilter/adapter_test.go
+++ b/pkg/packetfilter/adapter_test.go
@@ -23,6 +23,7 @@ import (
 	. "github.com/onsi/gomega"
 	"github.com/submariner-io/submariner/pkg/packetfilter"
 	fakePF "github.com/submariner-io/submariner/pkg/packetfilter/fake"
+	k8snet "k8s.io/utils/net"
 )
 
 const (
@@ -92,7 +93,7 @@ var _ = Describe("Adapter", func() {
 
 		var err error
 
-		adapter, err = packetfilter.New()
+		adapter, err = packetfilter.New(k8snet.IPv4)
 		Expect(err).To(Succeed())
 
 		Expect(pFilter.CreateChainIfNotExists(packetfilter.TableTypeNAT, &packetfilter.Chain{
@@ -179,7 +180,7 @@ var _ = Describe("Adapter", func() {
 	})
 })
 
-func assertRules(pFilter packetfilter.Driver, table packetfilter.TableType, expected ...*packetfilter.Rule) {
+func assertRules(pFilter *fakePF.PacketFilter, table packetfilter.TableType, expected ...*packetfilter.Rule) {
 	actual, err := pFilter.List(table, chain)
 	Expect(err).To(Succeed())
 	Expect(actual).To(Equal(expected))
diff --git a/pkg/packetfilter/fake/driver.go b/pkg/packetfilter/fake/driver.go
new file mode 100644
index 000000000..7f63a8b2b
--- /dev/null
+++ b/pkg/packetfilter/fake/driver.go
@@ -0,0 +1,139 @@
+/*
+SPDX-License-Identifier: Apache-2.0
+
+Copyright Contributors to the Submariner project.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package fake
+
+import (
+	"net"
+	"strings"
+
+	"github.com/pkg/errors"
+	"github.com/submariner-io/submariner/pkg/packetfilter"
+	utilerrors "k8s.io/apimachinery/pkg/util/errors"
+	k8snet "k8s.io/utils/net"
+)
+
+type driverImpl struct {
+	pfilter *PacketFilter
+	family  k8snet.IPFamily
+}
+
+func (d *driverImpl) ChainExists(table packetfilter.TableType, chain string) (bool, error) {
+	return d.pfilter.ChainExists(table, chain)
+}
+
+func (d *driverImpl) CreateIPHookChainIfNotExists(chain *packetfilter.ChainIPHook) error {
+	return d.pfilter.CreateIPHookChainIfNotExists(chain)
+}
+
+func (d *driverImpl) CreateChainIfNotExists(table packetfilter.TableType, chain *packetfilter.Chain) error {
+	return d.pfilter.CreateChainIfNotExists(table, chain)
+}
+
+func (d *driverImpl) DeleteIPHookChain(chain *packetfilter.ChainIPHook) error {
+	return d.pfilter.DeleteIPHookChain(chain)
+}
+
+func (d *driverImpl) DeleteChain(table packetfilter.TableType, chain string) error {
+	return d.pfilter.DeleteChain(table, chain)
+}
+
+func (d *driverImpl) ClearChain(table packetfilter.TableType, chain string) error {
+	return d.pfilter.ClearChain(table, chain)
+}
+
+func (d *driverImpl) List(table packetfilter.TableType, chain string) ([]*packetfilter.Rule, error) {
+	return d.pfilter.List(table, chain)
+}
+
+func (d *driverImpl) Delete(table packetfilter.TableType, chain string, rule *packetfilter.Rule) error {
+	if err := d.verifyRule(rule); err != nil {
+		return err
+	}
+
+	return d.pfilter.Delete(table, chain, rule)
+}
+
+func (d *driverImpl) AppendUnique(table packetfilter.TableType, chain string, rule *packetfilter.Rule) error {
+	if err := d.verifyRule(rule); err != nil {
+		return err
+	}
+
+	return d.pfilter.AppendUnique(table, chain, rule)
+}
+
+func (d *driverImpl) Append(table packetfilter.TableType, chain string, rule *packetfilter.Rule) error {
+	if err := d.verifyRule(rule); err != nil {
+		return err
+	}
+
+	return d.pfilter.Append(table, chain, rule)
+}
+
+func (d *driverImpl) Insert(table packetfilter.TableType, chain string, pos int, rule *packetfilter.Rule) error {
+	if err := d.verifyRule(rule); err != nil {
+		return err
+	}
+
+	return d.pfilter.Insert(table, chain, pos, rule)
+}
+
+func (d *driverImpl) NewNamedSet(set *packetfilter.SetInfo) packetfilter.NamedSet {
+	return d.pfilter.NewNamedSet(set, d.family)
+}
+
+func (d *driverImpl) DestroySets(nameFilter func(string) bool) error {
+	return d.pfilter.DestroySets(nameFilter)
+}
+
+func (d *driverImpl) verifyRule(rule *packetfilter.Rule) error {
+	var errs []error
+
+	return utilerrors.NewAggregate(append(errs, verifyFamilyOf(rule.SrcCIDR, "SrcCIDR", d.family),
+		verifyFamilyOf(rule.DestCIDR, "DestCIDR", d.family),
+		verifyFamilyOf(rule.SnatCIDR, "SnatCIDR", d.family),
+		verifyFamilyOf(rule.DnatCIDR, "DnatCIDR", d.family)))
+}
+
+func verifyFamilyOf(s, name string, expectedFamily k8snet.IPFamily) error {
+	if s == "" {
+		return nil
+	}
+
+	ipRange := strings.Split(s, "-")
+	if len(ipRange) == 2 {
+		return utilerrors.NewAggregate([]error{
+			verifyFamilyOf(ipRange[0], name, expectedFamily),
+			verifyFamilyOf(ipRange[1], name, expectedFamily),
+		})
+	}
+
+	var family k8snet.IPFamily
+
+	if ip := net.ParseIP(s); ip != nil {
+		family = k8snet.IPFamilyOf(ip)
+	} else {
+		family = k8snet.IPFamilyOfCIDRString(s)
+	}
+
+	if family == expectedFamily {
+		return nil
+	}
+
+	return errors.Errorf("the family of %q (IPv%v) for %q is not allowed", s, family, name)
+}
diff --git a/pkg/packetfilter/fake/namedset.go b/pkg/packetfilter/fake/namedset.go
index c2ebeb3e6..50e89a172 100644
--- a/pkg/packetfilter/fake/namedset.go
+++ b/pkg/packetfilter/fake/namedset.go
@@ -26,12 +26,14 @@ import (
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
 	"github.com/submariner-io/submariner/pkg/packetfilter"
+	k8snet "k8s.io/utils/net"
 	"k8s.io/utils/set"
 )
 
 type namedSet struct {
 	setInfo *packetfilter.SetInfo
 	pfilter *PacketFilter
+	family  k8snet.IPFamily
 }
 
 func (n *namedSet) Name() string {
@@ -52,10 +54,18 @@ func (n *namedSet) Create(ignoreExistErr bool) error {
 }
 
 func (n *namedSet) AddEntry(entry string, ignoreExistErr bool) error {
+	if err := verifyFamilyOf(entry, "AddEntry", n.family); err != nil {
+		return err
+	}
+
 	return n.pfilter.addEntry(entry, n.setInfo, ignoreExistErr)
 }
 
 func (n *namedSet) DelEntry(entry string) error {
+	if err := verifyFamilyOf(entry, "DelEntry", n.family); err != nil {
+		return err
+	}
+
 	return n.pfilter.delEntry(entry, n.setInfo.Name)
 }
 
@@ -204,10 +214,11 @@ func (i *PacketFilter) DestroySets(nameFilter func(string) bool) error {
 	return nil
 }
 
-func (i *PacketFilter) NewNamedSet(setInfo *packetfilter.SetInfo) packetfilter.NamedSet {
+func (i *PacketFilter) NewNamedSet(setInfo *packetfilter.SetInfo, family k8snet.IPFamily) packetfilter.NamedSet {
 	return &namedSet{
 		setInfo: setInfo,
 		pfilter: i,
+		family:  family,
 	}
 }
 
diff --git a/pkg/packetfilter/fake/packetfilter.go b/pkg/packetfilter/fake/packetfilter.go
index 87e179297..60f7ed1df 100644
--- a/pkg/packetfilter/fake/packetfilter.go
+++ b/pkg/packetfilter/fake/packetfilter.go
@@ -28,6 +28,7 @@ import (
 	. "github.com/onsi/gomega"
 	"github.com/pkg/errors"
 	"github.com/submariner-io/submariner/pkg/packetfilter"
+	k8snet "k8s.io/utils/net"
 	"k8s.io/utils/set"
 )
 
@@ -44,14 +45,22 @@ type PacketFilter struct {
 	failOnDelEntryMatchers   []interface{}
 }
 
-func New() *PacketFilter {
+func New(allowedFamilies ...k8snet.IPFamily) *PacketFilter {
+	if len(allowedFamilies) == 0 {
+		allowedFamilies = []k8snet.IPFamily{k8snet.IPv4}
+	}
+
 	pf := &PacketFilter{
 		chainRules: map[string][]string{},
 		sets:       map[string]set.Set[string]{},
 	}
 
-	packetfilter.SetNewDriverFn(func() (packetfilter.Driver, error) {
-		return pf, nil
+	packetfilter.SetNewDriverFn(func(family k8snet.IPFamily) (packetfilter.Driver, error) {
+		if slices.Contains(allowedFamilies, family) {
+			return &driverImpl{pfilter: pf, family: family}, nil
+		}
+
+		return nil, errors.Errorf("IPv%v is not allowed", family)
 	})
 
 	return pf
diff --git a/pkg/packetfilter/iptables/iptables.go b/pkg/packetfilter/iptables/iptables.go
index 292394857..f56272e08 100644
--- a/pkg/packetfilter/iptables/iptables.go
+++ b/pkg/packetfilter/iptables/iptables.go
@@ -26,6 +26,7 @@ import (
 	"github.com/submariner-io/admiral/pkg/log"
 	"github.com/submariner-io/submariner/pkg/ipset"
 	"github.com/submariner-io/submariner/pkg/packetfilter"
+	k8snet "k8s.io/utils/net"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 )
 
@@ -60,6 +61,11 @@ var (
 		packetfilter.RuleActionDNAT:   "DNAT",
 	}
 
+	protocolByFamily = map[k8snet.IPFamily]iptables.Protocol{
+		k8snet.IPv4: iptables.ProtocolIPv4,
+		k8snet.IPv6: iptables.ProtocolIPv6,
+	}
+
 	logger = log.Logger{Logger: logf.Log.WithName("IPTables")}
 )
 
@@ -72,17 +78,12 @@ func (r RuleSpec) String() string {
 type packetFilter struct {
 	ipt        *iptables.IPTables
 	ipSetIface ipset.Interface
+	family     k8snet.IPFamily
 }
 
-func New() (packetfilter.Driver, error) {
-	return newiptables(iptables.ProtocolIPv4)
-}
-
-func NewV6() (packetfilter.Driver, error) {
-	return newiptables(iptables.ProtocolIPv6)
-}
+func New(family k8snet.IPFamily) (packetfilter.Driver, error) {
+	proto := protocolByFamily[family]
 
-func newiptables(proto iptables.Protocol) (packetfilter.Driver, error) {
 	ipt, err := iptables.New(iptables.IPFamily(proto), iptables.Timeout(5))
 	if err != nil {
 		return nil, errors.Wrapf(err, "error creating IP tables for protocol %d", proto)
@@ -93,6 +94,7 @@ func newiptables(proto iptables.Protocol) (packetfilter.Driver, error) {
 	return &packetFilter{
 		ipt:        ipt,
 		ipSetIface: ipSetIface,
+		family:     family,
 	}, nil
 }
 
diff --git a/pkg/packetfilter/iptables/namedset.go b/pkg/packetfilter/iptables/namedset.go
index 73919e6a6..92d8867e8 100644
--- a/pkg/packetfilter/iptables/namedset.go
+++ b/pkg/packetfilter/iptables/namedset.go
@@ -22,6 +22,7 @@ import (
 	"github.com/pkg/errors"
 	"github.com/submariner-io/submariner/pkg/ipset"
 	"github.com/submariner-io/submariner/pkg/packetfilter"
+	k8snet "k8s.io/utils/net"
 )
 
 type namedSet struct {
@@ -31,7 +32,7 @@ type namedSet struct {
 
 func (p *packetFilter) NewNamedSet(set *packetfilter.SetInfo) packetfilter.NamedSet {
 	hashFamily := ipset.ProtocolFamilyIPV4
-	if set.Family == packetfilter.SetFamilyV6 {
+	if p.family == k8snet.IPv6 {
 		hashFamily = ipset.ProtocolFamilyIPV6
 	}
 
diff --git a/pkg/packetfilter/nftables/namedset.go b/pkg/packetfilter/nftables/namedset.go
index dd1fb73aa..1bf66c31d 100644
--- a/pkg/packetfilter/nftables/namedset.go
+++ b/pkg/packetfilter/nftables/namedset.go
@@ -24,6 +24,7 @@ import (
 	"github.com/pkg/errors"
 	"github.com/submariner-io/submariner/pkg/packetfilter"
 	utilerrors "k8s.io/apimachinery/pkg/util/errors"
+	k8snet "k8s.io/utils/net"
 	"k8s.io/utils/ptr"
 	"sigs.k8s.io/knftables"
 )
@@ -35,6 +36,9 @@ type namedSet struct {
 
 func (p *packetFilter) NewNamedSet(set *packetfilter.SetInfo) packetfilter.NamedSet {
 	setType := "ipv4_addr"
+	if p.family == k8snet.IPv6 {
+		setType = "ipv6_addr"
+	}
 
 	return &namedSet{
 		set: knftables.Set{
diff --git a/pkg/packetfilter/nftables/nftables.go b/pkg/packetfilter/nftables/nftables.go
index 437f881ba..4bd7574dc 100644
--- a/pkg/packetfilter/nftables/nftables.go
+++ b/pkg/packetfilter/nftables/nftables.go
@@ -26,6 +26,7 @@ import (
 	"github.com/pkg/errors"
 	"github.com/submariner-io/admiral/pkg/log"
 	"github.com/submariner-io/submariner/pkg/packetfilter"
+	k8snet "k8s.io/utils/net"
 	"k8s.io/utils/ptr"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 	"sigs.k8s.io/knftables"
@@ -66,6 +67,11 @@ var (
 		packetfilter.RuleActionJump:   {"jump"},
 	}
 
+	nftFamilies = map[k8snet.IPFamily]knftables.Family{
+		k8snet.IPv4: knftables.IPv4Family,
+		k8snet.IPv6: knftables.IPv6Family,
+	}
+
 	logger = log.Logger{Logger: logf.Log.WithName("NFTables")}
 )
 
@@ -77,20 +83,22 @@ func (r RuleSpec) String() string {
 
 type packetFilter struct {
 	nftables knftables.Interface
+	family   k8snet.IPFamily
 }
 
-func New() (packetfilter.Driver, error) {
-	nft, err := knftables.New(knftables.IPv4Family, submarinerTable)
+func New(family k8snet.IPFamily) (packetfilter.Driver, error) {
+	nft, err := knftables.New(nftFamilies[family], submarinerTable)
 	if err != nil {
-		return nil, errors.Wrap(err, "error creating knftables")
+		return nil, errors.Wrapf(err, "error creating knftables for family IPv%s", family)
 	}
 
-	return NewWithNft(nft), nil
+	return NewWithNft(nft, family), nil
 }
 
-func NewWithNft(nft knftables.Interface) packetfilter.Driver {
+func NewWithNft(nft knftables.Interface, family k8snet.IPFamily) packetfilter.Driver {
 	return &packetFilter{
 		nftables: nft,
+		family:   family,
 	}
 }
 
diff --git a/pkg/packetfilter/nftables/nftables_test.go b/pkg/packetfilter/nftables/nftables_test.go
index 628dae31b..34c614b34 100644
--- a/pkg/packetfilter/nftables/nftables_test.go
+++ b/pkg/packetfilter/nftables/nftables_test.go
@@ -25,6 +25,7 @@ import (
 	. "github.com/onsi/gomega"
 	"github.com/submariner-io/submariner/pkg/packetfilter"
 	"github.com/submariner-io/submariner/pkg/packetfilter/nftables"
+	k8snet "k8s.io/utils/net"
 	"sigs.k8s.io/knftables"
 )
 
@@ -111,15 +112,14 @@ var _ = Describe("Interface", func() {
 		pf            packetfilter.Driver
 
 		setInfo = &packetfilter.SetInfo{
-			Name:   setName,
-			Table:  packetfilter.TableTypeNAT,
-			Family: packetfilter.SetFamilyV4,
+			Name:  setName,
+			Table: packetfilter.TableTypeNAT,
 		}
 	)
 
 	BeforeEach(func() {
 		fakeKnftables = &fakeKnftablesWrapper{knftables.NewFake(knftables.IPv4Family, "submariner")}
-		pf = nftables.NewWithNft(fakeKnftables)
+		pf = nftables.NewWithNft(fakeKnftables, k8snet.IPv4)
 	})
 
 	assertRules := func(r ...*packetfilter.Rule) {
diff --git a/pkg/packetfilter/packetfilter.go b/pkg/packetfilter/packetfilter.go
index cbf5667f9..babb55783 100644
--- a/pkg/packetfilter/packetfilter.go
+++ b/pkg/packetfilter/packetfilter.go
@@ -23,6 +23,7 @@ import (
 
 	"github.com/pkg/errors"
 	"github.com/submariner-io/admiral/pkg/log"
+	k8snet "k8s.io/utils/net"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 )
 
@@ -250,14 +251,6 @@ type ChainIPHook struct {
 	JumpRule *Rule
 }
 
-type SetFamily uint32
-
-const (
-	// IPV4 and IPV6 sets are supported.
-	SetFamilyV4 SetFamily = iota
-	SetFamilyV6
-)
-
 // named set.
 type SetInfo struct {
 	// Name is the set name.
@@ -266,9 +259,6 @@ type SetInfo struct {
 	SetType string
 	// nftables named set attached to tables.
 	Table TableType
-	// SetFamily specifies the protocol family of the IP addresses to be stored in the set.
-	// The default is IPv4.
-	Family SetFamily
 }
 
 type NamedSet interface {
@@ -308,12 +298,9 @@ type Interface interface {
 	UpdateChainRules(table TableType, chain string, rules []*Rule) error
 }
 
-type DriverFn func() (Driver, error)
+type DriverFn func(family k8snet.IPFamily) (Driver, error)
 
-var (
-	newDriverFn   DriverFn
-	newDriverFnV6 DriverFn
-)
+var newDriverFn DriverFn
 
 func SetNewDriverFn(f DriverFn) {
 	newDriverFn = f
@@ -323,28 +310,16 @@ func GetNewDriverFn() DriverFn {
 	return newDriverFn
 }
 
-func SetNewDriverFnV6(f DriverFn) {
-	newDriverFnV6 = f
-}
-
 type Adapter struct {
 	Driver
 }
 
-func New() (Interface, error) {
-	return newImpl(newDriverFn)
-}
-
-func NewV6() (Interface, error) {
-	return newImpl(newDriverFnV6)
-}
-
-func newImpl(f func() (Driver, error)) (Interface, error) {
-	if f == nil {
+func New(family k8snet.IPFamily) (Interface, error) {
+	if newDriverFn == nil {
 		return nil, errors.New("no driver registered")
 	}
 
-	driver, err := f()
+	driver, err := newDriverFn(family)
 	if err != nil {
 		return nil, errors.Wrap(err, "error creating packet filter Driver")
 	}
diff --git a/pkg/routeagent_driver/handlers/kubeproxy/kp_packetfilter.go b/pkg/routeagent_driver/handlers/kubeproxy/kp_packetfilter.go
index b6b29e5be..69ae03f68 100644
--- a/pkg/routeagent_driver/handlers/kubeproxy/kp_packetfilter.go
+++ b/pkg/routeagent_driver/handlers/kubeproxy/kp_packetfilter.go
@@ -35,6 +35,7 @@ import (
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 	"k8s.io/apimachinery/pkg/util/wait"
 	"k8s.io/client-go/util/retry"
+	k8snet "k8s.io/utils/net"
 	"k8s.io/utils/set"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 )
@@ -63,7 +64,7 @@ type SyncHandler struct {
 var logger = log.Logger{Logger: logf.Log.WithName("KubeProxy")}
 
 func NewSyncHandler(localClusterCidr, localServiceCidr []string) *SyncHandler {
-	pFilter, err := packetfilter.New()
+	pFilter, err := packetfilter.New(k8snet.IPv4)
 	utilruntime.Must(err)
 
 	return &SyncHandler{
diff --git a/pkg/routeagent_driver/handlers/kubeproxy/uninstall.go b/pkg/routeagent_driver/handlers/kubeproxy/uninstall.go
index 9dc68fca5..ce95839db 100644
--- a/pkg/routeagent_driver/handlers/kubeproxy/uninstall.go
+++ b/pkg/routeagent_driver/handlers/kubeproxy/uninstall.go
@@ -27,6 +27,7 @@ import (
 	"github.com/submariner-io/submariner/pkg/port"
 	"github.com/submariner-io/submariner/pkg/routeagent_driver/constants"
 	"github.com/vishvananda/netlink"
+	k8snet "k8s.io/utils/net"
 )
 
 func (kp *SyncHandler) Uninstall() error {
@@ -72,7 +73,7 @@ func deleteVxLANInterface() {
 }
 
 func deleteIPTableChains() {
-	pFilter, err := packetfilter.New()
+	pFilter, err := packetfilter.New(k8snet.IPv4)
 	if err != nil {
 		logger.Errorf(err, "Failed to initialize packetfilter interface")
 		return
diff --git a/pkg/routeagent_driver/handlers/mtu/mtuhandler.go b/pkg/routeagent_driver/handlers/mtu/mtuhandler.go
index 53a067388..6851066e4 100644
--- a/pkg/routeagent_driver/handlers/mtu/mtuhandler.go
+++ b/pkg/routeagent_driver/handlers/mtu/mtuhandler.go
@@ -85,7 +85,7 @@ func (h *mtuHandler) GetName() string {
 func (h *mtuHandler) Init(_ context.Context) error {
 	var err error
 
-	h.pFilter, err = packetfilter.New()
+	h.pFilter, err = packetfilter.New(k8snet.IPv4)
 	if err != nil {
 		return errors.Wrap(err, "error initializing iptables")
 	}
@@ -220,8 +220,7 @@ func extractIPv4Subnets(endpoint *submV1.EndpointSpec) []string {
 
 func (h *mtuHandler) newNamedSetSet(key string) packetfilter.NamedSet {
 	return h.pFilter.NewNamedSet(&packetfilter.SetInfo{
-		Name:   key,
-		Family: packetfilter.SetFamilyV4,
+		Name: key,
 	})
 }
 
diff --git a/pkg/routeagent_driver/handlers/ovn/handler.go b/pkg/routeagent_driver/handlers/ovn/handler.go
index df4fb8795..b7f50d5ed 100644
--- a/pkg/routeagent_driver/handlers/ovn/handler.go
+++ b/pkg/routeagent_driver/handlers/ovn/handler.go
@@ -38,6 +38,7 @@ import (
 	"github.com/submariner-io/submariner/pkg/packetfilter"
 	"k8s.io/client-go/dynamic"
 	"k8s.io/client-go/kubernetes"
+	k8snet "k8s.io/utils/net"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 )
 
@@ -71,7 +72,7 @@ var logger = log.Logger{Logger: logf.Log.WithName("OVN")}
 
 func NewHandler(config *HandlerConfig) *Handler {
 	// We'll panic if env is nil, this is intentional
-	pFilter, err := packetfilter.New()
+	pFilter, err := packetfilter.New(k8snet.IPv4)
 	if err != nil {
 		logger.Fatalf("Error initializing packetfilter in OVN routeagent handler: %s", err)
 	}


Reviews:
user: login: yboaron
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T13:49:16Z
user: login: yboaron
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T10:51:29Z
user: login: tpantelis
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T13:28:08Z
user: login: dfarrell07
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-17T14:10:57Z

Review comments:
diff_hunk: @@ -79,7 +80,11 @@ type packetFilter struct {
 	nftables knftables.Interface
 }
 
-func New() (packetfilter.Driver, error) {
+func New(family k8snet.IPFamily) (packetfilter.Driver, error) {
+	if family != k8snet.IPv4 {
path: pkg/packetfilter/nftables/nftables.go
user: login: yboaron
body: Maybe we can also enable  IPV6 driver creation for nftables, it should be safe because currently all clients will only create a V4 driver
created_at: 2025-03-13T13:49:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -35,6 +36,9 @@ type namedSet struct {
 
 func (p *packetFilter) NewNamedSet(set *packetfilter.SetInfo) packetfilter.NamedSet {
 	setType := "ipv4_addr"
+	if p.family == k8snet.IPv6 {
+		setType = "ipv6_addr"
path: pkg/packetfilter/nftables/namedset.go
user: login: tpantelis
body: @yboaron I assume this is correct for IPv6? I couldn't find any concrete info/doc to confirm it...
created_at: 2025-03-14T13:28:07Z
author_association: CONTRIBUTOR

PR comments:
user: login: submariner-bot
created_at: 2025-03-13T12:27:56Z
body: 🤖 Created branch: z_pr3350/tpantelis/packetfilter_api_v6 
🚀 Full E2E won't run until the "ready-to-test" label is applied. I will add it automatically once the PR has 2 approvals, or you can add it manually.
author_association: CONTRIBUTOR
user: login: tpantelis
created_at: 2025-03-14T14:17:23Z
body: @yboaron I [updated the PR](https://github.com/submariner-io/submariner/compare/71822a74216a4e8a283e9d23976ddf93a9778be8..54899922041fd3c76337169b2a81432f9d7d24ce) to add verification of the expected IP family of IPs/CIDRs passed via the API (eg Rules) in the fake packet filter implementation and to [remove the Family field from SetInfo](https://github.com/submariner-io/submariner/pull/3350/commits/54899922041fd3c76337169b2a81432f9d7d24ce).
author_association: CONTRIBUTOR
user: login: submariner-bot
created_at: 2025-03-17T15:44:03Z
body: 🤖 Closed branches: [z_pr3350/tpantelis/packetfilter_api_v6]
author_association: CONTRIBUTOR