github.com/cilium/cilium@v1.16.2/pkg/datapath/tables/route.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package tables 5 6 import ( 7 "encoding/binary" 8 "fmt" 9 "net/netip" 10 11 "github.com/cilium/statedb" 12 "github.com/cilium/statedb/index" 13 ) 14 15 var ( 16 RouteIDIndex = statedb.Index[*Route, RouteID]{ 17 Name: "id", 18 FromObject: func(r *Route) index.KeySet { 19 return index.NewKeySet( 20 RouteID{ 21 Table: r.Table, 22 LinkIndex: r.LinkIndex, 23 Dst: r.Dst, 24 }.Key(), 25 ) 26 }, 27 FromKey: RouteID.Key, 28 Unique: true, 29 } 30 31 RouteLinkIndex = statedb.Index[*Route, int]{ 32 Name: "LinkIndex", 33 FromObject: func(r *Route) index.KeySet { 34 return index.NewKeySet(index.Int(r.LinkIndex)) 35 }, 36 FromKey: index.Int, 37 } 38 ) 39 40 func NewRouteTable() (statedb.RWTable[*Route], error) { 41 return statedb.NewTable( 42 "routes", 43 RouteIDIndex, 44 RouteLinkIndex, 45 ) 46 } 47 48 type RouteID struct { 49 Table RouteTable 50 LinkIndex int 51 Dst netip.Prefix 52 } 53 54 func (id RouteID) Key() index.Key { 55 key := make([]byte, 0, 4 /* table */ +4 /* link */ +17 /* prefix & bits */) 56 key = binary.BigEndian.AppendUint32(key, uint32(id.Table)) 57 key = binary.BigEndian.AppendUint32(key, uint32(id.LinkIndex)) 58 addrBytes := id.Dst.Addr().As16() 59 key = append(key, addrBytes[:]...) 60 return append(key, uint8(id.Dst.Bits())) 61 } 62 63 type Route struct { 64 Table RouteTable 65 LinkIndex int 66 67 Scope uint8 68 Dst netip.Prefix 69 Src netip.Addr 70 Gw netip.Addr 71 } 72 73 func (r *Route) DeepCopy() *Route { 74 r2 := *r 75 return &r2 76 } 77 78 func (r *Route) String() string { 79 return fmt.Sprintf("Route{Dst: %s, Src: %s, Table: %d, LinkIndex: %d}", 80 r.Dst, r.Src, r.Table, r.LinkIndex) 81 } 82 83 func (*Route) TableHeader() []string { 84 return []string{ 85 "Destination", 86 "Source", 87 "Gateway", 88 "LinkIndex", 89 "Table", 90 "Scope", 91 } 92 } 93 94 func (r *Route) TableRow() []string { 95 // Addr.String() shows "invalid IP" for zero value, but here 96 // we're expecting absence of IPs, so return empty string for 97 // invalid IPs. 98 showAddr := func(addr netip.Addr) string { 99 if !addr.IsValid() { 100 return "" 101 } 102 return addr.String() 103 } 104 return []string{ 105 r.Dst.String(), 106 showAddr(r.Src), 107 showAddr(r.Gw), 108 fmt.Sprintf("%d", r.LinkIndex), 109 fmt.Sprintf("%d", r.Table), 110 fmt.Sprintf("%d", r.Scope), 111 } 112 } 113 114 func HasDefaultRoute(tbl statedb.Table[*Route], rxn statedb.ReadTxn, linkIndex int) bool { 115 // Device has a default route when a route exists in the main table 116 // with a zero destination. 117 for _, prefix := range []netip.Prefix{zeroPrefixV4, zeroPrefixV6} { 118 r, _, _ := tbl.Get(rxn, RouteIDIndex.Query(RouteID{ 119 RT_TABLE_MAIN, 120 linkIndex, 121 prefix, 122 })) 123 if r != nil { 124 return true 125 } 126 } 127 return false 128 } 129 130 var ( 131 zeroPrefixV4 = netip.PrefixFrom(netip.IPv4Unspecified(), 0) 132 zeroPrefixV6 = netip.PrefixFrom(netip.IPv6Unspecified(), 0) 133 ) 134 135 type ( 136 RouteScope uint8 137 RouteTable uint32 138 ) 139 140 // Definitions for route scopes and tables. These are repeated here from the unix 141 // package to keep the tables package buildable on non-Linux platforms. 142 const ( 143 RT_SCOPE_UNIVERSE = RouteScope(0x0) 144 RT_SCOPE_SITE = RouteScope(0xc8) 145 RT_SCOPE_LINK = RouteScope(0xfd) 146 RT_SCOPE_HOST = RouteScope(0xfe) 147 RT_SCOPE_NOWHERE = RouteScope(0xff) 148 RT_TABLE_UNSPEC = RouteTable(0x0) 149 RT_TABLE_COMPAT = RouteTable(0xfc) 150 RT_TABLE_DEFAULT = RouteTable(0xfd) 151 RT_TABLE_MAIN = RouteTable(0xfe) 152 RT_TABLE_LOCAL = RouteTable(0xff) 153 RT_TABLE_MAX = RouteTable(0xffffffff) 154 )