go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ipsecplugin/vppcalls/vpp2202/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 vpp2202 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/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 "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 }