Skip to main content

gwr_models/
ethernet_frame.rs

1// Copyright (c) 2023 Graphcore Ltd. All rights reserved.
2
3//! The EthernetFrame provides an implementation of a standard Ethernet frame
4
5use std::fmt::Display;
6use std::rc::Rc;
7
8use gwr_engine::traits::{Routable, SimObject, TotalBytes};
9use gwr_engine::types::AccessType;
10use gwr_track::entity::Entity;
11use gwr_track::id::Unique;
12use gwr_track::{Id, create_id, track_create_object};
13
14pub const PREAMBLE_BYTES: usize = 7;
15pub const SFD_BYTES: usize = 1;
16pub const DEST_MAC_BYTES: usize = 6;
17pub const SRC_MAC_BYTES: usize = 6;
18pub const FRAME_OVERHEAD_BYTES: usize = PREAMBLE_BYTES + SFD_BYTES + DEST_MAC_BYTES + SRC_MAC_BYTES;
19
20#[must_use]
21pub fn mac_to_u64(mac: &[u8; DEST_MAC_BYTES]) -> u64 {
22    ((mac[5] as u64) << (8 * 5))
23        | ((mac[4] as u64) << (8 * 4))
24        | ((mac[3] as u64) << (8 * 3))
25        | ((mac[2] as u64) << (8 * 2))
26        | ((mac[1] as u64) << 8)
27        | (mac[0] as u64)
28}
29
30#[must_use]
31pub fn u64_to_mac(value: u64) -> [u8; DEST_MAC_BYTES] {
32    let mut mac = [0_u8; DEST_MAC_BYTES];
33    mac[0] = (value & 0xff) as u8;
34    mac[1] = ((value >> 8) & 0xff) as u8;
35    mac[2] = ((value >> (8 * 2)) & 0xff) as u8;
36    mac[3] = ((value >> (8 * 3)) & 0xff) as u8;
37    mac[4] = ((value >> (8 * 4)) & 0xff) as u8;
38    mac[5] = ((value >> (8 * 5)) & 0xff) as u8;
39    mac
40}
41
42#[derive(Clone, Debug, PartialEq)]
43pub struct EthernetFrame {
44    id: Id,
45
46    // We don't include the Preamble / SFD bytes in the frame contents
47    dst_mac: [u8; DEST_MAC_BYTES],
48    src_mac: [u8; SRC_MAC_BYTES],
49
50    // Currently we don't store any actual frame contents
51    payload_size_bytes: usize,
52}
53
54impl EthernetFrame {
55    #[must_use]
56    pub fn new(created_by: &Rc<Entity>, payload_size_bytes: usize) -> Self {
57        let frame = Self {
58            id: create_id!(created_by),
59            dst_mac: [0; DEST_MAC_BYTES],
60            src_mac: [0; DEST_MAC_BYTES],
61            payload_size_bytes,
62        };
63        // Having just created the frame the req_type must be valid
64        track_create_object!(
65            created_by;
66            frame.id,
67            frame.total_bytes(),
68            "bytes",
69            frame.access_type() as u8,
70            "EthernetFrame: {frame}"
71        );
72        frame
73    }
74
75    #[must_use]
76    pub fn set_dest(mut self, dst_mac: [u8; DEST_MAC_BYTES]) -> Self {
77        self.dst_mac = dst_mac;
78        self
79    }
80
81    #[must_use]
82    pub fn set_src(mut self, src_mac: [u8; SRC_MAC_BYTES]) -> Self {
83        self.src_mac = src_mac;
84        self
85    }
86
87    #[must_use]
88    pub fn get_dst(&self) -> u64 {
89        mac_to_u64(&self.dst_mac)
90    }
91
92    #[must_use]
93    pub fn get_src(&self) -> u64 {
94        mac_to_u64(&self.src_mac)
95    }
96}
97
98impl SimObject for EthernetFrame {}
99
100impl Display for EthernetFrame {
101    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
102        write!(
103            f,
104            "{:?} -> {:?} ({} bytes)",
105            self.src_mac, self.dst_mac, self.payload_size_bytes
106        )
107    }
108}
109
110impl TotalBytes for EthernetFrame {
111    fn total_bytes(&self) -> usize {
112        self.payload_size_bytes + PREAMBLE_BYTES + SFD_BYTES + DEST_MAC_BYTES + SRC_MAC_BYTES
113    }
114}
115
116impl Unique for EthernetFrame {
117    fn id(&self) -> Id {
118        self.id
119    }
120}
121
122impl Routable for EthernetFrame {
123    fn destination(&self) -> u64 {
124        self.get_dst()
125    }
126
127    fn access_type(&self) -> AccessType {
128        // Simply return a default value
129        AccessType::Control
130    }
131}
132
133/// Allow Box of any SimObject type to be used
134impl SimObject for Box<EthernetFrame> {}
135
136impl TotalBytes for Box<EthernetFrame> {
137    fn total_bytes(&self) -> usize {
138        self.as_ref().total_bytes()
139    }
140}
141
142impl Unique for Box<EthernetFrame> {
143    fn id(&self) -> gwr_track::Id {
144        self.as_ref().id()
145    }
146}
147
148impl Routable for Box<EthernetFrame> {
149    fn destination(&self) -> u64 {
150        self.as_ref().destination()
151    }
152    fn access_type(&self) -> AccessType {
153        self.as_ref().access_type()
154    }
155}