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