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 }