vmm/utils/net/
mac.rs

1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
5// Use of this source code is governed by a BSD-style license that can be
6// found in the THIRD-PARTY file.
7
8//! Contains support for parsing and constructing MAC addresses
9//! More information about MAC addresses can be found [here]
10//!
11//! [here]: https://en.wikipedia.org/wiki/MAC_address
12
13use std::fmt;
14use std::str::FromStr;
15
16use serde::de::{Deserialize, Deserializer, Error};
17use serde::ser::{Serialize, Serializer};
18
19/// The number of tuples (the ones separated by ":") contained in a MAC address.
20pub const MAC_ADDR_LEN: u8 = 6;
21
22/// Represents a MAC address
23#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
24#[repr(transparent)]
25/// Representation of a MAC address.
26pub struct MacAddr {
27    bytes: [u8; MAC_ADDR_LEN as usize],
28}
29
30impl fmt::Display for MacAddr {
31    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32        let b = &self.bytes;
33        write!(
34            f,
35            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
36            b[0], b[1], b[2], b[3], b[4], b[5]
37        )
38    }
39}
40
41impl From<[u8; 6]> for MacAddr {
42    fn from(bytes: [u8; 6]) -> Self {
43        Self { bytes }
44    }
45}
46
47impl From<MacAddr> for [u8; 6] {
48    fn from(mac: MacAddr) -> Self {
49        mac.bytes
50    }
51}
52
53impl FromStr for MacAddr {
54    type Err = String;
55    /// Try to turn a `&str` into a `MacAddr` object. The method will return the `str` that failed
56    /// to be parsed.
57    /// # Arguments
58    ///
59    /// * `s` - reference that can be converted to &str.
60    fn from_str(s: &str) -> Result<Self, Self::Err> {
61        let v: Vec<&str> = s.split(':').collect();
62        let mut bytes = [0u8; MAC_ADDR_LEN as usize];
63
64        if v.len() != MAC_ADDR_LEN as usize {
65            return Err(String::from(s));
66        }
67
68        for i in 0..MAC_ADDR_LEN as usize {
69            if v[i].len() != 2 {
70                return Err(String::from(s));
71            }
72            bytes[i] = u8::from_str_radix(v[i], 16).map_err(|_| String::from(s))?;
73        }
74
75        Ok(MacAddr { bytes })
76    }
77}
78
79impl MacAddr {
80    /// Create a `MacAddr` from a slice.
81    /// Does not check whether `src.len()` == `MAC_ADDR_LEN`.
82    /// # Arguments
83    ///
84    /// * `src` - slice from which to copy MAC address content.
85    #[inline]
86    pub fn from_bytes_unchecked(src: &[u8]) -> MacAddr {
87        // TODO: using something like std::mem::uninitialized could avoid the extra initialization,
88        // if this ever becomes a performance bottleneck.
89        let mut bytes = [0u8; MAC_ADDR_LEN as usize];
90        bytes[..].copy_from_slice(src);
91
92        MacAddr { bytes }
93    }
94
95    /// Return the underlying content of this `MacAddr` in bytes.
96    #[inline]
97    pub fn get_bytes(&self) -> &[u8] {
98        &self.bytes
99    }
100}
101
102impl Serialize for MacAddr {
103    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104    where
105        S: Serializer,
106    {
107        Serialize::serialize(&self.to_string(), serializer)
108    }
109}
110
111impl<'de> Deserialize<'de> for MacAddr {
112    fn deserialize<D>(deserializer: D) -> Result<MacAddr, D::Error>
113    where
114        D: Deserializer<'de>,
115    {
116        let s = <std::string::String as Deserialize>::deserialize(deserializer)?;
117        MacAddr::from_str(&s).map_err(|_| D::Error::custom("The provided MAC address is invalid."))
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    #[test]
126    fn test_mac_addr() {
127        // too long
128        MacAddr::from_str("aa:aa:aa:aa:aa:aa:aa").unwrap_err();
129
130        // invalid hex
131        MacAddr::from_str("aa:aa:aa:aa:aa:ax").unwrap_err();
132
133        // single digit mac address component should be invalid
134        MacAddr::from_str("aa:aa:aa:aa:aa:b").unwrap_err();
135
136        // components with more than two digits should also be invalid
137        MacAddr::from_str("aa:aa:aa:aa:aa:bbb").unwrap_err();
138
139        let mac = MacAddr::from_str("12:34:56:78:9a:BC").unwrap();
140
141        println!("parsed MAC address: {}", mac);
142
143        let bytes = mac.get_bytes();
144        assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]);
145    }
146
147    #[test]
148    fn test_mac_addr_serialization_and_deserialization() {
149        let mac: MacAddr =
150            serde_json::from_str("\"12:34:56:78:9a:bc\"").expect("MacAddr deserialization failed.");
151
152        let bytes = mac.get_bytes();
153        assert_eq!(bytes, [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc]);
154
155        let s = serde_json::to_string(&mac).expect("MacAddr serialization failed.");
156        assert_eq!(s, "\"12:34:56:78:9a:bc\"");
157    }
158}