go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/l3plugin/vppcalls/vpp2210/route_dump.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  	"fmt"
    19  	"net"
    20  
    21  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2210/fib_types"
    22  	vpp_ip "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2210/ip"
    23  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2210/ip_types"
    24  	"go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vppcalls"
    25  	l3 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l3"
    26  )
    27  
    28  // DumpRoutes implements route handler.
    29  func (h *RouteHandler) DumpRoutes() (routes []*vppcalls.RouteDetails, err error) {
    30  	// dump routes for every VRF and for both IP versions
    31  	for _, vrfMeta := range h.vrfIndexes.ListAllVrfMetadata() {
    32  		ipRoutes, err := h.dumpRoutesForVrfAndIP(vrfMeta.GetIndex(), vrfMeta.GetProtocol())
    33  		if err != nil {
    34  			return nil, err
    35  		}
    36  		routes = append(routes, ipRoutes...)
    37  	}
    38  	return routes, nil
    39  }
    40  
    41  // dumpRoutesForVrf returns routes for given VRF and IP versiob
    42  func (h *RouteHandler) dumpRoutesForVrfAndIP(vrfID uint32, proto l3.VrfTable_Protocol) (routes []*vppcalls.RouteDetails, err error) {
    43  	reqCtx := h.callsChannel.SendMultiRequest(&vpp_ip.IPRouteDump{
    44  		Table: vpp_ip.IPTable{
    45  			TableID: vrfID,
    46  			IsIP6:   proto == l3.VrfTable_IPV6,
    47  		},
    48  	})
    49  	for {
    50  		fibDetails := &vpp_ip.IPRouteDetails{}
    51  		stop, err := reqCtx.ReceiveReply(fibDetails)
    52  		if stop {
    53  			break
    54  		}
    55  		if err != nil {
    56  			return nil, err
    57  		}
    58  		ipRoute, err := h.dumpRouteIPDetails(fibDetails.Route)
    59  		if err != nil {
    60  			return nil, err
    61  		}
    62  		routes = append(routes, ipRoute...)
    63  	}
    64  
    65  	return routes, nil
    66  }
    67  
    68  // dumpRouteIPDetails processes static route details and returns a route objects. Number of routes returned
    69  // depends on size of path list.
    70  func (h *RouteHandler) dumpRouteIPDetails(ipRoute vpp_ip.IPRoute) ([]*vppcalls.RouteDetails, error) {
    71  	// Common fields for every route path (destination IP, VRF)
    72  	var dstIP string
    73  	if ipRoute.Prefix.Address.Af == ip_types.ADDRESS_IP6 {
    74  		ip6Addr := ipRoute.Prefix.Address.Un.GetIP6()
    75  		dstIP = fmt.Sprintf("%s/%d", net.IP(ip6Addr[:]).To16().String(), uint32(ipRoute.Prefix.Len))
    76  	} else {
    77  		ip4Addr := ipRoute.Prefix.Address.Un.GetIP4()
    78  		dstIP = fmt.Sprintf("%s/%d", net.IP(ip4Addr[:4]).To4().String(), uint32(ipRoute.Prefix.Len))
    79  	}
    80  
    81  	var routeDetails []*vppcalls.RouteDetails
    82  
    83  	// Paths
    84  	if ipRoute.NPaths > 0 {
    85  		for _, path := range ipRoute.Paths {
    86  			// Next hop IP address
    87  			var nextHopIP string
    88  			netIP := make([]byte, 16)
    89  			copy(netIP[:], path.Nh.Address.XXX_UnionData[:])
    90  			if path.Proto == fib_types.FIB_API_PATH_NH_PROTO_IP6 {
    91  				nextHopIP = net.IP(netIP).To16().String()
    92  			} else {
    93  				nextHopIP = net.IP(netIP[:4]).To4().String()
    94  			}
    95  
    96  			// Route type (if via VRF is used)
    97  			var routeType l3.Route_RouteType
    98  			var viaVrfID uint32
    99  			if path.Type == fib_types.FIB_API_PATH_TYPE_DROP {
   100  				routeType = l3.Route_DROP
   101  			} else if path.SwIfIndex == NextHopOutgoingIfUnset && path.TableID != ipRoute.TableID {
   102  				// outgoing interface not specified and path table is not equal to route table id = inter-VRF route
   103  				routeType = l3.Route_INTER_VRF
   104  				viaVrfID = path.TableID
   105  			} else {
   106  				routeType = l3.Route_INTRA_VRF // default
   107  			}
   108  
   109  			// Outgoing interface
   110  			var ifName string
   111  			var ifIdx uint32
   112  			if path.SwIfIndex == NextHopOutgoingIfUnset {
   113  				ifIdx = NextHopOutgoingIfUnset
   114  			} else {
   115  				var exists bool
   116  				ifIdx = path.SwIfIndex
   117  				if ifName, _, exists = h.ifIndexes.LookupBySwIfIndex(path.SwIfIndex); !exists {
   118  					h.log.Warnf("Static route dump: interface name for index %d not found", path.SwIfIndex)
   119  				}
   120  			}
   121  
   122  			// Route configuration
   123  			route := &l3.Route{
   124  				Type:              routeType,
   125  				VrfId:             ipRoute.TableID,
   126  				DstNetwork:        dstIP,
   127  				NextHopAddr:       nextHopIP,
   128  				OutgoingInterface: ifName,
   129  				Weight:            uint32(path.Weight),
   130  				Preference:        uint32(path.Preference),
   131  				ViaVrfId:          viaVrfID,
   132  			}
   133  
   134  			labelStack := make([]vppcalls.FibMplsLabel, len(path.LabelStack))
   135  			for i, l := range path.LabelStack {
   136  				labelStack[i] = vppcalls.FibMplsLabel{
   137  					IsUniform: uintToBool(l.IsUniform),
   138  					Label:     l.Label,
   139  					TTL:       l.TTL,
   140  					Exp:       l.Exp,
   141  				}
   142  			}
   143  
   144  			// Route metadata
   145  			meta := &vppcalls.RouteMeta{
   146  				OutgoingIfIdx: ifIdx,
   147  				IsIPv6:        path.Proto == fib_types.FIB_API_PATH_NH_PROTO_IP6,
   148  				NextHopID:     path.Nh.ObjID,
   149  				RpfID:         path.RpfID,
   150  				LabelStack:    labelStack,
   151  			}
   152  			resolvePathType(meta, path.Type)
   153  			resolvePathFlags(meta, path.Flags)
   154  			// Note: VPP does not return table name as in older versions, the field
   155  			// is filled using index map
   156  			vrfName, _, exists := h.vrfIndexes.LookupByVRFIndex(ipRoute.TableID)
   157  			if exists {
   158  				meta.TableName = vrfName
   159  			}
   160  
   161  			routeDetails = append(routeDetails, &vppcalls.RouteDetails{
   162  				Route: route,
   163  				Meta:  meta,
   164  			})
   165  		}
   166  	} else {
   167  		// Return route without path fields, but this is not a valid configuration
   168  		h.log.Warnf("Route with destination IP %s (VRF %d) has no path specified", dstIP, ipRoute.TableID)
   169  		routeDetails = append(routeDetails, &vppcalls.RouteDetails{
   170  			Route: &l3.Route{
   171  				Type:       l3.Route_INTRA_VRF, // default
   172  				VrfId:      ipRoute.TableID,
   173  				DstNetwork: dstIP,
   174  			},
   175  		})
   176  	}
   177  
   178  	return routeDetails, nil
   179  }
   180  
   181  func resolvePathType(meta *vppcalls.RouteMeta, pathType fib_types.FibPathType) {
   182  	switch pathType {
   183  	case fib_types.FIB_API_PATH_TYPE_LOCAL:
   184  		meta.IsLocal = true
   185  	case fib_types.FIB_API_PATH_TYPE_UDP_ENCAP:
   186  		meta.IsUDPEncap = true
   187  	case fib_types.FIB_API_PATH_TYPE_ICMP_UNREACH:
   188  		meta.IsUnreach = true
   189  	case fib_types.FIB_API_PATH_TYPE_ICMP_PROHIBIT:
   190  		meta.IsProhibit = true
   191  	case fib_types.FIB_API_PATH_TYPE_DVR:
   192  		meta.IsDvr = true
   193  	case fib_types.FIB_API_PATH_TYPE_SOURCE_LOOKUP:
   194  		meta.IsSourceLookup = true
   195  	}
   196  }
   197  
   198  func resolvePathFlags(meta *vppcalls.RouteMeta, pathFlags fib_types.FibPathFlags) {
   199  	switch pathFlags {
   200  	case fib_types.FIB_API_PATH_FLAG_RESOLVE_VIA_HOST:
   201  		meta.IsResolveHost = true
   202  	case fib_types.FIB_API_PATH_FLAG_RESOLVE_VIA_ATTACHED:
   203  		meta.IsResolveAttached = true
   204  	}
   205  }