1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! # Usage
//! Packets and headers are defined using the procedural macros
//! [`Ingot`] (headers), [`choice`] (selecting between headers), and
//! [`Parse`] (chains of individual layers).
//!
//! The documentation for each macro (as well as the packet and header types)
//! defined here double as examples of their use. See also the `ingot-examples`
//! crate.
//!
//! Headers can be used directly (as with any other rust struct), or using
//! protocol-specific traits and the `Header` type when we need to hold mixed
//! owned/borrowed data.
//!
//! ```text
//! ╔═╗
//! ║P║ pub struct Packet<Owned, View> { pub struct DirectPacket<Owned, View> {
//! ║r║ Repr(Box<Owned>), Repr(Owned),
//! ║o║ Raw(View), Raw(View),
//! ║v║ } }
//! ║i║ │ │
//! ║d║ │ │
//! ║e║ └───────────────┬────────IMPL─────────────┴──────┐
//! ║d║ │ │
//! ╚═╝─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─
//! ▼ ▼
//! ╔═╗ │ #[derive(Ingot)] #[derive(Ingot)]
//! ║U║ #[derive(Ingot)] pub trait UdpRef { pub trait UdpMut {
//! ║s║ pub struct Udp { │ fn src(&self) -> u16; fn set_src(&mut self, val: u16);
//! ║e║ // ... ──┐ fn dst(&self) -> u16; fn set_dst(&mut self, val: u16);
//! ║r║ } ▲ │ ││ // ... // ...
//! ╚═╝ │ │ │} }
//! │ HasView ││ ▲ ▲
//! ─ ─ ─ ─│─ ─ ─ ─ ─ ┼ ─ ─ ─│ │ │
//! HasRepr │ ├────────────┴───────────IMPL─────────────────┘
//! │ │ │
//! │ │ │ ╔═══════════╗
//! │ ▼ ║ Generated ║
//! pub struct ValidUdp<B: ByteSlice> ( ╚═══════════╝
//! Ref<B, UdpPart0>, // Zerocopy, repr(C)
//! );
//! ```
//!
//! Headers define *owned* and *borrowed* versions of their contents, with shared
//! traits to use and modify each individually or through the `Header` abstraction.
//! Base traits, primitive types, and assorted helpers are defined in [`ingot_types`].
//!
//! ## Working with packets.
//! Packets/headers can be read and modified whether they are owned or borrowed:
//! ```rust
//! use ingot::ethernet::{Ethernet, Ethertype, EthernetRef, EthernetMut, ValidEthernet};
//! use ingot::types::{Emit, HeaderParse, Header};
//! use macaddr::MacAddr6;
//!
//! let owned_ethernet = Ethernet {
//! destination: MacAddr6::broadcast(),
//! source: MacAddr6::nil(),
//! ethertype: Ethertype::ARP,
//! };
//!
//! // ----------------
//! // Field reads.
//! // ----------------
//!
//! let emitted_ethernet = owned_ethernet.emit_vec();
//! let (reparsed_ethernet, ..) = ValidEthernet::parse(&emitted_ethernet[..]).unwrap();
//!
//! // via EthernetRef
//! assert_eq!(reparsed_ethernet.source(), MacAddr6::nil());
//!
//! // compile error!
//! // assert_eq!(reparsed_ethernet.set_source(), MacAddr6::nil());
//!
//! // ----------------
//! // Field mutation.
//! // ----------------
//!
//! let mut emitted_ethernet = emitted_ethernet;
//! let (mut rereparsed_ethernet, ..) = ValidEthernet::parse(&mut emitted_ethernet[..]).unwrap();
//! rereparsed_ethernet.set_source(MacAddr6::broadcast());
//! rereparsed_ethernet.set_destination(MacAddr6::nil());
//!
//! assert_eq!(rereparsed_ethernet.source(), MacAddr6::broadcast());
//! assert_eq!(rereparsed_ethernet.destination(), MacAddr6::nil());
//!
//! // ----------------
//! // ...and via Header
//! // ----------------
//! let eth_pkt = Header::from(rereparsed_ethernet);
//! assert_eq!(eth_pkt.source(), MacAddr6::broadcast());
//! ```
//!
//! Packets can also be written into any buffer easily for any tuple of headers:
//! ```rust
//! # use ingot::ethernet::{Ethernet, Ethertype, EthernetRef, EthernetMut, ValidEthernet};
//! # use ingot::types::{Emit, HeaderParse, Header};
//! # use macaddr::MacAddr6;
//! use ingot::geneve::*;
//! use ingot::udp::*;
//!
//! // Headers can be emitted on their own.
//! let owned_ethernet = Ethernet {
//! destination: MacAddr6::broadcast(),
//! source: MacAddr6::nil(),
//! ethertype: Ethertype::ARP,
//! };
//!
//! let emitted_ethernet = owned_ethernet.emit_vec();
//! let (reparsed_ethernet, hint, rest) = ValidEthernet::parse(&emitted_ethernet[..]).unwrap();
//!
//! // Or we can easily emit an arbitrary stack in order
//! let makeshift_stack = (
//! Udp { source: 1234, destination: 5678, length: 77, checksum: 0xffff },
//! Geneve {
//! flags: GeneveFlags::CRITICAL_OPTS,
//! protocol_type: Ethertype::ETHERNET,
//! vni: 7777.try_into().unwrap(),
//! ..Default::default()
//! },
//! &[1, 2, 3, 4][..],
//! reparsed_ethernet,
//! );
//!
//! // ...to a new buffer.
//! let out = makeshift_stack.emit_vec();
//!
//! // ...or to an existing one
//! let mut slot = [0u8; 1500];
//! let _remainder = makeshift_stack.emit_prefix(&mut slot[..]).unwrap();
//! ```
// This lets us consistently use ::ingot::types regardless
// of call site in the macro (i.e., our code or downstream user
// packets).
extern crate self as ingot;
extern crate alloc;
extern crate std;
pub use ;
/// Primitive types and core traits needed to generate and use
/// `ingot` packets.
pub use ingot_types as types;