1#![allow(incomplete_features)]
61#![allow(non_camel_case_types)]
62
63use std::fmt;
64use std::net::IpAddr;
65
66pub use error::TryFromSliceError;
67use serde::{Deserialize, Serialize};
68
69use bitvec::prelude::*;
70
71pub mod error;
72pub mod bitmath;
75pub mod checksum;
76pub mod externs;
77pub mod table;
78
79#[usdt::provider]
80mod p4rs_provider {
81 fn match_miss(_: &str) {}
82}
83
84#[derive(Debug)]
85pub struct Bit<'a, const N: usize>(pub &'a [u8]);
86
87impl<'a, const N: usize> Bit<'a, N> {
88 pub fn new(data: &'a [u8]) -> Result<Self, TryFromSliceError> {
92 let required_bytes = if N & 7 > 0 { (N >> 3) + 1 } else { N >> 3 };
93 if data.len() < required_bytes {
94 return Err(TryFromSliceError(N));
95 }
96 Ok(Self(&data[..required_bytes]))
97 }
98}
99
100impl<const N: usize> fmt::LowerHex for Bit<'_, N> {
101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102 for x in self.0 {
103 fmt::LowerHex::fmt(&x, f)?;
104 }
105 Ok(())
106 }
107}
108
109impl<'a> From<Bit<'a, 16>> for u16 {
111 fn from(b: Bit<'a, 16>) -> u16 {
112 u16::from_be_bytes([b.0[0], b.0[1]])
113 }
114}
115
116impl std::hash::Hash for Bit<'_, 8> {
118 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
119 self.0[0].hash(state);
120 }
121}
122
123impl std::cmp::PartialEq for Bit<'_, 8> {
124 fn eq(&self, other: &Self) -> bool {
125 self.0[0] == other.0[0]
126 }
127}
128
129impl std::cmp::Eq for Bit<'_, 8> {}
130
131#[derive(Debug)]
135pub struct packet_in<'a> {
136 pub data: &'a [u8],
138
139 pub index: usize,
143}
144
145#[derive(Debug)]
146pub struct packet_out<'a> {
147 pub header_data: Vec<u8>,
148 pub payload_data: &'a [u8],
149}
150
151#[derive(Debug, Serialize, Deserialize)]
152pub struct TableEntry {
153 pub action_id: String,
154 pub keyset_data: Vec<u8>,
155 pub parameter_data: Vec<u8>,
156}
157
158pub trait Pipeline: Send {
159 fn process_packet<'a>(
163 &mut self,
164 port: u16,
165 pkt: &mut packet_in<'a>,
166 ) -> Vec<(packet_out<'a>, u16)>;
167
168 fn add_table_entry(
171 &mut self,
172 table_id: &str,
173 action_id: &str,
174 keyset_data: &[u8],
175 parameter_data: &[u8],
176 priority: u32,
177 );
178
179 fn remove_table_entry(&mut self, table_id: &str, keyset_data: &[u8]);
181
182 fn get_table_entries(&self, table_id: &str) -> Option<Vec<TableEntry>>;
184
185 fn get_table_ids(&self) -> Vec<&str>;
187}
188
189pub trait Header {
191 fn new() -> Self;
192 fn size() -> usize;
193 fn set(&mut self, buf: &[u8]) -> Result<(), TryFromSliceError>;
194 fn set_valid(&mut self);
195 fn set_invalid(&mut self);
196 fn is_valid(&self) -> bool;
197 fn to_bitvec(&self) -> BitVec<u8, Msb0>;
198}
199
200impl<'a> packet_in<'a> {
201 pub fn new(data: &'a [u8]) -> Self {
202 Self { data, index: 0 }
203 }
204
205 pub fn extract<H: Header>(&mut self, h: &mut H) {
214 let n = H::size();
216 let start = if self.index > 0 { self.index >> 3 } else { 0 };
217 match h.set(&self.data[start..start + (n >> 3)]) {
218 Ok(_) => {}
219 Err(e) => {
220 println!("packet extraction failed: {}", e);
222 }
223 }
224 self.index += n;
225 h.set_valid();
226 }
227
228 pub fn extract_new<H: Header>(&mut self) -> Result<H, TryFromSliceError> {
231 let n = H::size();
232 let start = if self.index > 0 { self.index >> 3 } else { 0 };
233 self.index += n;
234 let mut x = H::new();
235 x.set(&self.data[start..start + (n >> 3)])?;
236 Ok(x)
237 }
238}
239
240pub fn bitvec_to_biguint(bv: &BitVec<u8, Msb0>) -> table::BigUintKey {
242 let s = bv.as_raw_slice();
243 table::BigUintKey {
244 value: num::BigUint::from_bytes_le(s),
245 width: s.len(),
246 }
247}
248
249pub fn bitvec_to_ip6addr(bv: &BitVec<u8, Msb0>) -> std::net::IpAddr {
250 let mut arr: [u8; 16] = bv.as_raw_slice().try_into().unwrap();
251 arr.reverse();
252 std::net::IpAddr::V6(std::net::Ipv6Addr::from(arr))
253}
254
255#[repr(C, align(16))]
256pub struct AlignedU128(pub u128);
257
258pub fn int_to_bitvec(x: i128) -> BitVec<u8, Msb0> {
259 let mut bv = bitvec![mut u8, Msb0; 0; 128];
261 bv.store(x);
262 bv
263}
264
265pub fn bitvec_to_bitvec16(mut x: BitVec<u8, Msb0>) -> BitVec<u8, Msb0> {
266 x.resize(16, false);
267 x
268}
269
270pub fn dump_bv(x: &BitVec<u8, Msb0>) -> String {
271 if x.is_empty() {
272 "∅".into()
273 } else {
274 let v: u128 = x.load_le();
275 format!("{:x}", v)
276 }
277}
278
279pub fn extract_exact_key(
280 keyset_data: &[u8],
281 offset: usize,
282 len: usize,
283) -> table::Key {
284 table::Key::Exact(table::BigUintKey {
285 value: num::BigUint::from_bytes_le(&keyset_data[offset..offset + len]),
286 width: len,
287 })
288}
289
290pub fn extract_range_key(
291 keyset_data: &[u8],
292 offset: usize,
293 len: usize,
294) -> table::Key {
295 table::Key::Range(
296 table::BigUintKey {
297 value: num::BigUint::from_bytes_le(
298 &keyset_data[offset..offset + len],
299 ),
300 width: len,
301 },
302 table::BigUintKey {
303 value: num::BigUint::from_bytes_le(
304 &keyset_data[offset + len..offset + len + len],
305 ),
306 width: len,
307 },
308 )
309}
310
311pub fn extract_ternary_key(
317 keyset_data: &[u8],
318 offset: usize,
319 len: usize,
320) -> table::Key {
321 let care = keyset_data[offset];
322 if care != 0 {
323 table::Key::Ternary(table::Ternary::Value(table::BigUintKey {
324 value: num::BigUint::from_bytes_le(
325 &keyset_data[offset + 1..offset + 1 + len],
326 ),
327 width: len,
328 }))
329 } else {
330 table::Key::Ternary(table::Ternary::DontCare)
331 }
332}
333
334pub fn extract_lpm_key(
335 keyset_data: &[u8],
336 offset: usize,
337 _len: usize,
338) -> table::Key {
339 let (addr, len) = match keyset_data.len() {
340 5 => {
342 let data: [u8; 4] =
343 keyset_data[offset..offset + 4].try_into().unwrap();
344 (IpAddr::from(data), keyset_data[offset + 4])
345 }
346 17 => {
348 let data: [u8; 16] =
349 keyset_data[offset..offset + 16].try_into().unwrap();
350 (IpAddr::from(data), keyset_data[offset + 16])
351 }
352 x => {
353 panic!("lpm: key must be len 5 (ipv4) or 17 (ipv6) found {}", x);
354 }
355 };
356
357 table::Key::Lpm(table::Prefix { addr, len })
358}
359
360pub fn extract_bool_action_parameter(
361 parameter_data: &[u8],
362 offset: usize,
363) -> bool {
364 parameter_data[offset] == 1
365}
366
367pub fn extract_bit_action_parameter(
368 parameter_data: &[u8],
369 offset: usize,
370 size: usize,
371) -> BitVec<u8, Msb0> {
372 let mut byte_size = size >> 3;
373 if size % 8 != 0 {
374 byte_size += 1;
375 }
376 let mut b: BitVec<u8, Msb0> =
377 BitVec::from_slice(¶meter_data[offset..offset + byte_size]);
378 b.resize(size, false);
379 b
380}