go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ipsecplugin/vppcalls/vpp2202/ipsec_vppcalls.go (about)

     1  //  Copyright (c) 2022 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 vpp2202
    16  
    17  import (
    18  	"encoding/hex"
    19  
    20  	"github.com/pkg/errors"
    21  	"go.ligato.io/cn-infra/v2/utils/addrs"
    22  
    23  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/interface_types"
    24  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/ip_types"
    25  	vpp_ipsec "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/ipsec"
    26  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/ipsec_types"
    27  	ipsec "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/ipsec"
    28  )
    29  
    30  // AddSPD implements IPSec handler.
    31  func (h *IPSecVppHandler) AddSPD(spdID uint32) error {
    32  	return h.spdAddDel(spdID, true)
    33  }
    34  
    35  // DeleteSPD implements IPSec handler.
    36  func (h *IPSecVppHandler) DeleteSPD(spdID uint32) error {
    37  	return h.spdAddDel(spdID, false)
    38  }
    39  
    40  // AddSP implements IPSec handler.
    41  func (h *IPSecVppHandler) AddSP(sp *ipsec.SecurityPolicy) error {
    42  	return h.spdAddDelEntry(sp, true)
    43  }
    44  
    45  // DeleteSP implements IPSec handler.
    46  func (h *IPSecVppHandler) DeleteSP(sp *ipsec.SecurityPolicy) error {
    47  	return h.spdAddDelEntry(sp, false)
    48  }
    49  
    50  // AddSPDInterface implements IPSec handler.
    51  func (h *IPSecVppHandler) AddSPDInterface(spdID uint32, ifaceCfg *ipsec.SecurityPolicyDatabase_Interface) error {
    52  	ifaceMeta, found := h.ifIndexes.LookupByName(ifaceCfg.Name)
    53  	if !found {
    54  		return errors.New("failed to get interface metadata")
    55  	}
    56  	return h.interfaceAddDelSpd(spdID, ifaceMeta.SwIfIndex, true)
    57  }
    58  
    59  // DeleteSPDInterface implements IPSec handler.
    60  func (h *IPSecVppHandler) DeleteSPDInterface(spdID uint32, ifaceCfg *ipsec.SecurityPolicyDatabase_Interface) error {
    61  	ifaceMeta, found := h.ifIndexes.LookupByName(ifaceCfg.Name)
    62  	if !found {
    63  		return errors.New("failed to get interface metadata")
    64  	}
    65  	return h.interfaceAddDelSpd(spdID, ifaceMeta.SwIfIndex, false)
    66  }
    67  
    68  // AddSA implements IPSec handler.
    69  func (h *IPSecVppHandler) AddSA(sa *ipsec.SecurityAssociation) error {
    70  	return h.sadAddDelEntry(sa, true)
    71  }
    72  
    73  // DeleteSA implements IPSec handler.
    74  func (h *IPSecVppHandler) DeleteSA(sa *ipsec.SecurityAssociation) error {
    75  	return h.sadAddDelEntry(sa, false)
    76  }
    77  
    78  // AddTunnelProtection implements IPSec handler for adding a tunnel protection.
    79  func (h *IPSecVppHandler) AddTunnelProtection(tp *ipsec.TunnelProtection) error {
    80  	ifaceMeta, found := h.ifIndexes.LookupByName(tp.Interface)
    81  	if !found {
    82  		return errors.New("failed to get interface metadata")
    83  	}
    84  	return h.tunProtectAddUpdateEntry(tp, ifaceMeta.SwIfIndex)
    85  }
    86  
    87  // UpdateTunnelProtection implements IPSec handler for updating a tunnel protection.
    88  func (h *IPSecVppHandler) UpdateTunnelProtection(tp *ipsec.TunnelProtection) error {
    89  	ifaceMeta, found := h.ifIndexes.LookupByName(tp.Interface)
    90  	if !found {
    91  		return errors.New("failed to get interface metadata")
    92  	}
    93  	return h.tunProtectAddUpdateEntry(tp, ifaceMeta.SwIfIndex)
    94  }
    95  
    96  // DeleteTunnelProtection implements IPSec handler for deleting a tunnel protection.
    97  func (h *IPSecVppHandler) DeleteTunnelProtection(tp *ipsec.TunnelProtection) error {
    98  	ifaceMeta, found := h.ifIndexes.LookupByName(tp.Interface)
    99  	if !found {
   100  		return errors.New("failed to get interface metadata")
   101  	}
   102  	return h.tunProtectDelEntry(tp, ifaceMeta.SwIfIndex)
   103  }
   104  
   105  func (h *IPSecVppHandler) spdAddDel(spdID uint32, isAdd bool) error {
   106  	req := &vpp_ipsec.IpsecSpdAddDel{
   107  		IsAdd: isAdd,
   108  		SpdID: spdID,
   109  	}
   110  	reply := &vpp_ipsec.IpsecSpdAddDelReply{}
   111  
   112  	if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
   113  		return err
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  func (h *IPSecVppHandler) spdAddDelEntry(sp *ipsec.SecurityPolicy, isAdd bool) error {
   120  	req := &vpp_ipsec.IpsecSpdEntryAddDel{
   121  		IsAdd: isAdd,
   122  		Entry: vpp_ipsec.IpsecSpdEntry{
   123  			SpdID:           sp.SpdIndex,
   124  			Priority:        sp.Priority,
   125  			IsOutbound:      sp.IsOutbound,
   126  			Protocol:        uint8(sp.Protocol),
   127  			RemotePortStart: uint16(sp.RemotePortStart),
   128  			RemotePortStop:  uint16(sp.RemotePortStop),
   129  			LocalPortStart:  uint16(sp.LocalPortStart),
   130  			LocalPortStop:   uint16(sp.LocalPortStop),
   131  			Policy:          vpp_ipsec.IpsecSpdAction(sp.Action),
   132  			SaID:            sp.SaIndex,
   133  		},
   134  	}
   135  	if req.Entry.RemotePortStop == 0 {
   136  		req.Entry.RemotePortStop = ^req.Entry.RemotePortStop
   137  	}
   138  	if req.Entry.LocalPortStop == 0 {
   139  		req.Entry.LocalPortStop = ^req.Entry.LocalPortStop
   140  	}
   141  
   142  	var err error
   143  	req.Entry.RemoteAddressStart, err = IPToAddress(ipOr(sp.RemoteAddrStart, "0.0.0.0"))
   144  	if err != nil {
   145  		return err
   146  	}
   147  	req.Entry.RemoteAddressStop, err = IPToAddress(ipOr(sp.RemoteAddrStop, "255.255.255.255"))
   148  	if err != nil {
   149  		return err
   150  	}
   151  	req.Entry.LocalAddressStart, err = IPToAddress(ipOr(sp.LocalAddrStart, "0.0.0.0"))
   152  	if err != nil {
   153  		return err
   154  	}
   155  	req.Entry.LocalAddressStop, err = IPToAddress(ipOr(sp.LocalAddrStop, "255.255.255.255"))
   156  	if err != nil {
   157  		return err
   158  	}
   159  
   160  	reply := &vpp_ipsec.IpsecSpdEntryAddDelReply{}
   161  	if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
   162  		return err
   163  	}
   164  
   165  	return nil
   166  }
   167  
   168  func ipOr(s, o string) string {
   169  	if s != "" {
   170  		return s
   171  	}
   172  	return o
   173  }
   174  
   175  func (h *IPSecVppHandler) interfaceAddDelSpd(spdID, swIfIdx uint32, isAdd bool) error {
   176  	req := &vpp_ipsec.IpsecInterfaceAddDelSpd{
   177  		IsAdd:     isAdd,
   178  		SwIfIndex: interface_types.InterfaceIndex(swIfIdx),
   179  		SpdID:     spdID,
   180  	}
   181  	reply := &vpp_ipsec.IpsecInterfaceAddDelSpdReply{}
   182  
   183  	if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
   184  		return err
   185  	}
   186  
   187  	return nil
   188  }
   189  
   190  func (h *IPSecVppHandler) sadAddDelEntry(sa *ipsec.SecurityAssociation, isAdd bool) error {
   191  	cryptoKey, err := hex.DecodeString(sa.CryptoKey)
   192  	if err != nil {
   193  		return err
   194  	}
   195  	integKey, err := hex.DecodeString(sa.IntegKey)
   196  	if err != nil {
   197  		return err
   198  	}
   199  
   200  	var flags ipsec_types.IpsecSadFlags
   201  	if sa.UseEsn {
   202  		flags |= ipsec_types.IPSEC_API_SAD_FLAG_USE_ESN
   203  	}
   204  	if sa.UseAntiReplay {
   205  		flags |= ipsec_types.IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY
   206  	}
   207  	if sa.EnableUdpEncap {
   208  		flags |= ipsec_types.IPSEC_API_SAD_FLAG_UDP_ENCAP
   209  	}
   210  	var tunnelSrc, tunnelDst ip_types.Address
   211  	if sa.TunnelSrcAddr != "" {
   212  		flags |= ipsec_types.IPSEC_API_SAD_FLAG_IS_TUNNEL
   213  		isIPv6, err := addrs.IsIPv6(sa.TunnelSrcAddr)
   214  		if err != nil {
   215  			return err
   216  		}
   217  		if isIPv6 {
   218  			flags |= ipsec_types.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6
   219  		}
   220  		tunnelSrc, err = IPToAddress(sa.TunnelSrcAddr)
   221  		if err != nil {
   222  			return err
   223  		}
   224  		tunnelDst, err = IPToAddress(sa.TunnelDstAddr)
   225  		if err != nil {
   226  			return err
   227  		}
   228  	}
   229  	const undefinedPort = ^uint16(0)
   230  	udpSrcPort := undefinedPort
   231  	if sa.TunnelSrcPort != 0 {
   232  		udpSrcPort = uint16(sa.TunnelSrcPort)
   233  	}
   234  	udpDstPort := undefinedPort
   235  	if sa.TunnelDstPort != 0 {
   236  		udpDstPort = uint16(sa.TunnelDstPort)
   237  	}
   238  
   239  	req := &vpp_ipsec.IpsecSadEntryAddDel{
   240  		IsAdd: isAdd,
   241  		Entry: ipsec_types.IpsecSadEntry{
   242  			SadID:           sa.Index,
   243  			Spi:             sa.Spi,
   244  			Protocol:        protocolToIpsecProto(sa.Protocol),
   245  			CryptoAlgorithm: ipsec_types.IpsecCryptoAlg(sa.CryptoAlg),
   246  			CryptoKey: ipsec_types.Key{
   247  				Data:   cryptoKey,
   248  				Length: uint8(len(cryptoKey)),
   249  			},
   250  			Salt:               sa.CryptoSalt,
   251  			IntegrityAlgorithm: ipsec_types.IpsecIntegAlg(sa.IntegAlg),
   252  			IntegrityKey: ipsec_types.Key{
   253  				Data:   integKey,
   254  				Length: uint8(len(integKey)),
   255  			},
   256  			TunnelSrc:  tunnelSrc,
   257  			TunnelDst:  tunnelDst,
   258  			Flags:      flags,
   259  			UDPSrcPort: udpSrcPort,
   260  			UDPDstPort: udpDstPort,
   261  		},
   262  	}
   263  	reply := &vpp_ipsec.IpsecSadEntryAddDelReply{}
   264  
   265  	if err = h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
   266  		return err
   267  	}
   268  
   269  	return nil
   270  }
   271  
   272  func ipsecProtoToProtocol(ipsecProto ipsec_types.IpsecProto) ipsec.SecurityAssociation_IPSecProtocol {
   273  	switch ipsecProto {
   274  	case ipsec_types.IPSEC_API_PROTO_AH:
   275  		return ipsec.SecurityAssociation_AH
   276  	case ipsec_types.IPSEC_API_PROTO_ESP:
   277  		return ipsec.SecurityAssociation_ESP
   278  	default:
   279  		return 0
   280  	}
   281  }
   282  
   283  func protocolToIpsecProto(protocol ipsec.SecurityAssociation_IPSecProtocol) ipsec_types.IpsecProto {
   284  	switch protocol {
   285  	case ipsec.SecurityAssociation_AH:
   286  		return ipsec_types.IPSEC_API_PROTO_AH
   287  	case ipsec.SecurityAssociation_ESP:
   288  		return ipsec_types.IPSEC_API_PROTO_ESP
   289  	default:
   290  		return 0
   291  	}
   292  }
   293  
   294  func (h *IPSecVppHandler) tunProtectAddUpdateEntry(tp *ipsec.TunnelProtection, swIfIndex uint32) error {
   295  	if len(tp.SaOut) == 0 || len(tp.SaIn) == 0 {
   296  		return errors.New("missing outbound/inbound SA")
   297  	}
   298  	if len(tp.SaIn) > int(^uint8(0)) {
   299  		return errors.New("invalid number of inbound SAs")
   300  	}
   301  	req := &vpp_ipsec.IpsecTunnelProtectUpdate{Tunnel: vpp_ipsec.IpsecTunnelProtect{
   302  		SwIfIndex: interface_types.InterfaceIndex(swIfIndex),
   303  		SaOut:     tp.SaOut[0],
   304  		SaIn:      tp.SaIn,
   305  		NSaIn:     uint8(len(tp.SaIn)),
   306  	}}
   307  	if tp.NextHopAddr != "" {
   308  		nh, err := IPToAddress(tp.NextHopAddr)
   309  		if err != nil {
   310  			return err
   311  		}
   312  		req.Tunnel.Nh = nh
   313  	}
   314  	reply := &vpp_ipsec.IpsecTunnelProtectUpdateReply{}
   315  	if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
   316  		return err
   317  	}
   318  	return nil
   319  }
   320  
   321  func (h *IPSecVppHandler) tunProtectDelEntry(tp *ipsec.TunnelProtection, swIfIndex uint32) error {
   322  	req := &vpp_ipsec.IpsecTunnelProtectDel{
   323  		SwIfIndex: interface_types.InterfaceIndex(swIfIndex),
   324  	}
   325  	if tp.NextHopAddr != "" {
   326  		nh, err := IPToAddress(tp.NextHopAddr)
   327  		if err != nil {
   328  			return err
   329  		}
   330  		req.Nh = nh
   331  	}
   332  	reply := &vpp_ipsec.IpsecTunnelProtectDelReply{}
   333  	if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
   334  		return err
   335  	}
   336  	return nil
   337  }