Skip to content

Commit e2a2c44

Browse files
fixup! iptunnel: add support to ipip, ipip6 and ip6ip6 tunnels
1 parent 27d9f7d commit e2a2c44

File tree

3 files changed

+121
-23
lines changed

3 files changed

+121
-23
lines changed

src/link/link_info/info_data.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use anyhow::Context;
44

55
use netlink_packet_utils::{
66
nla::{Nla, NlaBuffer, NlasIterator},
7-
DecodeError, Emitable, Parseable,
7+
DecodeError, Emitable, Parseable, ParseableParametrized,
88
};
99

1010
use super::super::{
@@ -362,7 +362,8 @@ impl InfoData {
362362
let nla = &nla.context(format!(
363363
"invalid IFLA_INFO_DATA for {kind} {payload:?}"
364364
))?;
365-
let parsed = InfoIpTunnel::parse(nla)?;
365+
let parsed =
366+
InfoIpTunnel::parse_with_param(nla, kind.clone())?;
366367
v.push(parsed);
367368
}
368369
InfoData::IpTunnel(v)

src/link/link_info/iptunnel.rs

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use byteorder::{ByteOrder, NativeEndian};
88
use netlink_packet_utils::{
99
nla::{DefaultNla, Nla, NlaBuffer},
1010
parsers::{parse_u16, parse_u32, parse_u8},
11-
traits::Parseable,
11+
traits::{Parseable, ParseableParametrized},
1212
DecodeError,
1313
};
1414

@@ -45,7 +45,9 @@ pub enum InfoIpTunnel {
4545
Tos(u8),
4646
EncapLimit(u8),
4747
FlowInfo(u32),
48-
Flags(TunnelFlags),
48+
Ipv6SitFlags(u16),
49+
Ipv4Flags(u16),
50+
Ipv6Flags(u32),
4951
Protocol(IpProtocol),
5052
PMtuDisc(bool),
5153
Ipv6RdPrefix(Ipv6Addr),
@@ -70,8 +72,10 @@ impl Nla for InfoIpTunnel {
7072
IpAddr::V4(_) => 4,
7173
IpAddr::V6(_) => 16,
7274
},
73-
Link(_) | FwMark(_) | FlowInfo(_) | Flags(_) => 4,
74-
EncapType(_)
75+
Link(_) | FwMark(_) | FlowInfo(_) | Ipv6Flags(_) => 4,
76+
Ipv6SitFlags(_)
77+
| Ipv4Flags(_)
78+
| EncapType(_)
7579
| EncapFlags(_)
7680
| EncapSPort(_)
7781
| EncapDPort(_)
@@ -92,8 +96,11 @@ impl Nla for InfoIpTunnel {
9296
Link(value) | FwMark(value) | FlowInfo(value) => {
9397
NativeEndian::write_u32(buffer, *value)
9498
}
95-
Flags(f) => {
96-
NativeEndian::write_u32(buffer, f.bits());
99+
Ipv6Flags(val) => {
100+
NativeEndian::write_u32(buffer, *val);
101+
}
102+
Ipv6SitFlags(val) | Ipv4Flags(val) => {
103+
NativeEndian::write_u16(buffer, *val);
97104
}
98105
Local(value) | Remote(value) => match value {
99106
IpAddr::V4(ipv4) => buffer.copy_from_slice(&ipv4.octets()),
@@ -109,7 +116,7 @@ impl Nla for InfoIpTunnel {
109116
| Ipv6RdRelayPrefixLen(value) => {
110117
NativeEndian::write_u16(buffer, *value)
111118
}
112-
Protocol(value) => buffer[0] = i32::from(*value) as u8,
119+
Protocol(value) => buffer[0] = u8::from(*value),
113120
Ttl(value) | Tos(value) | EncapLimit(value) => buffer[0] = *value,
114121
PMtuDisc(value) | CollectMetada(value) => {
115122
buffer[0] = if *value { 1 } else { 0 }
@@ -128,7 +135,7 @@ impl Nla for InfoIpTunnel {
128135
Tos(_) => IFLA_IPTUN_TOS,
129136
EncapLimit(_) => IFLA_IPTUN_ENCAP_LIMIT,
130137
FlowInfo(_) => IFLA_IPTUN_FLOWINFO,
131-
Flags(_) => IFLA_IPTUN_FLAGS,
138+
Ipv6SitFlags(_) | Ipv4Flags(_) | Ipv6Flags(_) => IFLA_IPTUN_FLAGS,
132139
Protocol(_) => IFLA_IPTUN_PROTO,
133140
PMtuDisc(_) => IFLA_IPTUN_PMTUDISC,
134141
Ipv6RdPrefix(_) => IFLA_IPTUN_6RD_PREFIX,
@@ -146,8 +153,13 @@ impl Nla for InfoIpTunnel {
146153
}
147154
}
148155

149-
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoIpTunnel {
150-
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
156+
impl<'a, T: AsRef<[u8]> + ?Sized>
157+
ParseableParametrized<NlaBuffer<&'a T>, super::InfoKind> for InfoIpTunnel
158+
{
159+
fn parse_with_param(
160+
buf: &NlaBuffer<&'a T>,
161+
kind: super::InfoKind,
162+
) -> Result<Self, DecodeError> {
151163
use self::InfoIpTunnel::*;
152164
let payload = buf.value();
153165
Ok(match buf.kind() {
@@ -202,12 +214,27 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoIpTunnel {
202214
parse_u32(payload)
203215
.context("invalid IFLA_IPTUN_FLOWINFO value")?,
204216
),
205-
IFLA_IPTUN_FLAGS => Flags(TunnelFlags::from_bits_retain(
206-
parse_u32(payload).context("invalid IFLA_IPTUN_FLAGS value")?,
207-
)),
217+
IFLA_IPTUN_FLAGS => match kind {
218+
super::InfoKind::SitTun => InfoIpTunnel::Ipv6SitFlags(
219+
parse_u16(payload)
220+
.context("invalid IFLA_IPTUN_FLAGS for SIT")?,
221+
),
222+
super::InfoKind::Tun => InfoIpTunnel::Ipv4Flags(
223+
parse_u16(payload)
224+
.context("invalid IFLA_IPTUN_FLAGS for IPIP")?,
225+
),
226+
super::InfoKind::Ip6Tnl => InfoIpTunnel::Ipv6Flags(
227+
parse_u32(payload)
228+
.context("invalid IFLA_IPTUN_FLAGS for IP6")?,
229+
),
230+
_ => {
231+
return Err(DecodeError::from(format!(
232+
"unsupported InfoKind for IFLA_IPTUN_FLAGS: {kind:?}"
233+
)));
234+
}
235+
},
208236
IFLA_IPTUN_PROTO => Protocol(IpProtocol::from(
209-
parse_u8(payload).context("invalid IFLA_IPTUN_PROTO value")?
210-
as i32,
237+
parse_u8(payload).context("invalid IFLA_IPTUN_PROTO value")?,
211238
)),
212239
IFLA_IPTUN_PMTUDISC => PMtuDisc(
213240
parse_u8(payload)

src/link/tests/iptunnel.rs

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
use std::net::{Ipv4Addr, Ipv6Addr};
44
use std::str::FromStr;
55

6-
use netlink_packet_utils::{Emitable, Parseable};
6+
use netlink_packet_utils::{nla::DefaultNla, Emitable, Parseable};
77

88
use crate::link::{
9-
InfoData, InfoIpTunnel, InfoKind, LinkAttribute, LinkFlags, LinkHeader,
10-
LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer, TunnelEncapFlags,
11-
TunnelEncapType, TunnelFlags,
9+
InfoData, InfoIpTunnel, InfoKind, InfoSitTun, LinkAttribute, LinkFlags,
10+
LinkHeader, LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer,
11+
TunnelEncapFlags, TunnelEncapType,
1212
};
1313

1414
use crate::{AddressFamily, IpProtocol};
@@ -124,7 +124,7 @@ fn test_iptunnel_ipip6_link_info() {
124124
InfoIpTunnel::Ttl(64),
125125
InfoIpTunnel::EncapLimit(4),
126126
InfoIpTunnel::FlowInfo(0),
127-
InfoIpTunnel::Flags(TunnelFlags::from_bits_retain(0x30000)),
127+
InfoIpTunnel::Ipv6Flags(0x30000),
128128
InfoIpTunnel::Protocol(IpProtocol::Ipip),
129129
InfoIpTunnel::FwMark(0),
130130
InfoIpTunnel::EncapType(TunnelEncapType::None),
@@ -193,7 +193,7 @@ fn test_iptunnel_ip6ip6_link_info() {
193193
InfoIpTunnel::Ttl(64),
194194
InfoIpTunnel::EncapLimit(4),
195195
InfoIpTunnel::FlowInfo(0),
196-
InfoIpTunnel::Flags(TunnelFlags::from_bits_retain(0x30000)),
196+
InfoIpTunnel::Ipv6Flags(0x30000),
197197
InfoIpTunnel::Protocol(IpProtocol::Ipv6),
198198
InfoIpTunnel::FwMark(0),
199199
InfoIpTunnel::EncapType(TunnelEncapType::None),
@@ -215,3 +215,73 @@ fn test_iptunnel_ip6ip6_link_info() {
215215

216216
assert_eq!(buf, raw);
217217
}
218+
219+
#[test]
220+
fn test_iptunnel_sit_link_info() {
221+
let raw: Vec<u8> = vec![
222+
0x00, 0x00, // AF_UNSPEC and reserved
223+
0x00, 0x03, // Link Layer Type IPTUNNEL (768)
224+
0x07, 0x00, 0x00, 0x00, // iface ifindex 7
225+
0x90, 0x00, 0x00, 0x00, // flags
226+
0x00, 0x00, 0x00, 0x00, // changed flags
227+
0xa4, 0x00, // length = 164
228+
0x12, 0x00, // IFLA_LINK_INFO (18)
229+
0x08, 0x00, 0x01, 0x00, b's', b'i', b't', 0x00, // "sit\0"
230+
0x98, 0x00, 0x02, 0x00, // IFLA_INFO_DATA nested
231+
0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
232+
0xc0, 0xa8, 0x7a, 0xb7, 0x08, 0x00, 0x03, 0x00, 0x0a, 0xff, 0xfe, 0x02,
233+
0x05, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
234+
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00,
235+
0x05, 0x00, 0x09, 0x00, 0x29, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
236+
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
237+
0x14, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00,
239+
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
240+
0x06, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00,
241+
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
242+
0x06, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00,
243+
0x00, 0x00, 0x00, 0x00,
244+
];
245+
246+
let expected = LinkMessage {
247+
header: LinkHeader {
248+
interface_family: AddressFamily::Unspec,
249+
index: 7,
250+
link_layer_type: LinkLayerType::Tunnel,
251+
flags: LinkFlags::Noarp | LinkFlags::Pointopoint,
252+
change_mask: LinkFlags::empty(),
253+
},
254+
attributes: vec![LinkAttribute::LinkInfo(vec![
255+
LinkInfo::Kind(InfoKind::SitTun),
256+
LinkInfo::Data(InfoData::SitTun(vec![
257+
InfoSitTun::Other(DefaultNla::new(1, vec![0, 0, 0, 0])),
258+
InfoSitTun::Other(DefaultNla::new(2, vec![192, 168, 122, 183])),
259+
InfoSitTun::Other(DefaultNla::new(3, vec![10, 255, 254, 2])),
260+
InfoSitTun::Other(DefaultNla::new(4, vec![64])),
261+
InfoSitTun::Other(DefaultNla::new(5, vec![0])),
262+
InfoSitTun::Other(DefaultNla::new(10, vec![1])),
263+
InfoSitTun::Other(DefaultNla::new(9, vec![41])),
264+
InfoSitTun::Other(DefaultNla::new(8, vec![0, 0])),
265+
InfoSitTun::Other(DefaultNla::new(20, vec![0, 0, 0, 0])),
266+
InfoSitTun::Other(DefaultNla::new(11, vec![0; 16])),
267+
InfoSitTun::Other(DefaultNla::new(12, vec![0, 0, 0, 0])),
268+
InfoSitTun::Other(DefaultNla::new(13, vec![0, 0])),
269+
InfoSitTun::Other(DefaultNla::new(14, vec![0, 0])),
270+
InfoSitTun::Other(DefaultNla::new(15, vec![0, 0])),
271+
InfoSitTun::Other(DefaultNla::new(17, vec![0, 0])),
272+
InfoSitTun::Other(DefaultNla::new(18, vec![0, 0])),
273+
InfoSitTun::Other(DefaultNla::new(16, vec![0, 0])),
274+
])),
275+
])],
276+
};
277+
278+
assert_eq!(
279+
expected,
280+
LinkMessage::parse(&LinkMessageBuffer::new(&raw)).unwrap()
281+
);
282+
283+
let mut buf = vec![0; expected.buffer_len()];
284+
expected.emit(&mut buf);
285+
286+
assert_eq!(buf, raw);
287+
}

0 commit comments

Comments
 (0)