Skip to content

Commit

Permalink
primitive wrapper types for u16 & u32 (capsule-rs#97)
Browse files Browse the repository at this point in the history
primitive wrapper types for u16 & u32 to ensure proper conversion of packet data to/from network byte order.

Includes:

- impls bit and/or/xor/*assign and not (!) for types
- includes updates throughout the packets module to use these types
- additional flag tests
  • Loading branch information
zeeshanlakhani authored and Zeeshan Lakhani committed May 11, 2020
1 parent 6b0ab55 commit b9a1122
Show file tree
Hide file tree
Showing 34 changed files with 527 additions and 310 deletions.
64 changes: 32 additions & 32 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#![doc(html_root_url = "https://docs.rs/capsule/0.1.3")]

//! A framework for network function development. Written in Rust, inspired by
//! [`NetBricks`] and built on Intel's [`Data Plane Development Kit`].
//! [NetBricks] and built on Intel's [Data Plane Development Kit].
//!
//! The goal of Capsule is to offer an ergonomic framework for network function
//! development that traditionally has high barriers of entry for developers.
Expand All @@ -43,17 +43,17 @@
//! ## Getting started
//!
//! The easiest way to start developing Capsule applications is to use the
//! `Vagrant` [`virtual machine`] and the `Docker` [`sandbox`] provided by the
//! `Vagrant` [virtual machine] and the `Docker` [sandbox] provided by the
//! Capsule team. The sandbox is preconfigured with all the necessary tools and
//! libraries for Capsule development, including:
//!
//! * [`DPDK 19.11`]
//! * [`Clang`] and [`LLVM`]
//! * [`Rust 1.43`]
//! * [`rr`] 5.3
//! * [DPDK 19.11]
//! * [Clang] and [LLVM]
//! * [Rust 1.43]
//! * [rr] 5.3
//!
//! For more information on getting started, please check out Capsule's
//! [`README`], as well as our [`sandbox repo`] for developer environments.
//! [README], as well as our [sandbox repo] for developer environments.
//!
//! ### Adding Capsule as a Cargo dependency
//!
Expand All @@ -80,33 +80,33 @@
//!
//! ### Examples
//!
//! - [`kni`]: Kernel NIC interface example.
//! - [`nat64`]: IPv6 to IPv4 NAT gateway example.
//! - [`ping4d`]: Ping4 daemon example.
//! - [`pktdump`]: Packet dump example.
//! - [`signals`]: Linux signal handling example.
//! - [`skeleton`]: Base skeleton example.
//! - [`syn-flood`]: TCP SYN flood example.
//! - [kni]: Kernel NIC interface example.
//! - [nat64]: IPv6 to IPv4 NAT gateway example.
//! - [ping4d]: Ping4 daemon example.
//! - [pktdump]: Packet dump example.
//! - [signals]: Linux signal handling example.
//! - [skeleton]: Base skeleton example.
//! - [syn-flood]: TCP SYN flood example.
//!
//! [`NetBricks`]: https://www.usenix.org/system/files/conference/osdi16/osdi16-panda.pdf
//! [`Data Plane Development Kit`]: https://www.dpdk.org/
//! [`virtual machine`]: https://github.com/capsule-rs/sandbox/blob/master/Vagrantfile
//! [`sandbox`]: https://hub.docker.com/repository/docker/getcapsule/sandbox
//! [`DPDK 19.11`]: https://doc.dpdk.org/guides-19.11/rel_notes/release_19_11.html
//! [`Clang`]: https://clang.llvm.org/
//! [`LLVM`]: https://www.llvm.org/
//! [`Rust 1.43`]: https://blog.rust-lang.org/2020/04/23/Rust-1.43.0.html
//! [`rr`]: https://rr-project.org/
//! [`README`]: https://github.com/capsule-rs/capsule/blob/master/README.md
//! [`sandbox repo`]: https://github.com/capsule-rs/sandbox
//! [NetBricks]: https://www.usenix.org/system/files/conference/osdi16/osdi16-panda.pdf
//! [Data Plane Development Kit]: https://www.dpdk.org/
//! [virtual machine]: https://github.com/capsule-rs/sandbox/blob/master/Vagrantfile
//! [sandbox]: https://hub.docker.com/repository/docker/getcapsule/sandbox
//! [DPDK 19.11]: https://doc.dpdk.org/guides-19.11/rel_notes/release_19_11.html
//! [Clang]: https://clang.llvm.org/
//! [LLVM]: https://www.llvm.org/
//! [Rust 1.43]: https://blog.rust-lang.org/2020/04/23/Rust-1.43.0.html
//! [rr]: https://rr-project.org/
//! [README]: https://github.com/capsule-rs/capsule/blob/master/README.md
//! [sandbox repo]: https://github.com/capsule-rs/sandbox
//! [`metrics`]: crate::metrics
//! [`kni`]: https://github.com/capsule-rs/capsule/tree/master/examples/kni
//! [`nat64`]: https://github.com/capsule-rs/capsule/tree/master/examples/nat64
//! [`ping4d`]: https://github.com/capsule-rs/capsule/tree/master/examples/ping4d
//! [`pktdump`]: https://github.com/capsule-rs/capsule/tree/master/examples/pktdump
//! [`signals`]: https://github.com/capsule-rs/capsule/tree/master/examples/signals
//! [`skeleton`]: https://github.com/capsule-rs/capsule/tree/master/examples/skeleton
//! [`syn-flood`]: https://github.com/capsule-rs/capsule/tree/master/examples/syn-flood
//! [kni]: https://github.com/capsule-rs/capsule/tree/master/examples/kni
//! [nat64]: https://github.com/capsule-rs/capsule/tree/master/examples/nat64
//! [ping4d]: https://github.com/capsule-rs/capsule/tree/master/examples/ping4d
//! [pktdump]: https://github.com/capsule-rs/capsule/tree/master/examples/pktdump
//! [signals]: https://github.com/capsule-rs/capsule/tree/master/examples/signals
//! [skeleton]: https://github.com/capsule-rs/capsule/tree/master/examples/skeleton
//! [syn-flood]: https://github.com/capsule-rs/capsule/tree/master/examples/syn-flood
// alias for the macros
extern crate self as capsule;
Expand Down
4 changes: 2 additions & 2 deletions core/src/net/cidr/v4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ use std::str::FromStr;

const IPV4ADDR_BITS: usize = 32;

/// [`CIDR`] range for IPv4 addresses.
/// [CIDR] range for IPv4 addresses.
///
/// [`CIDR`]: https://tools.ietf.org/html/rfc4632#section-3.1
/// [CIDR]: https://tools.ietf.org/html/rfc4632#section-3.1
#[derive(Clone, Debug, PartialEq)]
pub struct Ipv4Cidr {
address: Ipv4Addr,
Expand Down
4 changes: 2 additions & 2 deletions core/src/net/cidr/v6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ use std::str::FromStr;

const IPV6ADDR_BITS: usize = 128;

/// [`CIDR`] range for IPv6 addresses.
/// [CIDR] range for IPv6 addresses.
///
/// [`CIDR`]: https://tools.ietf.org/html/rfc4291#section-2.3
/// [CIDR]: https://tools.ietf.org/html/rfc4291#section-2.3
#[derive(Clone, Debug, PartialEq)]
pub struct Ipv6Cidr {
address: Ipv6Addr,
Expand Down
12 changes: 6 additions & 6 deletions core/src/packets/checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ fn v4_csum(src: Ipv4Addr, dst: Ipv4Addr, packet_len: u16, protocol: ProtocolNumb
}

/// Calculates the upper-layer checksum using the IPv6 psuedo-header as
/// defined in [`IETF RFC 2460`].
/// defined in [IETF RFC 2460].
///
/// ```
/// 0 1 2 3
Expand All @@ -119,15 +119,15 @@ fn v4_csum(src: Ipv4Addr, dst: Ipv4Addr, packet_len: u16, protocol: ProtocolNumb
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
///
/// [`IETF RFC 2460`]: https://tools.ietf.org/html/rfc2460#section-8.1
/// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460#section-8.1
fn v6_csum(src: Ipv6Addr, dst: Ipv6Addr, packet_len: u16, protocol: ProtocolNumber) -> u32 {
src.segments().iter().fold(0, |acc, &x| acc + u32::from(x))
+ dst.segments().iter().fold(0, |acc, &x| acc + u32::from(x))
+ u32::from(packet_len)
+ u32::from(protocol.0)
}

/// Computes the Internet checksum as defined in [`IETF RFC 1071`].
/// Computes the Internet checksum as defined in [IETF RFC 1071].
///
/// 1. Adjacent octets to be checksummed are paired to form 16-bit integers,
/// and the 1's complement sum of these 16-bit integers is formed.
Expand All @@ -140,7 +140,7 @@ fn v6_csum(src: Ipv6Addr, dst: Ipv6Addr, packet_len: u16, protocol: ProtocolNumb
/// set of octets, including the checksum field. If the result is all 1 bits
/// (-0 in 1's complement arithmetic), the check succeeds.
///
/// [`IETF RFC 1071`]: https://tools.ietf.org/html/rfc1071
/// [IETF RFC 1071]: https://tools.ietf.org/html/rfc1071
#[allow(clippy::cast_ptr_alignment)]
pub fn compute(pseudo_header_sum: u16, payload: &[u8]) -> u16 {
let len = payload.len();
Expand Down Expand Up @@ -168,7 +168,7 @@ pub fn compute(pseudo_header_sum: u16, payload: &[u8]) -> u16 {
}

/// Computes the Internet checksum via incremental update as defined in
/// [`IETF RFC 1624`].
/// [IETF RFC 1624].
///
/// Given the following notation:
/// * `HC` - old checksum in header
Expand All @@ -178,7 +178,7 @@ pub fn compute(pseudo_header_sum: u16, payload: &[u8]) -> u16 {
///
/// `HC' = ~(~HC + ~m + m')`
///
/// [`IETF RFC 1624`]: https://tools.ietf.org/html/rfc1624
/// [IETF RFC 1624]: https://tools.ietf.org/html/rfc1624
pub fn compute_inc(old_checksum: u16, old_value: &[u16], new_value: &[u16]) -> u16 {
let mut checksum = old_value
.iter()
Expand Down
38 changes: 21 additions & 17 deletions core/src/packets/ethernet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

use crate::dpdk::BufferError;
use crate::net::MacAddr;
use crate::packets::types::u16be;
use crate::packets::{Internal, Packet};
use crate::{ensure, Mbuf, SizeOf};
use failure::Fallible;
Expand Down Expand Up @@ -59,7 +60,7 @@ const VLAN_802_1AD: u16 = 0x88a8;
/// # 802.1Q aka Dot1q
///
/// For networks support virtual LANs, the frame may include an extra VLAN
/// tag after the source MAC as specified in [`IEEE 802.1Q`].
/// tag after the source MAC as specified in [IEEE 802.1Q].
///
/// ```
/// 0 1 2 3
Expand Down Expand Up @@ -100,7 +101,7 @@ const VLAN_802_1AD: u16 = 0x88a8;
///
/// # 802.1ad aka QinQ
///
/// The frame may be double tagged as per [`IEEE 802.1ad`].
/// The frame may be double tagged as per [IEEE 802.1ad].
///
/// ```
/// 0 1 2 3
Expand All @@ -115,8 +116,8 @@ const VLAN_802_1AD: u16 = 0x88a8;
/// S-TAG, or service tag, comes first, followed by the inner C-TAG, or customer
/// tag. In such cases, 802.1ad specifies a TPID of `0x88a8` for S-TAG.
///
/// [`IEEE 802.1Q`]: https://en.wikipedia.org/wiki/IEEE_802.1Q
/// [`IEEE 802.1ad`]: https://en.wikipedia.org/wiki/IEEE_802.1ad
/// [IEEE 802.1Q]: https://en.wikipedia.org/wiki/IEEE_802.1Q
/// [IEEE 802.1ad]: https://en.wikipedia.org/wiki/IEEE_802.1ad
pub struct Ethernet {
envelope: Mbuf,
header: NonNull<EthernetHeader>,
Expand Down Expand Up @@ -161,7 +162,7 @@ impl Ethernet {
/// Returns the marker that indicates whether the frame is VLAN.
#[inline]
fn vlan_marker(&self) -> u16 {
unsafe { u16::from_be(self.header().chunk.ether_type) }
unsafe { self.header().chunk.ether_type.into() }
}

/// Returns the protocol identifier of the payload.
Expand All @@ -176,13 +177,13 @@ impl Ethernet {
}
};

EtherType::new(u16::from_be(ether_type))
EtherType::new(ether_type.into())
}

/// Sets the protocol identifier of the payload.
#[inline]
pub fn set_ether_type(&mut self, ether_type: EtherType) {
let ether_type = u16::to_be(ether_type.0);
let ether_type = ether_type.0.into();
match self.vlan_marker() {
VLAN_802_1Q => self.header_mut().chunk.dot1q.ether_type = ether_type,
VLAN_802_1AD => self.header_mut().chunk.qinq.ether_type = ether_type,
Expand Down Expand Up @@ -366,8 +367,8 @@ impl fmt::Display for EtherType {
#[derive(Clone, Copy, Debug, Default, SizeOf)]
#[repr(C, packed)]
struct VlanTag {
tpid: u16,
tci: u16,
tpid: u16be,
tci: u16be,
}

#[allow(clippy::trivially_copy_pass_by_ref)]
Expand All @@ -376,29 +377,30 @@ impl VlanTag {
#[allow(dead_code)]
#[inline]
fn tag_id(&self) -> u16 {
self.tpid
self.tpid.into()
}

/// Returns the priority code point.
#[allow(dead_code)]
#[inline]
fn priority(&self) -> u8 {
(self.tci >> 13) as u8
let tci: u16 = self.tci.into();
(tci >> 13) as u8
}

/// Returns whether the frame is eligible to be dropped in the presence
/// of congestion.
#[allow(dead_code)]
#[inline]
fn drop_eligible(&self) -> bool {
self.tci & 0x1000 > 0
self.tci & u16be::from(0x1000) > u16be::MIN
}

/// Returns the VLAN identifier.
#[allow(dead_code)]
#[inline]
fn identifier(&self) -> u16 {
self.tci & 0x0fff
(self.tci & u16be::from(0x0fff)).into()
}
}

Expand All @@ -407,7 +409,7 @@ impl VlanTag {
#[repr(C, packed)]
struct Dot1q {
tag: VlanTag,
ether_type: u16,
ether_type: u16be,
}

/// QinQ chunk for a VLAN header.
Expand All @@ -416,22 +418,24 @@ struct Dot1q {
struct Qinq {
stag: VlanTag,
ctag: VlanTag,
ether_type: u16,
ether_type: u16be,
}

/// The Ethernet header chunk follows the source MAC.
#[allow(missing_debug_implementations)]
#[derive(Clone, Copy)]
#[repr(C, packed)]
union Chunk {
ether_type: u16,
ether_type: u16be,
dot1q: Dot1q,
qinq: Qinq,
}

impl Default for Chunk {
fn default() -> Chunk {
Chunk { ether_type: 0 }
Chunk {
ether_type: u16be::default(),
}
}
}

Expand Down
13 changes: 7 additions & 6 deletions core/src/packets/icmp/v4/echo_reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

use crate::packets::icmp::v4::{Icmpv4, Icmpv4Message, Icmpv4Packet, Icmpv4Type, Icmpv4Types};
use crate::packets::types::u16be;
use crate::packets::{Internal, Packet};
use crate::SizeOf;
use failure::Fallible;
Expand Down Expand Up @@ -65,25 +66,25 @@ impl EchoReply {
/// Returns the identifier.
#[inline]
pub fn identifier(&self) -> u16 {
u16::from_be(self.body().identifier)
self.body().identifier.into()
}

/// Sets the identifier.
#[inline]
pub fn set_identifier(&mut self, identifier: u16) {
self.body_mut().identifier = u16::to_be(identifier);
self.body_mut().identifier = identifier.into();
}

/// Returns the sequence number.
#[inline]
pub fn seq_no(&self) -> u16 {
u16::from_be(self.body().seq_no)
self.body().seq_no.into()
}

/// Sets the sequence number.
#[inline]
pub fn set_seq_no(&mut self, seq_no: u16) {
self.body_mut().seq_no = u16::to_be(seq_no);
self.body_mut().seq_no = seq_no.into();
}

/// Returns the offset where the data field in the message body starts.
Expand Down Expand Up @@ -195,8 +196,8 @@ impl Icmpv4Message for EchoReply {
#[derive(Clone, Copy, Debug, Default, SizeOf)]
#[repr(C, packed)]
struct EchoReplyBody {
identifier: u16,
seq_no: u16,
identifier: u16be,
seq_no: u16be,
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit b9a1122

Please sign in to comment.