11// SPDX-License-Identifier: MIT
22
3+ use std:: { fmt:: Debug , net:: Ipv6Addr } ;
4+
35use anyhow:: Context ;
6+ use byteorder:: { BigEndian , ByteOrder , NetworkEndian } ;
47use netlink_packet_utils:: {
58 nla:: { DefaultNla , Nla , NlaBuffer , NlasIterator } ,
9+ parsers:: { parse_u16_be, parse_u8} ,
610 traits:: { Emitable , Parseable , ParseableParametrized } ,
711 DecodeError ,
812} ;
913
14+ use crate :: ip:: parse_ipv6_addr;
15+
1016use super :: { RouteMplsIpTunnel , RouteSeg6IpTunnel } ;
1117
1218const LWTUNNEL_ENCAP_NONE : u16 = 0 ;
@@ -21,6 +27,20 @@ const LWTUNNEL_ENCAP_RPL: u16 = 8;
2127const LWTUNNEL_ENCAP_IOAM6 : u16 = 9 ;
2228const LWTUNNEL_ENCAP_XFRM : u16 = 10 ;
2329
30+ const LWTUNNEL_IP6_UNSPEC : u16 = 0 ;
31+ const LWTUNNEL_IP6_ID : u16 = 1 ;
32+ const LWTUNNEL_IP6_DST : u16 = 2 ;
33+ const LWTUNNEL_IP6_SRC : u16 = 3 ;
34+ const LWTUNNEL_IP6_HOPLIMIT : u16 = 4 ;
35+ const LWTUNNEL_IP6_TC : u16 = 5 ;
36+ const LWTUNNEL_IP6_FLAGS : u16 = 6 ;
37+ //const LWTUNNEL_IP6_PAD: u16 = 7;
38+ //const LWTUNNEL_IP6_OPTS: u16 = 8;
39+
40+ const IP_TUNNEL_CSUM_BIT : u16 = 1 ;
41+ const IP_TUNNEL_KEY_BIT : u16 = 4 ;
42+ const IP_TUNNEL_SEQ_BIT : u16 = 8 ;
43+
2444#[ derive( Debug , PartialEq , Eq , Clone , Copy , Default ) ]
2545#[ non_exhaustive]
2646pub enum RouteLwEnCapType {
@@ -106,11 +126,152 @@ impl std::fmt::Display for RouteLwEnCapType {
106126 }
107127}
108128
129+ #[ derive( Debug , PartialEq , Eq , Clone , Default ) ]
130+ #[ non_exhaustive]
131+ pub enum RouteIp6Tunnel {
132+ #[ default]
133+ Unspecified ,
134+ Id ( u64 ) ,
135+ Destination ( Ipv6Addr ) ,
136+ Source ( Ipv6Addr ) ,
137+ Hoplimit ( u8 ) ,
138+ Tc ( u8 ) ,
139+ Flags ( RouteIp6TunnelFlags ) ,
140+ Other ( DefaultNla ) ,
141+ }
142+
143+ bitflags ! {
144+ #[ non_exhaustive]
145+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
146+ pub struct RouteIp6TunnelFlags : u16 {
147+ const Key = IP_TUNNEL_KEY_BIT ;
148+ const Checksum = IP_TUNNEL_CSUM_BIT ;
149+ const Sequence = IP_TUNNEL_SEQ_BIT ;
150+ const _ = !0 ;
151+ }
152+ }
153+
154+ impl std:: fmt:: Display for RouteIp6Tunnel {
155+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
156+ match self {
157+ Self :: Unspecified => write ! ( f, "unspecified" ) ,
158+ Self :: Id ( id) => write ! ( f, "id {id}" ) ,
159+ Self :: Destination ( dst) => write ! ( f, "dst {dst}" ) ,
160+ Self :: Source ( src) => write ! ( f, "src, {src}" ) ,
161+ Self :: Hoplimit ( hoplimit) => write ! ( f, "hoplimit {hoplimit}" ) ,
162+ Self :: Tc ( tc) => write ! ( f, "tc {tc}" ) ,
163+ Self :: Flags ( flags) => {
164+ if flags. contains ( RouteIp6TunnelFlags :: Key ) {
165+ write ! ( f, "key " ) ?;
166+ }
167+ if flags. contains ( RouteIp6TunnelFlags :: Checksum ) {
168+ write ! ( f, "csum " ) ?;
169+ }
170+
171+ if flags. contains ( RouteIp6TunnelFlags :: Sequence ) {
172+ write ! ( f, "seq " ) ?;
173+ }
174+
175+ Ok ( ( ) )
176+ }
177+ Self :: Other ( other) => other. fmt ( f) ,
178+ }
179+ }
180+ }
181+
182+ impl Nla for RouteIp6Tunnel {
183+ fn value_len ( & self ) -> usize {
184+ match self {
185+ Self :: Unspecified => 0 ,
186+ Self :: Id ( _) => const { size_of :: < u64 > ( ) } ,
187+ Self :: Destination ( _) => const { size_of :: < Ipv6Addr > ( ) } ,
188+ Self :: Source ( _) => const { size_of :: < Ipv6Addr > ( ) } ,
189+ Self :: Hoplimit ( _) => const { size_of :: < u8 > ( ) } ,
190+ Self :: Tc ( _) => const { size_of :: < u8 > ( ) } ,
191+ Self :: Flags ( _) => const { size_of :: < u16 > ( ) } ,
192+ Self :: Other ( _) => const { size_of :: < DefaultNla > ( ) } ,
193+ }
194+ }
195+
196+ fn kind ( & self ) -> u16 {
197+ match self {
198+ Self :: Unspecified => LWTUNNEL_IP6_UNSPEC ,
199+ Self :: Id ( _) => LWTUNNEL_IP6_ID ,
200+ Self :: Destination ( _) => LWTUNNEL_IP6_DST ,
201+ Self :: Source ( _) => LWTUNNEL_IP6_SRC ,
202+ Self :: Hoplimit ( _) => LWTUNNEL_IP6_HOPLIMIT ,
203+ Self :: Tc ( _) => LWTUNNEL_IP6_TC ,
204+ Self :: Flags ( _) => LWTUNNEL_IP6_FLAGS ,
205+ Self :: Other ( other) => other. kind ( ) ,
206+ }
207+ }
208+
209+ fn emit_value ( & self , buffer : & mut [ u8 ] ) {
210+ match self {
211+ Self :: Unspecified => { }
212+ Self :: Id ( id) => NetworkEndian :: write_u64 ( buffer, * id) ,
213+ Self :: Destination ( ip) | Self :: Source ( ip) => {
214+ buffer. copy_from_slice ( & ip. octets ( ) ) ;
215+ }
216+ Self :: Hoplimit ( value) | Self :: Tc ( value) => buffer[ 0 ] = * value,
217+ Self :: Flags ( flags) => BigEndian :: write_u16 ( buffer, flags. bits ( ) ) ,
218+ Self :: Other ( other) => other. emit_value ( buffer) ,
219+ }
220+ }
221+ }
222+
223+ // should probably be in utils
224+ fn parse_u64_be ( payload : & [ u8 ] ) -> Result < u64 , DecodeError > {
225+ if payload. len ( ) != size_of :: < u64 > ( ) {
226+ return Err ( format ! ( "invalid u64: {payload:?}" ) . into ( ) ) ;
227+ }
228+ Ok ( BigEndian :: read_u64 ( payload) )
229+ }
230+
231+ impl < ' a , T > Parseable < NlaBuffer < & ' a T > > for RouteIp6Tunnel
232+ where
233+ T : AsRef < [ u8 ] > + ?Sized ,
234+ {
235+ fn parse ( buf : & NlaBuffer < & ' a T > ) -> Result < Self , DecodeError > {
236+ let payload = buf. value ( ) ;
237+ Ok ( match buf. kind ( ) {
238+ LWTUNNEL_IP6_UNSPEC => Self :: Unspecified ,
239+ LWTUNNEL_IP6_ID => Self :: Id (
240+ parse_u64_be ( payload)
241+ . context ( "invalid LWTUNNEL_IP6_ID value" ) ?,
242+ ) ,
243+ LWTUNNEL_IP6_DST => Self :: Destination (
244+ parse_ipv6_addr ( payload)
245+ . context ( "invalid LWTUNNEL_IP6_DST value" ) ?,
246+ ) ,
247+ LWTUNNEL_IP6_SRC => Self :: Source (
248+ parse_ipv6_addr ( payload)
249+ . context ( "invalid LWTUNNEL_IP6_SRC value" ) ?,
250+ ) ,
251+ LWTUNNEL_IP6_HOPLIMIT => Self :: Hoplimit (
252+ parse_u8 ( payload)
253+ . context ( "invalid LWTUNNEL_IP6_HOPLIMIT value" ) ?,
254+ ) ,
255+ LWTUNNEL_IP6_TC => Self :: Tc (
256+ parse_u8 ( payload) . context ( "invalid LWTUNNEL_IP6_TC value" ) ?,
257+ ) ,
258+ LWTUNNEL_IP6_FLAGS => {
259+ Self :: Flags ( RouteIp6TunnelFlags :: from_bits_retain (
260+ parse_u16_be ( payload)
261+ . context ( "invalid LWTUNNEL_IP6_FLAGS value" ) ?,
262+ ) )
263+ }
264+ _ => Self :: Other ( DefaultNla :: parse ( buf) ?) ,
265+ } )
266+ }
267+ }
268+
109269#[ derive( Debug , PartialEq , Eq , Clone ) ]
110270#[ non_exhaustive]
111271pub enum RouteLwTunnelEncap {
112272 Mpls ( RouteMplsIpTunnel ) ,
113273 Seg6 ( RouteSeg6IpTunnel ) ,
274+ Ip6 ( RouteIp6Tunnel ) ,
114275 Other ( DefaultNla ) ,
115276}
116277
@@ -119,6 +280,7 @@ impl Nla for RouteLwTunnelEncap {
119280 match self {
120281 Self :: Mpls ( v) => v. value_len ( ) ,
121282 Self :: Seg6 ( v) => v. value_len ( ) ,
283+ Self :: Ip6 ( v) => v. value_len ( ) ,
122284 Self :: Other ( v) => v. value_len ( ) ,
123285 }
124286 }
@@ -127,6 +289,7 @@ impl Nla for RouteLwTunnelEncap {
127289 match self {
128290 Self :: Mpls ( v) => v. emit_value ( buffer) ,
129291 Self :: Seg6 ( v) => v. emit_value ( buffer) ,
292+ Self :: Ip6 ( v) => v. emit_value ( buffer) ,
130293 Self :: Other ( v) => v. emit_value ( buffer) ,
131294 }
132295 }
@@ -135,6 +298,7 @@ impl Nla for RouteLwTunnelEncap {
135298 match self {
136299 Self :: Mpls ( v) => v. kind ( ) ,
137300 Self :: Seg6 ( v) => v. kind ( ) ,
301+ Self :: Ip6 ( v) => v. kind ( ) ,
138302 Self :: Other ( v) => v. kind ( ) ,
139303 }
140304 }
@@ -156,6 +320,7 @@ where
156320 RouteLwEnCapType :: Seg6 => {
157321 Self :: Seg6 ( RouteSeg6IpTunnel :: parse ( buf) ?)
158322 }
323+ RouteLwEnCapType :: Ip6 => Self :: Ip6 ( RouteIp6Tunnel :: parse ( buf) ?) ,
159324 _ => Self :: Other ( DefaultNla :: parse ( buf) ?) ,
160325 } )
161326 }
0 commit comments