go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ifplugin/vppcalls/vpp2202/ipip_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 "fmt" 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 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/ipip" 26 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/tunnel_types" 27 "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls" 28 interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 29 ) 30 31 // AddIpipTunnel adds new IPIP tunnel interface. 32 func (h *InterfaceVppHandler) AddIpipTunnel(ifName string, vrf uint32, ipipLink *interfaces.IPIPLink) (uint32, error) { 33 req := &ipip.IpipAddTunnel{ 34 Tunnel: ipip.IpipTunnel{ 35 Instance: ^uint32(0), 36 TableID: vrf, 37 }, 38 } 39 40 if ipipLink == nil { 41 return 0, errors.New("missing IPIP tunnel information") 42 } 43 var srcAddr, dstAddr net.IP 44 var isSrcIPv6, isDstIPv6 bool 45 46 srcAddr = net.ParseIP(ipipLink.SrcAddr) 47 if srcAddr == nil { 48 err := errors.New("bad source address for IPIP tunnel") 49 return 0, err 50 } 51 if srcAddr.To4() == nil { 52 isSrcIPv6 = true 53 } 54 55 if ipipLink.TunnelMode == interfaces.IPIPLink_POINT_TO_POINT { 56 dstAddr = net.ParseIP(ipipLink.DstAddr) 57 if dstAddr == nil { 58 err := errors.New("bad destination address for IPIP tunnel") 59 return 0, err 60 } 61 if dstAddr.To4() == nil { 62 isDstIPv6 = true 63 } 64 } 65 66 if !isSrcIPv6 && (dstAddr == nil || !isDstIPv6) { 67 var src, dst [4]uint8 68 copy(src[:], srcAddr.To4()) 69 req.Tunnel.Src = ip_types.Address{ 70 Af: ip_types.ADDRESS_IP4, 71 Un: ip_types.AddressUnionIP4(src), 72 } 73 if dstAddr != nil { 74 copy(dst[:], dstAddr.To4()) 75 req.Tunnel.Dst = ip_types.Address{ 76 Af: ip_types.ADDRESS_IP4, 77 Un: ip_types.AddressUnionIP4(dst), 78 } 79 } 80 } else if isSrcIPv6 && (dstAddr == nil || isDstIPv6) { 81 var src, dst [16]uint8 82 copy(src[:], srcAddr.To16()) 83 req.Tunnel.Src = ip_types.Address{ 84 Af: ip_types.ADDRESS_IP6, 85 Un: ip_types.AddressUnionIP6(src), 86 } 87 if dstAddr != nil { 88 copy(dst[:], dstAddr.To16()) 89 req.Tunnel.Dst = ip_types.Address{ 90 Af: ip_types.ADDRESS_IP6, 91 Un: ip_types.AddressUnionIP6(dst), 92 } 93 } 94 } else { 95 return 0, errors.New("source and destination addresses must be both either IPv4 or IPv6") 96 } 97 98 if ipipLink.TunnelMode == interfaces.IPIPLink_POINT_TO_MULTIPOINT { 99 req.Tunnel.Mode = tunnel_types.TUNNEL_API_MODE_MP 100 } 101 102 reply := &ipip.IpipAddTunnelReply{} 103 104 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 105 return 0, err 106 } 107 swIfIndex := uint32(reply.SwIfIndex) 108 return swIfIndex, h.SetInterfaceTag(ifName, swIfIndex) 109 } 110 111 // DelIpipTunnel removes IPIP tunnel interface. 112 func (h *InterfaceVppHandler) DelIpipTunnel(ifName string, ifIdx uint32) error { 113 req := &ipip.IpipDelTunnel{ 114 SwIfIndex: interface_types.InterfaceIndex(ifIdx), 115 } 116 reply := &ipip.IpipDelTunnelReply{} 117 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 118 return err 119 } 120 return h.RemoveInterfaceTag(ifName, ifIdx) 121 } 122 123 // dumpIpipDetails dumps IPIP interface details from VPP and fills them into the provided interface map. 124 func (h *InterfaceVppHandler) dumpIpipDetails(ifc map[uint32]*vppcalls.InterfaceDetails) error { 125 126 reqCtx := h.callsChannel.SendMultiRequest(&ipip.IpipTunnelDump{ 127 SwIfIndex: ^interface_types.InterfaceIndex(0), 128 }) 129 for { 130 ipipDetails := &ipip.IpipTunnelDetails{} 131 stop, err := reqCtx.ReceiveReply(ipipDetails) 132 if stop { 133 break // Break from the loop. 134 } 135 if err != nil { 136 return fmt.Errorf("failed to dump IPIP tunnel interface details: %v", err) 137 } 138 _, ifIdxExists := ifc[uint32(ipipDetails.Tunnel.SwIfIndex)] 139 if !ifIdxExists { 140 continue 141 } 142 143 ipipLink := &interfaces.IPIPLink{} 144 if ipipDetails.Tunnel.Src.Af == ip_types.ADDRESS_IP6 { 145 srcAddrArr := ipipDetails.Tunnel.Src.Un.GetIP6() 146 ipipLink.SrcAddr = net.IP(srcAddrArr[:]).To16().String() 147 if ipipDetails.Tunnel.Mode == tunnel_types.TUNNEL_API_MODE_P2P { 148 dstAddrArr := ipipDetails.Tunnel.Dst.Un.GetIP6() 149 ipipLink.DstAddr = net.IP(dstAddrArr[:]).To16().String() 150 } 151 } else { 152 srcAddrArr := ipipDetails.Tunnel.Src.Un.GetIP4() 153 ipipLink.SrcAddr = net.IP(srcAddrArr[:4]).To4().String() 154 if ipipDetails.Tunnel.Mode == tunnel_types.TUNNEL_API_MODE_P2P { 155 dstAddrArr := ipipDetails.Tunnel.Dst.Un.GetIP4() 156 ipipLink.DstAddr = net.IP(dstAddrArr[:4]).To4().String() 157 } 158 } 159 160 if ipipDetails.Tunnel.Mode == tunnel_types.TUNNEL_API_MODE_MP { 161 ipipLink.TunnelMode = interfaces.IPIPLink_POINT_TO_MULTIPOINT 162 } 163 164 // TODO: temporary fix since VPP does not dump the tunnel mode properly. 165 // If dst address is empty, this must be a multipoint tunnel. 166 if ipipLink.DstAddr == "0.0.0.0" { 167 ipipLink.TunnelMode = interfaces.IPIPLink_POINT_TO_MULTIPOINT 168 ipipLink.DstAddr = "" 169 } 170 171 ifc[uint32(ipipDetails.Tunnel.SwIfIndex)].Interface.Link = &interfaces.Interface_Ipip{Ipip: ipipLink} 172 ifc[uint32(ipipDetails.Tunnel.SwIfIndex)].Interface.Type = interfaces.Interface_IPIP_TUNNEL 173 } 174 return nil 175 }