go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ipsecplugin/vppcalls/vpp2210/dump_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  	"net"
    20  
    21  	"github.com/pkg/errors"
    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/ipsecplugin/vppcalls"
    28  	ipsec "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/ipsec"
    29  )
    30  
    31  // DumpIPSecSA implements IPSec handler.
    32  func (h *IPSecVppHandler) DumpIPSecSA() (saList []*vppcalls.IPSecSaDetails, err error) {
    33  	return h.DumpIPSecSAWithIndex(^uint32(0)) // Get everything
    34  }
    35  
    36  // DumpIPSecSAWithIndex implements IPSec handler.
    37  func (h *IPSecVppHandler) DumpIPSecSAWithIndex(saID uint32) (saList []*vppcalls.IPSecSaDetails, err error) {
    38  	saDetails, err := h.dumpSecurityAssociations(saID)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	for _, saData := range saDetails {
    44  		// Skip tunnel interfaces
    45  		if uint32(saData.SwIfIndex) != ^uint32(0) {
    46  			continue
    47  		}
    48  
    49  		var tunnelSrcAddr, tunnelDstAddr net.IP
    50  		if saData.Entry.Tunnel.Dst.Af == ip_types.ADDRESS_IP6 {
    51  			src := saData.Entry.Tunnel.Src.Un.GetIP6()
    52  			dst := saData.Entry.Tunnel.Dst.Un.GetIP6()
    53  			tunnelSrcAddr, tunnelDstAddr = net.IP(src[:]), net.IP(dst[:])
    54  		} else {
    55  			src := saData.Entry.Tunnel.Src.Un.GetIP4()
    56  			dst := saData.Entry.Tunnel.Dst.Un.GetIP4()
    57  			tunnelSrcAddr, tunnelDstAddr = net.IP(src[:]), net.IP(dst[:])
    58  		}
    59  
    60  		sa := &ipsec.SecurityAssociation{
    61  			Index:          saData.Entry.SadID,
    62  			Spi:            saData.Entry.Spi,
    63  			Protocol:       ipsecProtoToProtocol(saData.Entry.Protocol),
    64  			CryptoAlg:      ipsec.CryptoAlg(saData.Entry.CryptoAlgorithm),
    65  			CryptoKey:      hex.EncodeToString(saData.Entry.CryptoKey.Data[:saData.Entry.CryptoKey.Length]),
    66  			CryptoSalt:     saData.Entry.Salt,
    67  			IntegAlg:       ipsec.IntegAlg(saData.Entry.IntegrityAlgorithm),
    68  			IntegKey:       hex.EncodeToString(saData.Entry.IntegrityKey.Data[:saData.Entry.IntegrityKey.Length]),
    69  			UseEsn:         (saData.Entry.Flags & ipsec_types.IPSEC_API_SAD_FLAG_USE_ESN) != 0,
    70  			UseAntiReplay:  (saData.Entry.Flags & ipsec_types.IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY) != 0,
    71  			EnableUdpEncap: (saData.Entry.Flags & ipsec_types.IPSEC_API_SAD_FLAG_UDP_ENCAP) != 0,
    72  			TunnelSrcPort:  uint32(saData.Entry.UDPSrcPort),
    73  			TunnelDstPort:  uint32(saData.Entry.UDPDstPort),
    74  		}
    75  		if !tunnelSrcAddr.IsUnspecified() {
    76  			sa.TunnelSrcAddr = tunnelSrcAddr.String()
    77  		}
    78  		if !tunnelDstAddr.IsUnspecified() {
    79  			sa.TunnelDstAddr = tunnelDstAddr.String()
    80  		}
    81  		meta := &vppcalls.IPSecSaMeta{
    82  			SaID:           saData.Entry.SadID,
    83  			IfIdx:          uint32(saData.SwIfIndex),
    84  			SeqOutbound:    saData.SeqOutbound,
    85  			LastSeqInbound: saData.LastSeqInbound,
    86  			ReplayWindow:   saData.ReplayWindow,
    87  		}
    88  		saList = append(saList, &vppcalls.IPSecSaDetails{
    89  			Sa:   sa,
    90  			Meta: meta,
    91  		})
    92  	}
    93  
    94  	return saList, nil
    95  }
    96  
    97  // DumpIPSecSPD returns a list of IPSec security policy databases
    98  func (h *IPSecVppHandler) DumpIPSecSPD() (spdList []*ipsec.SecurityPolicyDatabase, err error) {
    99  	/* TODO: dumping of SPD interfaces is broken in VPP
   100  	          - instead of the SPD index value given by control-plane, the index to the VPP's internal array of SPDs
   101  	            is returned, which is useless
   102  	spdInterfaces, err := h.dumpSpdInterfaces()
   103  	if err != nil {
   104  		err = fmt.Errorf("dumping of SPD interfaces failed: %v", err)
   105  		return nil, err
   106  	}
   107  	*/
   108  
   109  	// Get all VPP SPD indexes
   110  	spdIndexes, err := h.dumpSpdIndexes()
   111  	if err != nil {
   112  		return nil, errors.Errorf("failed to dump SPD indexes: %v", err)
   113  	}
   114  
   115  	for spdIdx := range spdIndexes {
   116  		spd := &ipsec.SecurityPolicyDatabase{
   117  			Index: spdIdx,
   118  		}
   119  		/*
   120  			for _, swIfIndex := range spdInterfaces[spdIdx] {
   121  				name, _, found := h.ifIndexes.LookupBySwIfIndex(swIfIndex)
   122  				if !found {
   123  					h.log.Warnf("Failed to find interface with sw_if_index %d", swIfIndex)
   124  					continue
   125  				}
   126  				spd.Interfaces = append(spd.Interfaces, &ipsec.SecurityPolicyDatabase_Interface{
   127  					Name: name,
   128  				})
   129  			}
   130  		*/
   131  		spdList = append(spdList, spd)
   132  	}
   133  
   134  	return spdList, nil
   135  }
   136  
   137  // DumpIPSecSP returns a list of configured security policies
   138  func (h *IPSecVppHandler) DumpIPSecSP() (spList []*ipsec.SecurityPolicy, err error) {
   139  	// Get all VPP SPD indexes
   140  	spdIndexes, err := h.dumpSpdIndexes()
   141  	if err != nil {
   142  		return nil, errors.Errorf("failed to dump SPD indexes: %v", err)
   143  	}
   144  	for spdIdx := range spdIndexes {
   145  		req := &vpp_ipsec.IpsecSpdDump{
   146  			SpdID: spdIdx,
   147  			SaID:  ^uint32(0),
   148  		}
   149  		requestCtx := h.callsChannel.SendMultiRequest(req)
   150  
   151  		for {
   152  			spdDetails := &vpp_ipsec.IpsecSpdDetails{}
   153  			stop, err := requestCtx.ReceiveReply(spdDetails)
   154  			if stop {
   155  				break
   156  			}
   157  			if err != nil {
   158  				return nil, err
   159  			}
   160  
   161  			// Addresses
   162  			remoteStartAddr := ipsecAddrToIP(spdDetails.Entry.RemoteAddressStart)
   163  			remoteStopAddr := ipsecAddrToIP(spdDetails.Entry.RemoteAddressStop)
   164  			localStartAddr := ipsecAddrToIP(spdDetails.Entry.LocalAddressStart)
   165  			localStopAddr := ipsecAddrToIP(spdDetails.Entry.LocalAddressStop)
   166  
   167  			// Prepare policy entry and put to the SPD
   168  			sp := &ipsec.SecurityPolicy{
   169  				SpdIndex:        spdIdx,
   170  				SaIndex:         spdDetails.Entry.SaID,
   171  				Priority:        spdDetails.Entry.Priority,
   172  				IsOutbound:      spdDetails.Entry.IsOutbound,
   173  				RemoteAddrStart: remoteStartAddr.String(),
   174  				RemoteAddrStop:  remoteStopAddr.String(),
   175  				LocalAddrStart:  localStartAddr.String(),
   176  				LocalAddrStop:   localStopAddr.String(),
   177  				Protocol:        uint32(spdDetails.Entry.Protocol),
   178  				RemotePortStart: uint32(spdDetails.Entry.RemotePortStart),
   179  				RemotePortStop:  resetPort(spdDetails.Entry.RemotePortStop),
   180  				LocalPortStart:  uint32(spdDetails.Entry.LocalPortStart),
   181  				LocalPortStop:   resetPort(spdDetails.Entry.LocalPortStop),
   182  				Action:          ipsec.SecurityPolicy_Action(spdDetails.Entry.Policy),
   183  			}
   184  			spList = append(spList, sp)
   185  		}
   186  	}
   187  
   188  	return spList, nil
   189  }
   190  
   191  // DumpTunnelProtections returns configured IPSec tunnel protections.
   192  func (h *IPSecVppHandler) DumpTunnelProtections() (tpList []*ipsec.TunnelProtection, err error) {
   193  	req := &vpp_ipsec.IpsecTunnelProtectDump{
   194  		SwIfIndex: interface_types.InterfaceIndex(^uint32(0)),
   195  	}
   196  	requestCtx := h.callsChannel.SendMultiRequest(req)
   197  	for {
   198  		tpDetails := &vpp_ipsec.IpsecTunnelProtectDetails{}
   199  		stop, err := requestCtx.ReceiveReply(tpDetails)
   200  		if stop {
   201  			break
   202  		}
   203  		if err != nil {
   204  			return nil, err
   205  		}
   206  		ifName, _, exists := h.ifIndexes.LookupBySwIfIndex(uint32(tpDetails.Tun.SwIfIndex))
   207  		if !exists {
   208  			h.log.Warnf("Tunnel protection dump: interface name for index %d not found", tpDetails.Tun.SwIfIndex)
   209  			continue
   210  		}
   211  		tp := &ipsec.TunnelProtection{
   212  			Interface: ifName,
   213  			SaOut:     []uint32{tpDetails.Tun.SaOut},
   214  		}
   215  		tp.SaIn = append(tp.SaIn, tpDetails.Tun.SaIn...)
   216  		tpList = append(tpList, tp)
   217  
   218  		if tpDetails.Tun.Nh.Af == ip_types.ADDRESS_IP6 {
   219  			nhAddrArr := tpDetails.Tun.Nh.Un.GetIP6()
   220  			nhAddr := net.IP(nhAddrArr[:]).To16()
   221  			if !nhAddr.IsUnspecified() {
   222  				tp.NextHopAddr = nhAddr.String()
   223  			}
   224  		} else {
   225  			nhAddrArr := tpDetails.Tun.Nh.Un.GetIP4()
   226  			nhAddr := net.IP(nhAddrArr[:4]).To4()
   227  			if !nhAddr.IsUnspecified() {
   228  				tp.NextHopAddr = nhAddr.String()
   229  			}
   230  		}
   231  	}
   232  	return
   233  }
   234  
   235  // TODO: dumping of SPD interfaces is broken in VPP. Instead of the SPD index value given by control-plane,
   236  // the index to the VPP's internal array of SPDs is returned, which is useless.
   237  
   238  // Get all interfaces of SPD configured on the VPP
   239  // func (h *IPSecVppHandler) dumpSpdInterfaces() (map[uint32][]uint32, error) {
   240  // 	// SPD index to interface indexes
   241  // 	spdInterfaces := make(map[uint32][]uint32)
   242  
   243  // 	req := &vpp_ipsec.IpsecSpdInterfaceDump{}
   244  // 	reqCtx := h.callsChannel.SendMultiRequest(req)
   245  
   246  // 	for {
   247  // 		spdDetails := &vpp_ipsec.IpsecSpdInterfaceDetails{}
   248  // 		stop, err := reqCtx.ReceiveReply(spdDetails)
   249  // 		if stop {
   250  // 			break
   251  // 		}
   252  // 		if err != nil {
   253  // 			return nil, err
   254  // 		}
   255  
   256  // 		spdInterfaces[spdDetails.SpdIndex] = append(spdInterfaces[spdDetails.SpdIndex], uint32(spdDetails.SwIfIndex))
   257  // 	}
   258  
   259  // 	return spdInterfaces, nil
   260  // }
   261  
   262  // Get all indexes of SPD configured on the VPP
   263  func (h *IPSecVppHandler) dumpSpdIndexes() (map[uint32]uint32, error) {
   264  	// SPD index to number of policies
   265  	spdIndexes := make(map[uint32]uint32)
   266  
   267  	req := &vpp_ipsec.IpsecSpdsDump{}
   268  	reqCtx := h.callsChannel.SendMultiRequest(req)
   269  
   270  	for {
   271  		spdDetails := &vpp_ipsec.IpsecSpdsDetails{}
   272  		stop, err := reqCtx.ReceiveReply(spdDetails)
   273  		if stop {
   274  			break
   275  		}
   276  		if err != nil {
   277  			return nil, err
   278  		}
   279  
   280  		spdIndexes[spdDetails.SpdID] = spdDetails.Npolicies
   281  	}
   282  
   283  	return spdIndexes, nil
   284  }
   285  
   286  // Get all security association (used also for tunnel interfaces) in binary api format
   287  func (h *IPSecVppHandler) dumpSecurityAssociations(saID uint32) (saList []*vpp_ipsec.IpsecSaV3Details, err error) {
   288  	req := &vpp_ipsec.IpsecSaV3Dump{
   289  		SaID: saID,
   290  	}
   291  	requestCtx := h.callsChannel.SendMultiRequest(req)
   292  
   293  	for {
   294  		saDetails := &vpp_ipsec.IpsecSaV3Details{}
   295  		stop, err := requestCtx.ReceiveReply(saDetails)
   296  		if stop {
   297  			break
   298  		}
   299  		if err != nil {
   300  			return nil, err
   301  		}
   302  
   303  		saList = append(saList, saDetails)
   304  	}
   305  
   306  	return saList, nil
   307  }
   308  
   309  // ResetPort returns 0 if stop port has maximum value (default VPP value if stop port is not defined)
   310  func resetPort(port uint16) uint32 {
   311  	if port == ^uint16(0) {
   312  		return 0
   313  	}
   314  	return uint32(port)
   315  }