go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/aclplugin/vppcalls/vpp2101/acl_vppcalls.go (about) 1 // Copyright (c) 2019 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package vpp2101 16 17 import ( 18 "fmt" 19 "net" 20 "strings" 21 22 "go.ligato.io/cn-infra/v2/utils/addrs" 23 24 "go.ligato.io/vpp-agent/v3/plugins/vpp/aclplugin/vppcalls" 25 vpp_acl "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/acl" 26 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/acl_types" 27 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2101/ip_types" 28 acl "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/acl" 29 ) 30 31 // AddACL implements ACL handler. 32 func (h *ACLVppHandler) AddACL(rules []*acl.ACL_Rule, aclName string) (uint32, error) { 33 // Prepare Ip rules 34 aclIPRules, err := transformACLIpRules(rules) 35 if err != nil { 36 return 0, err 37 } 38 if len(aclIPRules) == 0 { 39 return 0, fmt.Errorf("no rules found for ACL %v", aclName) 40 } 41 42 req := &vpp_acl.ACLAddReplace{ 43 ACLIndex: 0xffffffff, // to make new Entry 44 Count: uint32(len(aclIPRules)), 45 Tag: aclName, 46 R: aclIPRules, 47 } 48 reply := &vpp_acl.ACLAddReplaceReply{} 49 50 if err = h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 51 return 0, fmt.Errorf("failed to write ACL %v: %v", aclName, err) 52 } 53 54 return reply.ACLIndex, nil 55 } 56 57 // AddMACIPACL implements ACL handler. 58 func (h *ACLVppHandler) AddMACIPACL(rules []*acl.ACL_Rule, aclName string) (uint32, error) { 59 // Prepare MAc Ip rules 60 aclMacIPRules, err := h.transformACLMacIPRules(rules) 61 if err != nil { 62 return 0, err 63 } 64 if len(aclMacIPRules) == 0 { 65 return 0, fmt.Errorf("no rules found for ACL %v", aclName) 66 } 67 68 req := &vpp_acl.MacipACLAdd{ 69 Count: uint32(len(aclMacIPRules)), 70 Tag: aclName, 71 R: aclMacIPRules, 72 } 73 reply := &vpp_acl.MacipACLAddReply{} 74 75 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 76 return 0, fmt.Errorf("failed to write ACL %v: %v", aclName, err) 77 } 78 79 return reply.ACLIndex, nil 80 } 81 82 // ModifyACL implements ACL handler. 83 func (h *ACLVppHandler) ModifyACL(aclIndex uint32, rules []*acl.ACL_Rule, aclName string) error { 84 // Prepare Ip rules 85 aclIPRules, err := transformACLIpRules(rules) 86 if err != nil { 87 return err 88 } 89 if len(aclIPRules) == 0 { 90 return nil 91 } 92 93 req := &vpp_acl.ACLAddReplace{ 94 ACLIndex: aclIndex, 95 Count: uint32(len(aclIPRules)), 96 Tag: aclName, 97 R: aclIPRules, 98 } 99 reply := &vpp_acl.ACLAddReplaceReply{} 100 101 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 102 return fmt.Errorf("failed to write ACL %v: %v", aclName, err) 103 } 104 105 return nil 106 } 107 108 // ModifyMACIPACL implements ACL handler. 109 func (h *ACLVppHandler) ModifyMACIPACL(aclIndex uint32, rules []*acl.ACL_Rule, aclName string) error { 110 // Prepare MAc Ip rules 111 aclMacIPRules, err := h.transformACLMacIPRules(rules) 112 if err != nil { 113 return err 114 } 115 if len(aclMacIPRules) == 0 { 116 return fmt.Errorf("no rules found for ACL %v", aclName) 117 } 118 119 req := &vpp_acl.MacipACLAddReplace{ 120 ACLIndex: aclIndex, 121 Count: uint32(len(aclMacIPRules)), 122 Tag: aclName, 123 R: aclMacIPRules, 124 } 125 reply := &vpp_acl.MacipACLAddReplaceReply{} 126 127 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 128 return fmt.Errorf("failed to write ACL %v: %v", aclName, err) 129 } 130 131 return nil 132 } 133 134 // DeleteACL implements ACL handler. 135 func (h *ACLVppHandler) DeleteACL(aclIndex uint32) error { 136 req := &vpp_acl.ACLDel{ 137 ACLIndex: aclIndex, 138 } 139 reply := &vpp_acl.ACLDelReply{} 140 141 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 142 return fmt.Errorf("failed to remove L3/L4 ACL %v: %v", aclIndex, err) 143 } 144 145 return nil 146 } 147 148 // DeleteMACIPACL implements ACL handler. 149 func (h *ACLVppHandler) DeleteMACIPACL(aclIndex uint32) error { 150 req := &vpp_acl.MacipACLDel{ 151 ACLIndex: aclIndex, 152 } 153 reply := &vpp_acl.MacipACLDelReply{} 154 155 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 156 return fmt.Errorf("failed to remove L2 ACL %v: %v", aclIndex, err) 157 } 158 159 return nil 160 } 161 162 // Method transforms provided set of IP proto ACL rules to binapi ACL rules. 163 func transformACLIpRules(rules []*acl.ACL_Rule) (aclIPRules []acl_types.ACLRule, err error) { 164 for _, rule := range rules { 165 aclRule := &acl_types.ACLRule{ 166 IsPermit: ruleAction(rule.Action), 167 } 168 // Match 169 if ipRule := rule.GetIpRule(); ipRule != nil { 170 // Concerned to IP rules only 171 // L3 172 if ipRule.Ip != nil { 173 aclRule, err = ipACL(ipRule.Ip, aclRule) 174 if err != nil { 175 return nil, err 176 } 177 } 178 // ICMP/L4 179 switch ipRule.Ip.GetProtocol() { 180 case 0: // determine protocol based on rule definition 181 if ipRule.Icmp != nil { 182 aclRule = icmpACL(ipRule.Icmp, aclRule) 183 } else if ipRule.Tcp != nil { 184 aclRule = tcpACL(ipRule.Tcp, aclRule) 185 } else if ipRule.Udp != nil { 186 aclRule = udpACL(ipRule.Udp, aclRule) 187 } 188 case vppcalls.ICMPv4Proto: 189 fallthrough 190 case vppcalls.ICMPv6Proto: 191 if ipRule.Icmp != nil { 192 aclRule = icmpACL(ipRule.Icmp, aclRule) 193 } 194 case vppcalls.TCPProto: 195 if ipRule.Tcp != nil { 196 aclRule = tcpACL(ipRule.Tcp, aclRule) 197 } 198 case vppcalls.UDPProto: 199 if ipRule.Udp != nil { 200 aclRule = udpACL(ipRule.Udp, aclRule) 201 } 202 } 203 aclIPRules = append(aclIPRules, *aclRule) 204 } 205 } 206 return aclIPRules, nil 207 } 208 209 func (h *ACLVppHandler) transformACLMacIPRules(rules []*acl.ACL_Rule) (aclMacIPRules []acl_types.MacipACLRule, err error) { 210 for _, rule := range rules { 211 aclMacIPRule := &acl_types.MacipACLRule{ 212 IsPermit: ruleAction(rule.Action), 213 } 214 // Matche 215 if macIPRule := rule.GetMacipRule(); macIPRule != nil { 216 // Concerned to MAC IP rules only 217 // Source IP Address + Prefix 218 aclMacIPRule.SrcPrefix, err = IPtoPrefix(macIPRule.SourceAddress) 219 if err != nil { 220 return nil, fmt.Errorf("invalid IP address %v", macIPRule.SourceAddress) 221 } 222 aclMacIPRule.SrcPrefix.Len = uint8(macIPRule.SourceAddressPrefix) 223 // MAC + mask 224 srcMac, err := net.ParseMAC(macIPRule.SourceMacAddress) 225 if err != nil { 226 return aclMacIPRules, err 227 } 228 srcMacMask, err := net.ParseMAC(macIPRule.SourceMacAddressMask) 229 if err != nil { 230 return aclMacIPRules, err 231 } 232 copy(aclMacIPRule.SrcMac[:], srcMac) 233 copy(aclMacIPRule.SrcMacMask[:], srcMacMask) 234 aclMacIPRules = append(aclMacIPRules, *aclMacIPRule) 235 } 236 } 237 return aclMacIPRules, nil 238 } 239 240 // The function sets an IP ACL rule fields into provided ACL Rule object. Source 241 // and destination addresses have to be the same IP version and contain a network mask. 242 func ipACL(ipRule *acl.ACL_Rule_IpRule_Ip, aclRule *acl_types.ACLRule) (*acl_types.ACLRule, error) { 243 var ( 244 err error 245 srcNetwork *net.IPNet 246 dstNetwork *net.IPNet 247 ) 248 249 if strings.TrimSpace(ipRule.SourceNetwork) != "" { 250 // Resolve source address 251 _, srcNetwork, err = net.ParseCIDR(ipRule.SourceNetwork) 252 if err != nil { 253 return nil, err 254 } 255 if srcNetwork == nil { 256 srcNetwork = &net.IPNet{} 257 } 258 if srcNetwork.IP.To4() == nil && srcNetwork.IP.To16() == nil { 259 return aclRule, fmt.Errorf("source address %v is invalid", ipRule.SourceNetwork) 260 } 261 } else { 262 return aclRule, fmt.Errorf("source address is empty") 263 } 264 265 if strings.TrimSpace(ipRule.DestinationNetwork) != "" { 266 // Resolve destination address 267 _, dstNetwork, err = net.ParseCIDR(ipRule.DestinationNetwork) 268 if err != nil { 269 return nil, err 270 } 271 if dstNetwork == nil { 272 dstNetwork = &net.IPNet{} 273 } 274 if dstNetwork.IP.To4() == nil && dstNetwork.IP.To16() == nil { 275 return aclRule, fmt.Errorf("destination address %v is invalid", ipRule.DestinationNetwork) 276 } 277 } else { 278 return aclRule, fmt.Errorf("destination address is empty") 279 } 280 281 // Check IP version (they should be the same), beware: IPv4 address can be converted to IPv6. 282 if (srcNetwork.IP.To4() != nil && dstNetwork.IP.To4() == nil && dstNetwork.IP.To16() != nil) || 283 (srcNetwork.IP.To4() == nil && srcNetwork.IP.To16() != nil && dstNetwork.IP.To4() != nil) { 284 return aclRule, fmt.Errorf("source address %v and destionation address %v have different IP versions", 285 ipRule.SourceNetwork, ipRule.DestinationNetwork) 286 } 287 288 if srcNetwork.IP.To4() != nil || dstNetwork.IP.To4() != nil { 289 // Ipv4 case 290 aclRule.SrcPrefix = IPNetToPrefix(srcNetwork) 291 aclRule.DstPrefix = IPNetToPrefix(dstNetwork) 292 } else if srcNetwork.IP.To16() != nil || dstNetwork.IP.To16() != nil { 293 // Ipv6 case 294 aclRule.SrcPrefix = IPNetToPrefix(srcNetwork) 295 aclRule.DstPrefix = IPNetToPrefix(dstNetwork) 296 } 297 aclRule.Proto = ip_types.IPProto(ipRule.GetProtocol()) 298 return aclRule, nil 299 } 300 301 // The function sets an ICMP ACL rule fields into provided ACL Rule object. 302 // The ranges are exclusive, use first = 0 and last = 255/65535 (icmpv4/icmpv6) to match "any". 303 func icmpACL(icmpRule *acl.ACL_Rule_IpRule_Icmp, aclRule *acl_types.ACLRule) *acl_types.ACLRule { 304 if icmpRule == nil { 305 return aclRule 306 } 307 if icmpRule.Icmpv6 { 308 aclRule.Proto = vppcalls.ICMPv6Proto // IANA ICMPv6 309 // ICMPv6 type range 310 aclRule.SrcportOrIcmptypeFirst = uint16(icmpRule.IcmpTypeRange.First) 311 aclRule.SrcportOrIcmptypeLast = uint16(icmpRule.IcmpTypeRange.Last) 312 // ICMPv6 code range 313 aclRule.DstportOrIcmpcodeFirst = uint16(icmpRule.IcmpCodeRange.First) 314 aclRule.DstportOrIcmpcodeLast = uint16(icmpRule.IcmpCodeRange.Last) 315 } else { 316 aclRule.Proto = vppcalls.ICMPv4Proto // IANA ICMPv4 317 // ICMPv4 type range 318 aclRule.SrcportOrIcmptypeFirst = uint16(icmpRule.IcmpTypeRange.First) 319 aclRule.SrcportOrIcmptypeLast = uint16(icmpRule.IcmpTypeRange.Last) 320 // ICMPv4 code range 321 aclRule.DstportOrIcmpcodeFirst = uint16(icmpRule.IcmpCodeRange.First) 322 aclRule.DstportOrIcmpcodeLast = uint16(icmpRule.IcmpCodeRange.Last) 323 } 324 return aclRule 325 } 326 327 // Sets an TCP ACL rule fields into provided ACL Rule object. 328 func tcpACL(tcpRule *acl.ACL_Rule_IpRule_Tcp, aclRule *acl_types.ACLRule) *acl_types.ACLRule { 329 aclRule.Proto = vppcalls.TCPProto // IANA TCP 330 aclRule.SrcportOrIcmptypeFirst = uint16(tcpRule.SourcePortRange.LowerPort) 331 aclRule.SrcportOrIcmptypeLast = uint16(tcpRule.SourcePortRange.UpperPort) 332 aclRule.DstportOrIcmpcodeFirst = uint16(tcpRule.DestinationPortRange.LowerPort) 333 aclRule.DstportOrIcmpcodeLast = uint16(tcpRule.DestinationPortRange.UpperPort) 334 aclRule.TCPFlagsValue = uint8(tcpRule.TcpFlagsValue) 335 aclRule.TCPFlagsMask = uint8(tcpRule.TcpFlagsMask) 336 return aclRule 337 } 338 339 // Sets an UDP ACL rule fields into provided ACL Rule object. 340 func udpACL(udpRule *acl.ACL_Rule_IpRule_Udp, aclRule *acl_types.ACLRule) *acl_types.ACLRule { 341 aclRule.Proto = vppcalls.UDPProto // IANA UDP 342 aclRule.SrcportOrIcmptypeFirst = uint16(udpRule.SourcePortRange.LowerPort) 343 aclRule.SrcportOrIcmptypeLast = uint16(udpRule.SourcePortRange.UpperPort) 344 aclRule.DstportOrIcmpcodeFirst = uint16(udpRule.DestinationPortRange.LowerPort) 345 aclRule.DstportOrIcmpcodeLast = uint16(udpRule.DestinationPortRange.UpperPort) 346 return aclRule 347 } 348 349 func ruleAction(action acl.ACL_Rule_Action) acl_types.ACLAction { 350 switch action { 351 case acl.ACL_Rule_DENY: 352 return acl_types.ACL_ACTION_API_DENY 353 case acl.ACL_Rule_PERMIT: 354 return acl_types.ACL_ACTION_API_PERMIT 355 case acl.ACL_Rule_REFLECT: 356 return acl_types.ACL_ACTION_API_PERMIT_REFLECT 357 default: 358 return 0 359 } 360 } 361 362 func IPNetToPrefix(dstNetwork *net.IPNet) ip_types.Prefix { 363 var addr ip_types.Address 364 if dstNetwork.IP.To4() == nil { 365 addr.Af = ip_types.ADDRESS_IP6 366 var ip6addr ip_types.IP6Address 367 copy(ip6addr[:], dstNetwork.IP.To16()) 368 addr.Un.SetIP6(ip6addr) 369 } else { 370 addr.Af = ip_types.ADDRESS_IP4 371 var ip4addr ip_types.IP4Address 372 copy(ip4addr[:], dstNetwork.IP.To4()) 373 addr.Un.SetIP4(ip4addr) 374 } 375 mask, _ := dstNetwork.Mask.Size() 376 return ip_types.Prefix{ 377 Address: addr, 378 Len: uint8(mask), 379 } 380 } 381 382 func IPtoPrefix(addr string) (ip_types.Prefix, error) { 383 ipAddr, isIPv6, err := addrs.ParseIPWithPrefix(addr) 384 if err != nil { 385 return ip_types.Prefix{}, err 386 } 387 var prefix ip_types.Prefix 388 maskSize, _ := ipAddr.Mask.Size() 389 prefix.Len = byte(maskSize) 390 if isIPv6 { 391 prefix.Address.Af = ip_types.ADDRESS_IP6 392 var ip6addr ip_types.IP6Address 393 copy(ip6addr[:], ipAddr.IP.To16()) 394 prefix.Address.Un.SetIP6(ip6addr) 395 } else { 396 prefix.Address.Af = ip_types.ADDRESS_IP4 397 var ip4addr ip_types.IP4Address 398 copy(ip4addr[:], ipAddr.IP.To4()) 399 prefix.Address.Un.SetIP4(ip4addr) 400 } 401 return prefix, nil 402 }