-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8f2d6ec
commit 61c14d4
Showing
24 changed files
with
5,410 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
use netlink_packet_utils::DecodeError; | ||
|
||
/// An identifier for an encapsulation key used by a tunnel. | ||
/// | ||
/// Examples include a VNIs for VXLAN and Geneve tunnels, ERSPAN/GRE keys, and | ||
/// GTP tunnel keys. | ||
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)] | ||
#[repr(transparent)] | ||
pub struct EncKeyId(u32); | ||
|
||
impl EncKeyId { | ||
/// Create a new `EncKeyId` without checking the validity of the ID value. | ||
/// | ||
/// # Safety | ||
/// | ||
/// Failure to ensure the ID is within the valid range for the tunnel in | ||
/// question may lead to semantically invalid netlink messages. | ||
/// | ||
/// If you know the tunnel type (e.g., vxlan) and wish to confirm that the | ||
/// ID is within the valid range of values for that tunnel type, use the | ||
/// corresponding new method (e.g., `new_vxlan_vni`). | ||
#[must_use] | ||
pub const fn new_unchecked(id: u32) -> Self { | ||
Self(id) | ||
} | ||
|
||
/// Create a new `EncKeyId` and confirm that it is within the valid range | ||
/// of vxlan vni values. | ||
/// | ||
/// # Errors | ||
/// Returns an error if the ID is zero or greater than or equal to 2^24. | ||
pub fn new_vxlan_vni(id: u32) -> Result<Self, DecodeError> { | ||
crate::net::vxlan::Vni::new(id).map(Into::into) | ||
} | ||
|
||
/// Create a new `EncKeyId` and confirm that it is within the valid range | ||
/// of geneve vni values. | ||
/// | ||
/// # Errors | ||
/// | ||
/// Returns an error if the ID is greater than or equal to 2^24. | ||
pub fn new_geneve_vni(id: u32) -> Result<Self, DecodeError> { | ||
match Self::new_nbit::<24>(id) { | ||
Ok(id) => Ok(id), | ||
Err(_) => Err(DecodeError::from( | ||
"Geneve VNI must be less than 2^24, received {id}", | ||
)), | ||
} | ||
} | ||
|
||
/// Create a new `EncKeyId` in the space of valid GRE keys. | ||
/// | ||
/// # Safety | ||
/// | ||
/// Since GRE keys are 32 bits and all values are legal, this method is not | ||
/// failable. | ||
#[must_use] | ||
pub fn new_gre_key(id: u32) -> Self { | ||
Self(id) | ||
} | ||
|
||
/// Create a new `EncKeyId` and confirm that it is within the valid range | ||
/// of gtp tunnel key values. | ||
/// | ||
/// # Errors | ||
/// | ||
/// Returns an error if the ID is zero. | ||
pub fn new_gtp_key(id: u32) -> Result<Self, DecodeError> { | ||
if id == 0 { | ||
return Err(DecodeError::from( | ||
"zero is not a legal GTP tunnel key", | ||
)); | ||
} | ||
Ok(Self(id)) | ||
} | ||
|
||
/// Create a new `EncKeyId` and confirm that it is within the valid range | ||
/// of N bit values. | ||
/// | ||
/// # Errors | ||
/// | ||
/// Returns an error if the ID is greater than or equal to 2^N. | ||
const fn new_nbit<const N: usize>(id: u32) -> Result<Self, KeyTooLarge> { | ||
if id >= (1 << N) { | ||
return Err(KeyTooLarge); | ||
}; | ||
Ok(Self(id)) | ||
} | ||
} | ||
|
||
impl From<EncKeyId> for u32 { | ||
fn from(id: EncKeyId) -> u32 { | ||
id.0 | ||
} | ||
} | ||
|
||
impl AsRef<u32> for EncKeyId { | ||
fn as_ref(&self) -> &u32 { | ||
&self.0 | ||
} | ||
} | ||
|
||
impl From<u32> for EncKeyId { | ||
/// Convert `u32` to an `EncKeyId`. | ||
/// | ||
/// # Safety | ||
/// | ||
/// This conversion is infallible but may produce a semantically invalid key | ||
/// depending on the tunnel type. | ||
/// | ||
/// If you know the tunnel type (e.g., vxlan) and wish to confirm that the | ||
/// ID is within the valid range of values for that tunnel type, use the | ||
/// corresponding "new" method on the `EncKeyId` type (e.g., | ||
/// `EncKeyId::new_vxlan_vni`). | ||
fn from(id: u32) -> Self { | ||
Self(id) | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
#[must_use] | ||
struct KeyTooLarge; | ||
|
||
impl From<crate::net::vxlan::Vni> for EncKeyId { | ||
fn from(vni: crate::net::vxlan::Vni) -> Self { | ||
Self(vni.into()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
const RESERVED: u8 = 0; | ||
const REQUEST: u8 = 1; | ||
const REPLY: u8 = 2; | ||
const REQUEST_REVERSE: u8 = 3; | ||
const REPLY_REVERSE: u8 = 4; | ||
const DRARP_REQUEST: u8 = 5; | ||
const DRARP_REPLY: u8 = 6; | ||
const DRARP_ERROR: u8 = 7; | ||
const IN_ARP_REQUEST: u8 = 8; | ||
const IN_ARP_REPLY: u8 = 9; | ||
const ARP_NAK: u8 = 10; | ||
const MARS_REQUEST: u8 = 11; | ||
const MARS_MULTI: u8 = 12; | ||
const MARS_MSERV: u8 = 13; | ||
const MARS_JOIN: u8 = 14; | ||
const MARS_LEAVE: u8 = 15; | ||
const MARS_NAK: u8 = 16; | ||
const MARS_UNSERV: u8 = 17; | ||
const MARS_SJOIN: u8 = 18; | ||
const MARS_SLEAVE: u8 = 19; | ||
const MARS_GROUP_LIST_REQUEST: u8 = 20; | ||
const MARS_GROUP_LIST_REPLY: u8 = 21; | ||
const MARS_REDIRECT_MAP: u8 = 22; | ||
const MAPO_SUNARP: u8 = 23; | ||
const OP_EXP1: u8 = 24; | ||
const OP_EXP2: u8 = 25; | ||
|
||
/// Enum of ARP operation codes. | ||
/// | ||
/// List from [iana.org][1] | ||
/// | ||
/// [1]: https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml | ||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, Hash)] | ||
#[non_exhaustive] | ||
#[repr(u8)] | ||
pub enum Operation { | ||
Reserved = RESERVED, | ||
Request = REQUEST, | ||
Reply = REPLY, | ||
RequestReverse = REQUEST_REVERSE, | ||
ReplyReverse = REPLY_REVERSE, | ||
DrarpRequest = DRARP_REQUEST, | ||
DrarpReply = DRARP_REPLY, | ||
DrarpError = DRARP_ERROR, | ||
InArpRequest = IN_ARP_REQUEST, | ||
InArpReply = IN_ARP_REPLY, | ||
ArpNak = ARP_NAK, | ||
MarsRequest = MARS_REQUEST, | ||
MarsMulti = MARS_MULTI, | ||
MarsMServ = MARS_MSERV, | ||
MarsJoin = MARS_JOIN, | ||
MarsLeave = MARS_LEAVE, | ||
MarsNAK = MARS_NAK, | ||
MarsUnserv = MARS_UNSERV, | ||
MarsSJoin = MARS_SJOIN, | ||
MarsSLeave = MARS_SLEAVE, | ||
MarsGroupListRequest = MARS_GROUP_LIST_REQUEST, | ||
MarsGroupListReply = MARS_GROUP_LIST_REPLY, | ||
MarsRedirectMap = MARS_REDIRECT_MAP, | ||
MapoSUnarp = MAPO_SUNARP, | ||
OpExp1 = OP_EXP1, | ||
OpExp2 = OP_EXP2, | ||
Other(u8), | ||
} | ||
|
||
impl AsRef<u8> for Operation { | ||
fn as_ref(&self) -> &u8 { | ||
match self { | ||
Operation::Reserved => &RESERVED, | ||
Operation::Request => &REQUEST, | ||
Operation::Reply => &REPLY, | ||
Operation::RequestReverse => &REQUEST_REVERSE, | ||
Operation::ReplyReverse => &REPLY_REVERSE, | ||
Operation::DrarpRequest => &DRARP_REQUEST, | ||
Operation::DrarpReply => &DRARP_REPLY, | ||
Operation::DrarpError => &DRARP_ERROR, | ||
Operation::InArpRequest => &IN_ARP_REQUEST, | ||
Operation::InArpReply => &IN_ARP_REPLY, | ||
Operation::ArpNak => &ARP_NAK, | ||
Operation::MarsRequest => &MARS_REQUEST, | ||
Operation::MarsMulti => &MARS_MULTI, | ||
Operation::MarsMServ => &MARS_MSERV, | ||
Operation::MarsJoin => &MARS_JOIN, | ||
Operation::MarsLeave => &MARS_LEAVE, | ||
Operation::MarsNAK => &MARS_NAK, | ||
Operation::MarsUnserv => &MARS_UNSERV, | ||
Operation::MarsSJoin => &MARS_SJOIN, | ||
Operation::MarsSLeave => &MARS_SLEAVE, | ||
Operation::MarsGroupListRequest => &MARS_GROUP_LIST_REQUEST, | ||
Operation::MarsGroupListReply => &MARS_GROUP_LIST_REPLY, | ||
Operation::MarsRedirectMap => &MARS_REDIRECT_MAP, | ||
Operation::MapoSUnarp => &MAPO_SUNARP, | ||
Operation::OpExp1 => &OP_EXP1, | ||
Operation::OpExp2 => &OP_EXP2, | ||
Operation::Other(x) => x, | ||
} | ||
} | ||
} | ||
|
||
impl From<u8> for Operation { | ||
fn from(value: u8) -> Self { | ||
match value { | ||
RESERVED => Operation::Reserved, | ||
REQUEST => Operation::Request, | ||
REPLY => Operation::Reply, | ||
REQUEST_REVERSE => Operation::RequestReverse, | ||
REPLY_REVERSE => Operation::ReplyReverse, | ||
DRARP_REQUEST => Operation::DrarpRequest, | ||
DRARP_REPLY => Operation::DrarpReply, | ||
DRARP_ERROR => Operation::DrarpError, | ||
IN_ARP_REQUEST => Operation::InArpRequest, | ||
IN_ARP_REPLY => Operation::InArpReply, | ||
ARP_NAK => Operation::ArpNak, | ||
MARS_REQUEST => Operation::MarsRequest, | ||
MARS_MULTI => Operation::MarsMulti, | ||
MARS_MSERV => Operation::MarsMServ, | ||
MARS_JOIN => Operation::MarsJoin, | ||
MARS_LEAVE => Operation::MarsLeave, | ||
MARS_NAK => Operation::MarsNAK, | ||
MARS_UNSERV => Operation::MarsUnserv, | ||
MARS_SJOIN => Operation::MarsSJoin, | ||
MARS_SLEAVE => Operation::MarsSLeave, | ||
MARS_GROUP_LIST_REQUEST => Operation::MarsGroupListRequest, | ||
MARS_GROUP_LIST_REPLY => Operation::MarsGroupListReply, | ||
MARS_REDIRECT_MAP => Operation::MarsRedirectMap, | ||
MAPO_SUNARP => Operation::MapoSUnarp, | ||
OP_EXP1 => Operation::OpExp1, | ||
OP_EXP2 => Operation::OpExp2, | ||
x => Operation::Other(x), | ||
} | ||
} | ||
} | ||
|
||
impl From<Operation> for u8 { | ||
fn from(value: Operation) -> Self { | ||
*value.as_ref() | ||
} | ||
} |
Oops, something went wrong.