go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ipsecplugin/vppcalls/vpp2106/ipsec_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 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/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 ipsec "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/ipsec" 28 ) 29 30 // AddSPD implements IPSec handler. 31 func (h *IPSecVppHandler) AddSPD(spdID uint32) error { 32 return h.spdAddDel(spdID, true) 33 } 34 35 // DeleteSPD implements IPSec handler. 36 func (h *IPSecVppHandler) DeleteSPD(spdID uint32) error { 37 return h.spdAddDel(spdID, false) 38 } 39 40 // AddSP implements IPSec handler. 41 func (h *IPSecVppHandler) AddSP(sp *ipsec.SecurityPolicy) error { 42 return h.spdAddDelEntry(sp, true) 43 } 44 45 // DeleteSP implements IPSec handler. 46 func (h *IPSecVppHandler) DeleteSP(sp *ipsec.SecurityPolicy) error { 47 return h.spdAddDelEntry(sp, false) 48 } 49 50 // AddSPDInterface implements IPSec handler. 51 func (h *IPSecVppHandler) AddSPDInterface(spdID uint32, ifaceCfg *ipsec.SecurityPolicyDatabase_Interface) error { 52 ifaceMeta, found := h.ifIndexes.LookupByName(ifaceCfg.Name) 53 if !found { 54 return errors.New("failed to get interface metadata") 55 } 56 return h.interfaceAddDelSpd(spdID, ifaceMeta.SwIfIndex, true) 57 } 58 59 // DeleteSPDInterface implements IPSec handler. 60 func (h *IPSecVppHandler) DeleteSPDInterface(spdID uint32, ifaceCfg *ipsec.SecurityPolicyDatabase_Interface) error { 61 ifaceMeta, found := h.ifIndexes.LookupByName(ifaceCfg.Name) 62 if !found { 63 return errors.New("failed to get interface metadata") 64 } 65 return h.interfaceAddDelSpd(spdID, ifaceMeta.SwIfIndex, false) 66 } 67 68 // AddSA implements IPSec handler. 69 func (h *IPSecVppHandler) AddSA(sa *ipsec.SecurityAssociation) error { 70 return h.sadAddDelEntry(sa, true) 71 } 72 73 // DeleteSA implements IPSec handler. 74 func (h *IPSecVppHandler) DeleteSA(sa *ipsec.SecurityAssociation) error { 75 return h.sadAddDelEntry(sa, false) 76 } 77 78 // AddTunnelProtection implements IPSec handler for adding a tunnel protection. 79 func (h *IPSecVppHandler) AddTunnelProtection(tp *ipsec.TunnelProtection) error { 80 ifaceMeta, found := h.ifIndexes.LookupByName(tp.Interface) 81 if !found { 82 return errors.New("failed to get interface metadata") 83 } 84 return h.tunProtectAddUpdateEntry(tp, ifaceMeta.SwIfIndex) 85 } 86 87 // UpdateTunnelProtection implements IPSec handler for updating a tunnel protection. 88 func (h *IPSecVppHandler) UpdateTunnelProtection(tp *ipsec.TunnelProtection) error { 89 ifaceMeta, found := h.ifIndexes.LookupByName(tp.Interface) 90 if !found { 91 return errors.New("failed to get interface metadata") 92 } 93 return h.tunProtectAddUpdateEntry(tp, ifaceMeta.SwIfIndex) 94 } 95 96 // DeleteTunnelProtection implements IPSec handler for deleting a tunnel protection. 97 func (h *IPSecVppHandler) DeleteTunnelProtection(tp *ipsec.TunnelProtection) error { 98 ifaceMeta, found := h.ifIndexes.LookupByName(tp.Interface) 99 if !found { 100 return errors.New("failed to get interface metadata") 101 } 102 return h.tunProtectDelEntry(tp, ifaceMeta.SwIfIndex) 103 } 104 105 func (h *IPSecVppHandler) spdAddDel(spdID uint32, isAdd bool) error { 106 req := &vpp_ipsec.IpsecSpdAddDel{ 107 IsAdd: isAdd, 108 SpdID: spdID, 109 } 110 reply := &vpp_ipsec.IpsecSpdAddDelReply{} 111 112 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 113 return err 114 } 115 116 return nil 117 } 118 119 func (h *IPSecVppHandler) spdAddDelEntry(sp *ipsec.SecurityPolicy, isAdd bool) error { 120 req := &vpp_ipsec.IpsecSpdEntryAddDel{ 121 IsAdd: isAdd, 122 Entry: vpp_ipsec.IpsecSpdEntry{ 123 SpdID: sp.SpdIndex, 124 Priority: sp.Priority, 125 IsOutbound: sp.IsOutbound, 126 Protocol: uint8(sp.Protocol), 127 RemotePortStart: uint16(sp.RemotePortStart), 128 RemotePortStop: uint16(sp.RemotePortStop), 129 LocalPortStart: uint16(sp.LocalPortStart), 130 LocalPortStop: uint16(sp.LocalPortStop), 131 Policy: vpp_ipsec.IpsecSpdAction(sp.Action), 132 SaID: sp.SaIndex, 133 }, 134 } 135 if req.Entry.RemotePortStop == 0 { 136 req.Entry.RemotePortStop = ^req.Entry.RemotePortStop 137 } 138 if req.Entry.LocalPortStop == 0 { 139 req.Entry.LocalPortStop = ^req.Entry.LocalPortStop 140 } 141 142 var err error 143 req.Entry.RemoteAddressStart, err = IPToAddress(ipOr(sp.RemoteAddrStart, "0.0.0.0")) 144 if err != nil { 145 return err 146 } 147 req.Entry.RemoteAddressStop, err = IPToAddress(ipOr(sp.RemoteAddrStop, "255.255.255.255")) 148 if err != nil { 149 return err 150 } 151 req.Entry.LocalAddressStart, err = IPToAddress(ipOr(sp.LocalAddrStart, "0.0.0.0")) 152 if err != nil { 153 return err 154 } 155 req.Entry.LocalAddressStop, err = IPToAddress(ipOr(sp.LocalAddrStop, "255.255.255.255")) 156 if err != nil { 157 return err 158 } 159 160 reply := &vpp_ipsec.IpsecSpdEntryAddDelReply{} 161 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 162 return err 163 } 164 165 return nil 166 } 167 168 func ipOr(s, o string) string { 169 if s != "" { 170 return s 171 } 172 return o 173 } 174 175 func (h *IPSecVppHandler) interfaceAddDelSpd(spdID, swIfIdx uint32, isAdd bool) error { 176 req := &vpp_ipsec.IpsecInterfaceAddDelSpd{ 177 IsAdd: isAdd, 178 SwIfIndex: interface_types.InterfaceIndex(swIfIdx), 179 SpdID: spdID, 180 } 181 reply := &vpp_ipsec.IpsecInterfaceAddDelSpdReply{} 182 183 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 184 return err 185 } 186 187 return nil 188 } 189 190 func (h *IPSecVppHandler) sadAddDelEntry(sa *ipsec.SecurityAssociation, isAdd bool) error { 191 cryptoKey, err := hex.DecodeString(sa.CryptoKey) 192 if err != nil { 193 return err 194 } 195 integKey, err := hex.DecodeString(sa.IntegKey) 196 if err != nil { 197 return err 198 } 199 200 var flags ipsec_types.IpsecSadFlags 201 if sa.UseEsn { 202 flags |= ipsec_types.IPSEC_API_SAD_FLAG_USE_ESN 203 } 204 if sa.UseAntiReplay { 205 flags |= ipsec_types.IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY 206 } 207 if sa.EnableUdpEncap { 208 flags |= ipsec_types.IPSEC_API_SAD_FLAG_UDP_ENCAP 209 } 210 var tunnelSrc, tunnelDst ip_types.Address 211 if sa.TunnelSrcAddr != "" { 212 flags |= ipsec_types.IPSEC_API_SAD_FLAG_IS_TUNNEL 213 isIPv6, err := addrs.IsIPv6(sa.TunnelSrcAddr) 214 if err != nil { 215 return err 216 } 217 if isIPv6 { 218 flags |= ipsec_types.IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 219 } 220 tunnelSrc, err = IPToAddress(sa.TunnelSrcAddr) 221 if err != nil { 222 return err 223 } 224 tunnelDst, err = IPToAddress(sa.TunnelDstAddr) 225 if err != nil { 226 return err 227 } 228 } 229 const undefinedPort = ^uint16(0) 230 udpSrcPort := undefinedPort 231 if sa.TunnelSrcPort != 0 { 232 udpSrcPort = uint16(sa.TunnelSrcPort) 233 } 234 udpDstPort := undefinedPort 235 if sa.TunnelDstPort != 0 { 236 udpDstPort = uint16(sa.TunnelDstPort) 237 } 238 239 req := &vpp_ipsec.IpsecSadEntryAddDel{ 240 IsAdd: isAdd, 241 Entry: ipsec_types.IpsecSadEntry{ 242 SadID: sa.Index, 243 Spi: sa.Spi, 244 Protocol: protocolToIpsecProto(sa.Protocol), 245 CryptoAlgorithm: ipsec_types.IpsecCryptoAlg(sa.CryptoAlg), 246 CryptoKey: ipsec_types.Key{ 247 Data: cryptoKey, 248 Length: uint8(len(cryptoKey)), 249 }, 250 Salt: sa.CryptoSalt, 251 IntegrityAlgorithm: ipsec_types.IpsecIntegAlg(sa.IntegAlg), 252 IntegrityKey: ipsec_types.Key{ 253 Data: integKey, 254 Length: uint8(len(integKey)), 255 }, 256 TunnelSrc: tunnelSrc, 257 TunnelDst: tunnelDst, 258 Flags: flags, 259 UDPSrcPort: udpSrcPort, 260 UDPDstPort: udpDstPort, 261 }, 262 } 263 reply := &vpp_ipsec.IpsecSadEntryAddDelReply{} 264 265 if err = h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 266 return err 267 } 268 269 return nil 270 } 271 272 func ipsecProtoToProtocol(ipsecProto ipsec_types.IpsecProto) ipsec.SecurityAssociation_IPSecProtocol { 273 switch ipsecProto { 274 case ipsec_types.IPSEC_API_PROTO_AH: 275 return ipsec.SecurityAssociation_AH 276 case ipsec_types.IPSEC_API_PROTO_ESP: 277 return ipsec.SecurityAssociation_ESP 278 default: 279 return 0 280 } 281 } 282 283 func protocolToIpsecProto(protocol ipsec.SecurityAssociation_IPSecProtocol) ipsec_types.IpsecProto { 284 switch protocol { 285 case ipsec.SecurityAssociation_AH: 286 return ipsec_types.IPSEC_API_PROTO_AH 287 case ipsec.SecurityAssociation_ESP: 288 return ipsec_types.IPSEC_API_PROTO_ESP 289 default: 290 return 0 291 } 292 } 293 294 func (h *IPSecVppHandler) tunProtectAddUpdateEntry(tp *ipsec.TunnelProtection, swIfIndex uint32) error { 295 if len(tp.SaOut) == 0 || len(tp.SaIn) == 0 { 296 return errors.New("missing outbound/inbound SA") 297 } 298 if len(tp.SaIn) > int(^uint8(0)) { 299 return errors.New("invalid number of inbound SAs") 300 } 301 req := &vpp_ipsec.IpsecTunnelProtectUpdate{Tunnel: vpp_ipsec.IpsecTunnelProtect{ 302 SwIfIndex: interface_types.InterfaceIndex(swIfIndex), 303 SaOut: tp.SaOut[0], 304 SaIn: tp.SaIn, 305 NSaIn: uint8(len(tp.SaIn)), 306 }} 307 if tp.NextHopAddr != "" { 308 nh, err := IPToAddress(tp.NextHopAddr) 309 if err != nil { 310 return err 311 } 312 req.Tunnel.Nh = nh 313 } 314 reply := &vpp_ipsec.IpsecTunnelProtectUpdateReply{} 315 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 316 return err 317 } 318 return nil 319 } 320 321 func (h *IPSecVppHandler) tunProtectDelEntry(tp *ipsec.TunnelProtection, swIfIndex uint32) error { 322 req := &vpp_ipsec.IpsecTunnelProtectDel{ 323 SwIfIndex: interface_types.InterfaceIndex(swIfIndex), 324 } 325 if tp.NextHopAddr != "" { 326 nh, err := IPToAddress(tp.NextHopAddr) 327 if err != nil { 328 return err 329 } 330 req.Nh = nh 331 } 332 reply := &vpp_ipsec.IpsecTunnelProtectDelReply{} 333 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 334 return err 335 } 336 return nil 337 }