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