...
1
2
3 package tc
4
5 import (
6 "fmt"
7 "net"
8
9 "github.com/vishvananda/netlink"
10
11 "edge-infra.dev/pkg/lib/kernel/netlink/ip"
12 )
13
14 type MatchIP struct {
15 ip *net.IP
16 mask *net.IP
17 *ip.IPv4HeaderBitOffset
18 }
19
20 func NewMatchIP() *MatchIP {
21 return &MatchIP{}
22 }
23
24 func (m *MatchIP) WithIP(ip *net.IP) *MatchIP {
25 m.ip = ip
26 return m
27 }
28
29 func (m *MatchIP) WithMask(mask *net.IP) *MatchIP {
30 m.mask = mask
31 return m
32 }
33
34 func (m *MatchIP) WithIPNet(ipnet *net.IPNet) *MatchIP {
35 m.ip = &ipnet.IP
36 mask := net.IP(ipnet.Mask)
37 m.mask = &mask
38 return m
39 }
40
41 func (m *MatchIP) WithIPv4HeaderOffset(offset ip.IPv4HeaderBitOffset) *MatchIP {
42 m.IPv4HeaderBitOffset = &offset
43 return m
44 }
45
46 type MatchPort struct {
47 port uint32
48 mask uint32
49 }
50
51 func NewMatchPort() *MatchPort {
52 return &MatchPort{}
53 }
54
55
56 func (m *MatchPort) WithDstPort(dstPort uint32) *MatchPort {
57 m.port = dstPort
58 m.mask = ip.DstPortMask
59 return m
60 }
61
62
63 func (m *MatchPort) WithSrcPort(srcPort uint32) *MatchPort {
64 m.port = srcPort
65 m.mask = ip.SrcPortMask
66 return m
67 }
68
69 type U32Filter struct {
70 matchIP []*MatchIP
71 matchPort []*MatchPort
72 attrs netlink.FilterAttrs
73 classid uint32
74 actions []netlink.Action
75 divisor uint32
76 hashtable uint32
77 }
78
79 func NewU32Filter() *U32Filter {
80 return &U32Filter{}
81 }
82
83 func (f *U32Filter) WithHashTable(hashtable uint32) *U32Filter {
84 f.hashtable = hashtable
85 return f
86 }
87
88 func (f *U32Filter) WithDivisor(divisor uint32) *U32Filter {
89 f.divisor = divisor
90 return f
91 }
92
93 func (f *U32Filter) WithMatchIP(m *MatchIP) *U32Filter {
94 f.matchIP = append(f.matchIP, m)
95 return f
96 }
97
98 func (f *U32Filter) WithMatchPort(m *MatchPort) *U32Filter {
99 f.matchPort = append(f.matchPort, m)
100 return f
101 }
102
103 func (f *U32Filter) WithAttrs(attrs netlink.FilterAttrs) *U32Filter {
104 f.attrs = attrs
105 return f
106 }
107
108 func (f *U32Filter) WithAction(action netlink.Action) *U32Filter {
109 f.actions = append(f.actions, action)
110 return f
111 }
112
113 func (f *U32Filter) WithClassID(classid uint32) *U32Filter {
114 f.classid = classid
115 return f
116 }
117
118 func (f *U32Filter) WithMakeClassID(major, minor uint16) *U32Filter {
119 f.classid = netlink.MakeHandle(major, minor)
120 return f
121 }
122
123
124
125 func (f *U32Filter) Replace() error {
126 filter, err := f.Build()
127 if err != nil {
128 return err
129 }
130 link, err := netlink.LinkByIndex(filter.Attrs().LinkIndex)
131 if err != nil {
132 return err
133 }
134 if err := netlink.FilterDel(filter); err != nil && !errorIsNotFound(err) {
135 return fmt.Errorf(
136 "error replacing u32 filter with parent %s and handle %s (dev %s): %w",
137 netlink.HandleStr(filter.Attrs().Parent),
138 netlink.HandleStr(filter.Attrs().Handle),
139 link.Attrs().Name,
140 err,
141 )
142 }
143 if err := netlink.FilterAdd(filter); err != nil {
144 return fmt.Errorf(
145 "error replacing u32 filter with parent %s and handle %s (dev %s): %w",
146 netlink.HandleStr(filter.Attrs().Parent),
147 netlink.HandleStr(filter.Attrs().Handle),
148 link.Attrs().Name,
149 err,
150 )
151 }
152 return nil
153 }
154
155 func (f *U32Filter) Add() error {
156 filter, err := f.Build()
157 if err != nil {
158 return err
159 }
160 if err := netlink.FilterAdd(filter); err != nil && !errorIsFileExists(err) {
161 return formatTcError("error creating u32 filter", filter.Attrs().LinkIndex, filter.Attrs().Parent, filter.Attrs().Handle, err)
162 }
163 return nil
164 }
165
166 func (f *U32Filter) Delete() error {
167 filter, err := f.Build()
168 if err != nil {
169 return err
170 }
171 if err := netlink.FilterDel(filter); err != nil && !errorIsNotFound(err) {
172 return err
173 }
174 return nil
175 }
176
177 func (f *U32Filter) Build() (netlink.Filter, error) {
178 keys := []netlink.TcU32Key{}
179
180 for _, matchIP := range f.matchIP {
181 keys = append(keys, getIPSelKey(matchIP))
182 }
183
184 for _, matchPort := range f.matchPort {
185 keys = append(keys, getPortSelKey(matchPort))
186 }
187
188 filter := netlink.U32{}
189 sel := netlink.TcU32Sel{
190 Flags: netlink.TC_U32_TERMINAL,
191 Keys: keys,
192 }
193 filter.Sel = &sel
194 filter.FilterAttrs = f.attrs
195 filter.ClassId = f.classid
196 filter.Actions = f.actions
197 filter.Divisor = f.divisor
198 filter.Hash = f.hashtable
199 return &filter, nil
200 }
201
202 func getIPSelKey(m *MatchIP) netlink.TcU32Key {
203 if m.ip == nil || m.mask == nil || m.IPv4HeaderBitOffset == nil {
204 return netlink.TcU32Key{}
205 }
206
207 ipAddr := ip.IPv4ToUInt32(*m.ip)
208 mask := ip.IPv4ToUInt32(*m.mask)
209
210 offset := int32(*m.IPv4HeaderBitOffset)
211
212 return netlink.TcU32Key{
213 Mask: mask,
214 Val: ipAddr,
215 Off: offset,
216 OffMask: 0,
217 }
218 }
219
220 func getPortSelKey(m *MatchPort) netlink.TcU32Key {
221 return netlink.TcU32Key{
222 Mask: m.mask,
223 Val: m.port,
224 Off: int32(ip.OptionsBitOffset),
225 OffMask: 0,
226 }
227 }
228
View as plain text