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

add action oxm and others

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