Skip to content

Commit 6ab3d83

Browse files
add ip4gre tunnel
1 parent 0626f22 commit 6ab3d83

File tree

15 files changed

+840
-20
lines changed

15 files changed

+840
-20
lines changed

core/src/packets/checksum.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,10 @@ fn v6_csum(src: Ipv6Addr, dst: Ipv6Addr, packet_len: u16, protocol: ProtocolNumb
142142
///
143143
/// [IETF RFC 1071]: https://tools.ietf.org/html/rfc1071
144144
#[allow(clippy::cast_ptr_alignment)]
145-
pub fn compute(pseudo_header_sum: u16, payload: &[u8]) -> u16 {
145+
pub fn ones_complement(base: u16, payload: &[u8]) -> u16 {
146146
let len = payload.len();
147147
let mut data = payload;
148-
let mut checksum = u32::from(pseudo_header_sum);
148+
let mut checksum = u32::from(base);
149149

150150
// odd # of bytes, we add the last byte with padding separately
151151
if len % 2 > 0 {

core/src/packets/ethernet.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ impl Packet for Ethernet {
315315
// the buffer will cause data corruption because it will write
316316
// past the 14 bytes we extended the buffer by.
317317
mbuf.extend(offset, ETH_HEADER_SIZE)?;
318-
let _ = mbuf.write_data_slice(offset, &[0; ETH_HEADER_SIZE])?;
318+
let _ = mbuf.write_data_slice(offset, &[0u8; ETH_HEADER_SIZE])?;
319319
let header = mbuf.read_data(offset)?;
320320

321321
Ok(Ethernet {

core/src/packets/gre/ip4gre.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright 2019 Comcast Cable Communications Management, LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
*/
18+
19+
use crate::ensure;
20+
use crate::packets::ethernet::Ethernet;
21+
use crate::packets::gre::{Gre, GreTunnelPacket};
22+
use crate::packets::ip::v4::Ipv4;
23+
use crate::packets::ip::{IpPacket, ProtocolNumbers};
24+
use crate::packets::{Datalink, Packet, Tunnel};
25+
use anyhow::{anyhow, Result};
26+
use std::marker::PhantomData;
27+
28+
/// Arbitrary layer 3 protocol encapsulated in IPv4 with GRE based on
29+
/// [IETF RFC 2784].
30+
///
31+
/// The payload is first encapsulated in a GRE packet. The resulting
32+
/// GRE packet is then encapsulated in IPv4 and then forwarded.
33+
///
34+
/// [IETF RFC 2784]: https://datatracker.ietf.org/doc/html/rfc2784
35+
/// [IPv4]: crate::packets::ip::v4::Ipv4
36+
#[derive(Debug)]
37+
pub struct Ip4Gre<P: Packet<Envelope = D>, D: Datalink = Ethernet> {
38+
_phantom1: PhantomData<P>,
39+
_phantom2: PhantomData<D>,
40+
}
41+
42+
impl<P: Packet<Envelope = D>, D: Datalink> Tunnel for Ip4Gre<P, D> {
43+
type Payload = P;
44+
type Delivery = Ipv4<D>;
45+
46+
/// Encapsulates the existing layer-3 packet by prepending an outer IPv4
47+
/// and a GRE packets.
48+
fn encap(payload: Self::Payload) -> Result<Self::Delivery> {
49+
let envelope = payload.deparse();
50+
let protocol_type = envelope.protocol_type();
51+
let ip4 = envelope.push::<Self::Delivery>()?;
52+
let mut gre = ip4.push::<Gre<Self::Delivery>>()?;
53+
gre.set_protocol_type(protocol_type);
54+
gre.reconcile_all();
55+
Ok(gre.deparse())
56+
}
57+
58+
/// Decapsulates the outer IPv4 and GRE packets and returns the original
59+
/// layer-3 packet.
60+
fn decap(delivery: Self::Delivery) -> Result<Self::Payload> {
61+
ensure!(delivery.gre_payload(), anyhow!("not an Ip4Gre tunnel."));
62+
63+
let gre = delivery.parse::<Gre<Self::Delivery>>()?;
64+
let protocol_type = gre.protocol_type();
65+
66+
let mut envelope = gre.remove()?.remove()?;
67+
envelope.set_protocol_type(protocol_type);
68+
envelope.parse::<Self::Payload>()
69+
}
70+
}
71+
72+
/// Generic impl for all IpPacket.
73+
impl<T: IpPacket> GreTunnelPacket for T {
74+
fn gre_payload(&self) -> bool {
75+
self.next_protocol() == ProtocolNumbers::Gre
76+
}
77+
78+
fn mark_gre_payload(&mut self) {
79+
self.set_next_protocol(ProtocolNumbers::Gre)
80+
}
81+
}
82+
83+
#[cfg(test)]
84+
mod tests {
85+
use super::*;
86+
use crate::packets::ethernet::EtherTypes;
87+
use crate::packets::icmp::v4::EchoRequest;
88+
use crate::packets::icmp::v6::EchoReply;
89+
use crate::packets::ip::v6::Ipv6;
90+
use crate::packets::Mbuf;
91+
use crate::testils::byte_arrays::{IP4GRE_PACKET, IPIP_PACKET};
92+
93+
#[capsule::test]
94+
fn encap_ip4gre_payload() {
95+
let packet = Mbuf::new().unwrap();
96+
let ethernet = packet.push::<Ethernet>().unwrap();
97+
let ip6 = ethernet.push::<Ipv6>().unwrap();
98+
let mut ip6 = ip6.push::<EchoReply>().unwrap().deparse();
99+
ip6.reconcile();
100+
let payload_len = ip6.len();
101+
102+
let delivery = ip6.encap::<Ip4Gre<Ipv6>>().unwrap();
103+
assert_eq!(EtherTypes::Ipv4, delivery.envelope().protocol_type());
104+
assert_eq!(ProtocolNumbers::Gre, delivery.protocol());
105+
106+
let gre = delivery.parse::<Gre<Ipv4>>().unwrap();
107+
assert_eq!(EtherTypes::Ipv6, gre.protocol_type());
108+
109+
// check payload matches original packet length
110+
assert_eq!(payload_len, gre.payload_len());
111+
}
112+
113+
#[capsule::test]
114+
fn decap_ip4gre_delivery() {
115+
let packet = Mbuf::from_bytes(&IP4GRE_PACKET).unwrap();
116+
let ethernet = packet.parse::<Ethernet>().unwrap();
117+
let delivery = ethernet.parse::<Ipv4>().unwrap();
118+
let payload = delivery.decap::<Ip4Gre<Ipv4>>().unwrap();
119+
120+
assert_eq!("1.1.1.1", payload.src().to_string());
121+
assert_eq!("2.2.2.2", payload.dst().to_string());
122+
123+
// parse the payload's payload to verify packet integrity
124+
assert!(payload.parse::<EchoRequest>().is_ok());
125+
}
126+
127+
#[capsule::test]
128+
fn decap_not_ip4gre() {
129+
let packet = Mbuf::from_bytes(&IPIP_PACKET).unwrap();
130+
let ethernet = packet.parse::<Ethernet>().unwrap();
131+
let notip4gre = ethernet.parse::<Ipv4>().unwrap();
132+
133+
// not an ip4gre tunnel
134+
assert!(notip4gre.decap::<Ip4Gre<Ipv4>>().is_err());
135+
}
136+
}

0 commit comments

Comments
 (0)