Commit 8d6b00b8 authored by Nawasan Wisitsingkhon's avatar Nawasan Wisitsingkhon

add flowMod

parent d904d5c7
pub fn bit_bool(position: u16, byte: u16) -> bool {
(byte >> position) & 1 == 1
pub trait NumberTrait {
fn get_value(&self) -> u32;
}
impl NumberTrait for u32 {
fn get_value(&self) -> u32 {
*self as u32
}
}
impl NumberTrait for u16 {
fn get_value(&self) -> u32 {
*self as u32
}
}
pub fn bit_bool<T: NumberTrait>(position: u16, byte: T) -> bool {
(byte.get_value() >> position) & 1 == 1
}
pub fn set_bit(byte: u32, position: u32, set: bool) -> u32 {
if set {
byte | (1 << position)
} else {
byte & !(1 << position)
}
}
pub fn mac_to_bytes(byte: [u8; 6]) -> u64 {
......@@ -9,3 +32,11 @@ pub fn mac_to_bytes(byte: [u8; 6]) -> u64 {
}
u64::from_be_bytes(addr)
}
pub fn bytes_to_mac(bytes: u64) -> [u8; 6] {
let mut address = [0; 6];
for i in 0..6 {
address[i] = ((bytes >> (8 * i)) & 0xff) as u8;
}
address
}
pub enum FlowModCommand {
Add,
Modify,
ModifyStrict,
Delete,
DeleteStrict,
Unparsable,
}
impl FlowModCommand {
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 std::{
io::{BufRead, Cursor},
mem::size_of,
};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use crate::{
etherparser::tools::bits::{bytes_to_mac, mac_to_bytes},
openflow::PseudoPort,
};
use super::flow_actions_type::FlowActionType;
pub enum FlowAction {
Oputput(PseudoPort),
SetDlVlan(Option<u16>),
SetDlVlanPcp(u8),
SetDlSrc(u64),
SetDlDest(u64),
SetIpSrc(u32),
SetIpDes(u32),
SetTos(u8),
SetTpSrc(u16),
SetTpDest(u16),
Enqueue(PseudoPort, u32),
Unparsable,
}
impl FlowAction {
pub fn to_action_code(&self) -> FlowActionType {
match self {
FlowAction::Oputput(_) => FlowActionType::Output,
FlowAction::SetDlVlan(_) => FlowActionType::SetVlanId,
FlowAction::SetDlVlanPcp(_) => FlowActionType::SetVlanPCP,
FlowAction::SetDlSrc(_) => FlowActionType::SetSrcMac,
FlowAction::SetDlDest(_) => FlowActionType::SetDstMac,
FlowAction::SetIpSrc(_) => FlowActionType::SetIPv4Src,
FlowAction::SetIpDes(_) => FlowActionType::SetIPv4Des,
FlowAction::SetTos(_) => FlowActionType::SetTos,
FlowAction::SetTpSrc(_) => FlowActionType::SetTpSrc,
FlowAction::SetTpDest(_) => FlowActionType::SetTpDst,
FlowAction::Enqueue(_, _) => FlowActionType::Enqueue,
FlowAction::Unparsable => panic!("Unparse FlowAction to FlowActionType"),
}
}
pub fn length(&self) -> usize {
let header = size_of::<(u16, u16)>();
let body = match self {
FlowAction::Oputput(_) => size_of::<(u16, u16)>(),
FlowAction::SetDlVlan(_) => size_of::<(u16, u16)>(),
FlowAction::SetDlVlanPcp(_) => size_of::<(u8, [u8; 3])>(),
FlowAction::SetDlSrc(_) => size_of::<([u8; 6], [u8; 6])>(),
FlowAction::SetDlDest(_) => size_of::<([u8; 6], [u8; 6])>(),
FlowAction::SetIpSrc(_) => size_of::<u32>(),
FlowAction::SetIpDes(_) => size_of::<u32>(),
FlowAction::SetTos(_) => size_of::<(u8, [u8; 3])>(),
FlowAction::SetTpSrc(_) => size_of::<(u16, u16)>(),
FlowAction::SetTpDest(_) => size_of::<(u16, u16)>(),
FlowAction::Enqueue(_, _) => size_of::<(u16, [u8; 6], u32)>(),
FlowAction::Unparsable => 0,
};
header + body
}
pub fn marshal(&self, bytes: &mut Vec<u8>) {
let _ = bytes.write_u16::<BigEndian>(self.to_action_code() as u16);
let _ = bytes.write_u16::<BigEndian>(self.length() as u16);
match self {
FlowAction::Oputput(pseudo) => {
pseudo.marshal(bytes);
let _ = bytes.write_u16::<BigEndian>(match pseudo {
PseudoPort::Controller(w) => *w as u16,
_ => 0,
});
}
FlowAction::SetDlVlan(None) => {
let _ = bytes.write_u32::<BigEndian>(0xffff);
}
FlowAction::SetDlVlan(Some(vid)) => {
let _ = bytes.write_u16::<BigEndian>(*vid);
let _ = bytes.write_u16::<BigEndian>(0);
}
FlowAction::SetDlVlanPcp(pcp) => {
let _ = bytes.write_u8(*pcp);
for _ in 0..3 {
let _ = bytes.write_u8(0);
}
}
FlowAction::SetDlSrc(mac) | FlowAction::SetDlDest(mac) => {
let mac = bytes_to_mac(*mac);
for m in mac {
let _ = bytes.write_u8(m);
}
for _ in 0..6 {
let _ = bytes.write_u8(0);
}
}
FlowAction::SetIpSrc(address) | FlowAction::SetIpDes(address) => {
let _ = bytes.write_u32::<BigEndian>(*address);
}
FlowAction::SetTos(n) => {
let _ = bytes.write_u8(*n);
}
FlowAction::SetTpSrc(pt) | FlowAction::SetTpDest(pt) => {
let _ = bytes.write_u16::<BigEndian>(*pt);
let _ = bytes.write_u16::<BigEndian>(0);
}
FlowAction::Enqueue(pp, qid) => {
pp.marshal(bytes);
for _ in 0..6 {
let _ = bytes.write_u8(0);
}
let _ = bytes.write_u32::<BigEndian>(*qid);
}
FlowAction::Unparsable => todo!(),
}
}
pub fn parse_sequence(bytes: &mut Cursor<Vec<u8>>) -> Vec<FlowAction> {
if bytes.get_ref().is_empty() {
vec![]
} else {
let action = FlowAction::parse(bytes);
let mut v = vec![action];
v.append(&mut FlowAction::parse_sequence(bytes));
v
}
}
pub fn parse(bytes: &mut Cursor<Vec<u8>>) -> FlowAction {
let action_code = bytes.read_u16::<BigEndian>().unwrap();
let _ = bytes.read_u16::<BigEndian>().unwrap();
match action_code {
t if t == (FlowActionType::Output as u16) => {
let port_code = bytes.read_u16::<BigEndian>().unwrap();
let len = bytes.read_u16::<BigEndian>().unwrap();
FlowAction::Oputput(PseudoPort::new(port_code, Some(len as u64)))
}
t if t == (FlowActionType::SetVlanId as u16) => {
let vid = bytes.read_u16::<BigEndian>().unwrap();
bytes.consume(2);
if vid == 0xffff {
FlowAction::SetDlVlan(None)
} else {
FlowAction::SetDlVlan(Some(vid))
}
}
t if t == (FlowActionType::SetVlanPCP as u16) => {
let pcp = bytes.read_u8().unwrap();
bytes.consume(3);
FlowAction::SetDlVlanPcp(pcp)
}
t if t == (FlowActionType::StripVlan as u16) => {
bytes.consume(4);
FlowAction::SetDlVlan(None)
}
t if t == (FlowActionType::SetSrcMac as u16) => {
let mut addr = [0u8; 6];
for i in 0..6 {
addr[i] = bytes.read_u8().unwrap();
}
bytes.consume(6);
FlowAction::SetDlSrc(mac_to_bytes(addr))
}
t if t == (FlowActionType::SetDstMac as u16) => {
let mut addr = [0u8; 6];
for i in 0..6 {
addr[i] = bytes.read_u8().unwrap();
}
bytes.consume(6);
FlowAction::SetDlDest(mac_to_bytes(addr))
}
t if t == (FlowActionType::SetIPv4Src as u16) => {
FlowAction::SetIpSrc(bytes.read_u32::<BigEndian>().unwrap())
}
t if t == (FlowActionType::SetIPv4Des as u16) => {
FlowAction::SetIpDes(bytes.read_u32::<BigEndian>().unwrap())
}
t if t == (FlowActionType::SetTos as u16) => {
let tos = bytes.read_u8().unwrap();
bytes.consume(3);
FlowAction::SetTos(tos)
}
t if t == (FlowActionType::SetTpSrc as u16) => {
let pt = bytes.read_u16::<BigEndian>().unwrap();
bytes.consume(2);
FlowAction::SetTpSrc(pt)
}
t if t == (FlowActionType::SetTpDst as u16) => {
let pt = bytes.read_u16::<BigEndian>().unwrap();
bytes.consume(2);
FlowAction::SetTpDest(pt)
}
t if t == (FlowActionType::Enqueue as u16) => {
let pt = bytes.read_u16::<BigEndian>().unwrap();
bytes.consume(6);
let qid = bytes.read_u32::<BigEndian>().unwrap();
FlowAction::Enqueue(PseudoPort::new(pt, Some(0)), qid)
}
_ => FlowAction::Unparsable,
}
}
}
/*
* it don't need to assign vlue.
* but I think I should assign for reading.
*/
pub enum FlowActionType {
Output = 0,
SetVlanId = 1,
SetVlanPCP = 2,
StripVlan = 3,
SetSrcMac = 4,
SetDstMac = 5,
SetIPv4Src = 6,
SetIPv4Des = 7,
SetTos = 8,
SetTpSrc = 9,
SetTpDst = 10,
Enqueue = 11,
}
\ No newline at end of file
use std::io::Cursor;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use crate::openflow::{OfpPort, PseudoPort};
use super::{FlowAction, FlowModCommand, 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 FlowMod {
command: FlowModCommand,
match_fields: MatchFields,
priority: u16,
actions: Vec<FlowAction>,
cookie: u64,
idle_timeout: Timeout,
hard_timeout: Timeout,
notify_when_removed: bool,
apply_to_packet: Option<u32>,
out_port: Option<PseudoPort>,
check_overlap: bool,
}
impl FlowMod {
pub fn get_controller_last(actions: Vec<FlowAction>) -> Vec<FlowAction> {
let mut not_ctrl: Vec<FlowAction> = Vec::new();
let mut is_ctrl: Vec<FlowAction> = Vec::new();
for act in actions {
match act {
FlowAction::Oputput(PseudoPort::Controller(_)) => {
is_ctrl.push(act);
}
_ => not_ctrl.push(act),
}
}
not_ctrl.append(&mut is_ctrl);
not_ctrl
}
pub fn size_of() -> usize {
24
}
pub fn parse(buf: &[u8]) -> FlowMod {
let mut bytes = Cursor::new(buf.to_vec());
let match_fields = MatchFields::parse(&mut bytes);
let cookie = bytes.read_u64::<BigEndian>().unwrap();
let command = FlowModCommand::parse(bytes.read_u16::<BigEndian>().unwrap());
let idle_timeout = Timeout::parse(bytes.read_u16::<BigEndian>().unwrap());
let hard_timeout = Timeout::parse(bytes.read_u16::<BigEndian>().unwrap());
let priority = bytes.read_u16::<BigEndian>().unwrap();
let buffer_id = bytes.read_i32::<BigEndian>().unwrap();
let out_port = PseudoPort::parse(bytes.read_u16::<BigEndian>().unwrap());
let flags = bytes.read_u16::<BigEndian>().unwrap();
let actions = FlowAction::parse_sequence(&mut bytes);
FlowMod {
command,
match_fields,
cookie,
actions,
priority,
idle_timeout,
hard_timeout,
notify_when_removed: flags & 1 != 0,
apply_to_packet: {
match buffer_id {
-1 => None,
n => Some(n as u32),
}
},
out_port,
check_overlap: flags & 2 != 0,
}
}
pub fn marshal(flowmod: FlowMod, bytes: &mut Vec<u8>) {
flowmod.match_fields.marshal(bytes);
let _ = bytes.write_u64::<BigEndian>(flowmod.cookie);
let _ = bytes.write_u16::<BigEndian>(flowmod.command as u16);
let _ = bytes.write_u16::<BigEndian>(flowmod.idle_timeout.to_int());
let _ = bytes.write_u16::<BigEndian>(flowmod.hard_timeout.to_int());
let _ = bytes.write_u16::<BigEndian>(flowmod.priority);
let _ = bytes.write_i32::<BigEndian>(match flowmod.apply_to_packet {
None => -1,
Some(buf_id) => buf_id as i32,
});
match flowmod.out_port {
None => bytes.write_u16::<BigEndian>(OfpPort::None as u16).unwrap(),
Some(p) => p.marshal(bytes),
}
let _ = bytes.write_u16::<BigEndian>(
(if flowmod.check_overlap { 1 << 1 } else { 0 })
| (if flowmod.notify_when_removed {
1 << 0
} else {
0
}),
);
for act in FlowMod::get_controller_last(flowmod.actions) {
match act {
FlowAction::Oputput(PseudoPort::Table) => {
panic!("Openflow table not allowed")
}
_ => (),
}
}
}
}
use std::io::{BufRead, Cursor};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use crate::etherparser::tools::bits::{bit_bool, mac_to_bytes, set_bit};
pub struct Mask<T> {
pub ip: T,
pub mask: Option<T>,
}
impl Mask<u32> {
pub fn to_int(&self) -> u32 {
match self.mask {
Some(v) => v,
None => 0,
}
}
}
struct Wildcards {
pub in_port: bool,
pub mac_dest: bool,
pub mac_src: bool,
pub ethernet_type: bool,
pub vlan_vid: bool,
pub vlan_pcp: bool,
pub ip_src: u32,
pub ip_dest: u32,
pub protocol: bool,
pub tos: bool,
pub transport_src: bool,
pub transport_dest: bool,
}
impl Wildcards {
pub fn parse(byte: u32) -> Wildcards {
Wildcards {
in_port: bit_bool(0, byte),
vlan_vid: bit_bool(1, byte),
mac_src: bit_bool(2, byte),
mac_dest: bit_bool(3, byte),
ethernet_type: bit_bool(4, byte),
protocol: bit_bool(5, byte),
transport_src: bit_bool(6, byte),
transport_dest: bit_bool(7, byte),
ip_src: Wildcards::get_nw_mask(byte, 8),
ip_dest: Wildcards::get_nw_mask(byte, 14),
vlan_pcp: bit_bool(20, byte),
tos: bit_bool(21, byte),
}
}
pub fn get_nw_mask(f: u32, offset: usize) -> u32 {
(f >> offset) & 0x3f
}
}
pub struct MatchFields {
pub in_port: Option<u16>,
pub mac_dest: Option<u64>,
pub mac_src: Option<u64>,
pub ethernet_type: Option<u16>,
pub vlan_vid: Option<u16>, // vlan type
pub vlan_pcp: Option<u8>,
pub ip_src: Option<Mask<u32>>,
pub ip_dest: Option<Mask<u32>>,
pub protocol: Option<u8>,
pub tos: Option<u8>,
pub transport_src: Option<u16>,
pub transport_dest: Option<u16>,
}
impl MatchFields {
pub fn marshal(self, bytes: &mut Vec<u8>) {
let mut match_f = 0u32;
match_f = set_bit(match_f, 0, self.in_port.is_some());
match_f = set_bit(match_f, 1, self.vlan_vid.is_some());
match_f = set_bit(match_f, 2, self.mac_src.is_some());
match_f = set_bit(match_f, 3, self.mac_dest.is_some());
match_f = set_bit(match_f, 4, self.ethernet_type.is_some());
match_f = set_bit(match_f, 5, self.protocol.is_some());
match_f = set_bit(match_f, 6, self.ip_src.is_some());
match_f = set_bit(match_f, 7, self.ip_dest.is_some());
match_f = MatchFields::set_nw_mask(match_f, 8, self.ip_src.unwrap().ip);
match_f = MatchFields::set_nw_mask(match_f, 14, self.ip_dest.unwrap().ip);
match_f = set_bit(match_f, 20, self.vlan_pcp.is_some());
match_f = set_bit(match_f, 21, self.tos.is_some());
bytes.write_u32::<BigEndian>(match_f).unwrap();
}
pub fn set_nw_mask(byte: u32, offset: usize, set: u32) -> u32 {
let value = (0x3f & set) << offset;
byte | value
}
pub fn get_ns_mask(byte: u32, offset: usize) -> u32 {
(byte >> offset) & 0x3f
}
pub fn parse(bytes: &mut Cursor<Vec<u8>>) -> MatchFields {
let wildcards = Wildcards::parse(bytes.read_u32::<BigEndian>().unwrap());
let in_port = if wildcards.in_port {
None
} else {
Some(bytes.read_u16::<BigEndian>().unwrap())
};
let mac_src = if wildcards.mac_src {
None
} else {
let mut arr: [u8; 6] = [0; 6];
for i in 0..6 {
arr[i] = bytes.read_u8().unwrap();
}
Some(mac_to_bytes(arr))
};
let mac_dest = if wildcards.mac_dest {
None
} else {
let mut arr: [u8; 6] = [0; 6];
for i in 0..6 {
arr[i] = bytes.read_u8().unwrap();
}
Some(mac_to_bytes(arr))
};
let vlan_vid = if wildcards.vlan_vid {
None
} else {
let vid = bytes.read_u16::<BigEndian>().unwrap();
if vid == 0xfff {
None
} else {
Some(bytes.read_u16::<BigEndian>().unwrap())
}
};
let vlan_pcp = if wildcards.vlan_pcp {
None
} else {
Some(bytes.read_u8().unwrap())
};
bytes.consume(1);
let ethernet_type = if wildcards.ethernet_type {
None
} else {
Some(bytes.read_u16::<BigEndian>().unwrap())
};
let tos = if wildcards.tos {
None
} else {
Some(bytes.read_u8().unwrap())
};
let protocol = if wildcards.protocol {
None
} else {
Some(bytes.read_u8().unwrap())
};
bytes.consume(2);
let ip_src = if wildcards.ip_src >= 32 {
None
} else if wildcards.ip_src == 0 {
Some(Mask {
ip: bytes.read_u32::<BigEndian>().unwrap(),
mask: None,
})
} else {
Some(Mask {
ip: bytes.read_u32::<BigEndian>().unwrap(),
mask: Some(wildcards.ip_src),
})
};
let ip_dest = if wildcards.ip_dest >= 32 {
None
} else if wildcards.ip_dest == 0 {
Some(Mask {
ip: bytes.read_u32::<BigEndian>().unwrap(),
mask: None,
})
} else {
Some(Mask {
ip: bytes.read_u32::<BigEndian>().unwrap(),
mask: Some(wildcards.ip_dest),
})
};
let transport_src = if wildcards.transport_src {
None
} else {
Some(bytes.read_u16::<BigEndian>().unwrap())
};
let transport_dest = if wildcards.transport_dest {
None
} else {
Some(bytes.read_u16::<BigEndian>().unwrap())
};
MatchFields {
in_port,
mac_src,
mac_dest,
ethernet_type,
vlan_vid,
vlan_pcp,
ip_src,
ip_dest,
protocol,
tos,
transport_src,
transport_dest,
}
}
}
pub mod flow_mod_handler;
pub mod command;
pub use command::FlowModCommand;
pub mod flow_actions;
pub use flow_actions::FlowAction;
pub mod flow_actions_type;
pub use flow_actions_type::FlowActionType;
pub mod match_fields;
pub use match_fields::{Mask, MatchFields};
pub mod packet_in;
pub use packet_in::{PacketInEvent, PacketInReason};
pub mod flow_mod;
......@@ -7,4 +7,7 @@ pub use message::Msg;
pub mod controller;
pub use controller::Controller;
pub mod events;
\ No newline at end of file
pub mod events;
pub mod ofp_port;
pub use ofp_port::{OfpPort, PseudoPort};
\ No newline at end of file
use byteorder::{BigEndian, WriteBytesExt};
pub enum OfpPort {
Max = 0xff00,
InPort = 0xfff8,
Table = 0xfff9,
Normal = 0xfffa,
Flood = 0xfffb,
All = 0xfffc,
Controller = 0xfffd,
Local = 0xfffe,
None = 0xffff,
}
pub enum PseudoPort {
PhysicalPort(u16),
InPort,
Table,
Normal,
Flood,
AllPorts,
Controller(u64),
Local,
Unsupport,
}
impl PseudoPort {
pub fn parse(byte: u16) -> Option<PseudoPort> {
if (OfpPort::None as u16) == byte {
None
} else {
Some(PseudoPort::new(byte, Some(0)))
}
}
pub fn new(port: u16, len: Option<u64>) -> PseudoPort {
match port {
p if p == (OfpPort::InPort as u16) => PseudoPort::InPort,
p if p == (OfpPort::Table as u16) => PseudoPort::Table,
p if p == (OfpPort::Normal as u16) => PseudoPort::Normal,
p if p == (OfpPort::Flood as u16) => PseudoPort::Flood,
p if p == (OfpPort::All as u16) => PseudoPort::AllPorts,
p if len.is_some() && p == (OfpPort::Controller as u16) => {
PseudoPort::Controller(len.unwrap())
}
p if p == (OfpPort::Local as u16) => PseudoPort::InPort,
_ => {
if port <= (OfpPort::Max as u16) {
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 u16,
PseudoPort::Table => OfpPort::Table as u16,
PseudoPort::Normal => OfpPort::Normal as u16,
PseudoPort::Flood => OfpPort::Flood as u16,
PseudoPort::AllPorts => OfpPort::All as u16,
PseudoPort::Controller(_) => OfpPort::Controller as u16,
PseudoPort::Local => OfpPort::Local as u16,
// not sure how to handle unsupport
PseudoPort::Unsupport => OfpPort::Flood as u16,
};
let _ = bytes.write_u16::<BigEndian>(port);
}
}
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