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 }