Commit b9221574 authored by Nawasan Wisitsingkhon's avatar Nawasan Wisitsingkhon

Merge 'origin/feature/ofp13'

parents cb082850 dbafd143
pub mod ether_type; pub mod ether_type;
pub mod ethernet; pub mod ethernet;
pub mod packet; pub mod packet;
pub mod tools; pub mod tools;
pub mod net;
pub use net::MacAddr;
use byteorder::WriteBytesExt;
#[derive(Clone)]
pub struct MacAddr {
mac: [u8; 6],
}
impl MacAddr {
pub fn new(mac: [u8; 6]) -> Self {
Self { mac }
}
}
impl MacAddr {
pub fn marshal(&self, bytes: &mut Vec<u8>) {
for i in 0..6 {
let _ = bytes.write_u8(match self.mac.get(5 - i) {
Some(v) => *v,
None => 0,
});
}
}
}
impl From<MacAddr> for u64 {
fn from(value: MacAddr) -> Self {
let mut byte: u64 = 0;
for i in 0..6 {
// byte = byte << 8;
byte += (value.mac[i] as u64) << i * 8;
}
byte
}
}
impl From<u64> for MacAddr {
fn from(value: u64) -> Self {
let mut mac = [0u8; 6];
for i in 0..6 {
mac[i] = (value >> (i * 8)) as u8;
}
Self { mac }
}
}
impl From<&str> for MacAddr {
fn from(value: &str) -> Self {
let mac_vec = value
.split(":")
.map(|x| match u8::from_str_radix(x, 16) {
Ok(v) => v,
Err(_) => 0,
})
.collect::<Vec<u8>>();
let mut mac = [0u8; 6];
for i in 0..6 {
mac[i] = mac_vec[i];
}
Self { mac }
}
}
pub mod mac_address;
pub use mac_address::MacAddr;
\ No newline at end of file
...@@ -16,11 +16,12 @@ use crate::{ ...@@ -16,11 +16,12 @@ use crate::{
* In production please remove allow unused. * In production please remove allow unused.
*/ */
pub struct Controller { #[derive(Clone)]
pub struct Controller10 {
mac_to_port: HashMap<u64, u16>, mac_to_port: HashMap<u64, u16>,
} }
impl ControllerFrame10 for Controller { impl ControllerFrame10 for Controller10 {
fn new() -> Self { fn new() -> Self {
Self { Self {
mac_to_port: HashMap::new(), mac_to_port: HashMap::new(),
...@@ -76,7 +77,7 @@ impl ControllerFrame10 for Controller { ...@@ -76,7 +77,7 @@ impl ControllerFrame10 for Controller {
} }
} }
impl Controller { impl Controller10 {
fn add_flow( fn add_flow(
&self, &self,
xid: u32, xid: u32,
......
#![allow(unused)]
#![allow(unused_variables)]
use std::{collections::HashMap, net::TcpStream};
use crate::{
etherparser::{ether_type::EtherType, MacAddr},
openflow::ofp13::{
self,
events::{flow_mod::MatchFields, Action},
ofp_manager::Openflow13,
ControllerFrame13, FlowModEvent, OfpMsgEvent, PacketInEvent,
},
};
/**
* Here is Controller you can modify and write the process or more you need.
* In production please remove allow unused.
*/
#[derive(Clone)]
pub struct Controller13 {
mac_to_port: HashMap<u64, u32>,
}
impl ControllerFrame13 for Controller13 {
fn new() -> Self {
Self {
mac_to_port: HashMap::new(),
}
}
/**
* Start here for handle packetIn message.
*/
fn switch_features_handler(
&self,
xid: u32,
features_reply: ofp13::FeaturesReplyEvent,
stream: &mut TcpStream,
) {
let matchs = MatchFields::match_all();
let actions = vec![Action::Oputput(ofp13::PseudoPort::Controller(!0))];
self.add_flow(xid, 0, matchs, &actions, 0, None, stream)
}
fn packet_in_handler(&mut self, xid: u32, packetin: PacketInEvent, stream: &mut TcpStream) {
let pkt = match packetin.ether_parse() {
Ok(pkt) => pkt,
Err(_) => return,
};
let in_port = match packetin.matchs.in_port {
Some(p) => p,
None => return,
};
println!(
"packet in {} {} {}",
pkt.mac_src_string(),
pkt.mac_dst_string(),
in_port
);
self.mac_to_port.insert(pkt.mac_src, in_port);
let mac_dst = pkt.mac_dst;
let mac_src = pkt.mac_src;
if let EtherType::LLDP = pkt.ether_type {
return;
}
let out_port = match self.mac_to_port.get(&mac_dst) {
Some(p) => ofp13::PseudoPort::PhysicalPort(*p),
None => ofp13::PseudoPort::Flood,
};
let actions = vec![Action::Oputput(out_port.clone())];
if let ofp13::PseudoPort::PhysicalPort(_) = out_port {
let mut match_fields = MatchFields::match_all();
match_fields.in_port = Some(in_port);
match_fields.eth_dst = Some(MacAddr::from(mac_dst));
match_fields.eth_src = Some(MacAddr::from(mac_src));
if let Some(buf_id) = packetin.buf_id {
self.add_flow(
xid,
1,
match_fields,
&actions,
packetin.table_id,
Some(buf_id as u32),
stream,
);
return;
} else {
self.add_flow(
xid,
1,
match_fields,
&actions,
packetin.table_id,
None,
stream,
);
}
}
let packet_out = self
.ofp()
.packet_out(Some(in_port), packetin.payload, actions);
self.send_msg(packet_out, xid, stream);
}
}
impl Controller13 {
fn add_flow(
&self,
xid: u32,
priority: u16,
flow: MatchFields,
actions: &Vec<Action>,
table_id: u8,
buffer_id: Option<u32>,
stream: &mut TcpStream,
) {
self.send_msg(
FlowModEvent::add_flow(priority, flow, actions.clone(), table_id, buffer_id),
xid,
stream,
)
}
}
pub mod ctrl13;
pub use ctrl13::Controller13;
pub mod ctrl10;
pub use ctrl10::Controller10;
\ No newline at end of file
...@@ -2,5 +2,4 @@ pub mod openflow; ...@@ -2,5 +2,4 @@ pub mod openflow;
pub mod etherparser; pub mod etherparser;
pub mod controller; pub mod example;
pub use controller::Controller; \ No newline at end of file
\ No newline at end of file
use tenjin::{openflow::ofp10::ControllerFrame10, Controller}; use tenjin::{example, openflow::ofp13::ControllerFrame13};
extern crate byteorder; extern crate byteorder;
fn main() -> Result<(), std::io::Error> { fn main() -> Result<(), std::io::Error> {
Controller::listener("127.0.0.1:6633"); let controller = example::Controller13::new();
controller.listener("127.0.0.1:6633");
Ok(()) Ok(())
} }
pub mod ofp10; pub mod ofp10;
pub mod ofp13;
\ No newline at end of file
...@@ -9,15 +9,24 @@ use super::{ ...@@ -9,15 +9,24 @@ use super::{
tcp_listener_handler, MessageMarshal, OfpMsgEvent, Openflow10, OpenflowHeader, tcp_listener_handler, MessageMarshal, OfpMsgEvent, Openflow10, OpenflowHeader,
}; };
pub trait ControllerFrame10 { pub trait ControllerFrame10
where
Self: 'static,
{
fn ofp(&self) -> ofp10::Openflow10 { fn ofp(&self) -> ofp10::Openflow10 {
Openflow10::new() Openflow10::new()
} }
fn packet_in_handler(&mut self, xid: u32, packetin: PacketInEvent, stream: &mut TcpStream); fn packet_in_handler(&mut self, xid: u32, packetin: PacketInEvent, stream: &mut TcpStream);
fn new() -> Self; fn new() -> Self;
fn listener(address: &str) { fn listener(&self, address: &str)
let _ = tcp_listener_handler(address); where
Self: Sized,
Self: Send,
Self: Clone,
{
println!("server run at {}", address);
let _ = tcp_listener_handler(address, self.clone());
} }
fn handle_header(&mut self, buf: &mut Vec<u8>) -> Option<(u8, usize, u32)> { fn handle_header(&mut self, buf: &mut Vec<u8>) -> Option<(u8, usize, u32)> {
......
use crate::Controller;
use std::{io::Read, net::TcpListener, thread}; use std::{io::Read, net::TcpListener, thread};
use crate::openflow::ofp10::HelloEvent; use crate::openflow::ofp10::HelloEvent;
use super::{ControllerFrame10, OfpMsgEvent}; use super::{ControllerFrame10, OfpMsgEvent};
pub fn tcp_listener_handler(address: &str) -> Result<(), std::io::Error> { pub fn tcp_listener_handler(
address: &str,
controller: impl ControllerFrame10 + Send + 'static + Clone,
) -> Result<(), std::io::Error> {
let listener = TcpListener::bind(address)?; let listener = TcpListener::bind(address)?;
for stream in listener.incoming() { for stream in listener.incoming() {
match stream { match stream {
Ok(mut stream) => { Ok(mut stream) => {
if let Ok(addr) = stream.local_addr() { if let Ok(addr) = stream.peer_addr() {
println!("server has connection from {}", addr); println!("server has connection from {}", addr);
} }
let mut ctrl = controller.clone();
thread::spawn(move || { thread::spawn(move || {
let mut ctrl = Controller::new();
ctrl.send_msg(HelloEvent::new(), 0, &mut stream); ctrl.send_msg(HelloEvent::new(), 0, &mut stream);
let ofp_size = ctrl.ofp().header_size(); let ofp_size = ctrl.ofp().header_size();
let mut buffer = vec![0u8; ofp_size]; let mut buffer = vec![0u8; ofp_size];
......
use crate::openflow::ofp13::{ErrorEvent, Msg, PacketInEvent};
use std::{
io::{Read, Write},
net::TcpStream,
};
use super::{
events::{echo_reply::EchoReplyEvent, EchoRequestEvent},
tcp_listener_handler, FeaturesReplyEvent, MessageMarshal, OfpMsgEvent, Openflow13,
OpenflowHeader,
};
pub trait ControllerFrame13
where
Self: 'static,
{
fn ofp(&self) -> Openflow13 {
Openflow13::new()
}
fn packet_in_handler(&mut self, xid: u32, packetin: PacketInEvent, stream: &mut TcpStream);
fn new() -> Self;
fn listener(&self, address: &str)
where
Self: Sized,
Self: Send,
Self: Clone,
{
println!("server run at {}", address);
let _ = tcp_listener_handler(address, self.clone());
}
fn handle_header(&mut self, buf: &mut Vec<u8>) -> Option<(u8, usize, u32)> {
let ofp_header = self.ofp().header_parse(&buf);
match ofp_header {
Ok(header) => Some((header.message(), header.pkt_size(), header.xid())),
Err(_) => None,
}
}
fn request_handler(&mut self, buf: &mut Vec<u8>, stream: &mut TcpStream) {
let ofp = self.ofp();
let (message, pkt_size, xid) = match self.handle_header(buf) {
Some(header) => header,
None => return,
};
let mut payload = vec![0u8; pkt_size];
let _ = stream.read(&mut payload);
let message = ofp.msg_parse(message as u8);
match message {
Msg::Hello => self.hello_handler(xid, stream),
Msg::Error => match ErrorEvent::parse(&payload) {
Ok(error) => self.error_handler(error),
Err(_) => (),
},
Msg::EchoRequest => {
self.echo_request_handler(xid, EchoRequestEvent::new(payload), stream)
}
Msg::FeaturesReply => match FeaturesReplyEvent::parse(&payload) {
Ok(features) => self.switch_features_handler(xid, features, stream),
Err(_) => (),
},
Msg::PacketIn => match PacketInEvent::parse(&payload) {
Ok(pkt_in) => self.packet_in_handler(xid, pkt_in, stream),
Err(_) => (),
},
_ => (),
}
}
fn send_msg<MSM: MessageMarshal>(&self, msg: MSM, xid: u32, stream: &mut TcpStream) {
let ofp = self.ofp();
let mut header_bytes: Vec<u8> = Vec::new();
let mut body_bytes: Vec<u8> = Vec::new();
msg.marshal(&mut body_bytes);
let ofp_header = ofp.header(msg.msg_usize() as u8, body_bytes.len() as u16, xid);
ofp_header.marshal(&mut header_bytes);
header_bytes.append(&mut body_bytes);
let _ = stream.write_all(&header_bytes);
}
/**
* for handle message
*/
fn hello_handler(&self, xid: u32, stream: &mut TcpStream) {
self.send_msg(self.ofp().fetures_req(), xid, stream);
}
fn error_handler(&self, error: ErrorEvent) {
println!("Error {:?} payload: {:x?}", error.error_type, error.payload);
}
fn echo_request_handler(&self, xid: u32, echo: EchoRequestEvent, stream: &mut TcpStream) {
self.send_msg(EchoReplyEvent::new(echo.payload), xid, stream);
}
#[allow(unused)]
fn switch_features_handler(
&self,
xid: u32,
features_reply: FeaturesReplyEvent,
stream: &mut TcpStream,
) {
}
}
use crate::{etherparser::MacAddr, openflow::ofp13::PseudoPort};
use byteorder::{BigEndian, WriteBytesExt};
use std::{
io::Error,
net::{Ipv4Addr, Ipv6Addr},
};
use super::flow_mod::{
instructions::InstructActions,
match_fields::{OxmHeader, OxmMatchFields},
};
#[derive(Clone)]
#[repr(u16)]
enum ActionType {
Output = 0, // Output to switch port.
CopyTtlOut = 11, // Copy TTL "outwards" -- from next-to-outermost to outermost
CopyTtlIn = 12, // Copy TTL "inwards" -- from outermost to next-to-outermost
SetMplsTtl = 15, // MPLS TTL
DecMplsTtl = 16, // Decrement MPLS TTL
PushVlan = 17, // Push a new VLAN tag
PopVlan = 18, // Pop the outer VLAN tag
PushMpls = 19, // Push a new MPLS tag
PopMpls = 20, // Pop the outer MPLS tag
SetQueue = 21, // Set queue id when outputting to a port
Group = 22, // Apply group.
SetNwTtl = 23, // IP TTL.
DecNwTtl = 24, // Decrement IP TTL.
SetField = 25, // Set a header field using OXM TLV format.
PushPbb = 26, // Push a new PBB service tag (I-TAG)
PopPbb = 27, // Pop the outer PBB service tag (I-TAG)
Experimenter = 0xffff,
}
impl ActionType {
pub fn marshal(&self, bytes: &mut Vec<u8>) -> Result<(), Error> {
bytes.write_u16::<BigEndian>(self.clone().into())?;
Ok(())
}
}
impl From<ActionType> for u16 {
fn from(value: ActionType) -> Self {
value as u16
}
}
#[allow(unused)]
#[derive(Clone)]
#[repr(u16)]
enum ControllerMaxLen {
Max = 0xffe5,
NoBuffer = 0xffff,
}
impl From<ControllerMaxLen> for u16 {
fn from(value: ControllerMaxLen) -> Self {
value as u16
}
}
#[derive(Clone)]
pub enum SetField {
InPort(PseudoPort), // Ingress port. This may be a physical or switch-defined logical port.
EthDst(MacAddr), // Ethernet source address. Can use arbitrary bitmask
EthSrc(MacAddr), // Ethernet destination address. Can use arbitrary bitmask
EthTyp(u16), // Ethernet type of the OpenFlow packet payload, after VLAN tags.
IpProto(u8), // IPv4 or IPv6 protocol number
Ipv4Src(Ipv4Addr), // IPv4 source address. Can use subnet mask or arbitrary bitmask
Ipv4Dst(Ipv4Addr), // IPv4 destination address. Can use subnet mask or arbitrary bitmask
Ipv6Src(Ipv6Addr), // IPv6 source address. Can use subnet mask or arbitrary bitmask
Ipv6Dst(Ipv6Addr), // IPv6 destination address. Can use subnet mask or arbitrary bitmask
TcpSrc(u16), // TCP source port
TcpDst(u16), // TCP destination port
UdpSrc(u16), // UDP source port
UdpDst(u16), // UDP destination port
}
impl SetField {
pub fn marshal(&self, bytes: &mut Vec<u8>) -> Result<(), Error> {
match &self {
SetField::InPort(port) => {
OxmHeader::new(OxmMatchFields::InPort, 4, false).marshal(bytes)?;
port.marshal(bytes);
}
SetField::EthDst(mac) => {
OxmHeader::new(OxmMatchFields::EthDst, 12, true).marshal(bytes)?;
mac.marshal(bytes);
MacAddr::from(!0).marshal(bytes);
}
SetField::EthSrc(mac) => {
OxmHeader::new(OxmMatchFields::EthSrc, 12, true).marshal(bytes)?;
mac.marshal(bytes);
MacAddr::from(!0).marshal(bytes);
}
SetField::EthTyp(eth) => {
OxmHeader::new(OxmMatchFields::EthType, 2, false).marshal(bytes)?;
bytes.write_u16::<BigEndian>(*eth)?;
}
SetField::IpProto(proto) => {
OxmHeader::new(OxmMatchFields::IpProto, 1, false).marshal(bytes)?;
bytes.write_u8(*proto)?;
}
SetField::Ipv4Src(ipv4) => {
OxmHeader::new(OxmMatchFields::Ipv4Src, 8, true).marshal(bytes)?;
bytes.write_u32::<BigEndian>(ipv4.clone().into())?;
bytes.write_u32::<BigEndian>(!0)?;
}
SetField::Ipv4Dst(ipv4) => {
OxmHeader::new(OxmMatchFields::Ipv4Dst, 8, true).marshal(bytes)?;
bytes.write_u32::<BigEndian>(ipv4.clone().into())?;
bytes.write_u32::<BigEndian>(!0)?;
}
SetField::Ipv6Src(ipv6) => {
OxmHeader::new(OxmMatchFields::Ipv6Src, 32, true).marshal(bytes)?;
bytes.write_u128::<BigEndian>(ipv6.clone().into())?;
bytes.write_u128::<BigEndian>(!0)?;
}
SetField::Ipv6Dst(ipv6) => {
OxmHeader::new(OxmMatchFields::Ipv6Dst, 32, true).marshal(bytes)?;
bytes.write_u128::<BigEndian>(ipv6.clone().into())?;
bytes.write_u128::<BigEndian>(!0)?;
}
SetField::TcpSrc(tcp) => {
OxmHeader::new(OxmMatchFields::TcpSrc, 2, false).marshal(bytes)?;
bytes.write_u16::<BigEndian>(*tcp)?;
}
SetField::TcpDst(tcp) => {
OxmHeader::new(OxmMatchFields::TcpDst, 2, false).marshal(bytes)?;
bytes.write_u16::<BigEndian>(*tcp)?;
}
SetField::UdpSrc(udp) => {
OxmHeader::new(OxmMatchFields::UdpSrc, 2, false).marshal(bytes)?;
bytes.write_u16::<BigEndian>(*udp)?;
}
SetField::UdpDst(udp) => {
OxmHeader::new(OxmMatchFields::UdpDst, 2, false).marshal(bytes)?;
bytes.write_u16::<BigEndian>(*udp)?;
}
}
Ok(())
}
}
pub type Buffer = u16;
#[derive(Clone)]
#[repr(u8)]
pub enum Action {
Oputput(PseudoPort),
CopyTtlOut, // Copy TTL "outwards" -- from next-to-outermost to outermost
CopyTtlIn, // Copy TTL "inwards" -- from outermost to next-to-outermost
SetMplsTtl(u8), // MPLS TTL
DecMplsTtl, // Decrement MPLS TTL
PushVlan(u16),
PushMpls(u16),
PushPbb(u16),
PopVlan(u16),
PopMpls(u16),
PopPbb(u16),
SetQueue(u32), // Set queue id when outputting to a port
Group(u32), // Apply group.
SetNwTtl(u8), // IP TTL.
DecNwTtl = 24, // Decrement IP TTL.
SetField(SetField), // Set a header field using OXM TLV format.
Experimenter(u32),
}
impl Action {
fn action_type(&self) -> ActionType {
match &self {
Action::Oputput(_) => ActionType::Output,
Action::CopyTtlOut => ActionType::CopyTtlOut,
Action::CopyTtlIn => ActionType::CopyTtlIn,
Action::SetMplsTtl(_) => ActionType::SetMplsTtl,
Action::DecMplsTtl => ActionType::DecMplsTtl,
Action::PushVlan(_) => ActionType::PushVlan,
Action::PushMpls(_) => ActionType::PushMpls,
Action::PushPbb(_) => ActionType::PushPbb,
Action::PopVlan(_) => ActionType::PopVlan,
Action::PopMpls(_) => ActionType::PopMpls,
Action::PopPbb(_) => ActionType::PopPbb,
Action::SetQueue(_) => ActionType::SetQueue,
Action::Group(_) => ActionType::Group,
Action::SetNwTtl(_) => ActionType::SetNwTtl,
Action::DecNwTtl => ActionType::DecNwTtl,
Action::SetField(_) => ActionType::SetField,
Action::Experimenter(_) => ActionType::Experimenter,
}
}
pub fn marshal(&self, bytes: &mut Vec<u8>) -> Result<(), Error> {
match &self {
Action::Oputput(port) => {
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(16)?; // len
port.marshal(bytes);
bytes.write_u16::<BigEndian>(ControllerMaxLen::NoBuffer.into())?;
// padding 48bit
bytes.write_u32::<BigEndian>(0)?;
bytes.write_u16::<BigEndian>(0)?;
}
Action::SetMplsTtl(mpls_ttl) => {
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(8)?;
bytes.write_u8(*mpls_ttl)?;
// padding 24bit
bytes.write_u16::<BigEndian>(0)?;
bytes.write_u8(0)?;
}
Action::PushVlan(ethertype)
| Action::PushMpls(ethertype)
| Action::PushPbb(ethertype) => {
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(8)?;
bytes.write_u16::<BigEndian>(*ethertype)?;
// padding 16 bit
bytes.write_u16::<BigEndian>(0)?;
}
Action::PopVlan(ethertype) | Action::PopMpls(ethertype) | Action::PopPbb(ethertype) => {
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(8)?;
bytes.write_u16::<BigEndian>(*ethertype)?;
bytes.write_u16::<BigEndian>(0)?;
}
Action::SetQueue(queue_id) => {
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(8)?;
bytes.write_u32::<BigEndian>(*queue_id)?;
}
Action::Group(group_id) => {
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(8)?;
bytes.write_u32::<BigEndian>(*group_id)?;
}
Action::SetNwTtl(nw_ttl) => {
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(8)?;
bytes.write_u8(*nw_ttl)?;
// padding 24bit
bytes.write_u16::<BigEndian>(0)?;
bytes.write_u8(0)?;
}
Action::SetField(omx_field) => {
let mut field_bytes: Vec<u8> = Vec::new();
omx_field.marshal(&mut field_bytes)?;
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(4 + field_bytes.len() as u16)?;
bytes.append(&mut field_bytes);
}
Action::Experimenter(exper_id) => {
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(8)?;
bytes.write_u32::<BigEndian>(*exper_id)?;
}
Action::DecMplsTtl | Action::DecNwTtl | Action::CopyTtlOut | Action::CopyTtlIn => {
self.action_type().marshal(bytes)?;
bytes.write_u16::<BigEndian>(8)?;
// padding 32 bit
bytes.write_u32::<BigEndian>(0)?;
}
}
Ok(())
}
// TODO
// pub fn parse_sequence(bytes: &mut Cursor<Vec<u8>>) -> Vec<Action> {
// if bytes.get_ref().is_empty() {
// vec![]
// } else {
// if let Ok(action) = Action::parse(bytes) {
// let mut v = vec![action];
// v.append(&mut Action::parse_sequence(bytes));
// v
// } else {
// vec![]
// }
// }
// }
// TODO
// pub fn parse(bytes: &mut Cursor<Vec<u8>>) -> Result<Action, Error> {
// }
}
pub trait ToInstruction {
fn to_instruct(&self) -> InstructActions;
}
impl ToInstruction for Vec<Action> {
fn to_instruct(&self) -> InstructActions {
let mut instruct = InstructActions::new(InstructActions::APPLY);
instruct.actions.append(&mut self.clone());
instruct
}
}
use std::io::Write;
use crate::openflow::ofp13::{self, MessageMarshal, Msg};
pub struct EchoReplyEvent {
pub payload: Vec<u8>,
}
impl EchoReplyEvent {
pub fn new(payload: Vec<u8>) -> Self {
Self { payload }
}
}
impl MessageMarshal for EchoReplyEvent {
fn marshal(&self, bytes: &mut Vec<u8>) {
let _ = bytes.write_all(&self.payload);
}
fn msg_code(&self) -> ofp13::Msg {
Msg::EchoReply
}
fn msg_usize(&self) -> usize {
Msg::EchoReply as usize
}
fn size_of(&self) -> usize {
self.payload.len()
}
}
use std::io::Write;
use crate::openflow::ofp13::{self, MessageMarshal, Msg};
pub struct EchoRequestEvent {
pub payload: Vec<u8>,
}
impl EchoRequestEvent {
pub fn new(payload: Vec<u8>) -> Self {
Self { payload }
}
}
impl MessageMarshal for EchoRequestEvent {
fn marshal(&self, bytes: &mut Vec<u8>) {
let _ = bytes.write_all(&self.payload);
}
fn msg_code(&self) -> ofp13::Msg {
Msg::EchoRequest
}
fn msg_usize(&self) -> usize {
Msg::EchoRequest as usize
}
fn size_of(&self) -> usize {
self.payload.len()
}
}
use std::{
io::{BufRead, Cursor, Error},
mem::size_of,
};
use super::error_type::ErrorType;
use crate::openflow::ofp13::{MessageMarshal, Msg};
use byteorder::{BigEndian, ReadBytesExt};
pub struct ErrorEvent {
pub error_type: ErrorType,
pub payload: Vec<u8>,
}
impl ErrorEvent {
pub fn new(error_type: ErrorType, payload: Vec<u8>) -> Self {
ErrorEvent {
error_type,
payload,
}
}
pub fn parse(buf: &Vec<u8>) -> Result<ErrorEvent, Error> {
let mut bytes = Cursor::new(buf);
let error_type = bytes.read_u16::<BigEndian>()?;
let error_code = bytes.read_u16::<BigEndian>()?;
let code = ErrorType::new(error_type, error_code);
let payload = bytes.fill_buf()?.to_vec();
Ok(ErrorEvent::new(code, payload))
}
}
impl MessageMarshal for ErrorEvent {
fn marshal(&self, _: &mut Vec<u8>) {}
fn msg_code(&self) -> Msg {
Msg::Error
}
fn msg_usize(&self) -> usize {
Msg::Error as usize
}
fn size_of(&self) -> usize {
size_of::<(u16, u16)>() + self.payload.len()
}
}
use std::mem::transmute;
#[repr(u16)]
#[derive(Debug)]
pub enum ErrorType {
HelloFailed(HelloFailed) = 0, /* Hello protocol failed. */
BadRequest(BadRequest) = 1, /* Request was not understood. */
BadAction(BadAction) = 2, /* Error in action description. */
BadInstruction(BadInstruction) = 3, /* Error in instruction list. */
BadMatch(BadMatch) = 4, /* Error in match. */
FlowModFailed(FlowModFailed) = 5, /* Problem modifying flow entry. */
GroupModFailed(GroupModFailed) = 6, /* Problem modifying group entry. */
PortModFailed(PortModFailed) = 7, /* Port mod request failed. */
TableModFailed(TableModFailed) = 8, /* Table mod request failed. */
QueueOpFailed(QueueOpFailed) = 9, /* Queue operation failed. */
SwitchConfigFailed(SwitchConfigFailed) = 10, /* Switch config request failed. */
RoleRequestFailed(RoleRequestFailed) = 11, /* Controller Role request failed. */
MeterModFailed(MeterModFailed) = 12, /* Error in meter. */
TableFeaturesFailed(TableFeaturesFailed) = 13, /* Setting table features failed. */
EXPERIMENTER = 0xffff, /* Experimenter error messages. */
}
impl ErrorType {
pub fn new(error_type: u16, error_code: u16) -> ErrorType {
match error_type {
0 => Self::HelloFailed(HelloFailed::new(error_code)),
1 => Self::BadRequest(BadRequest::new(error_code)),
2 => Self::BadAction(BadAction::new(error_code)),
3 => Self::BadInstruction(BadInstruction::new(error_code)),
4 => Self::BadMatch(BadMatch::new(error_code)),
5 => Self::FlowModFailed(FlowModFailed::new(error_code)),
6 => Self::GroupModFailed(GroupModFailed::new(error_code)),
7 => Self::PortModFailed(PortModFailed::new(error_code)),
8 => Self::TableModFailed(TableModFailed::new(error_code)),
9 => Self::QueueOpFailed(QueueOpFailed::new(error_code)),
10 => Self::SwitchConfigFailed(SwitchConfigFailed::new(error_code)),
11 => Self::RoleRequestFailed(RoleRequestFailed::new(error_code)),
12 => Self::MeterModFailed(MeterModFailed::new(error_code)),
13 => Self::TableFeaturesFailed(TableFeaturesFailed::new(error_code)),
_ => Self::EXPERIMENTER,
}
}
}
#[derive(Debug)]
pub enum HelloFailed {
Incompatible,
EPerm,
}
impl HelloFailed {
pub fn new(error_code: u16) -> Self {
match error_code {
0 => Self::Incompatible,
_ => Self::EPerm,
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum BadRequest {
BadVersion = 0, /* ofp_header.version not supported. */
BadType = 1, /* ofp_header.type not supported. */
BadMultipart = 2, /* ofp_multipart_request.type not supported. */
BadExperimenter = 3, /* Experimenter id not supported in ofp_experimenter_header or ofp_multipart_request or ofp_multipart_reply). */
BadExpType = 4, /* Experimenter type not supported. */
EPERM = 5, /* Permissions error. */
BadLen = 6, /* Wrong request length for type. */
BufferEmpty = 7, /* Specified buffer has already been used. */
BufferUnknown = 8, /* Specified buffer does not exist. */
BadTableId = 9, /* Specified table-id invalid or does not exist. */
IsSlave = 10, /* Denied because controller is slave. */
BadPort = 11, /* Invalid port. */
BadPacket = 12, /* Invalid packet in packet-out. */
MultipartBufferOverflow = 13, /* ofp_multipart_request overflowed the assigned buffer. */
}
impl BadRequest {
pub fn new(error_code: u16) -> Self {
if error_code < 14 {
unsafe { transmute::<u16, BadRequest>(error_code) }
} else {
BadRequest::BadType
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum BadAction {
BadType = 0, /* Unknown action type. */
BadLen = 1, /* Length problem in actions. */
BadExperimenter = 2, /* Unknown experimenter id specified. */
BadExpType = 3, /* Unknown action for experimenter id. */
BadOutPort = 4, /* Problem validating output port. */
BadArgument = 5, /* Bad action argument. */
EPERM = 6, /* Permissions error. */
TooMany = 7, /* Can’t handle this many actions. */
BadQueue = 8, /* Problem validating output queue. */
BadOutGroup = 9, /* Invalid group id in forward action. */
MatchInconsistent = 10, /* Action can’t apply for this match, or Set-Field missing prerequisite. */
UnsupportedOrder = 11, /* Action order is unsupported for the action list in an Apply-Actions instruction */
BadTag = 12, /* Actions uses an unsupported tag/encap. */
BadSetType = 13, /* Unsupported type in SET_FIELD action. */
BadSetLen = 14, /* Length problem in SET_FIELD action. */
BadSetArgument = 15, /* Bad argument in SET_FIELD action. */
}
impl Default for BadAction {
fn default() -> Self {
Self::EPERM
}
}
impl BadAction {
pub fn new(error_code: u16) -> Self {
if error_code < 16 {
unsafe { transmute::<u16, BadAction>(error_code) }
} else {
BadAction::BadType
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum BadInstruction {
UnknownInst = 0, /* Unknown instruction. */
UnsupInst = 1, /* Switch or table does not support the instruction. */
BadTableId = 2, /* Invalid Table-ID specified. */
UnsupMetadata = 3, /* Metadata value unsupported by datapath. */
UnsupMetadataMask = 4, /* Metadata mask value unsupported by datapath. */
BadExperimenter = 5, /* Unknown experimenter id specified. */
BadExpType = 6, /* Unknown instruction for experimenter id. */
BadLen = 7, /* Length problem in instructions. */
EPERM = 8, /* Permissions error. */
}
impl BadInstruction {
pub fn new(error_code: u16) -> Self {
if error_code < 9 {
unsafe { transmute::<u16, BadInstruction>(error_code) }
} else {
BadInstruction::EPERM
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum BadMatch {
BadType = 0, /* Unsupported match type specified by the match */
BadLen = 1, /* Length problem in match. */
BadTag = 2, /* Match uses an unsupported tag/encap. */
BadDlAddrMask = 3, /* Unsupported datalink addr mask - switch does not support arbitrary datalink address mask. */
BadNwAddrMask = 4, /* Unsupported network addr mask - switch does not support arbitrary network address mask. */
BadWildcards = 5, /* Unsupported combination of fields masked or omitted in the match. */
BadField = 6, /* Unsupported field type in the match. */
BadValue = 7, /* Unsupported value in a match field. */
BadMask = 8, /* Unsupported mask specified in the match, field is not dl-address or nw-address. */
BadPrereq = 9, /* A prerequisite was not met. */
DupField = 10, /* A field type was duplicated. */
EPERM = 11, /* Permissions error. */
}
impl BadMatch {
pub fn new(error_code: u16) -> Self {
if error_code < 12 {
unsafe { transmute(error_code) }
} else {
BadMatch::EPERM
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum FlowModFailed {
UNKNOWN = 0, /* Unspecified error. */
TableFull = 1, /* Flow not added because table was full. */
BadTableId = 2, /* Table does not exist */
OVERLAP = 3, /* Attempted to add overlapping flow with CHECK_OVERLAP flag set. */
EPERM = 4, /* Permissions error. */
BadTimeout = 5, /* Flow not added because of unsupported idle/hard timeout. */
BadCommand = 6, /* Unsupported or unknown command. */
BadFlags = 7, /* Unsupported or unknown flags. */
}
impl FlowModFailed {
pub fn new(error_code: u16) -> Self {
if error_code < 8 {
unsafe { transmute(error_code) }
} else {
FlowModFailed::EPERM
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum GroupModFailed {
GroupExists = 0, /* Group not added because a group ADD attempted to replace an already-present group. */
InvalidGroup = 1, /* Group not added because Group specified is invalid. */
WeightUnsupported = 2, /* Switch does not support unequal load sharing with select groups. */
OutOfGroups = 3, /* The group table is full. */
OutOfBuckets = 4, /* The maximum number of action buckets for a group has been exceeded. */
ChainingUnsupported = 5, /* Switch does not support groups that forward to groups. */
WatchUnsupported = 6, /* This group cannot watch the watch_port or watch_group specified. */
Loop = 7, /* Group entry would cause a loop. */
UnknownGroup = 8, /* Group not modified because a group MODIFY attempted to modify a non-existent group. */
ChainedGroup = 9, /* Group not deleted because another group is forwarding to it. */
BadType = 10, /* Unsupported or unknown group type. */
BadCommand = 11, /* Unsupported or unknown command. */
BadBucket = 12, /* Error in bucket. */
BadWatch = 13, /* Error in watch port/group. */
EPERM = 14, /* Permissions error. */
}
impl GroupModFailed {
pub fn new(error_code: u16) -> Self {
if error_code < 15 {
unsafe { transmute(error_code) }
} else {
Self::EPERM
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum PortModFailed {
BadPort = 0, /* Specified port number does not exist. */
BadHwAddr = 1, /* Specified hardware address does not * match the port number. */
BadConfig = 2, /* Specified config is invalid. */
BadAdvertise = 3, /* Specified advertise is invalid. */
EPERM = 4, /* Permissions error. */
}
impl PortModFailed {
pub fn new(error_code: u16) -> Self {
match error_code {
0 => Self::BadPort,
1 => Self::BadHwAddr,
2 => Self::BadConfig,
3 => Self::BadAdvertise,
_ => Self::EPERM,
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum TableModFailed {
BadTable = 0,
BadConfig = 1,
EPERM = 2,
}
impl TableModFailed {
pub fn new(error_code: u16) -> Self {
match error_code {
0 => Self::BadTable,
1 => Self::BadConfig,
_ => Self::EPERM,
}
}
}
#[derive(Debug)]
pub enum QueueOpFailed {
BadPort,
BadQueue,
EPerm,
}
impl QueueOpFailed {
pub fn new(error_code: u16) -> Self {
match error_code {
0 => Self::BadPort,
1 => Self::BadQueue,
_ => Self::EPerm,
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum SwitchConfigFailed {
BadFlags = 0,
BadLen = 1,
EPERM = 2,
}
impl SwitchConfigFailed {
pub fn new(error_code: u16) -> Self {
match error_code {
0 => Self::BadFlags,
1 => Self::BadLen,
_ => Self::EPERM,
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum RoleRequestFailed {
Stale = 0,
Unsup = 1,
BadRole = 2,
}
impl RoleRequestFailed {
pub fn new(error_code: u16) -> Self {
match error_code {
0 => Self::Stale,
1 => Self::Unsup,
_ => Self::BadRole,
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum MeterModFailed {
Unknown = 0, /* Unspecified error. */
MeterExists = 1, /* Meter not added because a Meter ADD * attempted to replace an existing Meter. */
InvalidMeter = 2, /* Meter not added because Meter specified * is invalid. */
UnknownMeter = 3, /* Meter not modified because a Meter MODIFY attempted to modify a non-existent Meter. */
BadCommand = 4, /* Unsupported or unknown command. */
BadFlags = 5, /* Flag configuration unsupported. */
BadRate = 6, /* Rate unsupported. */
BadBurst = 7, /* Burst size unsupported. */
BadBand = 8, /* Band unsupported. */
BadBandValue = 9, /* Band value unsupported. */
OutOfMeters = 10, /* No more meters available. */
OutOfBands = 11, /* The maximum number of properties * for a meter has been exceeded. */
}
impl MeterModFailed {
pub fn new(error_code: u16) -> Self {
if error_code < 12 {
unsafe { transmute(error_code) }
} else {
Self::OutOfBands
}
}
}
#[repr(u16)]
#[derive(Debug)]
pub enum TableFeaturesFailed {
BadTable = 0, /* Specified table does not exist. */
BadMetadata = 1, /* Invalid metadata mask. */
BadType = 2, /* Unknown property type. */
BadLen = 3, /* Length problem in properties. */
BadArgument = 4, /* Unsupported property value. */
EPERM = 5, /* Permissions error. */
}
impl TableFeaturesFailed {
pub fn new(error_code: u16) -> Self {
if error_code < 6 {
unsafe { transmute(error_code) }
} else {
Self::EPERM
}
}
}
pub mod error_handler;
pub use error_handler::ErrorEvent;
pub mod error_type;
use std::io::{BufRead, Cursor, Error};
use byteorder::{BigEndian, ReadBytesExt};
pub struct FeaturesReplyEvent {
pub datapath_id: u64,
pub n_buffers: u32,
pub n_tables: u8,
pub auxiliary: u8,
// pad 16 bit
pub capabilities: Capabilities,
pub reserved: u32,
}
impl FeaturesReplyEvent {
pub fn parse(bytes: &Vec<u8>) -> Result<Self, Error> {
let mut bytes = Cursor::new(bytes);
let datapath_id = bytes.read_u64::<BigEndian>()?;
let n_buffers = bytes.read_u32::<BigEndian>()?;
let n_tables = bytes.read_u8()?;
let auxiliary = bytes.read_u8()?;
bytes.consume(2);
let capabilities: Capabilities = bytes.read_u32::<BigEndian>()?.into();
let reserved = bytes.read_u32::<BigEndian>()?;
Ok(Self {
datapath_id,
n_buffers,
n_tables,
auxiliary,
capabilities,
reserved,
})
}
}
pub struct Capabilities {
pub flow_stats: bool,
pub table_stats: bool,
pub port_stats: bool,
pub group_stats: bool,
pub ip_reasm: bool,
pub queue_stats: bool,
pub port_blocked: bool,
}
impl From<u32> for Capabilities {
fn from(value: u32) -> Self {
Self {
flow_stats: value & 1 == 1,
table_stats: value >> 1 & 1 == 1,
port_stats: value >> 2 & 1 == 1,
group_stats: value >> 3 & 1 == 1,
ip_reasm: value >> 5 & 1 == 1,
queue_stats: value >> 6 & 1 == 1,
port_blocked: value >> 8 & 1 == 1,
}
}
}
impl From<Capabilities> for u32 {
fn from(value: Capabilities) -> Self {
(value.flow_stats as u32)
| ((value.table_stats as u32) << 1)
| (value.port_stats as u32) << 2
| (value.group_stats as u32) << 3
| (value.ip_reasm as u32) << 5
| (value.queue_stats as u32) << 6
| (value.port_blocked as u32) << 8
}
}
use crate::openflow::ofp13::{MessageMarshal, Msg};
pub struct FeaturesReqEvent {}
impl FeaturesReqEvent {
pub fn new() -> Self {
FeaturesReqEvent {}
}
}
impl MessageMarshal for FeaturesReqEvent {
fn marshal(&self, _: &mut Vec<u8>) {}
fn msg_code(&self) -> Msg {
Msg::FeaturesRequest
}
fn size_of(&self) -> usize {
0
}
fn msg_usize(&self) -> usize {
Msg::FeaturesRequest as usize
}
}
#[repr(u8)]
pub enum FlowModCommand {
Add = 0,
Modify = 1,
ModifyStrict = 2,
Delete = 3,
DeleteStrict = 4,
Unparsable = 0xff,
}
impl FlowModCommand {
pub fn to_number(&self) -> usize {
match self {
FlowModCommand::Add => Self::Add as usize,
FlowModCommand::Modify => Self::Modify as usize,
FlowModCommand::ModifyStrict => Self::ModifyStrict as usize,
FlowModCommand::Delete => Self::Delete as usize,
FlowModCommand::DeleteStrict => Self::DeleteStrict as usize,
FlowModCommand::Unparsable => Self::Unparsable as usize,
}
}
pub fn parse(byte: u16) -> Self {
match byte {
0 => Self::Add,
1 => Self::Modify,
2 => Self::ModifyStrict,
3 => Self::Delete,
4 => Self::DeleteStrict,
_ => Self::Unparsable,
}
}
}
use byteorder::{BigEndian, WriteBytesExt};
pub struct FlowModFlags {
pub send_flow_rem: bool,
pub check_overlap: bool,
pub reset_counts: bool,
pub no_pkt_counts: bool,
pub no_byt_counts: bool,
}
impl FlowModFlags {
pub fn new(
send_flow_rem: bool,
check_overlap: bool,
reset_counts: bool,
no_pkt_counts: bool,
no_byt_counts: bool,
) -> Self {
Self {
send_flow_rem,
check_overlap,
reset_counts,
no_pkt_counts,
no_byt_counts,
}
}
pub fn all_false() -> Self {
Self {
send_flow_rem: false,
check_overlap: false,
reset_counts: false,
no_pkt_counts: false,
no_byt_counts: false,
}
}
pub fn parse(byte: u16) -> Self {
let send_flow_rem = byte >> 0 & 1 != 0;
let check_overlap = byte >> 1 & 1 != 0;
let reset_counts = byte >> 2 & 1 != 0;
let no_pkt_counts = byte >> 3 & 1 != 0;
let no_byt_counts = byte >> 4 & 1 == 1;
Self {
send_flow_rem,
check_overlap,
reset_counts,
no_pkt_counts,
no_byt_counts,
}
}
pub fn marshal(&self, bytes: &mut Vec<u8>) {
let mut value = 0u16;
if self.send_flow_rem {
value |= 1 << 0;
}
if self.check_overlap {
value |= 1 << 1;
}
if self.reset_counts {
value |= 1 << 2;
}
if self.no_pkt_counts {
value |= 1 << 3;
}
if self.no_byt_counts {
value |= 1 << 4;
}
let _ = bytes.write_u16::<BigEndian>(value);
}
}
use byteorder::{BigEndian, WriteBytesExt};
use crate::openflow::ofp13::{
events::{actions::ToInstruction, Action},
ofp_port::OfpPort,
MessageMarshal, Msg, PseudoPort,
};
use super::{instructions::Instrucion, FlowModCommand, FlowModFlags, MatchFields};
pub enum Timeout {
Permanent,
ExpireAfter(u16),
}
impl Timeout {
pub fn parse(tm: u16) -> Self {
match tm {
0 => Self::Permanent,
d => Timeout::ExpireAfter(d),
}
}
pub fn to_int(&self) -> u16 {
match self {
Timeout::Permanent => 0,
Timeout::ExpireAfter(d) => *d,
}
}
}
pub struct FlowModEvent {
cookie: u64,
cookie_mask: u64,
table_id: u8,
command: FlowModCommand,
idle_timeout: Timeout,
hard_timeout: Timeout,
priority: u16,
buffer_id: Option<u32>,
out_port: Option<PseudoPort>,
out_group: Option<PseudoPort>,
flags: FlowModFlags,
// pad: [u8; 2],
// ofp_match
match_fields: MatchFields,
instruction: Instrucion,
}
impl FlowModEvent {
pub fn add_flow(
priority: u16,
match_fileds: MatchFields,
actions: Vec<Action>,
table_id: u8,
buffer_id: Option<u32>,
) -> Self {
Self {
cookie: 0,
cookie_mask: 0,
table_id,
command: FlowModCommand::Add,
idle_timeout: Timeout::Permanent,
hard_timeout: Timeout::Permanent,
priority,
buffer_id,
out_port: None,
out_group: None,
flags: FlowModFlags::all_false(),
match_fields: match_fileds,
instruction: Instrucion::InstructActions(actions.to_instruct()),
}
}
// TODO
// pub fn parse(buf: &[u8]) -> Result<FlowModEvent, Error> {
// }
}
impl MessageMarshal for FlowModEvent {
fn msg_usize(&self) -> usize {
Msg::FlowMod as usize
}
fn size_of(&self) -> usize {
24
}
fn msg_code(&self) -> Msg {
Msg::FlowMod
}
fn marshal(&self, bytes: &mut Vec<u8>) {
let _ = bytes.write_u64::<BigEndian>(self.cookie);
let _ = bytes.write_u64::<BigEndian>(self.cookie_mask);
let _ = bytes.write_u8(self.table_id);
let _ = bytes.write_u8(self.command.to_number() as u8);
let _ = bytes.write_u16::<BigEndian>(self.idle_timeout.to_int());
let _ = bytes.write_u16::<BigEndian>(self.hard_timeout.to_int());
let _ = bytes.write_u16::<BigEndian>(self.priority);
let _ = bytes.write_i32::<BigEndian>(match self.buffer_id {
None => -1,
Some(buf_id) => buf_id as i32,
});
match self.out_port.as_ref() {
Some(p) => p.marshal(bytes),
None => {
let _ = bytes.write_u32::<BigEndian>(OfpPort::Any as u32);
}
}
match self.out_group.as_ref() {
Some(p) => p.marshal(bytes),
None => {
let _ = bytes.write_u32::<BigEndian>(OfpPort::Any as u32);
}
}
self.flags.marshal(bytes);
// padding
let _ = bytes.write_u16::<BigEndian>(0);
let _ = self.match_fields.marshal(bytes);
self.instruction.marshal(bytes);
}
}
use byteorder::{BigEndian, WriteBytesExt};
use crate::openflow::ofp13::Action;
pub trait InstructTrait {
fn marshal(&self, bytes: &mut Vec<u8>);
}
#[derive(Clone)]
#[repr(u16)]
pub enum InstructType {
GotoTable = 1,
WriteMetadata = 2,
WriteActions = 3,
ApplyActions = 4,
ClearActions = 5,
Meter = 6,
Experimenter = 0xffff,
}
impl InstructType {
pub fn marshal(&self, bytes: &mut Vec<u8>) {
let _ = bytes.write_u16::<BigEndian>(self.clone().into());
}
}
impl From<InstructType> for u16 {
fn from(value: InstructType) -> Self {
value as u16
}
}
pub struct GotoTable {
typ: InstructType,
len: u16,
table_id: u8,
}
impl GotoTable {
pub fn new(table_id: u8) -> Self {
Self {
typ: InstructType::GotoTable,
len: 8,
table_id,
}
}
}
impl InstructTrait for GotoTable {
fn marshal(&self, bytes: &mut Vec<u8>) {
self.typ.marshal(bytes);
let _ = bytes.write_u16::<BigEndian>(self.len);
let _ = bytes.write_u8(self.table_id);
// padding
let _ = bytes.write_u16::<BigEndian>(0);
let _ = bytes.write_u8(0);
}
}
pub struct WriteMetadata {
typ: InstructType,
len: u16,
metadata: u64,
meta_mask: u64,
}
impl WriteMetadata {
pub fn new(metadata: u64, meta_mask: u64) -> Self {
Self {
typ: InstructType::WriteMetadata,
len: 24,
metadata,
meta_mask,
}
}
}
impl InstructTrait for WriteMetadata {
fn marshal(&self, bytes: &mut Vec<u8>) {
self.typ.marshal(bytes);
let _ = bytes.write_u16::<BigEndian>(self.len);
// padding
let _ = bytes.write_u32::<BigEndian>(0);
// *******
let _ = bytes.write_u64::<BigEndian>(self.metadata);
let _ = bytes.write_u64::<BigEndian>(self.meta_mask);
}
}
pub struct InstructActions {
typ: InstructType,
len: u16,
pub actions: Vec<Action>,
}
impl InstructActions {
pub const WRITE: InstructType = InstructType::WriteActions;
pub const APPLY: InstructType = InstructType::ApplyActions;
pub const CLEAR: InstructType = InstructType::ClearActions;
pub fn new(typ: InstructType) -> Self {
Self {
typ,
len: 8,
actions: Vec::new(),
}
}
}
impl InstructTrait for InstructActions {
fn marshal(&self, bytes: &mut Vec<u8>) {
let mut builder = Vec::new();
for act in self.actions.iter() {
let _ = act.marshal(&mut builder);
}
self.typ.marshal(bytes);
let _ = bytes.write_u16::<BigEndian>(self.len + (builder.len() as u16));
// padding
let _ = bytes.write_u32::<BigEndian>(0);
bytes.append(&mut builder);
}
}
pub struct InstructMeter {
typ: InstructType,
len: u16,
meter_id: u32,
}
impl InstructMeter {
pub fn new(meter_id: u32) -> Self {
Self {
typ: InstructType::Meter,
len: 8,
meter_id,
}
}
}
impl InstructTrait for InstructMeter {
fn marshal(&self, bytes: &mut Vec<u8>) {
self.typ.marshal(bytes);
let _ = bytes.write_u16::<BigEndian>(self.len);
let _ = bytes.write_u32::<BigEndian>(self.meter_id);
}
}
pub enum Instrucion {
GotoTable(GotoTable),
WriteMetadata(WriteMetadata),
InstructActions(InstructActions),
InstructMeter(InstructMeter),
}
impl Instrucion {
pub fn marshal(&self, bytes: &mut Vec<u8>) {
match &self {
Instrucion::GotoTable(v) => v.marshal(bytes),
Instrucion::WriteMetadata(v) => v.marshal(bytes),
Instrucion::InstructActions(v) => v.marshal(bytes),
Instrucion::InstructMeter(v) => v.marshal(bytes),
}
}
}
use std::{
io::{BufRead, Cursor, Error},
mem::transmute,
net::{Ipv4Addr, Ipv6Addr},
};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use crate::etherparser::MacAddr;
/**
* +---------------+---------------+---------------------------+
* | Type | Length | OXM Fields |
* +---------------+---------------+---------------------------+
* | (Optional) | (16 bits) | (Array of variable length)|
* |---------------+---------------+---------------------------+
*/
pub struct OfpMatch {
typ: MatchType,
length: u16,
oxm_fields: Vec<u8>,
}
impl OfpMatch {
pub fn new() -> Self {
Self {
typ: MatchType::OXM,
length: 4,
oxm_fields: Vec::new(),
}
}
pub fn marshal(&self, bytes: &mut Vec<u8>) -> Result<(), Error> {
bytes.write_u16::<BigEndian>(self.typ.clone().into())?;
bytes.write_u16::<BigEndian>(self.length + (self.oxm_fields.len() as u16))?;
bytes.append(&mut self.oxm_fields.clone());
// padding
bytes.write_u32::<BigEndian>(0)?;
Ok(())
}
}
#[derive(Clone)]
#[repr(u16)]
pub enum MatchType {
Standard = 0,
OXM = 1, //, the OpenFlow 1.1 match type OFPMT_STANDARD is deprecated
}
impl From<u16> for MatchType {
fn from(value: u16) -> Self {
match value {
0 => Self::Standard,
_ => Self::OXM,
}
}
}
impl From<MatchType> for u16 {
fn from(value: MatchType) -> Self {
value as u16
}
}
/**
*
* +----------------------------+----------------------------+
* | 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)| |
* +----------------------------+----------------------------+
*
*/
#[allow(unused)]
pub struct OxmHeader {
class: OxmClass, // Match class: member class or reserved class
field: OxmMatchFields, // 7bit Match field within the class
hasmask: bool, // 1bit Set if OXM include a bitmask in payload
length: u8, // Length of OXM payload
experimenter: Option<u32>,
}
impl OxmHeader {
pub fn new(field: OxmMatchFields, size: u8, hasmask: bool) -> Self {
Self {
class: OxmClass::OpenflowBasic,
field,
hasmask: hasmask,
length: size,
experimenter: None,
}
}
pub fn marshal(&self, bytes: &mut Vec<u8>) -> Result<(), Error> {
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 })?;
bytes.write_u8(self.length)?;
// if let Some(exp) = self.experimenter {
// bytes.write_u32::<BigEndian>(exp);
// }
Ok(())
}
}
/**
* NXM allocates only two vendors,
* 0x0000 for fields supported by OpenFlow 1.0
* and 0x0001 for fields implemented as an Open vSwitch extension
*/
#[derive(Clone)]
#[repr(u16)]
pub enum OxmClass {
Nxm0 = 0x0000, // Backward compatibility with NXM
Nxm1 = 0x0001, // Backward compatibility with NXM
OpenflowBasic = 0x8000, // Basic class for OpenFlow
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. */
pub enum OxmMatchFields {
InPort = 0, /* Switch input port. */
InPhyPort = 1, /* Switch physical input port. */
METADATA = 2, /* Metadata passed between tables. */
EthDst = 3, /* Ethernet destination address. */
EthSrc = 4, /* Ethernet source address. */
EthType = 5, /* Ethernet frame type. */
VlanVid = 6, /* VLAN id. */
VlanPcp = 7, /* VLAN priority. */
IpDscp = 8, /* IP DSCP (6 bits in ToS field). */
IpEcn = 9, /* IP ECN (2 bits in ToS field). */
IpProto = 10, /* IP protocol. */
Ipv4Src = 11, /* IPv4 source address. */
Ipv4Dst = 12, /* IPv4 destination address. */
TcpSrc = 13, /* TCP source port. */
TcpDst = 14, /* TCP destination port. */
UdpSrc = 15, /* UDP source port. */
UdpDst = 16, /* UDP destination port. */
SctpSrc = 17, /* SCTP source port. */
SctpDst = 18, /* SCTP destination port. */
Icmpv4Type = 19, /* ICMP type. */
Icmpv4Code = 20, /* ICMP code. */
ArpOp = 21, /* ARP opcode. */
ArpSpa = 22, /* ARP source IPv4 address. */
ArpTpa = 23, /* ARP target IPv4 address. */
ArpSha = 24, /* ARP source hardware address. */
ArpTha = 25, /* ARP target hardware address. */
Ipv6Src = 26, /* IPv6 source address. */
Ipv6Dst = 27, /* IPv6 destination address. */
Ipv6Flabel = 28, /* IPv6 Flow Label */
Icmpv6Type = 29, /* ICMPv6 type. */
Icmpv6Code = 30, /* ICMPv6 code. */
Ipv6NdTarget = 31, /* Target address for ND. */
Ipv6NdSll = 32, /* Source link-layer for ND. */
Ipv6NdTll = 33, /* Target link-layer for ND. */
MplsLabel = 34, /* MPLS label. */
MplsTc = 35, /* MPLS TC. */
MplsBos = 36, /* MPLS BoS bit. */
PbbIsid = 37, /* PBB I-SID. */
TunnelId = 38, /* Logical Port Metadata. */
Ipv6Exthdr = 39, /* IPv6 Extension Header pseudo-field */
Unparse,
}
impl From<u8> for OxmMatchFields {
fn from(value: u8) -> Self {
if value < 44 {
unsafe { transmute(value) }
} else {
Self::Unparse
}
}
}
impl From<OxmMatchFields> for u8 {
fn from(value: OxmMatchFields) -> Self {
value as u8
}
}
// Required match fields.
pub struct MatchFields {
pub in_port: Option<u32>, // Ingress port. This may be a physical or switch-defined logical port.
pub eth_dst: Option<MacAddr>, // Ethernet source address. Can use arbitrary bitmask
pub eth_src: Option<MacAddr>, // Ethernet destination address. Can use arbitrary bitmask
pub eth_typ: Option<u16>, // Ethernet type of the OpenFlow packet payload, after VLAN tags.
pub ip_proto: Option<u8>, // IPv4 or IPv6 protocol number
pub ipv4_src: Option<Ipv4Addr>, // IPv4 source address. Can use subnet mask or arbitrary bitmask
pub ipv4_dst: Option<Ipv4Addr>, // IPv4 destination address. Can use subnet mask or arbitrary bitmask
pub ipv6_src: Option<Ipv6Addr>, // IPv6 source address. Can use subnet mask or arbitrary bitmask
pub ipv6_dst: Option<Ipv6Addr>, // IPv6 destination address. Can use subnet mask or arbitrary bitmask
pub tcp_src: Option<u16>, // TCP source port
pub tcp_dst: Option<u16>, // TCP destination port
pub udp_src: Option<u16>, // UDP source port
pub udp_dst: Option<u16>, // UDP destination port
}
impl MatchFields {
pub fn match_all() -> Self {
Self {
in_port: None,
eth_dst: None,
eth_src: None,
eth_typ: None,
ip_proto: None,
ipv4_src: None,
ipv4_dst: None,
ipv6_src: None,
ipv6_dst: None,
tcp_src: None,
tcp_dst: None,
udp_src: None,
udp_dst: None,
}
}
pub fn marshal(&self, bytes: &mut Vec<u8>) -> Result<(), Error>{
let mut ofp_match = OfpMatch::new();
let ofp_byte = ofp_match.oxm_fields.as_mut();
if let Some(in_port) = &self.in_port {
let header = OxmHeader::new(OxmMatchFields::InPort, 4, false);
header.marshal(ofp_byte)?;
ofp_byte.write_u32::<BigEndian>(*in_port)?;
}
if let Some(eth_dst) = &self.eth_dst {
let header = OxmHeader::new(OxmMatchFields::EthDst, 12, true);
header.marshal(ofp_byte)?;
eth_dst.marshal(ofp_byte);
// mac mask
MacAddr::from(!0).marshal(ofp_byte);
}
if let Some(eth_src) = &self.eth_src {
let header = OxmHeader::new(OxmMatchFields::EthSrc, 12, true);
header.marshal(ofp_byte)?;
eth_src.marshal(ofp_byte);
// mac mask
MacAddr::from(!0).marshal(ofp_byte);
}
if let Some(eth_typ) = &self.eth_typ {
OxmHeader::new(OxmMatchFields::EthType, 2, false).marshal(ofp_byte)?;
ofp_byte.write_u16::<BigEndian>(*eth_typ)?;
}
if let Some(ip_proto) = &self.ip_proto {
OxmHeader::new(OxmMatchFields::IpProto, 1, false).marshal(ofp_byte)?;
ofp_byte.write_u8(*ip_proto)?;
}
if let Some(ipv4_src) = &self.ipv4_src {
OxmHeader::new(OxmMatchFields::Ipv4Src, 8, true).marshal(ofp_byte)?;
bytes.write_u32::<BigEndian>(ipv4_src.clone().into())?;
bytes.write_u32::<BigEndian>(!0)?;
}
if let Some(ipv4_dst) = &self.ipv4_dst {
OxmHeader::new(OxmMatchFields::Ipv4Dst, 8, true).marshal(ofp_byte)?;
bytes.write_u32::<BigEndian>(ipv4_dst.clone().into())?;
bytes.write_u32::<BigEndian>(!0)?;
}
if let Some(ipv6_src) = &self.ipv6_src {
OxmHeader::new(OxmMatchFields::Ipv6Src, 32, true).marshal(ofp_byte)?;
ofp_byte.write_u128::<BigEndian>(ipv6_src.clone().into())?;
ofp_byte.write_u128::<BigEndian>(!0)?;
}
if let Some(ipv6_dst) = &self.ipv6_dst {
OxmHeader::new(OxmMatchFields::Ipv6Dst, 32, true).marshal(ofp_byte)?;
ofp_byte.write_u128::<BigEndian>(ipv6_dst.clone().into())?;
ofp_byte.write_u128::<BigEndian>(!0)?;
}
if let Some(tcp_src) = &self.tcp_src {
OxmHeader::new(OxmMatchFields::TcpSrc, 2, false);
ofp_byte.write_u16::<BigEndian>(*tcp_src)?;
}
if let Some(tcp_dst) = &self.tcp_dst {
OxmHeader::new(OxmMatchFields::TcpDst, 2, false);
ofp_byte.write_u16::<BigEndian>(*tcp_dst)?;
}
if let Some(udp_src) = &self.udp_src {
OxmHeader::new(OxmMatchFields::UdpSrc, 2, false);
ofp_byte.write_u16::<BigEndian>(*udp_src)?;
}
if let Some(udp_dst) = &self.udp_dst {
OxmHeader::new(OxmMatchFields::UdpDst, 2, false);
ofp_byte.write_u16::<BigEndian>(*udp_dst)?;
}
ofp_match.marshal(bytes)?;
Ok(())
}
pub fn parse(bytes: &mut Cursor<Vec<u8>>) -> Result<MatchFields, Error> {
let mut matcher = MatchFields::match_all();
let _typ: MatchType = bytes.read_u16::<BigEndian>()?.into();
let length = bytes.read_u16::<BigEndian>()?;
let mut pkt_len = length - 4;
while pkt_len > 0 {
let _oxm_class = bytes.read_u16::<BigEndian>()?;
let oxm_field = bytes.read_u8()?;
let hash_mask = oxm_field & 1 == 1;
let oxm_field: OxmMatchFields = (oxm_field >> 1).into();
let oxm_length = bytes.read_u8()?;
match oxm_field {
OxmMatchFields::InPort => {
let port = bytes.read_u32::<BigEndian>()?;
let _mask = if hash_mask {
Some(bytes.read_u32::<BigEndian>())
} else {
None
};
matcher.in_port = Some(port);
}
OxmMatchFields::EthDst => {
let mut mac = [0u8; 6];
for i in 0..6 {
mac[i] = bytes.read_u8()?;
}
if hash_mask {
bytes.consume(6);
}
matcher.eth_dst = Some(MacAddr::new(mac));
}
OxmMatchFields::EthSrc => {
let mut mac = [0u8; 6];
for i in 0..6 {
mac[i] = bytes.read_u8()?;
}
if hash_mask {
bytes.consume(6);
}
matcher.eth_src = Some(MacAddr::new(mac));
}
OxmMatchFields::EthType => {
let eth_typ = bytes.read_u16::<BigEndian>()?;
if hash_mask {
bytes.consume(2);
}
matcher.eth_typ = Some(eth_typ);
}
OxmMatchFields::IpProto => {
let proto = bytes.read_u8()?;
if hash_mask {
bytes.consume(1);
}
matcher.ip_proto = Some(proto);
}
OxmMatchFields::Ipv4Src => {
let ip = bytes.read_u32::<BigEndian>()?;
if hash_mask {
bytes.consume(4);
}
matcher.ipv4_src = Some(Ipv4Addr::from(ip));
}
OxmMatchFields::Ipv4Dst => {
let ip = bytes.read_u32::<BigEndian>()?;
if hash_mask {
bytes.consume(4);
}
matcher.ipv4_dst = Some(Ipv4Addr::from(ip));
}
OxmMatchFields::Ipv6Src => {
let ipv6 = bytes.read_u128::<BigEndian>()?;
if hash_mask {
bytes.consume(16);
}
matcher.ipv6_src = Some(Ipv6Addr::from(ipv6));
}
OxmMatchFields::Ipv6Dst => {
let ipv6 = bytes.read_u128::<BigEndian>()?;
if hash_mask {
bytes.consume(16);
}
matcher.ipv6_dst = Some(Ipv6Addr::from(ipv6));
}
OxmMatchFields::TcpSrc => {
let tcp = bytes.read_u16::<BigEndian>()?;
if hash_mask {
bytes.consume(2);
}
matcher.tcp_src = Some(tcp);
}
OxmMatchFields::TcpDst => {
let tcp = bytes.read_u16::<BigEndian>()?;
if hash_mask {
bytes.consume(2);
}
matcher.tcp_dst = Some(tcp);
}
OxmMatchFields::UdpSrc => {
let udp = bytes.read_u16::<BigEndian>()?;
if hash_mask {
bytes.consume(2);
}
matcher.udp_src = Some(udp);
}
OxmMatchFields::UdpDst => {
let udp = bytes.read_u16::<BigEndian>()?;
if hash_mask {
bytes.consume(2);
}
matcher.udp_dst = Some(udp);
}
_ => {
bytes.consume((oxm_length - 4) as usize);
}
}
// 4 is size of oxm_tlv_header
pkt_len = pkt_len - (oxm_length as u16 + 4);
}
if length % 8 != 0 {
bytes.consume(4);
}
Ok(matcher)
}
}
pub mod flow_mod_handler;
pub use flow_mod_handler::FlowModEvent;
pub mod command;
pub use command::FlowModCommand;
pub mod match_fields;
pub use match_fields::{MatchFields, MatchType, OfpMatch};
pub mod flow_mod_flags;
pub use flow_mod_flags::FlowModFlags;
pub mod instructions;
use crate::openflow::ofp13::{MessageMarshal, Msg};
pub struct HelloEvent {}
impl HelloEvent {
pub fn new() -> Self {
HelloEvent {}
}
}
impl MessageMarshal for HelloEvent {
fn marshal(&self, _: &mut Vec<u8>) {}
fn msg_code(&self) -> Msg {
Msg::Hello
}
fn size_of(&self) -> usize {
0
}
fn msg_usize(&self) -> usize {
Msg::Hello as usize
}
}
pub mod error;
pub use error::ErrorEvent;
pub mod packet_in;
pub use packet_in::{PacketInEvent, PacketInReason};
pub mod packet_out;
pub use packet_out::PacketOutEvent;
pub mod flow_mod;
pub use flow_mod::{FlowModCommand, FlowModEvent, FlowModFlags, MatchFields};
pub mod actions;
pub use actions::Action;
pub mod hello;
pub use hello::HelloEvent;
pub mod features_req;
pub use features_req::FeaturesReqEvent;
pub mod features_reply;
pub use features_reply::FeaturesReplyEvent;
pub mod payload;
pub use payload::Payload;
pub mod echo_request;
pub use echo_request::EchoRequestEvent;
pub mod echo_reply;
pub use echo_reply::EchoReplyEvent;
use crate::etherparser::ethernet::EthernetFrame;
use super::{MatchFields, Payload};
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{BufRead, Cursor, Error};
#[repr(u8)]
#[derive(Debug)]
pub enum PacketInReason {
NoMatch,
Action,
InvalidTTL,
Unknown(u8),
}
impl PacketInReason {
fn new(code: u8) -> Self {
match code {
0 => PacketInReason::NoMatch,
1 => PacketInReason::Action,
2 => PacketInReason::InvalidTTL,
t => PacketInReason::Unknown(t),
}
}
}
pub struct PacketInEvent {
pub buf_id: Option<u32>,
pub total_len: u16,
pub reason: PacketInReason,
pub table_id: u8,
pub cookie: u64,
pub matchs: MatchFields,
pub payload: Payload,
}
impl PacketInEvent {
pub fn ether_parse(&self) -> Result<EthernetFrame, Error> {
match &self.payload {
Payload::Buffered(_, p) | Payload::NoBuffered(p) => EthernetFrame::parse(&p),
}
}
pub fn parse(payload: &Vec<u8>) -> Result<PacketInEvent, Error> {
let mut bytes = Cursor::new(payload.to_vec());
let buf_id = match bytes.read_i32::<BigEndian>()? {
-1 => None,
n => Some(n as u32),
};
let total_len = bytes.read_u16::<BigEndian>()?;
let reason = PacketInReason::new(bytes.read_u8()?);
let table_id = bytes.read_u8()?;
let cookie = bytes.read_u64::<BigEndian>()?;
let matchs = MatchFields::parse(&mut bytes)?;
// padding
bytes.consume(2);
let packet = bytes.fill_buf()?.to_vec();
let payload = match buf_id {
Some(n) => Payload::Buffered(n as u32, packet),
None => Payload::NoBuffered(packet),
};
Ok(PacketInEvent {
buf_id,
total_len,
reason,
table_id,
cookie,
matchs,
payload,
})
}
}
use crate::openflow::ofp13::PseudoPort;
use crate::openflow::ofp13::{ofp_port::OfpPort, MessageMarshal, Msg};
use byteorder::{BigEndian, WriteBytesExt};
use super::{Action, Payload};
pub struct PacketOutEvent {
// buffer_id is in Payload
pub in_port: Option<u32>,
pub actions: Vec<Action>,
pub payload: Payload,
}
impl MessageMarshal for PacketOutEvent {
fn marshal(&self, bytes: &mut Vec<u8>) {
// buffer id
let _ = bytes.write_i32::<BigEndian>(match self.payload {
Payload::Buffered(n, _) => n as i32,
Payload::NoBuffered(_) => -1,
});
// in_port
match self.in_port {
Some(id) => {
PseudoPort::PhysicalPort(id).marshal(bytes);
}
None => {
let _ = bytes.write_u32::<BigEndian>(OfpPort::Any as u32);
}
}
let mut action_byte: Vec<u8> = Vec::new();
for act in self.actions.iter() {
let _ = act.marshal(&mut action_byte);
}
let _ = bytes.write_u16::<BigEndian>(action_byte.len() as u16);
// padding 48 bit
let _ = bytes.write_u32::<BigEndian>(0);
let _ = bytes.write_u16::<BigEndian>(0);
bytes.append(&mut action_byte);
self.payload.marshal(bytes);
}
fn msg_code(&self) -> Msg {
Msg::PacketOut
}
fn msg_usize(&self) -> usize {
Msg::PacketOut as usize
}
fn size_of(&self) -> usize {
24
}
}
impl PacketOutEvent {
pub fn new(in_port: Option<u32>, payload: Payload, actions: Vec<Action>) -> Self {
Self {
in_port,
payload,
actions,
}
}
/* TODO
pub fn parse(buf: &Vec<u8>) -> Result<Self, Error> {
let mut bytes = Cursor::new(buf);
let buf_id = match bytes.read_i32::<BigEndian>()? {
-1 => None,
n => Some(n),
};
let in_port = bytes.read_u32::<BigEndian>()?;
let action_len = bytes.read_u16::<BigEndian>()?;
let mut actions_buf = vec![0; action_len as usize];
let _ = bytes.read_exact(&mut actions_buf);
let mut action_bytes = Cursor::new(actions_buf);
let actions = Action::parse_sequence(&mut action_bytes);
Ok(Self {
payload: match buf_id {
None => Payload::NoBuffered(bytes.fill_buf()?.to_vec()),
Some(n) => Payload::Buffered(n as u32, bytes.fill_buf()?.to_ascii_lowercase()),
},
in_port: {
if in_port == OfpPort::None as u16 {
None
} else {
Some(in_port)
}
},
actions,
})
} */
}
use std::io::Write;
pub enum Payload {
Buffered(u32, Vec<u8>),
NoBuffered(Vec<u8>),
}
impl Payload {
pub fn length(&self) -> usize {
match self {
Payload::Buffered(_, p) | Payload::NoBuffered(p) => p.len(),
}
}
pub fn marshal(&self, bytes: &mut Vec<u8>) {
match self {
Payload::Buffered(_, buf) | Payload::NoBuffered(buf) => {
let _ = bytes.write_all(&buf);
}
}
}
}
use std::mem::transmute;
#[repr(u8)]
#[derive(Clone)]
pub enum Msg {
Hello = 0,
Error = 1,
EchoRequest = 2,
EchoReply = 3,
Experimenter = 4,
FeaturesRequest = 5,
FeaturesReply = 6,
ConfigRequest = 7,
ConfigReply = 8,
SetConfig = 9,
PacketIn = 10,
FlowRemove = 11,
PortStatus = 12,
PacketOut = 13,
FlowMod = 14,
GroupMod = 15,
PortMod = 16,
TableMod = 17,
MultipartRequest = 18,
MultipartReply = 19,
BarrierRequest = 20,
BarrierReply = 21,
GetConfigRequest = 22,
GetConfigReply = 23,
RoleRequest = 24,
RoleReply = 25,
GetAsyncRequest = 26,
GetAsyncReply = 27,
SetAsync = 28,
MeterMod = 29,
NotFound = 0xff,
}
impl Msg {
pub fn to_int(&self) -> u8 {
self.clone().into()
}
pub fn from(msg_code: u8) -> Self {
if msg_code > 21 {
return Self::NotFound;
}
unsafe { transmute::<u8, Msg>(msg_code) }
}
}
impl From<Msg> for u8 {
fn from(value: Msg) -> Self {
value as u8
}
}
pub mod message;
pub use message::Msg;
pub mod ofp_port;
pub use ofp_port::PseudoPort;
pub mod events;
pub use events::{
Action, EchoReplyEvent, EchoRequestEvent, ErrorEvent, FeaturesReplyEvent, FlowModEvent,
HelloEvent, MatchFields, PacketInEvent, PacketOutEvent,
};
pub mod ofp_header;
pub use ofp_header::OfpHeader;
pub mod ofp_manager;
pub use ofp_manager::Openflow13;
pub mod controller_frame;
pub use controller_frame::ControllerFrame13;
pub mod tcp_listener;
pub use tcp_listener::tcp_listener_handler;
pub mod traiter;
pub use traiter::{MessageMarshal, OfpMsgEvent, OpenflowHeader};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::{
io::{Cursor, Error},
mem::size_of,
};
use crate::openflow::ofp13::OpenflowHeader;
use super::{OfpMsgEvent, Openflow13};
pub struct OfpHeader {
pub version: u8,
pub message: u8,
pub length: u16,
pub xid: u32,
}
impl OpenflowHeader for OfpHeader {
fn new(message: u8, length: usize, xid: usize) -> Self {
Self {
version: Openflow13::ofp_version() as u8,
message,
length: (size_of::<OfpHeader>() + length) as u16,
xid: xid as u32,
}
}
fn version(&self) -> usize {
Openflow13::ofp_version()
}
fn message(&self) -> u8 {
self.message
}
fn length(&self) -> usize {
self.length as usize
}
fn xid(&self) -> u32 {
self.xid
}
fn header_size(&self) -> usize {
size_of::<Self>()
}
fn pkt_size(&self) -> usize {
return self.length as usize - size_of::<Self>();
}
fn parse(buf: &Vec<u8>) -> Result<Self, Error> {
let mut buf_cursor = Cursor::new(buf);
let version = buf_cursor.read_u8()?;
let message = buf_cursor.read_u8()?;
let length = buf_cursor.read_u16::<BigEndian>()?;
let xid = buf_cursor.read_u32::<BigEndian>()?;
Ok(Self {
version,
message,
length,
xid,
})
}
fn marshal(&self, bytes: &mut Vec<u8>) {
let _ = bytes.write_u8(self.version);
let _ = bytes.write_u8(self.message);
let _ = bytes.write_u16::<BigEndian>(self.length);
let _ = bytes.write_u32::<BigEndian>(self.xid);
}
}
use super::{
events::{Action, FeaturesReqEvent, Payload},
ofp_header::OfpHeader,
HelloEvent, Msg, OfpMsgEvent, OpenflowHeader, PacketOutEvent,
};
pub struct Openflow13 {}
impl Openflow13 {
pub fn new() -> Self {
Openflow13 {}
}
}
impl OfpMsgEvent for Openflow13 {
fn header_parse(&self, bytes: &Vec<u8>) -> Result<OfpHeader, std::io::Error> {
OfpHeader::parse(bytes)
}
fn header_size(&self) -> usize {
8
}
fn hello_event(&self) -> HelloEvent {
HelloEvent::new()
}
fn fetures_req(&self) -> FeaturesReqEvent {
FeaturesReqEvent::new()
}
fn packet_out(
&self,
port_id: Option<u32>,
payload: Payload,
actions: Vec<Action>,
) -> PacketOutEvent {
PacketOutEvent::new(port_id, payload, actions)
}
fn ofp_version() -> usize {
0x04
}
fn version(&self) -> usize {
Self::ofp_version()
}
fn header(&self, message: u8, length: u16, xid: u32) -> OfpHeader {
OfpHeader::new(message, length as usize, xid as usize)
}
fn msg_parse(&self, msg: u8) -> Msg {
Msg::from(msg)
}
fn msg_usize(&self, msg: Msg) -> usize {
msg.to_int() as usize
}
}
use byteorder::{BigEndian, WriteBytesExt};
#[repr(u32)]
pub enum OfpPort {
Max = 0xffffff00,
InPort = 0xfffffff8,
Table = 0xfffffff9,
Normal = 0xfffffffa,
Flood = 0xfffffffb,
All = 0xfffffffc,
Controller = 0xfffffffd,
Local = 0xfffffffe,
Any = 0xffffffff,
}
#[derive(Clone)]
pub enum PseudoPort {
PhysicalPort(u32),
InPort,
Table,
Normal,
Flood,
AllPorts,
Controller(u64),
Local,
Unsupport,
}
impl PseudoPort {
pub fn parse(byte: u32) -> Option<PseudoPort> {
Some(PseudoPort::new(byte, Some(0)))
}
pub fn new(port: u32, len: Option<u64>) -> PseudoPort {
match port {
p if p == (OfpPort::InPort as u32) => PseudoPort::InPort,
p if p == (OfpPort::Table as u32) => PseudoPort::Table,
p if p == (OfpPort::Normal as u32) => PseudoPort::Normal,
p if p == (OfpPort::Flood as u32) => PseudoPort::Flood,
p if p == (OfpPort::All as u32) => PseudoPort::AllPorts,
p if p == (OfpPort::Controller as u32) => match len {
Some(len) => PseudoPort::Controller(len),
None => PseudoPort::Unsupport,
},
p if p == (OfpPort::Local as u32) => PseudoPort::InPort,
_ => {
if port <= (OfpPort::Max as u32) {
PseudoPort::PhysicalPort(port)
} else {
PseudoPort::Unsupport
}
}
}
}
pub fn marshal(&self, bytes: &mut Vec<u8>) {
let port = match *self {
PseudoPort::PhysicalPort(p) => p,
PseudoPort::InPort => OfpPort::InPort as u32,
PseudoPort::Table => OfpPort::Table as u32,
PseudoPort::Normal => OfpPort::Normal as u32,
PseudoPort::Flood => OfpPort::Flood as u32,
PseudoPort::AllPorts => OfpPort::All as u32,
PseudoPort::Controller(_) => OfpPort::Controller as u32,
PseudoPort::Local => OfpPort::Local as u32,
// not sure how to handle unsupport
PseudoPort::Unsupport => OfpPort::Flood as u32,
};
let _ = bytes.write_u32::<BigEndian>(port);
}
}
use std::{io::Read, net::TcpListener, thread};
use crate::openflow::ofp13::HelloEvent;
use super::{ControllerFrame13, OfpMsgEvent};
pub fn tcp_listener_handler(
address: &str,
controller: impl ControllerFrame13 + Send + 'static + Clone,
) -> Result<(), std::io::Error> {
let listener = TcpListener::bind(address)?;
for stream in listener.incoming() {
match stream {
Ok(mut stream) => {
if let Ok(addr) = stream.peer_addr() {
println!("server has connection from {}", addr);
}
let mut ctrl = controller.clone();
thread::spawn(move || {
ctrl.send_msg(HelloEvent::new(), 0, &mut stream);
let ofp_size = ctrl.ofp().header_size();
let mut buffer = vec![0u8; ofp_size];
loop {
match stream.read(&mut buffer) {
Ok(v) if v > 0 => {
ctrl.request_handler(&mut buffer, &mut stream);
}
Ok(_) => {
continue;
}
Err(_) => {
println!("cannot read packet");
break;
}
}
}
});
}
Err(_) => panic!("Connection failed!"),
}
}
Ok(())
}
use std::io::Error;
use crate::openflow::ofp13::{
events::{Action, FeaturesReqEvent, HelloEvent, PacketOutEvent, Payload},
ofp_header::OfpHeader,
Msg,
};
/**
* the trait for parse value to bytes.
* for use with Controller's send_msg.
*/
pub trait MessageMarshal {
fn marshal(&self, bytes: &mut Vec<u8>);
fn msg_code(&self) -> Msg;
fn msg_usize(&self) -> usize;
fn size_of(&self) -> usize;
}
/**
* for works with controller to create OfpMsgEvent
*/
pub trait OfpMsgEvent {
fn header(&self, message: u8, length: u16, xid: u32) -> OfpHeader;
fn header_parse(&self, bytes: &Vec<u8>) -> Result<OfpHeader, Error>;
fn version(&self) -> usize;
fn ofp_version() -> usize;
fn header_size(&self) -> usize;
fn msg_usize(&self, msg: Msg) -> usize;
fn msg_parse(&self, msg: u8) -> Msg;
fn hello_event(&self) -> HelloEvent;
fn fetures_req(&self) -> FeaturesReqEvent;
fn packet_out(
&self,
port_id: Option<u32>,
payload: Payload,
actions: Vec<Action>,
) -> PacketOutEvent;
}
use std::io::Error;
pub trait OpenflowHeader {
fn version(&self) -> usize;
fn message(&self) -> u8;
fn length(&self) -> usize;
fn xid(&self) -> u32;
fn pkt_size(&self) -> usize;
fn new(message: u8, length: usize, xid: usize) -> Self;
fn header_size(&self) -> usize;
fn parse(buf: &Vec<u8>) -> Result<Self, Error>
where
Self: Sized;
fn marshal(&self, bytes: &mut Vec<u8>);
}
pub mod header_trait;
pub use header_trait::OpenflowHeader;
pub mod event_trait;
pub use event_trait::{MessageMarshal, OfpMsgEvent};
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use tenjin::{ use tenjin::example::Controller10;
openflow::ofp10::{ControllerFrame10, Msg, OfpMsgEvent, OpenflowHeader}, use tenjin::openflow::ofp10::ControllerFrame10;
Controller, use tenjin::openflow::ofp10::{Msg, OfpMsgEvent, OpenflowHeader};
};
#[test] #[test]
fn test_header_v1_0_parser() { fn test_header_v1_0_parser() {
let ofp_header_bytes: Vec<u8> = vec![1, 0, 0, 8, 0, 0, 0, 1]; let ofp_header_bytes: Vec<u8> = vec![1, 0, 0, 8, 0, 0, 0, 1];
let controller = Controller::new(); let controller = Controller10::new();
let ofp = controller.ofp(); let ofp = controller.ofp();
let header = match ofp.header_parse(&ofp_header_bytes) { let header = match ofp.header_parse(&ofp_header_bytes) {
Ok(v) => v, Ok(v) => v,
...@@ -25,7 +24,7 @@ mod tests { ...@@ -25,7 +24,7 @@ mod tests {
fn test_header_v1_0_marshal() { fn test_header_v1_0_marshal() {
let ofp_header_bytes: Vec<u8> = vec![1, 0, 0, 8, 0, 0, 0, 0]; let ofp_header_bytes: Vec<u8> = vec![1, 0, 0, 8, 0, 0, 0, 0];
let controller = Controller::new(); let controller = Controller10::new();
let ofp = controller.ofp(); let ofp = controller.ofp();
let ofp_header = ofp.header(ofp.msg_usize(Msg::Hello) as u8, 0, 0); let ofp_header = ofp.header(ofp.msg_usize(Msg::Hello) as u8, 0, 0);
let mut bytes: Vec<u8> = Vec::new(); let mut bytes: Vec<u8> = Vec::new();
......
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