1mod nicira;
7pub mod nxm;
8pub mod types;
9
10#[cfg(test)]
11mod tests;
12
13use std::net::{Ipv4Addr, Ipv6Addr};
14
15use std::fmt;
16
17use crate::match_fields::MacAddr;
18use crate::oxm::{OxmClass, OxmField};
19
20#[allow(unused_imports)]
22pub use nicira::{learn_flags, LearnSpec, NxLearn};
23pub use types::{ct_flags, nat_flags, nat_range, port, NICIRA_VENDOR_ID};
24
25use types::ActionType;
27
28use nicira::{
30 decode_nicira_action, encode_nx_ct, encode_nx_ct_nat, encode_nx_learn, encode_nx_move,
31 encode_nx_reg_load_nxm, encode_nx_resubmit, encode_set_tunnel_id,
32};
33
34pub const CT_COMMIT: u16 = ct_flags::COMMIT;
36
37#[derive(Debug, Clone)]
60pub struct NatConfig {
61 pub flags: u16,
63 pub ipv4_min: Option<Ipv4Addr>,
65 pub ipv4_max: Option<Ipv4Addr>,
67 pub ipv6_min: Option<Ipv6Addr>,
69 pub ipv6_max: Option<Ipv6Addr>,
71 pub port_min: Option<u16>,
73 pub port_max: Option<u16>,
75}
76
77impl NatConfig {
78 pub fn snat(addr: Ipv4Addr) -> Self {
80 Self {
81 flags: nat_flags::SRC,
82 ipv4_min: Some(addr),
83 ipv4_max: None,
84 ipv6_min: None,
85 ipv6_max: None,
86 port_min: None,
87 port_max: None,
88 }
89 }
90
91 pub fn snat_range(min: Ipv4Addr, max: Ipv4Addr) -> Self {
93 Self {
94 flags: nat_flags::SRC,
95 ipv4_min: Some(min),
96 ipv4_max: Some(max),
97 ipv6_min: None,
98 ipv6_max: None,
99 port_min: None,
100 port_max: None,
101 }
102 }
103
104 pub fn dnat(addr: Ipv4Addr) -> Self {
106 Self {
107 flags: nat_flags::DST,
108 ipv4_min: Some(addr),
109 ipv4_max: None,
110 ipv6_min: None,
111 ipv6_max: None,
112 port_min: None,
113 port_max: None,
114 }
115 }
116
117 pub fn dnat_range(min: Ipv4Addr, max: Ipv4Addr) -> Self {
119 Self {
120 flags: nat_flags::DST,
121 ipv4_min: Some(min),
122 ipv4_max: Some(max),
123 ipv6_min: None,
124 ipv6_max: None,
125 port_min: None,
126 port_max: None,
127 }
128 }
129
130 pub fn snat_v6(addr: Ipv6Addr) -> Self {
132 Self {
133 flags: nat_flags::SRC,
134 ipv4_min: None,
135 ipv4_max: None,
136 ipv6_min: Some(addr),
137 ipv6_max: None,
138 port_min: None,
139 port_max: None,
140 }
141 }
142
143 pub fn dnat_v6(addr: Ipv6Addr) -> Self {
145 Self {
146 flags: nat_flags::DST,
147 ipv4_min: None,
148 ipv4_max: None,
149 ipv6_min: Some(addr),
150 ipv6_max: None,
151 port_min: None,
152 port_max: None,
153 }
154 }
155
156 pub fn snat_v6_range(min: Ipv6Addr, max: Ipv6Addr) -> Self {
158 Self {
159 flags: nat_flags::SRC,
160 ipv4_min: None,
161 ipv4_max: None,
162 ipv6_min: Some(min),
163 ipv6_max: Some(max),
164 port_min: None,
165 port_max: None,
166 }
167 }
168
169 pub fn dnat_v6_range(min: Ipv6Addr, max: Ipv6Addr) -> Self {
171 Self {
172 flags: nat_flags::DST,
173 ipv4_min: None,
174 ipv4_max: None,
175 ipv6_min: Some(min),
176 ipv6_max: Some(max),
177 port_min: None,
178 port_max: None,
179 }
180 }
181
182 pub fn port(mut self, port: u16) -> Self {
184 self.port_min = Some(port);
185 self.port_max = None;
186 self
187 }
188
189 pub fn port_range(mut self, min: u16, max: u16) -> Self {
191 self.port_min = Some(min);
192 self.port_max = Some(max);
193 self
194 }
195
196 pub fn persistent(mut self) -> Self {
198 self.flags |= nat_flags::PERSISTENT;
199 self
200 }
201
202 pub fn hash(mut self) -> Self {
204 self.flags |= nat_flags::PROTO_HASH;
205 self.flags &= !nat_flags::PROTO_RANDOM;
206 self
207 }
208
209 pub fn random(mut self) -> Self {
211 self.flags |= nat_flags::PROTO_RANDOM;
212 self.flags &= !nat_flags::PROTO_HASH;
213 self
214 }
215
216 pub(crate) fn range_present(&self) -> u16 {
218 let mut flags = 0u16;
219 if self.ipv4_min.is_some() {
220 flags |= nat_range::IPV4_MIN;
221 }
222 if self.ipv4_max.is_some() {
223 flags |= nat_range::IPV4_MAX;
224 }
225 if self.ipv6_min.is_some() {
226 flags |= nat_range::IPV6_MIN;
227 }
228 if self.ipv6_max.is_some() {
229 flags |= nat_range::IPV6_MAX;
230 }
231 if self.port_min.is_some() {
232 flags |= nat_range::PROTO_MIN;
233 }
234 if self.port_max.is_some() {
235 flags |= nat_range::PROTO_MAX;
236 }
237 flags
238 }
239}
240
241#[derive(Debug, Clone)]
243pub enum Action {
244 Output(OutputPort),
246 Drop,
248 Controller { max_len: u16 },
250 SetEthSrc(MacAddr),
252 SetEthDst(MacAddr),
254 SetVlanVid(u16),
256 PushVlan(u16),
258 PopVlan,
260 SetIpv4Src(Ipv4Addr),
262 SetIpv4Dst(Ipv4Addr),
264 SetTpSrc(u16),
266 SetTpDst(u16),
268 SetTtl(u8),
270 DecTtl,
272 GotoTable(u8),
274 WriteMetadata { metadata: u64, mask: u64 },
276 Meter(u32),
278 Group(u32),
280 SetTunnelId(u64),
282 NxResubmit {
284 port: Option<u16>,
285 table: Option<u8>,
286 },
287 NxLearn(NxLearn),
289 NxCt {
291 flags: u16,
292 zone: u16,
293 table: Option<u8>,
294 },
295 NxCtNat {
297 flags: u16,
298 zone: u16,
299 table: Option<u8>,
300 nat: NatConfig,
301 },
302 NxMove {
304 src_field: u32,
306 dst_field: u32,
308 n_bits: u16,
310 src_ofs: u16,
312 dst_ofs: u16,
314 },
315 NxRegLoad {
317 dst_field: u32,
319 dst_ofs: u16,
321 n_bits: u16,
323 value: u64,
325 },
326}
327
328#[derive(Debug, Clone, Copy)]
330pub enum OutputPort {
331 Port(u32),
333 Controller,
335 Flood,
337 All,
339 InPort,
341 Local,
343 Normal,
345 None,
347}
348
349impl From<u32> for OutputPort {
350 fn from(port: u32) -> Self {
351 Self::Port(port)
352 }
353}
354
355#[derive(Debug, Clone, Default)]
357pub struct ActionList {
358 actions: Vec<Action>,
359}
360
361impl ActionList {
362 pub fn new() -> Self {
364 Self::default()
365 }
366
367 pub fn push(&mut self, action: Action) {
369 self.actions.push(action);
370 }
371
372 pub fn output(mut self, port: impl Into<OutputPort>) -> Self {
374 self.actions.push(Action::Output(port.into()));
375 self
376 }
377
378 pub fn controller(mut self, max_len: u16) -> Self {
380 self.actions.push(Action::Controller { max_len });
381 self
382 }
383
384 pub fn drop(mut self) -> Self {
386 self.actions.push(Action::Drop);
387 self
388 }
389
390 pub fn set_eth_dst(mut self, mac: MacAddr) -> Self {
392 self.actions.push(Action::SetEthDst(mac));
393 self
394 }
395
396 pub fn set_eth_src(mut self, mac: MacAddr) -> Self {
398 self.actions.push(Action::SetEthSrc(mac));
399 self
400 }
401
402 pub fn push_vlan(mut self, tpid: u16) -> Self {
404 self.actions.push(Action::PushVlan(tpid));
405 self
406 }
407
408 pub fn pop_vlan(mut self) -> Self {
410 self.actions.push(Action::PopVlan);
411 self
412 }
413
414 pub fn set_vlan_vid(mut self, vid: u16) -> Self {
416 self.actions.push(Action::SetVlanVid(vid));
417 self
418 }
419
420 pub fn goto_table(mut self, table: u8) -> Self {
422 self.actions.push(Action::GotoTable(table));
423 self
424 }
425
426 pub fn dec_ttl(mut self) -> Self {
428 self.actions.push(Action::DecTtl);
429 self
430 }
431
432 pub fn flood(mut self) -> Self {
434 self.actions.push(Action::Output(OutputPort::Flood));
435 self
436 }
437
438 pub fn all(mut self) -> Self {
440 self.actions.push(Action::Output(OutputPort::All));
441 self
442 }
443
444 pub fn normal(mut self) -> Self {
446 self.actions.push(Action::Output(OutputPort::Normal));
447 self
448 }
449
450 pub fn in_port(mut self) -> Self {
452 self.actions.push(Action::Output(OutputPort::InPort));
453 self
454 }
455
456 pub fn set_tunnel_id(mut self, tunnel_id: u64) -> Self {
458 self.actions.push(Action::SetTunnelId(tunnel_id));
459 self
460 }
461
462 pub fn group(mut self, group_id: u32) -> Self {
464 self.actions.push(Action::Group(group_id));
465 self
466 }
467
468 pub fn resubmit(mut self, port: Option<u16>, table: Option<u8>) -> Self {
473 self.actions.push(Action::NxResubmit { port, table });
474 self
475 }
476
477 pub fn resubmit_table(mut self, table: u8) -> Self {
481 self.actions.push(Action::NxResubmit { port: None, table: Some(table) });
482 self
483 }
484
485 pub fn ct(mut self, flags: u16, zone: u16, table: Option<u8>) -> Self {
491 self.actions.push(Action::NxCt { flags, zone, table });
492 self
493 }
494
495 pub fn ct_commit(mut self, zone: u16) -> Self {
499 self.actions.push(Action::NxCt { flags: CT_COMMIT, zone, table: None });
500 self
501 }
502
503 pub fn ct_nat(mut self, flags: u16, zone: u16, table: Option<u8>, nat: NatConfig) -> Self {
529 self.actions.push(Action::NxCtNat { flags, zone, table, nat });
530 self
531 }
532
533 pub fn ct_snat(mut self, zone: u16, table: Option<u8>, addr: Ipv4Addr) -> Self {
550 self.actions.push(Action::NxCtNat {
551 flags: CT_COMMIT,
552 zone,
553 table,
554 nat: NatConfig::snat(addr),
555 });
556 self
557 }
558
559 pub fn ct_dnat(mut self, zone: u16, table: Option<u8>, addr: Ipv4Addr) -> Self {
576 self.actions.push(Action::NxCtNat {
577 flags: CT_COMMIT,
578 zone,
579 table,
580 nat: NatConfig::dnat(addr),
581 });
582 self
583 }
584
585 pub fn learn(mut self, learn: NxLearn) -> Self {
589 self.actions.push(Action::NxLearn(learn));
590 self
591 }
592
593 pub fn move_field(
604 mut self,
605 src_field: u32,
606 dst_field: u32,
607 n_bits: u16,
608 src_ofs: u16,
609 dst_ofs: u16,
610 ) -> Self {
611 self.actions.push(Action::NxMove {
612 src_field,
613 dst_field,
614 n_bits,
615 src_ofs,
616 dst_ofs,
617 });
618 self
619 }
620
621 pub fn load_field(mut self, dst_field: u32, dst_ofs: u16, n_bits: u16, value: u64) -> Self {
632 self.actions.push(Action::NxRegLoad {
633 dst_field,
634 dst_ofs,
635 n_bits,
636 value,
637 });
638 self
639 }
640
641 pub fn set_arp_op(self, opcode: u16) -> Self {
645 self.load_field(nxm::ARP_OP, 0, 16, opcode as u64)
646 }
647
648 pub fn set_arp_spa(self, ip: u32) -> Self {
650 self.load_field(nxm::ARP_SPA, 0, 32, ip as u64)
651 }
652
653 pub fn set_arp_tpa(self, ip: u32) -> Self {
655 self.load_field(nxm::ARP_TPA, 0, 32, ip as u64)
656 }
657
658 pub fn set_arp_sha(self, mac: u64) -> Self {
662 self.load_field(nxm::ARP_SHA, 0, 48, mac)
663 }
664
665 pub fn set_arp_tha(self, mac: u64) -> Self {
669 self.load_field(nxm::ARP_THA, 0, 48, mac)
670 }
671
672 pub fn actions(&self) -> &[Action] {
674 &self.actions
675 }
676
677 pub fn is_empty(&self) -> bool {
679 self.actions.is_empty()
680 }
681
682 pub fn len(&self) -> usize {
684 self.actions.len()
685 }
686
687 pub fn encode(&self) -> Vec<u8> {
691 let mut buf = Vec::new();
692 for action in &self.actions {
693 buf.extend(action.encode());
694 }
695 let padding = (8 - (buf.len() % 8)) % 8;
697 buf.extend(std::iter::repeat_n(0u8, padding));
698 buf
699 }
700
701 pub fn decode(data: &[u8]) -> crate::Result<Self> {
705 let mut actions = Vec::new();
706 let mut offset = 0;
707
708 while offset < data.len() {
709 if data.len() - offset < 4 {
711 break;
712 }
713
714 let length = u16::from_be_bytes([data[offset + 2], data[offset + 3]]) as usize;
716 if length == 0 {
717 break;
718 }
719
720 let (action, consumed) = Action::decode(&data[offset..])?;
721 if !matches!(action, Action::Drop) {
723 actions.push(action);
724 }
725 offset += consumed;
726 }
727
728 Ok(Self { actions })
729 }
730}
731
732impl OutputPort {
733 pub const fn to_wire_port(self) -> u32 {
735 match self {
736 Self::Port(p) => p,
737 Self::Controller => port::CONTROLLER,
738 Self::Flood => port::FLOOD,
739 Self::All => port::ALL,
740 Self::InPort => port::IN_PORT,
741 Self::Local => port::LOCAL,
742 Self::Normal => port::NORMAL,
743 Self::None => port::NONE,
744 }
745 }
746
747 pub const fn from_wire(port_num: u32) -> Self {
749 match port_num {
750 port::CONTROLLER => Self::Controller,
751 port::FLOOD => Self::Flood,
752 port::ALL => Self::All,
753 port::IN_PORT => Self::InPort,
754 port::LOCAL => Self::Local,
755 port::NORMAL => Self::Normal,
756 port::NONE => Self::None,
757 p => Self::Port(p),
758 }
759 }
760}
761
762fn format_mac(mac: MacAddr) -> String {
764 format!(
765 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
766 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
767 )
768}
769
770impl fmt::Display for OutputPort {
771 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
772 match self {
773 Self::Port(p) => write!(f, "{p}"),
774 Self::Controller => write!(f, "CONTROLLER"),
775 Self::Flood => write!(f, "FLOOD"),
776 Self::All => write!(f, "ALL"),
777 Self::InPort => write!(f, "IN_PORT"),
778 Self::Local => write!(f, "LOCAL"),
779 Self::Normal => write!(f, "NORMAL"),
780 Self::None => write!(f, "NONE"),
781 }
782 }
783}
784
785impl fmt::Display for NatConfig {
786 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
787 write!(f, "nat(")?;
788 if self.flags & nat_flags::SRC != 0 {
789 write!(f, "src")?;
790 } else if self.flags & nat_flags::DST != 0 {
791 write!(f, "dst")?;
792 }
793 if let Some(ip) = self.ipv4_min {
794 write!(f, "={ip}")?;
795 if let Some(max) = self.ipv4_max {
796 write!(f, "-{max}")?;
797 }
798 } else if let Some(ip) = self.ipv6_min {
799 write!(f, "={ip}")?;
800 if let Some(max) = self.ipv6_max {
801 write!(f, "-{max}")?;
802 }
803 }
804 if let Some(port) = self.port_min {
805 write!(f, ":{port}")?;
806 if let Some(max) = self.port_max {
807 write!(f, "-{max}")?;
808 }
809 }
810 write!(f, ")")
811 }
812}
813
814impl fmt::Display for Action {
815 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
816 match self {
817 Self::Output(OutputPort::Normal) => write!(f, "NORMAL"),
818 Self::Output(OutputPort::Flood) => write!(f, "FLOOD"),
819 Self::Output(OutputPort::All) => write!(f, "ALL"),
820 Self::Output(OutputPort::InPort) => write!(f, "IN_PORT"),
821 Self::Output(OutputPort::Local) => write!(f, "LOCAL"),
822 Self::Output(port) => write!(f, "output:{port}"),
823 Self::Drop => write!(f, "drop"),
824 Self::Controller { max_len } => write!(f, "CONTROLLER:{max_len}"),
825 Self::SetEthSrc(mac) => write!(f, "set_eth_src:{}", format_mac(*mac)),
826 Self::SetEthDst(mac) => write!(f, "set_eth_dst:{}", format_mac(*mac)),
827 Self::SetVlanVid(vid) => write!(f, "set_vlan_vid:{vid}"),
828 Self::PushVlan(ethertype) => write!(f, "push_vlan:0x{ethertype:04x}"),
829 Self::PopVlan => write!(f, "pop_vlan"),
830 Self::SetIpv4Src(ip) => write!(f, "set_ipv4_src:{ip}"),
831 Self::SetIpv4Dst(ip) => write!(f, "set_ipv4_dst:{ip}"),
832 Self::SetTpSrc(port) => write!(f, "set_tp_src:{port}"),
833 Self::SetTpDst(port) => write!(f, "set_tp_dst:{port}"),
834 Self::SetTtl(ttl) => write!(f, "set_ttl:{ttl}"),
835 Self::DecTtl => write!(f, "dec_ttl"),
836 Self::GotoTable(table) => write!(f, "goto_table:{table}"),
837 Self::WriteMetadata { metadata, mask } => {
838 write!(f, "write_metadata:0x{metadata:x}/0x{mask:x}")
839 }
840 Self::Meter(id) => write!(f, "meter:{id}"),
841 Self::Group(id) => write!(f, "group:{id}"),
842 Self::SetTunnelId(id) => write!(f, "set_tunnel:{id:#x}"),
843 Self::NxResubmit { port, table } => {
844 let port_str = port.map_or(String::new(), |p| p.to_string());
845 let table_str = table.map_or(String::new(), |t| t.to_string());
846 write!(f, "resubmit({port_str},{table_str})")
847 }
848 Self::NxLearn(learn) => {
849 write!(f, "learn(table={}", learn.table_id)?;
850 if learn.idle_timeout > 0 {
851 write!(f, ",idle_timeout={}", learn.idle_timeout)?;
852 }
853 if learn.hard_timeout > 0 {
854 write!(f, ",hard_timeout={}", learn.hard_timeout)?;
855 }
856 if learn.priority > 0 {
857 write!(f, ",priority={}", learn.priority)?;
858 }
859 write!(f, ")")
860 }
861 Self::NxCt { flags, zone, table } => {
862 write!(f, "ct(")?;
863 let mut parts = Vec::new();
864 if *flags & types::ct_flags::COMMIT != 0 {
865 parts.push("commit".to_string());
866 }
867 if *zone != 0 {
868 parts.push(format!("zone={zone}"));
869 }
870 if let Some(t) = table {
871 parts.push(format!("table={t}"));
872 }
873 write!(f, "{})", parts.join(","))
874 }
875 Self::NxCtNat { flags, zone, table, nat } => {
876 write!(f, "ct(")?;
877 let mut parts = Vec::new();
878 if *flags & types::ct_flags::COMMIT != 0 {
879 parts.push("commit".to_string());
880 }
881 if *zone != 0 {
882 parts.push(format!("zone={zone}"));
883 }
884 if let Some(t) = table {
885 parts.push(format!("table={t}"));
886 }
887 parts.push(nat.to_string());
888 write!(f, "{})", parts.join(","))
889 }
890 Self::NxMove { src_field, dst_field, n_bits, src_ofs, dst_ofs } => {
891 write!(f, "move:NXM({src_field:#x})[{src_ofs}..{n_bits}]->NXM({dst_field:#x})[{dst_ofs}..{n_bits}]")
892 }
893 Self::NxRegLoad { dst_field, dst_ofs, n_bits, value } => {
894 write!(f, "load:{value:#x}->NXM({dst_field:#x})[{dst_ofs}..{}]", dst_ofs + n_bits)
895 }
896 }
897 }
898}
899
900impl fmt::Display for ActionList {
901 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
902 if self.actions.is_empty() {
903 return write!(f, "drop");
904 }
905 for (i, action) in self.actions.iter().enumerate() {
906 if i > 0 {
907 write!(f, ",")?;
908 }
909 write!(f, "{action}")?;
910 }
911 Ok(())
912 }
913}
914
915impl Action {
916 #[allow(clippy::match_same_arms)]
918 pub fn encode(&self) -> Vec<u8> {
919 match self {
920 Self::Output(port) => encode_output(port.to_wire_port(), 0xffff),
921 Self::Drop => Vec::new(), Self::Controller { max_len } => encode_output(port::CONTROLLER, *max_len),
923 Self::SetEthSrc(mac) => encode_set_field_mac(OxmField::EthSrc, *mac),
924 Self::SetEthDst(mac) => encode_set_field_mac(OxmField::EthDst, *mac),
925 Self::SetVlanVid(vid) => encode_set_field_u16(OxmField::VlanVid, *vid | 0x1000),
926 Self::PushVlan(ethertype) => encode_push_vlan(*ethertype),
927 Self::PopVlan => encode_pop_vlan(),
928 Self::SetIpv4Src(addr) => encode_set_field_u32(OxmField::Ipv4Src, (*addr).into()),
929 Self::SetIpv4Dst(addr) => encode_set_field_u32(OxmField::Ipv4Dst, (*addr).into()),
930 Self::SetTpSrc(port) => encode_set_field_u16(OxmField::TcpSrc, *port),
931 Self::SetTpDst(port) => encode_set_field_u16(OxmField::TcpDst, *port),
932 Self::SetTtl(ttl) => encode_set_nw_ttl(*ttl),
933 Self::DecTtl => encode_dec_ttl(),
934 Self::GotoTable(_) => Vec::new(), Self::WriteMetadata { .. } => Vec::new(), Self::Meter(_) => Vec::new(), Self::Group(group_id) => encode_group(*group_id),
938 Self::SetTunnelId(tun_id) => encode_set_tunnel_id(*tun_id),
939 Self::NxResubmit { port, table } => encode_nx_resubmit(*port, *table),
940 Self::NxLearn(learn) => encode_nx_learn(learn),
941 Self::NxCt { flags, zone, table } => encode_nx_ct(*flags, *zone, *table),
942 Self::NxCtNat { flags, zone, table, nat } => {
943 encode_nx_ct_nat(*flags, *zone, *table, nat)
944 }
945 Self::NxMove { src_field, dst_field, n_bits, src_ofs, dst_ofs } => {
946 encode_nx_move(*src_field, *dst_field, *n_bits, *src_ofs, *dst_ofs)
947 }
948 Self::NxRegLoad { dst_field, dst_ofs, n_bits, value } => {
949 encode_nx_reg_load_nxm(*dst_field, *dst_ofs, *n_bits, *value)
950 }
951 }
952 }
953
954 #[allow(clippy::too_many_lines)]
958 pub fn decode(data: &[u8]) -> crate::Result<(Self, usize)> {
959 if data.len() < 4 {
960 return Err(crate::Error::Parse("action too short".into()));
961 }
962
963 let action_type = u16::from_be_bytes([data[0], data[1]]);
964 let length = u16::from_be_bytes([data[2], data[3]]) as usize;
965
966 if data.len() < length {
967 return Err(crate::Error::Parse("action truncated".into()));
968 }
969
970 let action_type = ActionType::try_from(action_type)?;
971
972 let action = match action_type {
973 ActionType::Output => {
974 if length < 16 {
975 return Err(crate::Error::Parse("output action too short".into()));
976 }
977 let port_num = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
978 let max_len = u16::from_be_bytes([data[8], data[9]]);
979 let output_port = OutputPort::from_wire(port_num);
980 if port_num == port::CONTROLLER {
981 Self::Controller { max_len }
982 } else {
983 Self::Output(output_port)
984 }
985 }
986 ActionType::PopVlan => Self::PopVlan,
987 ActionType::PushVlan => {
988 if length < 8 {
989 return Err(crate::Error::Parse("push_vlan action too short".into()));
990 }
991 let ethertype = u16::from_be_bytes([data[4], data[5]]);
992 Self::PushVlan(ethertype)
993 }
994 ActionType::DecNwTtl => Self::DecTtl,
995 ActionType::SetNwTtl => {
996 if length < 8 {
997 return Err(crate::Error::Parse("set_nw_ttl action too short".into()));
998 }
999 Self::SetTtl(data[4])
1000 }
1001 ActionType::Group => {
1002 if length < 8 {
1003 return Err(crate::Error::Parse("group action too short".into()));
1004 }
1005 let group_id = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
1006 Self::Group(group_id)
1007 }
1008 ActionType::SetField => {
1009 decode_set_field_action(&data[4..length])?
1010 }
1011 ActionType::Experimenter => {
1012 if length < 10 {
1013 return Err(crate::Error::Parse("experimenter action too short".into()));
1014 }
1015 let vendor = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
1016 if vendor == NICIRA_VENDOR_ID {
1017 decode_nicira_action(&data[8..length])?
1018 } else {
1019 return Err(crate::Error::Parse(format!(
1021 "unknown experimenter vendor: {vendor:#x}"
1022 )));
1023 }
1024 }
1025 ActionType::CopyTtlOut
1027 | ActionType::CopyTtlIn
1028 | ActionType::SetMplsTtl
1029 | ActionType::DecMplsTtl
1030 | ActionType::PushMpls
1031 | ActionType::PopMpls
1032 | ActionType::SetQueue
1033 | ActionType::PushPbb
1034 | ActionType::PopPbb => {
1035 Self::Drop
1037 }
1038 };
1039
1040 Ok((action, length))
1041 }
1042}
1043
1044fn encode_output(port_num: u32, max_len: u16) -> Vec<u8> {
1062 let mut buf = Vec::with_capacity(16);
1063 buf.extend((ActionType::Output as u16).to_be_bytes());
1064 buf.extend(16u16.to_be_bytes()); buf.extend(port_num.to_be_bytes());
1066 buf.extend(max_len.to_be_bytes());
1067 buf.extend([0u8; 6]); buf
1069}
1070
1071fn encode_pop_vlan() -> Vec<u8> {
1073 let mut buf = Vec::with_capacity(8);
1074 buf.extend((ActionType::PopVlan as u16).to_be_bytes());
1075 buf.extend(8u16.to_be_bytes()); buf.extend([0u8; 4]); buf
1078}
1079
1080fn encode_push_vlan(ethertype: u16) -> Vec<u8> {
1082 let mut buf = Vec::with_capacity(8);
1083 buf.extend((ActionType::PushVlan as u16).to_be_bytes());
1084 buf.extend(8u16.to_be_bytes()); buf.extend(ethertype.to_be_bytes());
1086 buf.extend([0u8; 2]); buf
1088}
1089
1090fn encode_dec_ttl() -> Vec<u8> {
1092 let mut buf = Vec::with_capacity(8);
1093 buf.extend((ActionType::DecNwTtl as u16).to_be_bytes());
1094 buf.extend(8u16.to_be_bytes()); buf.extend([0u8; 4]); buf
1097}
1098
1099fn encode_set_nw_ttl(ttl: u8) -> Vec<u8> {
1101 let mut buf = Vec::with_capacity(8);
1102 buf.extend((ActionType::SetNwTtl as u16).to_be_bytes());
1103 buf.extend(8u16.to_be_bytes()); buf.push(ttl);
1105 buf.extend([0u8; 3]); buf
1107}
1108
1109fn encode_group(group_id: u32) -> Vec<u8> {
1111 let mut buf = Vec::with_capacity(8);
1112 buf.extend((ActionType::Group as u16).to_be_bytes());
1113 buf.extend(8u16.to_be_bytes()); buf.extend(group_id.to_be_bytes());
1115 buf
1116}
1117
1118fn encode_set_field_mac(field: OxmField, mac: [u8; 6]) -> Vec<u8> {
1126 let mut buf = Vec::with_capacity(16);
1127 buf.extend((ActionType::SetField as u16).to_be_bytes());
1128 buf.extend(16u16.to_be_bytes()); let oxm_header =
1132 ((OxmClass::OpenflowBasic as u32) << 16) | ((field as u32) << 9) | 6;
1133 buf.extend(oxm_header.to_be_bytes());
1134 buf.extend(mac);
1135 buf.extend([0u8; 2]); buf
1137}
1138
1139fn encode_set_field_u16(field: OxmField, value: u16) -> Vec<u8> {
1141 let mut buf = Vec::with_capacity(16);
1142 buf.extend((ActionType::SetField as u16).to_be_bytes());
1143 buf.extend(16u16.to_be_bytes()); let oxm_header =
1147 ((OxmClass::OpenflowBasic as u32) << 16) | ((field as u32) << 9) | 2;
1148 buf.extend(oxm_header.to_be_bytes());
1149 buf.extend(value.to_be_bytes());
1150 buf.extend([0u8; 6]); buf
1152}
1153
1154fn encode_set_field_u32(field: OxmField, value: u32) -> Vec<u8> {
1156 let mut buf = Vec::with_capacity(16);
1157 buf.extend((ActionType::SetField as u16).to_be_bytes());
1158 buf.extend(16u16.to_be_bytes()); let oxm_header =
1162 ((OxmClass::OpenflowBasic as u32) << 16) | ((field as u32) << 9) | 4;
1163 buf.extend(oxm_header.to_be_bytes());
1164 buf.extend(value.to_be_bytes());
1165 buf.extend([0u8; 4]); buf
1167}
1168
1169fn decode_set_field_action(data: &[u8]) -> crate::Result<Action> {
1177 if data.len() < 4 {
1178 return Err(crate::Error::Parse("set_field action too short".into()));
1179 }
1180
1181 let oxm_header = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
1182 let oxm_class = (oxm_header >> 16) as u16;
1183 let field = ((oxm_header >> 9) & 0x7f) as u8;
1184 let length = (oxm_header & 0xff) as usize;
1185
1186 if data.len() < 4 + length {
1187 return Err(crate::Error::Parse("set_field value truncated".into()));
1188 }
1189
1190 let value = &data[4..4 + length];
1191
1192 if oxm_class == OxmClass::OpenflowBasic as u16 {
1194 match field {
1195 f if f == OxmField::EthSrc as u8 && length >= 6 => {
1196 let mut mac = [0u8; 6];
1197 mac.copy_from_slice(&value[..6]);
1198 Ok(Action::SetEthSrc(mac))
1199 }
1200 f if f == OxmField::EthDst as u8 && length >= 6 => {
1201 let mut mac = [0u8; 6];
1202 mac.copy_from_slice(&value[..6]);
1203 Ok(Action::SetEthDst(mac))
1204 }
1205 f if f == OxmField::VlanVid as u8 && length >= 2 => {
1206 let vid = u16::from_be_bytes([value[0], value[1]]);
1207 Ok(Action::SetVlanVid(vid & 0x0fff))
1209 }
1210 f if f == OxmField::Ipv4Src as u8 && length >= 4 => {
1211 let addr = Ipv4Addr::new(value[0], value[1], value[2], value[3]);
1212 Ok(Action::SetIpv4Src(addr))
1213 }
1214 f if f == OxmField::Ipv4Dst as u8 && length >= 4 => {
1215 let addr = Ipv4Addr::new(value[0], value[1], value[2], value[3]);
1216 Ok(Action::SetIpv4Dst(addr))
1217 }
1218 f if f == OxmField::TcpSrc as u8 && length >= 2 => {
1219 let port = u16::from_be_bytes([value[0], value[1]]);
1220 Ok(Action::SetTpSrc(port))
1221 }
1222 f if f == OxmField::TcpDst as u8 && length >= 2 => {
1223 let port = u16::from_be_bytes([value[0], value[1]]);
1224 Ok(Action::SetTpDst(port))
1225 }
1226 f if f == OxmField::UdpSrc as u8 && length >= 2 => {
1227 let port = u16::from_be_bytes([value[0], value[1]]);
1228 Ok(Action::SetTpSrc(port))
1229 }
1230 f if f == OxmField::UdpDst as u8 && length >= 2 => {
1231 let port = u16::from_be_bytes([value[0], value[1]]);
1232 Ok(Action::SetTpDst(port))
1233 }
1234 _ => {
1235 Ok(Action::Drop)
1237 }
1238 }
1239 } else if oxm_class == OxmClass::Nxm1 as u16 {
1240 if field == 16 && length >= 8 {
1243 let tun_id = u64::from_be_bytes([
1244 value[0], value[1], value[2], value[3],
1245 value[4], value[5], value[6], value[7],
1246 ]);
1247 Ok(Action::SetTunnelId(tun_id))
1248 } else {
1249 Ok(Action::Drop)
1250 }
1251 } else {
1252 Ok(Action::Drop)
1254 }
1255}