@@ -4,75 +4,41 @@ package fastpath
44
55import (
66 "context"
7+ "fmt"
8+ "math"
79 "net"
810 "time"
911
12+ "github.com/google/nftables"
13+ "github.com/google/nftables/binaryutil"
14+ "github.com/google/nftables/expr"
1015 "github.com/vishvananda/netlink"
1116 "golang.org/x/time/rate"
1217
1318 "k8s.io/apimachinery/pkg/util/sets"
1419 "k8s.io/klog/v2"
15- "sigs.k8s.io/knftables"
1620)
1721
1822const (
19- kindnetFlowtable = "kindnet-flowtables"
20- fastPathChain = "kindnet-fastpath-chain"
23+ kindnetFlowtable = "kindnet-flowtables"
24+ kindnetSetDevices = "kindnet-set-devices"
25+ fastPathChain = "kindnet-fastpath-chain"
2126)
2227
2328func NewFastpathAgent (packetThresold int ) (* FastPathAgent , error ) {
24- klog .V (2 ).Info ("Initializing nftables" )
25- nft , err := knftables .New (knftables .InetFamily , "kindnet-fastpath" )
26- if err != nil {
27- return nil , err
29+ if packetThresold > math .MaxUint32 {
30+ packetThresold = math .MaxUint32
2831 }
2932 return & FastPathAgent {
30- nft : nft ,
31- packetThresold : packetThresold ,
33+ packetThresold : uint32 (packetThresold ),
3234 }, nil
3335}
3436
3537type FastPathAgent struct {
36- nft knftables.Interface
37- packetThresold int
38+ packetThresold uint32
3839}
3940
4041func (ma * FastPathAgent ) Run (ctx context.Context ) error {
41- klog .Info ("Syncing nftables rules" )
42- table := & knftables.Table {
43- Comment : knftables .PtrTo ("rules for kindnet fastpath" ),
44- }
45- tx := ma .nft .NewTransaction ()
46- // do it once to delete the existing table
47- tx .Add (table )
48- tx .Delete (table )
49- tx .Add (table )
50-
51- tx .Add (& knftables.Flowtable {
52- Name : kindnetFlowtable ,
53- })
54-
55- tx .Add (& knftables.Chain {
56- Name : fastPathChain ,
57- Type : knftables .PtrTo (knftables .FilterType ),
58- Hook : knftables .PtrTo (knftables .ForwardHook ),
59- Priority : knftables .PtrTo (knftables .DNATPriority + "-10" ),
60- })
61-
62- tx .Add (& knftables.Rule {
63- Chain : fastPathChain ,
64- Rule : knftables .Concat (
65- "ct packets >" , ma .packetThresold ,
66- "flow offload" , "@" , kindnetFlowtable ,
67- "counter" ,
68- ),
69- })
70-
71- err := ma .nft .Run (ctx , tx )
72- if err != nil {
73- klog .Error (err , "failed to add network interfaces to the flowtable" )
74- }
75-
7642 minInterval := 5 * time .Second
7743 maxInterval := 1 * time .Minute
7844 rateLimiter := rate .NewLimiter (rate .Every (minInterval ), 1 )
@@ -97,12 +63,7 @@ func (ma *FastPathAgent) Run(ctx context.Context) error {
9763 }
9864
9965 if len (ifnames ) > 0 && ! ifnames .Equal (currentIf ) {
100- tx := ma .nft .NewTransaction ()
101- tx .Add (& knftables.Flowtable {
102- Name : kindnetFlowtable ,
103- Devices : ifnames .UnsortedList (),
104- })
105- err := ma .nft .Run (ctx , tx )
66+ err := ma .syncRules (ifnames .UnsortedList ())
10667 if err != nil {
10768 klog .Error (err , "failed to add network interfaces to the flowtable" )
10869 } else {
@@ -149,14 +110,124 @@ func (ma *FastPathAgent) getNodeInterfaces() (sets.Set[string], error) {
149110 return ifNames , nil
150111}
151112
113+ func (ma * FastPathAgent ) syncRules (devices []string ) error {
114+ klog .V (2 ).Info ("Syncing kindnet-fastpath nftables rules" )
115+ nft , err := nftables .New ()
116+ if err != nil {
117+ return fmt .Errorf ("fastpath failure, can not start nftables:%v" , err )
118+ }
119+
120+ // add + delete + add for flushing all the table
121+ fastpathTable := & nftables.Table {
122+ Name : "kindnet-fastpath" ,
123+ Family : nftables .TableFamilyINet ,
124+ }
125+ nft .AddTable (fastpathTable )
126+ nft .DelTable (fastpathTable )
127+ nft .AddTable (fastpathTable )
128+
129+ devicesSet := & nftables.Set {
130+ Table : fastpathTable ,
131+ Name : kindnetSetDevices ,
132+ KeyType : nftables .TypeIFName ,
133+ KeyByteOrder : binaryutil .NativeEndian ,
134+ }
135+
136+ elements := []nftables.SetElement {}
137+ for _ , dev := range devices {
138+ elements = append (elements , nftables.SetElement {
139+ Key : ifname (dev ),
140+ })
141+ }
142+
143+ if err := nft .AddSet (devicesSet , elements ); err != nil {
144+ return fmt .Errorf ("failed to add Set %s : %v" , devicesSet .Name , err )
145+ }
146+
147+ flowtable := & nftables.Flowtable {
148+ Table : fastpathTable ,
149+ Name : kindnetFlowtable ,
150+ Devices : devices ,
151+ Hooknum : nftables .FlowtableHookIngress ,
152+ Priority : nftables .FlowtablePriorityRef (5 ),
153+ }
154+ nft .AddFlowtable (flowtable )
155+
156+ chain := nft .AddChain (& nftables.Chain {
157+ Name : fastPathChain ,
158+ Table : fastpathTable ,
159+ Type : nftables .ChainTypeFilter ,
160+ Hooknum : nftables .ChainHookForward ,
161+ Priority : nftables .ChainPriorityMangle , // before DNAT
162+ })
163+
164+ // only offload devices that are being tracked
165+ // TODO: check if this is really needed, we are using a set in addition
166+ // to the flowtable.
167+ nft .AddRule (& nftables.Rule {
168+ Table : fastpathTable ,
169+ Chain : chain ,
170+ Exprs : []expr.Any {
171+ & expr.Meta {Key : expr .MetaKeyIIFNAME , SourceRegister : false , Register : 0x1 },
172+ & expr.Lookup {SourceRegister : 0x1 , DestRegister : 0x0 , IsDestRegSet : false , SetName : kindnetSetDevices , Invert : true },
173+ & expr.Verdict {Kind : expr .VerdictReturn },
174+ },
175+ })
176+
177+ nft .AddRule (& nftables.Rule {
178+ Table : fastpathTable ,
179+ Chain : chain ,
180+ Exprs : []expr.Any {
181+ & expr.Meta {Key : expr .MetaKeyOIFNAME , SourceRegister : false , Register : 0x1 },
182+ & expr.Lookup {SourceRegister : 0x1 , DestRegister : 0x0 , IsDestRegSet : false , SetName : kindnetSetDevices , Invert : true },
183+ & expr.Verdict {Kind : expr .VerdictReturn },
184+ },
185+ })
186+
187+ // ct packets > packetThresold flow add @kindnet-flowtables counter
188+ nft .AddRule (& nftables.Rule {
189+ Table : fastpathTable ,
190+ Chain : chain ,
191+ Exprs : []expr.Any {
192+ & expr.Ct {Register : 0x1 , SourceRegister : false , Key : expr .CtKeySTATE , Direction : 0x0 },
193+ & expr.Bitwise {SourceRegister : 0x1 , DestRegister : 0x1 , Len : 0x4 , Mask : binaryutil .NativeEndian .PutUint32 (expr .CtStateBitESTABLISHED ), Xor : binaryutil .NativeEndian .PutUint32 (0 )},
194+ & expr.Cmp {Op : 0x1 , Register : 0x1 , Data : []uint8 {0x0 , 0x0 , 0x0 , 0x0 }},
195+ & expr.Ct {Register : 0x1 , SourceRegister : false , Key : expr .CtKeyPKTS , Direction : 0x0 },
196+ & expr.Cmp {Op : expr .CmpOpGt , Register : 0x1 , Data : binaryutil .NativeEndian .PutUint64 (uint64 (ma .packetThresold ))},
197+ & expr.FlowOffload {Name : kindnetFlowtable },
198+ & expr.Counter {},
199+ },
200+ })
201+
202+ err = nft .Flush ()
203+ if err != nil {
204+ return fmt .Errorf ("failed to create kindnet-fastpath table: %v" , err )
205+ }
206+ return nil
207+ }
208+
152209func (ma * FastPathAgent ) CleanRules () {
153- tx := ma .nft .NewTransaction ()
210+ nft , err := nftables .New ()
211+ if err != nil {
212+ klog .Infof ("fastpath cleanup failure, can not start nftables:%v" , err )
213+ return
214+ }
154215 // Add+Delete is idempotent and won't return an error if the table doesn't already
155216 // exist.
156- tx .Add (& knftables.Table {})
157- tx .Delete (& knftables.Table {})
217+ fastpathTable := nft .AddTable (& nftables.Table {
218+ Family : nftables .TableFamilyINet ,
219+ Name : "kindnet-fastpath" ,
220+ })
221+ nft .DelTable (fastpathTable )
158222
159- if err := ma .nft .Run (context .TODO (), tx ); err != nil {
223+ err = nft .Flush ()
224+ if err != nil {
160225 klog .Infof ("error deleting nftables rules %v" , err )
161226 }
162227}
228+
229+ func ifname (n string ) []byte {
230+ b := make ([]byte , 16 )
231+ copy (b , []byte (n + "\x00 " ))
232+ return b
233+ }
0 commit comments