This repository has been archived by the owner on Aug 3, 2020. It is now read-only.
forked from ligato/vpp-agent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
acl_vppcalls.go
349 lines (314 loc) · 11 KB
/
acl_vppcalls.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
// Copyright (c) 2019 Cisco and/or its affiliates.
//
// 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 vpp2001
import (
"fmt"
"net"
"strings"
acl "github.com/ligato/vpp-agent/api/models/vpp/acl"
"github.com/ligato/vpp-agent/plugins/vpp/aclplugin/vppcalls"
vpp_acl "github.com/ligato/vpp-agent/plugins/vpp/binapi/vpp2001/acl"
)
// AddACL implements ACL handler.
func (h *ACLVppHandler) AddACL(rules []*acl.ACL_Rule, aclName string) (uint32, error) {
// Prepare Ip rules
aclIPRules, err := transformACLIpRules(rules)
if err != nil {
return 0, err
}
if len(aclIPRules) == 0 {
return 0, fmt.Errorf("no rules found for ACL %v", aclName)
}
req := &vpp_acl.ACLAddReplace{
ACLIndex: 0xffffffff, // to make new Entry
Count: uint32(len(aclIPRules)),
Tag: []byte(aclName),
R: aclIPRules,
}
reply := &vpp_acl.ACLAddReplaceReply{}
if err = h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
return 0, fmt.Errorf("failed to write ACL %v: %v", aclName, err)
}
return reply.ACLIndex, nil
}
// AddMACIPACL implements ACL handler.
func (h *ACLVppHandler) AddMACIPACL(rules []*acl.ACL_Rule, aclName string) (uint32, error) {
// Prepare MAc Ip rules
aclMacIPRules, err := h.transformACLMacIPRules(rules)
if err != nil {
return 0, err
}
if len(aclMacIPRules) == 0 {
return 0, fmt.Errorf("no rules found for ACL %v", aclName)
}
req := &vpp_acl.MacipACLAdd{
Count: uint32(len(aclMacIPRules)),
Tag: []byte(aclName),
R: aclMacIPRules,
}
reply := &vpp_acl.MacipACLAddReply{}
if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
return 0, fmt.Errorf("failed to write ACL %v: %v", aclName, err)
}
return reply.ACLIndex, nil
}
// ModifyACL implements ACL handler.
func (h *ACLVppHandler) ModifyACL(aclIndex uint32, rules []*acl.ACL_Rule, aclName string) error {
// Prepare Ip rules
aclIPRules, err := transformACLIpRules(rules)
if err != nil {
return err
}
if len(aclIPRules) == 0 {
return nil
}
req := &vpp_acl.ACLAddReplace{
ACLIndex: aclIndex,
Count: uint32(len(aclIPRules)),
Tag: []byte(aclName),
R: aclIPRules,
}
reply := &vpp_acl.ACLAddReplaceReply{}
if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
return fmt.Errorf("failed to write ACL %v: %v", aclName, err)
}
return nil
}
// ModifyMACIPACL implements ACL handler.
func (h *ACLVppHandler) ModifyMACIPACL(aclIndex uint32, rules []*acl.ACL_Rule, aclName string) error {
// Prepare MAc Ip rules
aclMacIPRules, err := h.transformACLMacIPRules(rules)
if err != nil {
return err
}
if len(aclMacIPRules) == 0 {
return fmt.Errorf("no rules found for ACL %v", aclName)
}
req := &vpp_acl.MacipACLAddReplace{
ACLIndex: aclIndex,
Count: uint32(len(aclMacIPRules)),
Tag: []byte(aclName),
R: aclMacIPRules,
}
reply := &vpp_acl.MacipACLAddReplaceReply{}
if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
return fmt.Errorf("failed to write ACL %v: %v", aclName, err)
}
return nil
}
// DeleteACL implements ACL handler.
func (h *ACLVppHandler) DeleteACL(aclIndex uint32) error {
req := &vpp_acl.ACLDel{
ACLIndex: aclIndex,
}
reply := &vpp_acl.ACLDelReply{}
if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
return fmt.Errorf("failed to remove L3/L4 ACL %v: %v", aclIndex, err)
}
return nil
}
// DeleteMACIPACL implements ACL handler.
func (h *ACLVppHandler) DeleteMACIPACL(aclIndex uint32) error {
req := &vpp_acl.MacipACLDel{
ACLIndex: aclIndex,
}
reply := &vpp_acl.MacipACLDelReply{}
if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
return fmt.Errorf("failed to remove L2 ACL %v: %v", aclIndex, err)
}
return nil
}
// Method transforms provided set of IP proto ACL rules to binapi ACL rules.
func transformACLIpRules(rules []*acl.ACL_Rule) (aclIPRules []vpp_acl.ACLRule, err error) {
for _, rule := range rules {
aclRule := &vpp_acl.ACLRule{
IsPermit: uint8(rule.Action),
}
// Match
if ipRule := rule.GetIpRule(); ipRule != nil {
// Concerned to IP rules only
// L3
if ipRule.Ip != nil {
aclRule, err = ipACL(ipRule.Ip, aclRule)
if err != nil {
return nil, err
}
}
// ICMP/L4
if ipRule.Icmp != nil {
aclRule = icmpACL(ipRule.Icmp, aclRule)
} else if ipRule.Tcp != nil {
aclRule = tcpACL(ipRule.Tcp, aclRule)
} else if ipRule.Udp != nil {
aclRule = udpACL(ipRule.Udp, aclRule)
}
aclIPRules = append(aclIPRules, *aclRule)
}
}
return aclIPRules, nil
}
func (h *ACLVppHandler) transformACLMacIPRules(rules []*acl.ACL_Rule) (aclMacIPRules []vpp_acl.MacipACLRule, err error) {
for _, rule := range rules {
aclMacIPRule := &vpp_acl.MacipACLRule{
IsPermit: uint8(rule.Action),
}
// Matche
if macIPRule := rule.GetMacipRule(); macIPRule != nil {
// Concerned to MAC IP rules only
// Source IP Address + Prefix
srcIPAddress := net.ParseIP(macIPRule.SourceAddress)
if srcIPAddress.To4() != nil {
aclMacIPRule.IsIPv6 = 0
aclMacIPRule.SrcIPAddr = srcIPAddress.To4()
aclMacIPRule.SrcIPPrefixLen = uint8(macIPRule.SourceAddressPrefix)
} else if srcIPAddress.To16() != nil {
aclMacIPRule.IsIPv6 = 1
aclMacIPRule.SrcIPAddr = srcIPAddress.To16()
aclMacIPRule.SrcIPPrefixLen = uint8(macIPRule.SourceAddressPrefix)
} else {
return nil, fmt.Errorf("invalid IP address %v", macIPRule.SourceAddress)
}
// MAC + mask
srcMac, err := net.ParseMAC(macIPRule.SourceMacAddress)
if err != nil {
return aclMacIPRules, err
}
srcMacMask, err := net.ParseMAC(macIPRule.SourceMacAddressMask)
if err != nil {
return aclMacIPRules, err
}
aclMacIPRule.SrcMac = srcMac
aclMacIPRule.SrcMacMask = srcMacMask
aclMacIPRules = append(aclMacIPRules, *aclMacIPRule)
}
}
return aclMacIPRules, nil
}
// The function sets an IP ACL rule fields into provided ACL Rule object. Source
// and destination addresses have to be the same IP version and contain a network mask.
func ipACL(ipRule *acl.ACL_Rule_IpRule_Ip, aclRule *vpp_acl.ACLRule) (*vpp_acl.ACLRule, error) {
var (
err error
srcNetwork *net.IPNet
dstNetwork *net.IPNet
srcMask uint8
dstMask uint8
)
if strings.TrimSpace(ipRule.SourceNetwork) != "" {
// Resolve source address
_, srcNetwork, err = net.ParseCIDR(ipRule.SourceNetwork)
if err != nil {
return nil, err
}
if srcNetwork == nil {
srcNetwork = &net.IPNet{}
}
if srcNetwork.IP.To4() == nil && srcNetwork.IP.To16() == nil {
return aclRule, fmt.Errorf("source address %v is invalid", ipRule.SourceNetwork)
}
maskSize, _ := srcNetwork.Mask.Size()
srcMask = uint8(maskSize)
} else {
return aclRule, fmt.Errorf("source address is empty")
}
if strings.TrimSpace(ipRule.DestinationNetwork) != "" {
// Resolve destination address
_, dstNetwork, err = net.ParseCIDR(ipRule.DestinationNetwork)
if err != nil {
return nil, err
}
if dstNetwork == nil {
dstNetwork = &net.IPNet{}
}
if dstNetwork.IP.To4() == nil && dstNetwork.IP.To16() == nil {
return aclRule, fmt.Errorf("destination address %v is invalid", ipRule.DestinationNetwork)
}
maskSize, _ := dstNetwork.Mask.Size()
dstMask = uint8(maskSize)
} else {
return aclRule, fmt.Errorf("destination address is empty")
}
// Check IP version (they should be the same), beware: IPv4 address can be converted to IPv6.
if (srcNetwork.IP.To4() != nil && dstNetwork.IP.To4() == nil && dstNetwork.IP.To16() != nil) ||
(srcNetwork.IP.To4() == nil && srcNetwork.IP.To16() != nil && dstNetwork.IP.To4() != nil) {
return aclRule, fmt.Errorf("source address %v and destionation address %v have different IP versions",
ipRule.SourceNetwork, ipRule.DestinationNetwork)
}
if srcNetwork.IP.To4() != nil || dstNetwork.IP.To4() != nil {
// Ipv4 case
aclRule.IsIPv6 = 0
aclRule.SrcIPAddr = srcNetwork.IP.To4()
aclRule.SrcIPPrefixLen = srcMask
aclRule.DstIPAddr = dstNetwork.IP.To4()
aclRule.DstIPPrefixLen = dstMask
} else if srcNetwork.IP.To16() != nil || dstNetwork.IP.To16() != nil {
// Ipv6 case
aclRule.IsIPv6 = 1
aclRule.SrcIPAddr = srcNetwork.IP.To16()
aclRule.SrcIPPrefixLen = srcMask
aclRule.DstIPAddr = dstNetwork.IP.To16()
aclRule.DstIPPrefixLen = dstMask
} else {
// Both empty
aclRule.IsIPv6 = 0
}
return aclRule, nil
}
// The function sets an ICMP ACL rule fields into provided ACL Rule object.
// The ranges are exclusive, use first = 0 and last = 255/65535 (icmpv4/icmpv6) to match "any".
func icmpACL(icmpRule *acl.ACL_Rule_IpRule_Icmp, aclRule *vpp_acl.ACLRule) *vpp_acl.ACLRule {
if icmpRule == nil {
return aclRule
}
if icmpRule.Icmpv6 {
aclRule.Proto = vppcalls.ICMPv6Proto // IANA ICMPv6
aclRule.IsIPv6 = 1
// ICMPv6 type range
aclRule.SrcportOrIcmptypeFirst = uint16(icmpRule.IcmpTypeRange.First)
aclRule.SrcportOrIcmptypeLast = uint16(icmpRule.IcmpTypeRange.Last)
// ICMPv6 code range
aclRule.DstportOrIcmpcodeFirst = uint16(icmpRule.IcmpCodeRange.First)
aclRule.DstportOrIcmpcodeLast = uint16(icmpRule.IcmpCodeRange.Last)
} else {
aclRule.Proto = vppcalls.ICMPv4Proto // IANA ICMPv4
aclRule.IsIPv6 = 0
// ICMPv4 type range
aclRule.SrcportOrIcmptypeFirst = uint16(icmpRule.IcmpTypeRange.First)
aclRule.SrcportOrIcmptypeLast = uint16(icmpRule.IcmpTypeRange.Last)
// ICMPv4 code range
aclRule.DstportOrIcmpcodeFirst = uint16(icmpRule.IcmpCodeRange.First)
aclRule.DstportOrIcmpcodeLast = uint16(icmpRule.IcmpCodeRange.Last)
}
return aclRule
}
// Sets an TCP ACL rule fields into provided ACL Rule object.
func tcpACL(tcpRule *acl.ACL_Rule_IpRule_Tcp, aclRule *vpp_acl.ACLRule) *vpp_acl.ACLRule {
aclRule.Proto = vppcalls.TCPProto // IANA TCP
aclRule.SrcportOrIcmptypeFirst = uint16(tcpRule.SourcePortRange.LowerPort)
aclRule.SrcportOrIcmptypeLast = uint16(tcpRule.SourcePortRange.UpperPort)
aclRule.DstportOrIcmpcodeFirst = uint16(tcpRule.DestinationPortRange.LowerPort)
aclRule.DstportOrIcmpcodeLast = uint16(tcpRule.DestinationPortRange.UpperPort)
aclRule.TCPFlagsValue = uint8(tcpRule.TcpFlagsValue)
aclRule.TCPFlagsMask = uint8(tcpRule.TcpFlagsMask)
return aclRule
}
// Sets an UDP ACL rule fields into provided ACL Rule object.
func udpACL(udpRule *acl.ACL_Rule_IpRule_Udp, aclRule *vpp_acl.ACLRule) *vpp_acl.ACLRule {
aclRule.Proto = vppcalls.UDPProto // IANA UDP
aclRule.SrcportOrIcmptypeFirst = uint16(udpRule.SourcePortRange.LowerPort)
aclRule.SrcportOrIcmptypeLast = uint16(udpRule.SourcePortRange.UpperPort)
aclRule.DstportOrIcmpcodeFirst = uint16(udpRule.DestinationPortRange.LowerPort)
aclRule.DstportOrIcmpcodeLast = uint16(udpRule.DestinationPortRange.UpperPort)
return aclRule
}