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