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 }