use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
#[repr(C)]
#[derive(Debug, Clone, Copy, Default, FromBytes, IntoBytes, Immutable, KnownLayout)]
pub struct Ipv6SrHdr {
pub nexthdr: u8,
pub hdrlen: u8,
pub sr_type: u8,
pub segments_left: u8,
pub first_segment: u8,
pub flags: u8,
pub tag: u16,
}
impl Ipv6SrHdr {
pub const SIZE: usize = std::mem::size_of::<Self>();
pub const SR_TYPE: u8 = 4;
pub fn new(num_segments: u8) -> Self {
let hdrlen = num_segments.saturating_mul(2);
Self {
nexthdr: 0, hdrlen,
sr_type: Self::SR_TYPE,
segments_left: num_segments.saturating_sub(1),
first_segment: num_segments.saturating_sub(1),
flags: 0,
tag: 0,
}
}
pub fn as_bytes(&self) -> &[u8] {
<Self as IntoBytes>::as_bytes(self)
}
pub fn from_bytes(data: &[u8]) -> Option<&Self> {
Self::ref_from_prefix(data).map(|(r, _)| r).ok()
}
}
pub mod seg6_mode {
pub const INLINE: u32 = 0;
pub const ENCAP: u32 = 1;
pub const L2ENCAP: u32 = 2;
pub const ENCAP_RED: u32 = 3;
pub const L2ENCAP_RED: u32 = 4;
}
pub mod seg6_iptunnel {
pub const UNSPEC: u16 = 0;
pub const SRH: u16 = 1;
}
pub mod seg6_local_action {
pub const UNSPEC: u32 = 0;
pub const END: u32 = 1;
pub const END_X: u32 = 2;
pub const END_T: u32 = 3;
pub const END_DX2: u32 = 4;
pub const END_DX6: u32 = 5;
pub const END_DX4: u32 = 6;
pub const END_DT6: u32 = 7;
pub const END_DT4: u32 = 8;
pub const END_B6: u32 = 9;
pub const END_B6_ENCAPS: u32 = 10;
pub const END_BM: u32 = 11;
pub const END_S: u32 = 12;
pub const END_AS: u32 = 13;
pub const END_AM: u32 = 14;
pub const END_BPF: u32 = 15;
pub const END_DT46: u32 = 16;
}
pub mod seg6_local {
pub const UNSPEC: u16 = 0;
pub const ACTION: u16 = 1;
pub const SRH: u16 = 2;
pub const TABLE: u16 = 3;
pub const NH4: u16 = 4;
pub const NH6: u16 = 5;
pub const IIF: u16 = 6;
pub const OIF: u16 = 7;
pub const BPF: u16 = 8;
pub const VRFTABLE: u16 = 9;
pub const COUNTERS: u16 = 10;
pub const FLAVORS: u16 = 11;
}
pub mod seg6_local_flv {
pub const UNSPEC: u16 = 0;
pub const OPERATION: u16 = 1;
pub const LCBLOCK_BITS: u16 = 2;
pub const LCNODE_FN_BITS: u16 = 3;
}
pub mod seg6_local_flv_op {
pub const PSP: u32 = 1 << 0;
pub const USP: u32 = 1 << 1;
pub const USD: u32 = 1 << 2;
pub const NEXT_CSID: u32 = 1 << 3;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ipv6_sr_hdr_size() {
assert_eq!(Ipv6SrHdr::SIZE, 8);
}
#[test]
fn test_ipv6_sr_hdr_new() {
let hdr = Ipv6SrHdr::new(3);
assert_eq!(hdr.sr_type, 4);
assert_eq!(hdr.hdrlen, 6); assert_eq!(hdr.segments_left, 2);
assert_eq!(hdr.first_segment, 2);
}
#[test]
fn test_ipv6_sr_hdr_single_segment() {
let hdr = Ipv6SrHdr::new(1);
assert_eq!(hdr.hdrlen, 2);
assert_eq!(hdr.segments_left, 0);
assert_eq!(hdr.first_segment, 0);
}
}