pub mod deserialize;
pub mod serialize;
use byteorder::{ByteOrder, NetworkEndian};
use bypass_csv::IpProtocol;
use ipnetwork::Ipv4Network;
use std::fmt;
pub enum ProtocolEndpoint {
Src,
Dst,
}
impl OfpErrorMsg {
fn first_64_bytes(header: &[u8], body: &[u8]) -> Vec<u8> {
let mut buf = vec![];
buf.extend_from_slice(header);
let target_length = 64 - header.len();
let shrunk_body = if body.len() < target_length {
body
}
else {
&body[0..target_length]
};
buf.extend_from_slice(shrunk_body);
buf
}
pub fn new_hello_failed() -> OfpErrorMsg {
OfpErrorMsg {
typ: OfpErrorType::HelloFailed as u16,
code: OfpHelloFailedCode::Incompatible as u16,
data: vec![],
}
}
pub fn new_bad_request(code: OfpBadRequestCode, header: &[u8], body: &[u8]) -> OfpErrorMsg {
OfpErrorMsg {
typ: OfpErrorType::BadRequest as u16,
code: code as u16,
data: Self::first_64_bytes(header, body),
}
}
pub fn check_table_full(&self) -> bool {
self.typ == OfpErrorType::FlowModFailed as u16
&& self.code == OfpFlowModFailedCode::TableFull as u16
}
}
impl fmt::Display for OfpErrorMsg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let t = self.typ;
let typ = if t == OfpErrorType::HelloFailed as u16 {
OfpErrorType::HelloFailed
}
else if t == OfpErrorType::BadRequest as u16 {
OfpErrorType::BadRequest
}
else if t == OfpErrorType::BadAction as u16 {
OfpErrorType::BadAction
}
else if t == OfpErrorType::BadInstruction as u16 {
OfpErrorType::BadInstruction
}
else if t == OfpErrorType::BadMatch as u16 {
OfpErrorType::BadMatch
}
else if t == OfpErrorType::FlowModFailed as u16 {
OfpErrorType::FlowModFailed
}
else if t == OfpErrorType::Experimenter as u16 {
OfpErrorType::Experimenter
}
else {
return write!(f, "OpenFlow Error: type({}), code({})", self.typ, self.code);
};
write!(f, "OpenFlow Error: {:?}, code({})", typ, self.code)
}
}
impl OfpHeader {
pub fn version(&self) -> u8 {
self.version
}
pub fn typ(&self) -> u8 {
self.typ
}
pub fn xid(&self) -> u32 {
self.xid
}
}
impl OfpSwitchFeatures {
pub fn datapath_id(&self) -> u64 {
self.datapath_id
}
}
impl OfpEchoRequest {
pub fn arbitrary(self) -> Vec<u8> {
self.arbitrary
}
}
#[derive(Debug)]
pub struct OfpEchoRequest {
arbitrary: Vec<u8>,
}
#[derive(Debug)]
pub struct OfpEchoReply {
arbitrary: Vec<u8>,
}
#[derive(Debug, Clone)]
pub struct OfpOxmTlv {
class: OfpOxmClass,
field: OxmOfbMatchFields,
hasmask: bool,
body: Vec<u8>,
}
pub const OFP_VERSION: u8 = 0x04;
pub const OFPP_MAX: u32 = 0xffff_ff00;
pub const OFPP_ANY: u32 = 0xffff_ffff;
pub enum OfpType {
Hello = 0,
Error = 1,
EchoRequest = 2,
EchoReply = 3,
FeaturesRequest = 5,
FeaturesReply = 6,
PortStatus = 12,
FlowMod = 14,
SetAsync = 28,
}
#[derive(Debug, PartialEq)]
pub struct OfpHeader {
version: u8,
typ: u8,
length: u16,
xid: u32,
}
#[derive(Debug, PartialEq)]
pub struct OfpSwitchFeatures {
datapath_id: u64,
n_buffers: u32,
n_tables: u8,
auxiliary_id: u8,
pad: [u8; 2],
capabilities: u32,
reserved: u32,
}
pub enum OfpMatchType {
Oxm = 1,
}
#[derive(Debug, Clone, Default)]
pub struct OfpMatch {
typ: u16,
oxm_fields: Vec<OfpOxmTlv>,
}
impl OfpOxmTlv {
fn new(field: OxmOfbMatchFields, hasmask: bool, body: Vec<u8>) -> OfpOxmTlv {
OfpOxmTlv {
class: OfpOxmClass::OpenflowBasic,
hasmask,
field,
body,
}
}
pub fn new_in_port(in_port: u32) -> OfpOxmTlv {
let mut port_bytes = vec![0; 4];
NetworkEndian::write_u32(&mut port_bytes, in_port);
OfpOxmTlv::new(OxmOfbMatchFields::InPort, false, port_bytes)
}
pub fn new_eth_type_ipv4() -> OfpOxmTlv {
OfpOxmTlv::new(OxmOfbMatchFields::EthType, false, vec![8, 0])
}
pub fn new_ip_proto(proto: &IpProtocol) -> OfpOxmTlv {
OfpOxmTlv::new(OxmOfbMatchFields::IpProto, false, vec![*proto as u8])
}
pub fn new_ipv4(cidr: &Ipv4Network, endpoint: &ProtocolEndpoint) -> OfpOxmTlv {
let field = match *endpoint {
ProtocolEndpoint::Src => OxmOfbMatchFields::Ipv4Src,
ProtocolEndpoint::Dst => OxmOfbMatchFields::Ipv4Dst,
};
let mut oxm_val_and_mask = vec![];
oxm_val_and_mask.extend_from_slice(&cidr.network().octets());
oxm_val_and_mask.extend_from_slice(&cidr.mask().octets());
OfpOxmTlv::new(field, true, oxm_val_and_mask)
}
pub fn new_port(
proto: &IpProtocol,
port: u16,
endpoint: &ProtocolEndpoint,
) -> Option<OfpOxmTlv> {
let field = match *proto {
IpProtocol::Tcp => match *endpoint {
ProtocolEndpoint::Src => OxmOfbMatchFields::TcpSrc,
ProtocolEndpoint::Dst => OxmOfbMatchFields::TcpDst,
},
IpProtocol::Udp => match *endpoint {
ProtocolEndpoint::Src => OxmOfbMatchFields::UdpSrc,
ProtocolEndpoint::Dst => OxmOfbMatchFields::UdpDst,
},
_ => return None,
};
let mut port_bytes = vec![0; 2];
NetworkEndian::write_u16(&mut port_bytes, port);
Some(OfpOxmTlv::new(field, false, port_bytes))
}
}
#[derive(Debug, Clone, Copy)]
enum OfpOxmClass {
OpenflowBasic = 0x8000,
}
#[derive(Debug, Clone, Copy)]
enum OxmOfbMatchFields {
InPort = 0,
EthType = 5,
IpProto = 10,
Ipv4Src = 11,
Ipv4Dst = 12,
TcpSrc = 13,
TcpDst = 14,
UdpSrc = 15,
UdpDst = 16,
}
#[derive(Debug)]
pub enum OfpErrorType {
HelloFailed = 0,
BadRequest = 1,
BadAction = 2,
BadInstruction = 3,
BadMatch = 4,
FlowModFailed = 5,
Experimenter = 0xffff,
}
pub enum OfpHelloFailedCode {
Incompatible = 0,
}
#[derive(Debug)]
pub enum OfpBadRequestCode {
BadVersion = 0,
BadType = 1,
BadLen = 6,
}
pub enum OfpActionType {
Output = 0,
}
#[derive(Debug)]
pub struct OfpActionOutput {
typ: u16,
len: u16,
port: u32,
max_len: u16,
pad: [u8; 6],
}
pub enum OfpInstructionType {
ApplyActions = 4,
}
#[derive(Debug)]
pub struct OfpInstructionActions {
typ: u16,
pad: [u8; 4],
actions: Vec<OfpActionOutput>,
}
#[derive(Clone, Copy)]
pub enum OfpFlowModCommand {
Add = 0,
DeleteStrict = 4,
}
pub const OFP_FLOW_PERMANENT: u16 = 0;
pub const OFP_DEFAULT_PRIORITY: u16 = 0x8000;
#[derive(Debug)]
pub struct OfpFlowMod {
cookie: u64,
cookie_mask: u64,
table_id: u8,
command: u8,
idle_timeout: u16,
hard_timeout: u16,
priority: u16,
buffer_id: u32,
out_port: u32,
out_group: u32,
flags: u16,
pad: [u8; 2],
match_field: OfpMatch,
instructions: Vec<OfpInstructionActions>,
}
pub const OFP_NO_BUFFER: u32 = 0xffff_ffff;
pub enum OfpBadActionCode {
BadOutPort = 4,
}
#[derive(Debug)]
pub enum OfpFlowModFailedCode {
TableFull = 1,
}
#[derive(Debug)]
pub struct OfpErrorMsg {
typ: u16,
code: u16,
data: Vec<u8>,
}
#[derive(Default)]
pub struct OfpAsyncConfig {
packet_in_mask: [u32; 2],
port_status_mask: [u32; 2],
flow_removed_mask: [u32; 2],
}