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>(
161 &mut self,
162 port: u16,
163 pkt: &mut packet_in<'a>,
164 ) -> Vec<(packet_out<'a>, u16)>;
165
166 fn add_table_entry(
169 &mut self,
170 table_id: &str,
171 action_id: &str,
172 keyset_data: &[u8],
173 parameter_data: &[u8],
174 priority: u32,
175 );
176
177 fn remove_table_entry(&mut self, table_id: &str, keyset_data: &[u8]);
179
180 fn clear_table_entries(&mut self, table_id: &str) -> bool;
189
190 fn get_table_entries(&self, table_id: &str) -> Option<Vec<TableEntry>>;
192
193 fn get_table_ids(&self) -> Vec<&str>;
195}
196
197pub trait Header {
199 fn new() -> Self;
200 fn size() -> usize;
201 fn set(&mut self, buf: &[u8]) -> Result<(), TryFromSliceError>;
202 fn set_valid(&mut self);
203 fn set_invalid(&mut self);
204 fn is_valid(&self) -> bool;
205 fn to_bitvec(&self) -> BitVec<u8, Msb0>;
206}
207
208impl<'a> packet_in<'a> {
209 pub fn new(data: &'a [u8]) -> Self {
210 Self { data, index: 0 }
211 }
212
213 pub fn extract<H: Header>(&mut self, h: &mut H) {
222 let n = H::size();
224 let start = if self.index > 0 { self.index >> 3 } else { 0 };
225 match h.set(&self.data[start..start + (n >> 3)]) {
226 Ok(_) => {}
227 Err(e) => {
228 println!("packet extraction failed: {}", e);
230 }
231 }
232 self.index += n;
233 h.set_valid();
234 }
235
236 pub fn extract_new<H: Header>(&mut self) -> Result<H, TryFromSliceError> {
239 let n = H::size();
240 let start = if self.index > 0 { self.index >> 3 } else { 0 };
241 self.index += n;
242 let mut x = H::new();
243 x.set(&self.data[start..start + (n >> 3)])?;
244 Ok(x)
245 }
246}
247
248pub fn bitvec_to_biguint(bv: &BitVec<u8, Msb0>) -> table::BigUintKey {
250 table::BigUintKey {
251 value: if bv.is_empty() {
252 num::BigUint::default()
253 } else {
254 bv.load_le::<u128>().into()
255 },
256 width: bv.len().div_ceil(8),
257 }
258}
259
260pub fn bitvec_to_ip6addr(bv: &BitVec<u8, Msb0>) -> std::net::IpAddr {
261 let mut arr: [u8; 16] = bv.as_raw_slice().try_into().unwrap();
262 arr.reverse();
263 std::net::IpAddr::V6(std::net::Ipv6Addr::from(arr))
264}
265
266#[repr(C, align(16))]
267pub struct AlignedU128(pub u128);
268
269pub fn int_to_bitvec(x: i128) -> BitVec<u8, Msb0> {
270 let mut bv = bitvec![mut u8, Msb0; 0; 128];
272 bv.store(x);
273 bv
274}
275
276pub fn bitvec_to_bitvec16(x: BitVec<u8, Msb0>) -> BitVec<u8, Msb0> {
278 bitvec_resize(x, 16)
279}
280
281pub fn bitvec_resize(x: BitVec<u8, Msb0>, width: usize) -> BitVec<u8, Msb0> {
290 let value: u128 = if x.is_empty() { 0 } else { x.load_le() };
291 let mut resized = bitvec![u8, Msb0; 0; width];
292 if width > 0 {
293 resized.store_le(value);
294 }
295 resized
296}
297
298pub fn dump_bv(x: &BitVec<u8, Msb0>) -> String {
299 if x.is_empty() {
300 "∅".into()
301 } else {
302 let v: u128 = x.load_le();
303 format!("{:x}", v)
304 }
305}
306
307pub fn extract_exact_key(
308 keyset_data: &[u8],
309 offset: usize,
310 len: usize,
311) -> table::Key {
312 table::Key::Exact(table::BigUintKey {
313 value: num::BigUint::from_bytes_le(&keyset_data[offset..offset + len]),
314 width: len,
315 })
316}
317
318pub fn extract_range_key(
319 keyset_data: &[u8],
320 offset: usize,
321 len: usize,
322) -> table::Key {
323 table::Key::Range(
324 table::BigUintKey {
325 value: num::BigUint::from_bytes_le(
326 &keyset_data[offset..offset + len],
327 ),
328 width: len,
329 },
330 table::BigUintKey {
331 value: num::BigUint::from_bytes_le(
332 &keyset_data[offset + len..offset + len + len],
333 ),
334 width: len,
335 },
336 )
337}
338
339pub fn extract_ternary_key(
345 keyset_data: &[u8],
346 offset: usize,
347 len: usize,
348) -> table::Key {
349 let care = keyset_data[offset];
350 if care != 0 {
351 table::Key::Ternary(table::Ternary::Value(table::BigUintKey {
352 value: num::BigUint::from_bytes_le(
353 &keyset_data[offset + 1..offset + 1 + len],
354 ),
355 width: len,
356 }))
357 } else {
358 table::Key::Ternary(table::Ternary::DontCare)
359 }
360}
361
362pub fn extract_lpm_key(
363 keyset_data: &[u8],
364 offset: usize,
365 len: usize,
366) -> table::Key {
367 let (addr, prefix_len) = match len {
368 4 => {
370 let data: [u8; 4] =
371 keyset_data[offset..offset + 4].try_into().unwrap();
372 (IpAddr::from(data), keyset_data[offset + 4])
373 }
374 16 => {
376 let data: [u8; 16] =
377 keyset_data[offset..offset + 16].try_into().unwrap();
378 (IpAddr::from(data), keyset_data[offset + 16])
379 }
380 x => {
381 panic!("lpm: data len must be 4 (ipv4) or 16 (ipv6) found {}", x);
382 }
383 };
384
385 table::Key::Lpm(table::Prefix {
386 addr,
387 len: prefix_len,
388 })
389}
390
391pub fn extract_bool_action_parameter(
392 parameter_data: &[u8],
393 offset: usize,
394) -> bool {
395 parameter_data[offset] == 1
396}
397
398pub fn extract_bit_action_parameter(
411 parameter_data: &[u8],
412 offset: usize,
413 size: usize,
414) -> BitVec<u8, Msb0> {
415 let byte_size = size.div_ceil(8);
416 let mut bytes = parameter_data[offset..offset + byte_size].to_vec();
417 let rem = size % 8;
418 if rem != 0 {
421 bytes[byte_size - 1] <<= 8 - rem;
422 }
423 let mut bv = BitVec::<u8, Msb0>::from_vec(bytes);
424 bv.resize(size, false);
425 bv
426}
427
428pub fn bitmap_to_port_list(
438 bitmap: &BitVec<u8, Msb0>,
439 ingress_port: u16,
440 radix: u16,
441) -> Vec<u16> {
442 if bitmap.is_empty() {
443 return Vec::new();
444 }
445 let val: u128 = bitmap.load_le();
446 (0..radix.min(128))
447 .filter(|&p| val & (1u128 << p) != 0 && p != ingress_port)
448 .collect()
449}
450
451#[cfg(test)]
452mod tests {
453 use super::*;
454 use num::bigint::BigUint;
455
456 #[test]
457 fn bitvec_resize_preserves_value() {
458 for (source_width, target_width, value) in [
459 (4, 8, 1u128),
460 (4, 16, 0xf),
461 (8, 12, 0xab),
462 (12, 16, 0xabc),
463 (12, 24, 0xabc),
464 (16, 128, 0xbeef),
465 (128, 128, u128::MAX),
466 ] {
467 let mut input = bitvec![u8, Msb0; 0; source_width];
468 input.store_le(value);
469
470 let out = bitvec_resize(input, target_width);
471
472 assert_eq!(out.len(), target_width);
473 assert_eq!(
474 out.load_le::<u128>(),
475 value,
476 "{source_width} -> {target_width}",
477 );
478 }
479 }
480
481 #[test]
482 fn extract_bit_action_parameter_sub_byte_widths() {
483 for (width, value) in [
484 (12, 100u16),
485 (12, 256),
486 (12, 300),
487 (12, 4094),
488 (4, 0xa),
489 (9, 0x1ab),
490 (10, 0x2ab),
491 (11, 0x5ab),
492 (13, 0x1abc),
493 (14, 0x2abc),
494 (15, 0x5abc),
495 (16, 0xbeef),
496 ] {
497 let mut data = vec![0xffu8];
498 data.extend_from_slice(&value.to_le_bytes());
499
500 let out = extract_bit_action_parameter(&data, 1, width);
501
502 assert_eq!(out.len(), width);
503 assert_eq!(out.load_le::<u16>(), value, "bit<{width}> = {value}");
504
505 let mut expected = bitvec![u8, Msb0; 0; width];
506 expected.store_le(value);
507 assert_eq!(out, expected, "bit<{width}> layout");
508 }
509 }
510
511 #[test]
512 fn extract_bit_action_parameter_wide_unaligned() {
513 let mut data = vec![0xa5u8; 16];
514 data.push(0x0f);
515
516 let out = extract_bit_action_parameter(&data, 0, 132);
517
518 assert_eq!(out.len(), 132);
519 let mut expected = vec![0xa5u8; 16];
520 expected.push(0xf0);
521 assert_eq!(out.as_raw_slice(), expected.as_slice());
522 }
523
524 #[test]
525 fn bitvec_resize_empty_values() {
526 let out = bitvec_resize(BitVec::new(), 8);
527 assert_eq!(out.len(), 8);
528 assert_eq!(out.load_le::<u8>(), 0);
529 assert!(bitvec_resize(BitVec::new(), 0).is_empty());
530 }
531
532 #[test]
533 fn bitvec_resize_aligns_slices() {
534 for offset in 0..8 {
535 for (source_width, target_width, value) in [
536 (4, 8, 0xbu128),
537 (8, 16, 0xab),
538 (12, 16, 0xabc),
539 (16, 24, 0xbeef),
540 (128, 128, u128::MAX),
541 ] {
542 let storage = bitvec![u8, Msb0; 0; offset + source_width];
543 let mut input = storage[offset..].to_bitvec();
544 input.store_le(value);
545
546 let out = bitvec_resize(input, target_width);
547 let mut expected = bitvec![u8, Msb0; 0; target_width];
548 expected.store_le(value);
549
550 assert_eq!(
551 out, expected,
552 "offset {offset}: {source_width} -> {target_width}",
553 );
554 }
555 }
556 }
557
558 #[test]
561 fn bitvec_to_biguint_non_byte_aligned() {
562 for width in 1..=16 {
563 let mut bv = bitvec![u8, Msb0; 0; width];
564 bv.store_le(0xbeefu16);
565
566 assert_eq!(
567 bitvec_to_biguint(&bv).value,
568 BigUint::from(bv.load_le::<u16>()),
569 );
570 }
571 }
572
573 #[test]
574 fn bitvec_to_biguint_parsed_ihl() {
575 let data = [0x45u8];
576 let ihl = data.view_bits::<Msb0>()[4..8].to_bitvec();
577 let key = bitvec_to_biguint(&ihl);
578
579 assert_eq!(key.value, BigUint::from(5u8));
580 assert_eq!(key.width, 1);
581 }
582
583 #[test]
584 fn bitvec_to_biguint_storage_offsets() {
585 for offset in 0..8 {
586 for width in 1..=128 {
587 let storage = bitvec![u8, Msb0; 1; offset + width];
588 let mut bv = storage[offset..].to_bitvec();
589 let expected = u128::MAX >> (128 - width);
590 bv.store_le(expected);
591 bv.set_uninitialized(true);
592 let key = bitvec_to_biguint(&bv);
593
594 assert_eq!(key.value, BigUint::from(expected));
595 assert_eq!(key.width, width.div_ceil(8));
596 }
597 }
598 }
599
600 #[test]
601 fn bitvec_to_biguint_empty() {
602 let key = bitvec_to_biguint(&BitVec::new());
603
604 assert_eq!(key.value, BigUint::default());
605 assert_eq!(key.width, 0);
606 }
607
608 #[test]
609 fn replication_radix_is_bounded_by_bitmap_width() {
610 let mut bitmap = bitvec![u8, Msb0; 0; 128];
611 bitmap.store_le(1u128 << 127);
612
613 assert_eq!(bitmap_to_port_list(&bitmap, 0, u16::MAX), vec![127]);
614 }
615
616 #[test]
617 fn replication_of_empty_bitmap_yields_no_ports() {
618 let bitmap: BitVec<u8, Msb0> = BitVec::new();
619
620 assert_eq!(bitmap_to_port_list(&bitmap, 0, 4), Vec::<u16>::new());
621 }
622}