Commit b9221574 authored by Nawasan Wisitsingkhon's avatar Nawasan Wisitsingkhon

Merge 'origin/feature/ofp13'

parents cb082850 dbafd143
pub mod ether_type;
pub mod ethernet;
pub mod packet;
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::{
* In production please remove allow unused.
*/
pub struct Controller {
#[derive(Clone)]
pub struct Controller10 {
mac_to_port: HashMap<u64, u16>,
}
impl ControllerFrame10 for Controller {
impl ControllerFrame10 for Controller10 {
fn new() -> Self {
Self {
mac_to_port: HashMap::new(),
......@@ -76,7 +77,7 @@ impl ControllerFrame10 for Controller {
}
}
impl Controller {
impl Controller10 {
fn add_flow(
&self,
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;
pub mod etherparser;
pub mod controller;
pub use controller::Controller;
\ No newline at end of file
pub mod example;
\ No newline at end of file
use tenjin::{openflow::ofp10::ControllerFrame10, Controller};
use tenjin::{example, openflow::ofp13::ControllerFrame13};
extern crate byteorder;
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(())
}
pub mod ofp10;
pub mod ofp13;
\ No newline at end of file
......@@ -9,15 +9,24 @@ use super::{
tcp_listener_handler, MessageMarshal, OfpMsgEvent, Openflow10, OpenflowHeader,
};
pub trait ControllerFrame10 {
pub trait ControllerFrame10
where
Self: 'static,
{
fn ofp(&self) -> ofp10::Openflow10 {
Openflow10::new()
}
fn packet_in_handler(&mut self, xid: u32, packetin: PacketInEvent, stream: &mut TcpStream);
fn new() -> Self;
fn listener(address: &str) {
let _ = tcp_listener_handler(address);
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)> {
......
use crate::Controller;
use std::{io::Read, net::TcpListener, thread};
use crate::openflow::ofp10::HelloEvent;
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)?;
for stream in listener.incoming() {
match stream {
Ok(mut stream) => {
if let Ok(addr) = stream.local_addr() {
if let Ok(addr) = stream.peer_addr() {
println!("server has connection from {}", addr);
}
let mut ctrl = controller.clone();
thread::spawn(move || {
let mut ctrl = Controller::new();
ctrl.send_msg(HelloEvent::new(), 0, &mut stream);
let ofp_size = ctrl.ofp().header_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,
) {
}
}
This diff is collapsed.
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()
}
}
This diff is collapsed.
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),
}
}
}
This diff is collapsed.
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)]
mod tests {
use tenjin::{
openflow::ofp10::{ControllerFrame10, Msg, OfpMsgEvent, OpenflowHeader},
Controller,
};
use tenjin::example::Controller10;
use tenjin::openflow::ofp10::ControllerFrame10;
use tenjin::openflow::ofp10::{Msg, OfpMsgEvent, OpenflowHeader};
#[test]
fn test_header_v1_0_parser() {
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 header = match ofp.header_parse(&ofp_header_bytes) {
Ok(v) => v,
......@@ -25,7 +24,7 @@ mod tests {
fn test_header_v1_0_marshal() {
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_header = ofp.header(ofp.msg_usize(Msg::Hello) as u8, 0, 0);
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