Commit 36bf05c2 authored by Nawasan Wisitsingkhon's avatar Nawasan Wisitsingkhon

match fields marshal

parent b2b05232
use byteorder::WriteBytesExt;
pub struct MacAddr { pub struct MacAddr {
mac: [u8; 6], mac: [u8; 6],
} }
...@@ -8,6 +10,14 @@ impl MacAddr { ...@@ -8,6 +10,14 @@ impl MacAddr {
} }
} }
impl MacAddr {
pub fn marshal(&self, bytes: &mut Vec<u8>) {
for m in self.mac.iter() {
bytes.write_u8(*m);
}
}
}
impl From<MacAddr> for u64 { impl From<MacAddr> for u64 {
fn from(value: MacAddr) -> Self { fn from(value: MacAddr) -> Self {
let mut byte: u64 = 0; let mut byte: u64 = 0;
......
use std::{ use std::{
io::{BufRead, Cursor, Error}, io::Cursor,
net::{Ipv4Addr, Ipv6Addr}, net::{Ipv4Addr, Ipv6Addr},
}; };
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, WriteBytesExt};
use crate::etherparser::{ use crate::etherparser::MacAddr;
tools::bits::{bit_bool, bytes_to_mac, mac_to_bytes, set_bit},
MacAddr,
};
struct Wildcards {
pub in_port: bool,
pub mac_dest: bool,
pub mac_src: bool,
pub ethernet_type: bool,
pub vlan_vid: bool, /**
pub vlan_pcp: bool, * +---------- ----+- -------------+---------------------------+
* | Type | Length | OXM Fields |
* +----- ---------+--- -----------+---------------------------+
* | (Optional) | (16 bits) | (Array of variable length)|
* |---------------+---------------+---------------------------+
*/
pub ip_src: u32, pub struct OfpMatch {
pub ip_dest: u32, typ: MatchType,
pub protocol: bool, length: u16,
pub tos: bool, oxm_fields: Vec<u8>,
pub transport_src: bool,
pub transport_dest: bool,
} }
impl Wildcards { impl OfpMatch {
pub fn from_match_fields(match_fields: &MatchFields) -> Wildcards { pub fn new() -> Self {
Wildcards { Self {
in_port: match_fields.in_port.is_none(), typ: MatchType::OXM,
vlan_vid: match_fields.vlan_vid.is_none(), length: 4,
mac_src: match_fields.mac_src.is_none(), oxm_fields: Vec::new(),
mac_dest: match_fields.mac_dest.is_none(),
ethernet_type: match_fields.ethernet_type.is_none(),
protocol: match_fields.protocol.is_none(),
transport_src: match_fields.transport_src.is_none(),
transport_dest: match_fields.transport_dest.is_none(),
ip_src: Wildcards::mask_bits(&match_fields.ip_src),
ip_dest: Wildcards::mask_bits(&match_fields.ip_dest),
vlan_pcp: match_fields.vlan_pcp.is_none(),
tos: match_fields.tos.is_none(),
}
}
pub fn parse(byte: u32) -> Wildcards {
Wildcards {
in_port: bit_bool(0, byte),
vlan_vid: bit_bool(1, byte),
mac_src: bit_bool(2, byte),
mac_dest: bit_bool(3, byte),
ethernet_type: bit_bool(4, byte),
protocol: bit_bool(5, byte),
transport_src: bit_bool(6, byte),
transport_dest: bit_bool(7, byte),
ip_src: Wildcards::get_nw_mask(byte, 8),
ip_dest: Wildcards::get_nw_mask(byte, 14),
vlan_pcp: bit_bool(20, byte),
tos: bit_bool(21, byte),
} }
} }
pub fn marshal(&self, bytes: &mut Vec<u8>) { pub fn marshal(&self, bytes: &mut Vec<u8>) {
let mut match_field = 0u32; bytes.write_u16::<BigEndian>(self.typ.clone().into());
match_field = set_bit(match_field, 0, self.in_port); bytes.write_u16::<BigEndian>(self.length + (self.oxm_fields.len() as u16));
match_field = set_bit(match_field, 1, self.vlan_vid); bytes.append(&mut self.oxm_fields.clone());
match_field = set_bit(match_field, 2, self.mac_src);
match_field = set_bit(match_field, 3, self.mac_dest);
match_field = set_bit(match_field, 4, self.ethernet_type);
match_field = set_bit(match_field, 5, self.protocol);
match_field = set_bit(match_field, 6, self.transport_src);
match_field = set_bit(match_field, 7, self.transport_dest);
match_field = Wildcards::set_nw_mask(match_field, 8, self.ip_src);
match_field = Wildcards::set_nw_mask(match_field, 14, self.ip_dest);
match_field = set_bit(match_field, 20, self.vlan_pcp);
match_field = set_bit(match_field, 21, self.tos);
let _ = bytes.write_u32::<BigEndian>(match_field);
}
pub fn get_nw_mask(f: u32, offset: usize) -> u32 {
(f >> offset) & 0x3f
}
pub fn set_nw_mask(byte: u32, offset: usize, set: u32) -> u32 {
let value = (0x3f & set) << offset;
byte | value
}
pub fn mask_bits(mask: &Option<Mask<u32>>) -> u32 {
match mask {
None => 32,
Some(m) => match m.mask {
None => 0,
Some(m) => m,
},
}
} }
} }
pub struct OfpMatch { #[derive(Clone)]
typ: MatchType, #[repr(u16)]
length: u16,
oxm_fields: OxmClass,
}
pub enum MatchType { pub enum MatchType {
Standard = 0, Standard = 0,
OXM = 1, //, the OpenFlow 1.1 match type OFPMT_STANDARD is deprecated OXM = 1, //, the OpenFlow 1.1 match type OFPMT_STANDARD is deprecated
} }
impl From<MatchType> for u16 {
fn from(value: MatchType) -> Self {
value as u16
}
}
/** /**
* | class | field | length | - | body | *
* | :---: | :---: | :----: | - | :--: | * +----------------------------+----------------------------+
* | 16 | 7 | 1 | - | length bytes | * | OXM Header | OXM Body |
*/ * +----------------------------+----------------------------+
* | Version (1 byte) | Value (variable length) |
* | OXM Type (1 byte) | Mask (variable length) |
* | Length (2 bytes) | |
* | OXM ID (4 bytes) (Optional)| |
* +----------------------------+----------------------------+
*
*/
pub struct OxmFields<T> {
header: OxmHeader,
body: OxmBody<T>,
}
pub struct OxmHeader { pub struct OxmHeader {
class: OxmClass, // Match class: member class or reserved class class: OxmClass, // Match class: member class or reserved class
field: OxmMatchFields, // 7bit Match field within the class field: OxmMatchFields, // 7bit Match field within the class
hasmask: bool, // 1bit Set if OXM include a bitmask in payload hasmask: bool, // 1bit Set if OXM include a bitmask in payload
length: u8, // Length of OXM payload length: u8, // Length of OXM payload
experimenter: Option<u32>,
}
impl OxmHeader {
fn new(field: OxmMatchFields, size: u8) -> Self {
Self {
class: OxmClass::OpenflowBasic,
field,
hasmask: false,
length: 4 + size,
experimenter: None,
}
}
fn marshal(&self, bytes: &mut Vec<u8>) {
bytes.write_u16::<BigEndian>(self.class.clone().into());
let field: u8 = self.field.clone().into();
bytes.write_u8(field << 1 | if self.hasmask { 1 } else { 0 });
}
}
pub struct OxmBody<T> {
value: T,
mask: T,
} }
/** /**
...@@ -124,6 +103,7 @@ pub struct OxmHeader { ...@@ -124,6 +103,7 @@ pub struct OxmHeader {
* and 0x0001 for fields implemented as an Open vSwitch extension * and 0x0001 for fields implemented as an Open vSwitch extension
*/ */
#[derive(Clone)]
#[repr(u16)] #[repr(u16)]
pub enum OxmClass { pub enum OxmClass {
Nxm0 = 0x0000, // Backward compatibility with NXM Nxm0 = 0x0000, // Backward compatibility with NXM
...@@ -132,6 +112,14 @@ pub enum OxmClass { ...@@ -132,6 +112,14 @@ pub enum OxmClass {
Experimenter = 0xffff, // Experimenter class Experimenter = 0xffff, // Experimenter class
} }
impl From<OxmClass> for u16 {
fn from(value: OxmClass) -> Self {
value as u16
}
}
#[derive(Clone)]
#[repr(u8)]
/* OXM Flow match field types for OpenFlow basic class. */ /* OXM Flow match field types for OpenFlow basic class. */
pub enum OxmMatchFields { pub enum OxmMatchFields {
InPort = 1, InPort = 1,
...@@ -182,6 +170,12 @@ pub enum OxmMatchFields { ...@@ -182,6 +170,12 @@ pub enum OxmMatchFields {
ActsetOutput = 43, // Output port from action set metadata ActsetOutput = 43, // Output port from action set metadata
} }
impl From<OxmMatchFields> for u8 {
fn from(value: OxmMatchFields) -> Self {
value as u8
}
}
// Required match fields. // Required match fields.
pub struct MatchFields { pub struct MatchFields {
in_port: Option<u32>, // Ingress port. This may be a physical or switch-defined logical port. in_port: Option<u32>, // Ingress port. This may be a physical or switch-defined logical port.
...@@ -218,174 +212,70 @@ impl MatchFields { ...@@ -218,174 +212,70 @@ impl MatchFields {
} }
} }
pub fn marshal(&self, bytes: &mut Vec<u8>) { pub fn marshal(&self, bytes: &mut Vec<u8>) {
let wildcard = Wildcards::from_match_fields(self); let mut ofp_match = OfpMatch::new();
wildcard.marshal(bytes); let ofp_byte = ofp_match.oxm_fields.as_mut();
let _ = bytes.write_u16::<BigEndian>(match self.in_port {
Some(p) => p, if let Some(in_port) = &self.in_port {
None => 0, let header = OxmHeader::new(OxmMatchFields::InPort, 4);
}); header.marshal(ofp_byte);
let mac_src = match self.mac_src { ofp_byte.write_u32::<BigEndian>(*in_port);
Some(mac) => bytes_to_mac(mac),
None => bytes_to_mac(0),
};
for m in mac_src {
let _ = bytes.write_u8(m);
} }
let mac_dest = match self.mac_dest { if let Some(eth_dst) = &self.eth_dst {
Some(mac) => bytes_to_mac(mac), let header = OxmHeader::new(OxmMatchFields::MacDest, 6);
None => bytes_to_mac(0), header.marshal(ofp_byte);
}; eth_dst.marshal(ofp_byte);
for m in mac_dest {
let _ = bytes.write_u8(m);
} }
let vlan = match self.vlan_vid { if let Some(eth_src) = &self.eth_src {
Some(v) => v, let header = OxmHeader::new(OxmMatchFields::MacSrc, 6);
None => 0xffff, header.marshal(ofp_byte);
}; eth_src.marshal(ofp_byte);
let _ = bytes.write_u16::<BigEndian>(vlan); }
let _ = bytes.write_u8(match self.vlan_pcp { if let Some(eth_typ) = &self.eth_typ {
Some(v) => v, OxmHeader::new(OxmMatchFields::EthernetType, 2).marshal(ofp_byte);
None => 0, ofp_byte.write_u16::<BigEndian>(*eth_typ);
}); }
let _ = bytes.write_u8(0); if let Some(ip_proto) = &self.ip_proto {
let _ = bytes.write_u16::<BigEndian>(match self.ethernet_type { OxmHeader::new(OxmMatchFields::Protocol, 1);
Some(v) => v, ofp_byte.write_u8(*ip_proto);
None => 0, }
}); if let Some(ipv4_src) = &self.ipv4_src {
let _ = bytes.write_u8(match self.tos { OxmHeader::new(OxmMatchFields::IpSrc, 4).marshal(ofp_byte);
Some(v) => v, bytes.write_u32::<BigEndian>(ipv4_src.clone().into());
None => 0, }
}); if let Some(ipv4_dst) = &self.ipv4_dst {
let _ = bytes.write_u8(match self.protocol { OxmHeader::new(OxmMatchFields::IpDst, 4).marshal(ofp_byte);
Some(v) => v, bytes.write_u32::<BigEndian>(ipv4_dst.clone().into());
None => 0, }
}); if let Some(ipv6_src) = &self.ipv6_src {
let _ = bytes.write_u16::<BigEndian>(0); OxmHeader::new(OxmMatchFields::Ipv6Src, 16);
ofp_byte.write_u128::<BigEndian>(ipv6_src.clone().into());
let _ = bytes.write_u32::<BigEndian>(match &self.ip_src { }
Some(ip) => ip.ip, if let Some(ipv6_dst) = &self.ipv6_dst {
None => 0, OxmHeader::new(OxmMatchFields::Ipv6Dst, 16);
}); ofp_byte.write_u128::<BigEndian>(ipv6_dst.clone().into());
let _ = bytes.write_u32::<BigEndian>(match &self.ip_dest { }
Some(ip) => ip.ip, if let Some(tcp_src) = &self.tcp_src {
None => 0, OxmHeader::new(OxmMatchFields::TcpSrc, 2);
}); ofp_byte.write_u16::<BigEndian>(*tcp_src);
let _ = bytes.write_u16::<BigEndian>(match self.transport_src { }
Some(v) => v, if let Some(tcp_dst) = &self.tcp_dst {
None => 0, OxmHeader::new(OxmMatchFields::TcpDst, 2);
}); ofp_byte.write_u16::<BigEndian>(*tcp_dst);
let _ = bytes.write_u16::<BigEndian>(match self.transport_dest { }
Some(v) => v, if let Some(udp_src) = &self.udp_src {
None => 0, OxmHeader::new(OxmMatchFields::UdpSrc, 2);
}); ofp_byte.write_u16::<BigEndian>(*udp_src);
}
if let Some(udp_dst) = &self.udp_dst {
OxmHeader::new(OxmMatchFields::UdpDst, 2);
ofp_byte.write_u16::<BigEndian>(*udp_dst);
}
ofp_match.marshal(bytes);
} }
pub fn parse(bytes: &mut Cursor<Vec<u8>>) -> Result<MatchFields, Error> { // pub fn parse(bytes: &mut Cursor<Vec<u8>>) {
let wildcards = Wildcards::parse(bytes.read_u32::<BigEndian>()?); /*
let in_port = if wildcards.in_port { * TODO Soon
None */
} else { // }
Some(bytes.read_u16::<BigEndian>()?)
};
let mac_src = if wildcards.mac_src {
None
} else {
let mut arr: [u8; 6] = [0; 6];
for i in 0..6 {
arr[i] = bytes.read_u8()?;
}
Some(mac_to_bytes(arr))
};
let mac_dest = if wildcards.mac_dest {
None
} else {
let mut arr: [u8; 6] = [0; 6];
for i in 0..6 {
arr[i] = bytes.read_u8()?;
}
Some(mac_to_bytes(arr))
};
let vlan_vid = if wildcards.vlan_vid {
None
} else {
let vid = bytes.read_u16::<BigEndian>()?;
if vid == 0xfff {
None
} else {
Some(bytes.read_u16::<BigEndian>()?)
}
};
let vlan_pcp = if wildcards.vlan_pcp {
None
} else {
Some(bytes.read_u8()?)
};
bytes.consume(1);
let ethernet_type = if wildcards.ethernet_type {
None
} else {
Some(bytes.read_u16::<BigEndian>()?)
};
let tos = if wildcards.tos {
None
} else {
Some(bytes.read_u8()?)
};
let protocol = if wildcards.protocol {
None
} else {
Some(bytes.read_u8()?)
};
bytes.consume(2);
let ip_src = if wildcards.ip_src >= 32 {
None
} else if wildcards.ip_src == 0 {
Some(Mask {
ip: bytes.read_u32::<BigEndian>()?,
mask: None,
})
} else {
Some(Mask {
ip: bytes.read_u32::<BigEndian>()?,
mask: Some(wildcards.ip_src),
})
};
let ip_dest = if wildcards.ip_dest >= 32 {
None
} else if wildcards.ip_dest == 0 {
Some(Mask {
ip: bytes.read_u32::<BigEndian>()?,
mask: None,
})
} else {
Some(Mask {
ip: bytes.read_u32::<BigEndian>()?,
mask: Some(wildcards.ip_dest),
})
};
let transport_src = if wildcards.transport_src {
None
} else {
Some(bytes.read_u16::<BigEndian>()?)
};
let transport_dest = if wildcards.transport_dest {
None
} else {
Some(bytes.read_u16::<BigEndian>()?)
};
Ok(MatchFields {
in_port,
mac_src,
mac_dest,
ethernet_type,
vlan_vid,
vlan_pcp,
ip_src,
ip_dest,
protocol,
tos,
transport_src,
transport_dest,
})
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment