go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ifplugin/vppcalls/vpp2106/ipip_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  	"fmt"
    19  	"net"
    20  
    21  	"github.com/pkg/errors"
    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  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/ipip"
    26  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/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  }