go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/aclplugin/vppcalls/vpp2106/acl_vppcalls.go (about)

     1  //  Copyright (c) 2021 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 vpp2106
    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/vpp2106/acl"
    26  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/acl_types"
    27  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/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  }