github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/route.go (about) 1 package netlink 2 3 import ( 4 "fmt" 5 "net" 6 "strings" 7 ) 8 9 // Scope is an enum representing a route scope. 10 type Scope uint8 11 12 type NextHopFlag int 13 14 const ( 15 RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota) 16 RT_FILTER_SCOPE 17 RT_FILTER_TYPE 18 RT_FILTER_TOS 19 RT_FILTER_IIF 20 RT_FILTER_OIF 21 RT_FILTER_DST 22 RT_FILTER_SRC 23 RT_FILTER_GW 24 RT_FILTER_TABLE 25 RT_FILTER_HOPLIMIT 26 RT_FILTER_PRIORITY 27 RT_FILTER_MARK 28 RT_FILTER_MASK 29 RT_FILTER_REALM 30 ) 31 32 type Destination interface { 33 Family() int 34 Decode([]byte) error 35 Encode() ([]byte, error) 36 String() string 37 Equal(Destination) bool 38 } 39 40 type Encap interface { 41 Type() int 42 Decode([]byte) error 43 Encode() ([]byte, error) 44 String() string 45 Equal(Encap) bool 46 } 47 48 // Protocol describe what was the originator of the route 49 type RouteProtocol int 50 51 // Route represents a netlink route. 52 type Route struct { 53 LinkIndex int 54 ILinkIndex int 55 Scope Scope 56 Dst *net.IPNet 57 Src net.IP 58 Gw net.IP 59 MultiPath []*NexthopInfo 60 Protocol RouteProtocol 61 Priority int 62 Family int 63 Table int 64 Type int 65 Tos int 66 Flags int 67 MPLSDst *int 68 NewDst Destination 69 Encap Encap 70 Via Destination 71 Realm int 72 MTU int 73 Window int 74 Rtt int 75 RttVar int 76 Ssthresh int 77 Cwnd int 78 AdvMSS int 79 Reordering int 80 Hoplimit int 81 InitCwnd int 82 Features int 83 RtoMin int 84 InitRwnd int 85 QuickACK int 86 Congctl string 87 FastOpenNoCookie int 88 } 89 90 func (r Route) String() string { 91 elems := []string{} 92 if len(r.MultiPath) == 0 { 93 elems = append(elems, fmt.Sprintf("Ifindex: %d", r.LinkIndex)) 94 } 95 if r.MPLSDst != nil { 96 elems = append(elems, fmt.Sprintf("Dst: %d", r.MPLSDst)) 97 } else { 98 elems = append(elems, fmt.Sprintf("Dst: %s", r.Dst)) 99 } 100 if r.NewDst != nil { 101 elems = append(elems, fmt.Sprintf("NewDst: %s", r.NewDst)) 102 } 103 if r.Encap != nil { 104 elems = append(elems, fmt.Sprintf("Encap: %s", r.Encap)) 105 } 106 if r.Via != nil { 107 elems = append(elems, fmt.Sprintf("Via: %s", r.Via)) 108 } 109 elems = append(elems, fmt.Sprintf("Src: %s", r.Src)) 110 if len(r.MultiPath) > 0 { 111 elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath)) 112 } else { 113 elems = append(elems, fmt.Sprintf("Gw: %s", r.Gw)) 114 } 115 elems = append(elems, fmt.Sprintf("Flags: %s", r.ListFlags())) 116 elems = append(elems, fmt.Sprintf("Table: %d", r.Table)) 117 elems = append(elems, fmt.Sprintf("Realm: %d", r.Realm)) 118 return fmt.Sprintf("{%s}", strings.Join(elems, " ")) 119 } 120 121 func (r Route) Equal(x Route) bool { 122 return r.LinkIndex == x.LinkIndex && 123 r.ILinkIndex == x.ILinkIndex && 124 r.Scope == x.Scope && 125 ipNetEqual(r.Dst, x.Dst) && 126 r.Src.Equal(x.Src) && 127 r.Gw.Equal(x.Gw) && 128 nexthopInfoSlice(r.MultiPath).Equal(x.MultiPath) && 129 r.Protocol == x.Protocol && 130 r.Priority == x.Priority && 131 r.Realm == x.Realm && 132 r.Table == x.Table && 133 r.Type == x.Type && 134 r.Tos == x.Tos && 135 r.Hoplimit == x.Hoplimit && 136 r.Flags == x.Flags && 137 (r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) && 138 (r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) && 139 (r.Via == x.Via || (r.Via != nil && r.Via.Equal(x.Via))) && 140 (r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap))) 141 } 142 143 func (r *Route) SetFlag(flag NextHopFlag) { 144 r.Flags |= int(flag) 145 } 146 147 func (r *Route) ClearFlag(flag NextHopFlag) { 148 r.Flags &^= int(flag) 149 } 150 151 type flagString struct { 152 f NextHopFlag 153 s string 154 } 155 156 // RouteUpdate is sent when a route changes - type is RTM_NEWROUTE or RTM_DELROUTE 157 type RouteUpdate struct { 158 Type uint16 159 Route 160 } 161 162 type NexthopInfo struct { 163 LinkIndex int 164 Hops int 165 Gw net.IP 166 Flags int 167 NewDst Destination 168 Encap Encap 169 Via Destination 170 } 171 172 func (n *NexthopInfo) String() string { 173 elems := []string{} 174 elems = append(elems, fmt.Sprintf("Ifindex: %d", n.LinkIndex)) 175 if n.NewDst != nil { 176 elems = append(elems, fmt.Sprintf("NewDst: %s", n.NewDst)) 177 } 178 if n.Encap != nil { 179 elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap)) 180 } 181 if n.Via != nil { 182 elems = append(elems, fmt.Sprintf("Via: %s", n.Via)) 183 } 184 elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1)) 185 elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw)) 186 elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags())) 187 return fmt.Sprintf("{%s}", strings.Join(elems, " ")) 188 } 189 190 func (n NexthopInfo) Equal(x NexthopInfo) bool { 191 return n.LinkIndex == x.LinkIndex && 192 n.Hops == x.Hops && 193 n.Gw.Equal(x.Gw) && 194 n.Flags == x.Flags && 195 (n.NewDst == x.NewDst || (n.NewDst != nil && n.NewDst.Equal(x.NewDst))) && 196 (n.Encap == x.Encap || (n.Encap != nil && n.Encap.Equal(x.Encap))) 197 } 198 199 type nexthopInfoSlice []*NexthopInfo 200 201 func (n nexthopInfoSlice) Equal(x []*NexthopInfo) bool { 202 if len(n) != len(x) { 203 return false 204 } 205 for i := range n { 206 if n[i] == nil || x[i] == nil { 207 return false 208 } 209 if !n[i].Equal(*x[i]) { 210 return false 211 } 212 } 213 return true 214 } 215 216 // ipNetEqual returns true iff both IPNet are equal 217 func ipNetEqual(ipn1 *net.IPNet, ipn2 *net.IPNet) bool { 218 if ipn1 == ipn2 { 219 return true 220 } 221 if ipn1 == nil || ipn2 == nil { 222 return false 223 } 224 m1, _ := ipn1.Mask.Size() 225 m2, _ := ipn2.Mask.Size() 226 return m1 == m2 && ipn1.IP.Equal(ipn2.IP) 227 }