Commit 08048f92 authored by Nawasan Wisitsingkhon's avatar Nawasan Wisitsingkhon

instruction and flowmod

parent af4ff504
...@@ -2,7 +2,10 @@ use crate::{etherparser::MacAddr, openflow::ofp13::PseudoPort}; ...@@ -2,7 +2,10 @@ use crate::{etherparser::MacAddr, openflow::ofp13::PseudoPort};
use byteorder::{BigEndian, WriteBytesExt}; use byteorder::{BigEndian, WriteBytesExt};
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use super::flow_mod::match_fields::{OxmHeader, OxmMatchFields}; use super::flow_mod::{
instructions::{InstructActions, InstructTrait},
match_fields::{OxmHeader, OxmMatchFields},
};
struct ActionHeader { struct ActionHeader {
typ: ActionType, typ: ActionType,
...@@ -272,7 +275,7 @@ struct ActionExperimenterHeader { ...@@ -272,7 +275,7 @@ struct ActionExperimenterHeader {
pub type Buffer = u16; pub type Buffer = u16;
#[derive(Clone)] #[derive(Clone)]
#[repr(u8)] #[repr(u8)]
enum Action { pub enum Action {
Oputput(PseudoPort, Option<Buffer>), Oputput(PseudoPort, Option<Buffer>),
CopyTtlOut, // Copy TTL "outwards" -- from next-to-outermost to outermost CopyTtlOut, // Copy TTL "outwards" -- from next-to-outermost to outermost
CopyTtlIn, // Copy TTL "inwards" -- from outermost to next-to-outermost CopyTtlIn, // Copy TTL "inwards" -- from outermost to next-to-outermost
...@@ -414,3 +417,15 @@ impl Action { ...@@ -414,3 +417,15 @@ impl Action {
// pub fn parse(bytes: &mut Cursor<Vec<u8>>) -> Result<Action, Error> { // 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
}
}
#[repr(u8)]
pub enum FlowModCommand { pub enum FlowModCommand {
Add = 0, Add = 0,
Modify = 1, Modify = 1,
ModifyStrict = 2, ModifyStrict = 2,
Delete = 3, Delete = 3,
DeleteStrict = 4, DeleteStrict = 4,
Unparsable = -1, Unparsable = 0xffff,
} }
impl FlowModCommand { impl FlowModCommand {
......
...@@ -3,32 +3,49 @@ use byteorder::{BigEndian, WriteBytesExt}; ...@@ -3,32 +3,49 @@ use byteorder::{BigEndian, WriteBytesExt};
pub struct FlowModFlags { pub struct FlowModFlags {
pub send_flow_rem: bool, pub send_flow_rem: bool,
pub check_overlap: bool, pub check_overlap: bool,
pub emerg: bool, pub reset_counts: bool,
pub no_pkt_counts: bool,
pub no_byt_counts: bool,
} }
impl FlowModFlags { impl FlowModFlags {
pub fn new(send_flow_rem: bool, check_overlap: bool, emerg: bool) -> Self { pub fn new(
send_flow_rem: bool,
check_overlap: bool,
reset_counts: bool,
no_pkt_counts: bool,
no_byt_counts: bool,
) -> Self {
Self { Self {
send_flow_rem, send_flow_rem,
check_overlap, check_overlap,
emerg, reset_counts,
no_pkt_counts,
no_byt_counts,
} }
} }
pub fn all_false() -> Self { pub fn all_false() -> Self {
Self { Self {
check_overlap: false,
emerg: false,
send_flow_rem: false, send_flow_rem: false,
check_overlap: false,
reset_counts: false,
no_pkt_counts: false,
no_byt_counts: false,
} }
} }
pub fn parse(byte: u16) -> Self { pub fn parse(byte: u16) -> Self {
let send_flow_rem = byte >> 0 & 1 != 0; let send_flow_rem = byte >> 0 & 1 != 0;
let check_overlap = byte >> 1 & 1 != 0; let check_overlap = byte >> 1 & 1 != 0;
let emerg = byte >> 2 & 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 { Self {
send_flow_rem, send_flow_rem,
check_overlap, check_overlap,
emerg, reset_counts,
no_pkt_counts,
no_byt_counts,
} }
} }
pub fn marshal(&self, bytes: &mut Vec<u8>) { pub fn marshal(&self, bytes: &mut Vec<u8>) {
...@@ -39,9 +56,15 @@ impl FlowModFlags { ...@@ -39,9 +56,15 @@ impl FlowModFlags {
if self.check_overlap { if self.check_overlap {
value |= 1 << 1; value |= 1 << 1;
} }
if self.emerg { if self.reset_counts {
value |= 1 << 2; 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); let _ = bytes.write_u16::<BigEndian>(value);
} }
} }
use std::io::{Cursor, Error}; use byteorder::{BigEndian, WriteBytesExt};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use crate::openflow::ofp13::{ use crate::openflow::ofp13::{
events::{actions::SizeCheck, Action}, events::{actions::ToInstruction, Action},
ofp_port::OfpPort, ofp_port::OfpPort,
MessageMarshal, Msg, PseudoPort, MessageMarshal, Msg, PseudoPort,
}; };
use super::{FlowModCommand, FlowModFlags, MatchFields}; use super::{instructions::Instrucion, FlowModCommand, FlowModFlags, MatchFields};
pub enum Timeout { pub enum Timeout {
Permanent, Permanent,
...@@ -30,16 +28,22 @@ impl Timeout { ...@@ -30,16 +28,22 @@ impl Timeout {
} }
pub struct FlowModEvent { pub struct FlowModEvent {
command: FlowModCommand,
match_fields: MatchFields,
priority: u16,
actions: Vec<Action>,
cookie: u64, cookie: u64,
cookie_mask: u64,
table_id: u8,
command: FlowModCommand,
idle_timeout: Timeout, idle_timeout: Timeout,
hard_timeout: Timeout, hard_timeout: Timeout,
flags: FlowModFlags, priority: u16,
buffer_id: Option<u32>, buffer_id: Option<u32>,
out_port: Option<PseudoPort>, out_port: Option<PseudoPort>,
out_group: Option<PseudoPort>,
flags: FlowModFlags,
// pad: [u8; 2],
// ofp_match
match_fields: MatchFields,
instruction: Instrucion,
} }
impl FlowModEvent { impl FlowModEvent {
...@@ -47,52 +51,29 @@ impl FlowModEvent { ...@@ -47,52 +51,29 @@ impl FlowModEvent {
priority: u16, priority: u16,
match_fileds: MatchFields, match_fileds: MatchFields,
actions: Vec<Action>, actions: Vec<Action>,
table_id: u8,
buffer_id: Option<u32>, buffer_id: Option<u32>,
) -> Self { ) -> Self {
Self { Self {
command: FlowModCommand::Add,
match_fields: match_fileds,
priority,
actions,
cookie: 0, cookie: 0,
cookie_mask: 0,
table_id,
command: FlowModCommand::Add,
idle_timeout: Timeout::Permanent, idle_timeout: Timeout::Permanent,
hard_timeout: Timeout::Permanent, hard_timeout: Timeout::Permanent,
flags: FlowModFlags::all_false(), priority,
buffer_id, buffer_id,
out_port: None, out_port: None,
out_group: None,
flags: FlowModFlags::all_false(),
match_fields: match_fileds,
instruction: Instrucion::InstructActions(actions.to_instruct()),
} }
} }
pub fn parse(buf: &[u8]) -> Result<FlowModEvent, Error> { // TODO
let mut bytes = Cursor::new(buf.to_vec()); // pub fn parse(buf: &[u8]) -> Result<FlowModEvent, Error> {
let match_fields = MatchFields::parse(&mut bytes)?; // }
let cookie = bytes.read_u64::<BigEndian>()?;
let command = FlowModCommand::parse(bytes.read_u16::<BigEndian>()?);
let idle_timeout = Timeout::parse(bytes.read_u16::<BigEndian>()?);
let hard_timeout = Timeout::parse(bytes.read_u16::<BigEndian>()?);
let priority = bytes.read_u16::<BigEndian>()?;
let buffer_id = bytes.read_i32::<BigEndian>()?;
let out_port = PseudoPort::parse(bytes.read_u32::<BigEndian>()?);
let flags = bytes.read_u16::<BigEndian>()?;
let actions = Action::parse_sequence(&mut bytes);
Ok(FlowModEvent {
command,
match_fields,
cookie,
actions,
priority,
idle_timeout,
hard_timeout,
flags: FlowModFlags::parse(flags),
buffer_id: {
match buffer_id {
-1 => None,
n => Some(n as u32),
}
},
out_port,
})
}
} }
impl MessageMarshal for FlowModEvent { impl MessageMarshal for FlowModEvent {
...@@ -108,7 +89,9 @@ impl MessageMarshal for FlowModEvent { ...@@ -108,7 +89,9 @@ impl MessageMarshal for FlowModEvent {
fn marshal(&self, bytes: &mut Vec<u8>) { fn marshal(&self, bytes: &mut Vec<u8>) {
self.match_fields.marshal(bytes); self.match_fields.marshal(bytes);
let _ = bytes.write_u64::<BigEndian>(self.cookie); let _ = bytes.write_u64::<BigEndian>(self.cookie);
let _ = bytes.write_u16::<BigEndian>(self.command.to_number() as u16); 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.idle_timeout.to_int());
let _ = bytes.write_u16::<BigEndian>(self.hard_timeout.to_int()); let _ = bytes.write_u16::<BigEndian>(self.hard_timeout.to_int());
let _ = bytes.write_u16::<BigEndian>(self.priority); let _ = bytes.write_u16::<BigEndian>(self.priority);
...@@ -122,15 +105,17 @@ impl MessageMarshal for FlowModEvent { ...@@ -122,15 +105,17 @@ impl MessageMarshal for FlowModEvent {
let _ = bytes.write_u32::<BigEndian>(OfpPort::Any as u32); let _ = bytes.write_u32::<BigEndian>(OfpPort::Any as u32);
} }
} }
self.flags.marshal(bytes); match self.out_group.as_ref() {
for act in self.actions.move_controller_last() { Some(p) => p.marshal(bytes),
match act { None => {
Action::Oputput(PseudoPort::Table) => { let _ = bytes.write_u32::<BigEndian>(OfpPort::Any as u32);
panic!("Openflow table not allowed")
}
_ => (),
} }
act.marshal(bytes);
} }
self.flags.marshal(bytes);
// padding
bytes.write_u16::<BigEndian>(0);
self.match_fields.marshal(bytes);
self.instruction.marshal(bytes);
} }
} }
use byteorder::{BigEndian, WriteBytesExt};
use crate::openflow::ofp13::Action; use crate::openflow::ofp13::Action;
pub trait InstructTrait {
fn marshal(&self, bytes: &mut Vec<u8>);
}
#[derive(Clone)]
#[repr(u16)] #[repr(u16)]
pub enum InstructType { pub enum InstructType {
GotoTable = 1, GotoTable = 1,
...@@ -11,6 +18,12 @@ pub enum InstructType { ...@@ -11,6 +18,12 @@ pub enum InstructType {
Experimenter = 0xffff, Experimenter = 0xffff,
} }
impl InstructType {
pub fn marshal(&self, bytes: &mut Vec<u8>) {
bytes.write_u16::<BigEndian>(self.clone().into());
}
}
impl From<InstructType> for u16 { impl From<InstructType> for u16 {
fn from(value: InstructType) -> Self { fn from(value: InstructType) -> Self {
value as u16 value as u16
...@@ -21,20 +34,130 @@ pub struct GotoTable { ...@@ -21,20 +34,130 @@ pub struct GotoTable {
typ: InstructType, typ: InstructType,
len: u16, len: u16,
table_id: u8, table_id: u8,
pad: [u8; 3], }
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);
bytes.write_u16::<BigEndian>(self.len);
bytes.write_u8(self.table_id);
// padding
bytes.write_u16::<BigEndian>(0);
bytes.write_u8(0);
}
} }
pub struct WriteMetadata { pub struct WriteMetadata {
typ: InstructType, typ: InstructType,
len: u16, len: u16,
pad: [u8; 4],
metadata: u64, metadata: u64,
meta_mask: 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);
bytes.write_u16::<BigEndian>(self.len);
// padding
bytes.write_u32::<BigEndian>(0);
// *******
bytes.write_u64::<BigEndian>(self.metadata);
bytes.write_u64::<BigEndian>(self.meta_mask);
}
}
pub struct InstructActions { pub struct InstructActions {
typ: InstructType, typ: InstructType,
len: u16, len: u16,
pad: [u8; 4], pub actions: Vec<Action>,
action_header: 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() {
act.marshal(&mut builder);
}
self.typ.marshal(bytes);
bytes.write_u16::<BigEndian>(self.len + (builder.len() as u16));
// padding
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);
bytes.write_u16::<BigEndian>(self.len);
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),
}
}
} }
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