Commit 6c677f99 authored by Nawasan Wisitsingkhon's avatar Nawasan Wisitsingkhon

add action oxm and others

parent 36bf05c2
use byteorder::WriteBytesExt; use byteorder::WriteBytesExt;
#[derive(Clone)]
pub struct MacAddr { pub struct MacAddr {
mac: [u8; 6], mac: [u8; 6],
} }
......
use crate::{
etherparser::{
tools::bits::{bytes_to_mac, mac_to_bytes},
MacAddr,
},
openflow::ofp13::{ofp_port::OfpPort, PseudoPort},
};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::{ use std::{
io::{BufRead, Cursor, Error}, io::{BufRead, Cursor, Error},
mem::size_of, mem::size_of,
net::{Ipv4Addr, Ipv6Addr},
}; };
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use super::flow_mod::match_fields::{OxmHeader, OxmMatchFields};
use crate::{ struct ActionHeader {
etherparser::tools::bits::{bytes_to_mac, mac_to_bytes}, typ: ActionType,
openflow::ofp13::PseudoPort, // len: u16,
}; // pad: [u8; 4],
}
impl ActionHeader {
pub fn new(typ: ActionType) -> Self {
Self { typ }
}
pub fn marshal(&self, bytes: &mut Vec<u8>) {
bytes.write_u16::<BigEndian>(self.typ.clone().into());
bytes.write_u16::<BigEndian>(8);
bytes.write_u32::<BigEndian>(0);
}
}
#[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
pub enum ActionType { DecMplsTtl = 16, // Decrement MPLS TTL
Output = 0, PushVlan = 17, // Push a new VLAN tag
SetVlanId = 1, PopVlan = 18, // Pop the outer VLAN tag
SetVlanPCP = 2, PushMpls = 19, // Push a new MPLS tag
StripVlan = 3, PopMpls = 20, // Pop the outer MPLS tag
SetSrcMac = 4, SetQueue = 21, // Set queue id when outputting to a port
SetDstMac = 5, Group = 22, // Apply group.
SetIPv4Src = 6, SetNwTtl = 23, // IP TTL.
SetIPv4Des = 7, DecNwTtl = 24, // Decrement IP TTL.
SetTos = 8, SetField = 25, // Set a header field using OXM TLV format.
SetTpSrc = 9, PushPbb = 26, // Push a new PBB service tag (I-TAG)
SetTpDst = 10, PopPbb = 27, // Pop the outer PBB service tag (I-TAG)
Enqueue = 11, Experimenter = 0xffff,
}
impl ActionType {
pub fn marshal(&self, bytes: &mut Vec<u8>) {
bytes.write_u16::<BigEndian>(self.clone().into());
}
}
impl From<ActionType> for u16 {
fn from(value: ActionType) -> Self {
value as u16
}
} }
#[derive(Clone)] #[derive(Clone)]
pub enum Action { #[repr(u16)]
Oputput(PseudoPort), enum ControllerMaxLen {
SetDlVlan(Option<u16>), Custom(u16),
SetDlVlanPcp(u8), Max = 0xffe5,
SetDlSrc(u64), NoBuffer = 0xffff,
SetDlDest(u64),
SetIpSrc(u32),
SetIpDes(u32),
SetTos(u8),
SetTpSrc(u16),
SetTpDest(u16),
Enqueue(PseudoPort, u32),
Unparsable,
} }
impl Action { impl From<ControllerMaxLen> for u16 {
pub fn to_action_code(&self) -> ActionType { fn from(value: ControllerMaxLen) -> Self {
match self { match value {
Action::Oputput(_) => ActionType::Output, ControllerMaxLen::Custom(v) => v,
Action::SetDlVlan(_) => ActionType::SetVlanId, ControllerMaxLen::Max => u16::from(ControllerMaxLen::Max),
Action::SetDlVlanPcp(_) => ActionType::SetVlanPCP, ControllerMaxLen::NoBuffer => u16::from(ControllerMaxLen::NoBuffer),
Action::SetDlSrc(_) => ActionType::SetSrcMac, }
Action::SetDlDest(_) => ActionType::SetDstMac, }
Action::SetIpSrc(_) => ActionType::SetIPv4Src, }
Action::SetIpDes(_) => ActionType::SetIPv4Des,
Action::SetTos(_) => ActionType::SetTos, struct ActionOutput {
Action::SetTpSrc(_) => ActionType::SetTpSrc, typ: ActionType, // u16
Action::SetTpDest(_) => ActionType::SetTpDst, port: PseudoPort, // u32
Action::Enqueue(_, _) => ActionType::Enqueue, max_len: ControllerMaxLen,
Action::Unparsable => panic!("Unparse Action to ActionType"), }
}
} impl ActionOutput {
pub fn length(&self) -> usize { pub const LEN: usize = 16;
let header = size_of::<(u16, u16)>(); pub fn marshal(&self, bytes: &mut Vec<u8>) {
let body = match self { self.typ.marshal(bytes);
Action::Oputput(_) => size_of::<(u16, u16)>(), self.port.marshal(bytes);
Action::SetDlVlan(_) => size_of::<(u16, u16)>(), bytes.write_u16::<BigEndian>(self.max_len.clone().into());
Action::SetDlVlanPcp(_) => size_of::<(u8, [u8; 3])>(), // write padding 48 bytes [32 + 16]
Action::SetDlSrc(_) => size_of::<([u8; 6], [u8; 6])>(), bytes.write_u32::<BigEndian>(0);
Action::SetDlDest(_) => size_of::<([u8; 6], [u8; 6])>(), bytes.write_u16::<BigEndian>(0);
Action::SetIpSrc(_) => size_of::<u32>(), }
Action::SetIpDes(_) => size_of::<u32>(), pub fn new(port: PseudoPort, max_len: ControllerMaxLen) -> Self {
Action::SetTos(_) => size_of::<(u8, [u8; 3])>(), Self {
Action::SetTpSrc(_) => size_of::<(u16, u16)>(), typ: ActionType::Output,
Action::SetTpDest(_) => size_of::<(u16, u16)>(), port,
Action::Enqueue(_, _) => size_of::<(u16, [u8; 6], u32)>(), max_len,
Action::Unparsable => 0, }
}; }
header + body }
struct ActionGroup {
typ: ActionType,
len: u16,
group_id: u32,
}
impl ActionGroup {
pub const LEN: usize = 8;
pub fn marshal(&self, bytes: &mut Vec<u8>) {
self.typ.marshal(bytes);
bytes.write_u16::<BigEndian>(self.len);
bytes.write_u32::<BigEndian>(self.group_id);
}
pub fn new(group_id: u32) -> Self {
Self {
typ: ActionType::Group,
len: Self::LEN as u16,
group_id,
}
}
}
struct ActionSetQueue {
typ: ActionType,
len: u16,
queue_id: u32,
}
impl ActionSetQueue {
pub const LEN: usize = 8;
pub fn marshal(&self, bytes: &mut Vec<u8>) {
self.typ.marshal(bytes);
bytes.write_u16::<BigEndian>(self.len);
bytes.write_u32::<BigEndian>(self.queue_id);
}
pub fn new(queue_id: u32) -> Self {
Self {
typ: ActionType::SetQueue,
len: Self::LEN as u16,
queue_id,
}
} }
}
struct ActionMplsTtl {
typ: ActionType,
len: u16,
mpls_ttl: u8,
pad: [u8; 3],
}
impl ActionMplsTtl {
pub const LEN: usize = 8;
}
struct ActionNwTtl {
typ: ActionType, // OFPAT_SET_NW_TTL
len: u16, // Length is 8.
nw_ttl: u8, // IP TTL
pad: [u8; 3],
}
impl ActionNwTtl {
pub const LEN: usize = 8;
}
struct ActionPush {
typ: ActionType,
len: u16,
ethertype: u16,
pad: [u8; 2],
}
impl ActionPush {
pub const LEN: usize = 8;
}
struct ActionPopMpls {
typ: ActionType,
len: u16,
ethertype: u16,
pad: [u8; 2],
}
impl ActionPopMpls {
pub const LEN: usize = 8;
}
#[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>) { pub fn marshal(&self, bytes: &mut Vec<u8>) {
let _ = bytes.write_u16::<BigEndian>(self.to_action_code() as u16); match &self {
let _ = bytes.write_u16::<BigEndian>(self.length() as u16); SetField::InPort(port) => {
match self { OxmHeader::new(OxmMatchFields::ActsetOutput, 4).marshal(bytes);
Action::Oputput(pseudo) => { port.marshal(bytes);
pseudo.marshal(bytes); }
let _ = bytes.write_u16::<BigEndian>(match pseudo { SetField::EthDst(mac) => {
PseudoPort::Controller(w) => *w as u16, OxmHeader::new(OxmMatchFields::MacDest, 6).marshal(bytes);
_ => 0, mac.marshal(bytes);
}); }
SetField::EthSrc(mac) => {
OxmHeader::new(OxmMatchFields::MacSrc, 6);
mac.marshal(bytes);
}
SetField::EthTyp(eth) => {
OxmHeader::new(OxmMatchFields::EthernetType, 2).marshal(bytes);
bytes.write_u16::<BigEndian>(*eth);
}
SetField::IpProto(proto) => {
OxmHeader::new(OxmMatchFields::Protocol, 1).marshal(bytes);
bytes.write_u8(*proto);
}
SetField::Ipv4Src(ipv4) => {
OxmHeader::new(OxmMatchFields::IpSrc, 4).marshal(bytes);
bytes.write_u32::<BigEndian>(ipv4.clone().into());
} }
Action::SetDlVlan(None) => { SetField::Ipv4Dst(ipv4) => {
let _ = bytes.write_u32::<BigEndian>(0xffff); OxmHeader::new(OxmMatchFields::IpDst, 4).marshal(bytes);
bytes.write_u32::<BigEndian>(ipv4.clone().into());
} }
Action::SetDlVlan(Some(vid)) => { SetField::Ipv6Src(ipv6) => {
let _ = bytes.write_u16::<BigEndian>(*vid); OxmHeader::new(OxmMatchFields::Ipv6Src, 16).marshal(bytes);
let _ = bytes.write_u16::<BigEndian>(0); bytes.write_u128::<BigEndian>(ipv6.clone().into());
} }
Action::SetDlVlanPcp(pcp) => { SetField::Ipv6Dst(ipv6) => {
let _ = bytes.write_u8(*pcp); OxmHeader::new(OxmMatchFields::Ipv6Dst, 16).marshal(bytes);
for _ in 0..3 { bytes.write_u128::<BigEndian>(ipv6.clone().into());
let _ = bytes.write_u8(0);
} }
SetField::TcpSrc(tcp) => {
OxmHeader::new(OxmMatchFields::TcpSrc, 2).marshal(bytes);
bytes.write_u16::<BigEndian>(*tcp);
} }
Action::SetDlSrc(mac) | Action::SetDlDest(mac) => { SetField::TcpDst(tcp) => {
let mac = bytes_to_mac(*mac); OxmHeader::new(OxmMatchFields::TcpDst, 2).marshal(bytes);
for m in mac { bytes.write_u16::<BigEndian>(*tcp);
let _ = bytes.write_u8(m);
} }
for _ in 0..6 { SetField::UdpSrc(udp) => {
let _ = bytes.write_u8(0); OxmHeader::new(OxmMatchFields::UdpSrc, 2).marshal(bytes);
bytes.write_u16::<BigEndian>(*udp);
} }
SetField::UdpDst(udp) => {
OxmHeader::new(OxmMatchFields::UdpDst, 2).marshal(bytes);
bytes.write_u16::<BigEndian>(*udp);
} }
Action::SetIpSrc(address) | Action::SetIpDes(address) => {
let _ = bytes.write_u32::<BigEndian>(*address);
} }
Action::SetTos(n) => {
let _ = bytes.write_u8(*n);
} }
Action::SetTpSrc(pt) | Action::SetTpDest(pt) => { }
let _ = bytes.write_u16::<BigEndian>(*pt);
let _ = bytes.write_u16::<BigEndian>(0); struct ActionExperimenterHeader {
typ: ActionType,
len: u16,
experimenter: u32,
}
pub type Buffer = u16;
#[derive(Clone)]
#[repr(u8)]
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
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 {
pub 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>) {
match &self {
Action::Oputput(port, buffer) => {
self.action_type().marshal(bytes);
bytes.write_u16::<BigEndian>(16); // len
port.marshal(bytes);
if let Some(buf_id) = buffer {
bytes.write_u16::<BigEndian>(*buf_id);
} else {
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::Enqueue(pp, qid) => { Action::Experimenter(exper_id) => {
pp.marshal(bytes); self.action_type().marshal(bytes);
for _ in 0..6 { bytes.write_u16::<BigEndian>(8);
let _ = bytes.write_u8(0); bytes.write_u32::<BigEndian>(*exper_id);
} }
let _ = bytes.write_u32::<BigEndian>(*qid); 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);
} }
Action::Unparsable => (),
} }
} }
pub fn parse_sequence(bytes: &mut Cursor<Vec<u8>>) -> Vec<Action> { pub fn parse_sequence(bytes: &mut Cursor<Vec<u8>>) -> Vec<Action> {
......
use crate::openflow::ofp13::Action;
#[repr(u16)]
pub enum InstructType {
GotoTable = 1,
WriteMetadata = 2,
WriteActions = 3,
ApplyActions = 4,
ClearActions = 5,
Meter = 6,
Experimenter = 0xffff,
}
impl From<InstructType> for u16 {
fn from(value: InstructType) -> Self {
value as u16
}
}
pub struct GotoTable {
typ: InstructType,
len: u16,
table_id: u8,
pad: [u8; 3],
}
pub struct WriteMetadata {
typ: InstructType,
len: u16,
pad: [u8; 4],
metadata: u64,
meta_mask: u64,
}
pub struct InstructActions {
typ: InstructType,
len: u16,
pad: [u8; 4],
action_header: Vec<Action>,
}
...@@ -76,7 +76,7 @@ pub struct OxmHeader { ...@@ -76,7 +76,7 @@ pub struct OxmHeader {
} }
impl OxmHeader { impl OxmHeader {
fn new(field: OxmMatchFields, size: u8) -> Self { pub fn new(field: OxmMatchFields, size: u8) -> Self {
Self { Self {
class: OxmClass::OpenflowBasic, class: OxmClass::OpenflowBasic,
field, field,
...@@ -85,7 +85,7 @@ impl OxmHeader { ...@@ -85,7 +85,7 @@ impl OxmHeader {
experimenter: None, experimenter: None,
} }
} }
fn marshal(&self, bytes: &mut Vec<u8>) { pub fn marshal(&self, bytes: &mut Vec<u8>) {
bytes.write_u16::<BigEndian>(self.class.clone().into()); bytes.write_u16::<BigEndian>(self.class.clone().into());
let field: u8 = self.field.clone().into(); let field: u8 = self.field.clone().into();
bytes.write_u8(field << 1 | if self.hasmask { 1 } else { 0 }); bytes.write_u8(field << 1 | if self.hasmask { 1 } else { 0 });
......
...@@ -9,3 +9,5 @@ pub use match_fields::{Mask, MatchFields}; ...@@ -9,3 +9,5 @@ pub use match_fields::{Mask, MatchFields};
pub mod flow_mod_flags; pub mod flow_mod_flags;
pub use flow_mod_flags::FlowModFlags; pub use flow_mod_flags::FlowModFlags;
pub mod instructions;
\ No newline at end of file
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